راهی وجود دارد که خطاهای پارسر دست کم در حالت Debug نشان داده شوند؟
راهی وجود دارد که خطاهای پارسر دست کم در حالت Debug نشان داده شوند؟
CREATE DATABASE [BloggingCore2016] GO USE [BloggingCore2016] GO CREATE TABLE [Blog] ( [BlogId] int NOT NULL IDENTITY, [Url] nvarchar(max) NOT NULL, CONSTRAINT [PK_Blog] PRIMARY KEY ([BlogId]) ); GO CREATE TABLE [Post] ( [PostId] int NOT NULL IDENTITY, [BlogId] int NOT NULL, [Content] nvarchar(max), [Title] nvarchar(max), CONSTRAINT [PK_Post] PRIMARY KEY ([PostId]), CONSTRAINT [FK_Post_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([BlogId]) ON DELETE CASCADE ); GO INSERT INTO [Blog] (Url) VALUES ('https://www.dntips.ir/'), ('http://blogs.msdn.com/dotnet'), ('http://blogs.msdn.com/webdev'), ('http://blogs.msdn.com/visualstudio') GO
dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose
public partial class MyDBDataContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true"); }
Usage: dotnet ef dbcontext scaffold [arguments] [options] Arguments: [connection] The connection string of the database [provider] The provider to use. For example, Microsoft.EntityFrameworkCore.SqlServer Options: -a|--data-annotations Use DataAnnotation attributes to configure the model where possible. If omitted, the output code will use only the fluent API. -c|--context <name> Name of the generated DbContext class. -f|--force Force scaffolding to overwrite existing files. Otherwise, the code will only proceed if no output files would be overwritten. -o|--output-dir <path> Directory of the project where the classes should be output. If omitted, the top-level project directory is used. --schema <schema> Selects a schema for which to generate classes. -t|--table <schema.table> Selects a table for which to generate classes. -e|--environment <environment> The environment to use. If omitted, "Development" is used. -h|--help Show help information -v|--verbose Enable verbose output
dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose --force --data-annotations
dotnet ef migrations add InitialDatabase
using Microsoft.EntityFrameworkCore.Migrations; namespace Core1RtmEmptyTest.DataLayer.Migrations { public partial class InitialDatabase : Migration { protected override void Up(MigrationBuilder migrationBuilder) { } protected override void Down(MigrationBuilder migrationBuilder) { } } }
dotnet ef database update
dotnet ef migrations add v2 dotnet ef database update
Create VIEW EmployeesView
AS
SELECT id,
FirstName
FROM Employees
using System.ComponentModel.DataAnnotations;
namespace EF_Sample04.Models
{
[Table("EmployeesView")]
public class EmployeesView
{
public int Id { set; get; }
public string FirstName { set; get; }
}
}
There is already an object named 'EmployeesView' in the database.
Database.SetInitializer<Sample04Context>(null);
Add-Migration Init -IgnoreChanges
Update-Database
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;
namespace EF_Sample04.Models
{
public class MyXMLTable
{
public int Id { get; set; }
[Column(TypeName = "xml")]
public string XmlValue { get; set; }
[NotMapped]
public XElement XmlValueWrapper
{
get { return XElement.Parse(XmlValue); }
set { XmlValue = value.ToString(); }
}
}
}
namespace EF_Sample04.Models
{
public class ActivityType
{
public int UserId { set; get; }
public int ActivityID { get; set; }
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample04.Models;
namespace EF_Sample04.Mappings
{
public class ActivityTypeConfig : EntityTypeConfiguration<ActivityType>
{
public ActivityTypeConfig()
{
this.HasKey(x => new { x.ActivityID, x.UserId });
}
}
}
var activity1 = db.ActivityTypes.Find(4, 1);
using System.Collections.Generic;
namespace EF_Sample04.Models
{
public class Employee
{
public int Id { set; get; }
public string FirstName { get; set; }
public string LastName { get; set; }
//public int? ManagerID { get; set; }
public virtual Employee Manager { get; set; }
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample04.Models;
namespace EF_Sample04.Mappings
{
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
public EmployeeConfig()
{
this.HasOptional(x => x.Manager)
.WithMany()
//.HasForeignKey(x => x.ManagerID)
.WillCascadeOnDelete(false);
}
}
}
FormsAuthentication.SetAuthCookie(... // ... FormsAuthentication.RedirectFromLoginPage(...
پروسه Full Load شامل مراحل زیر بود:
روی هم رفته Full Load مسئله ای مشکل ساز بود، زیرا نیاز به زمانی برای بارگذاری مجدد دادهها داشت و مسئلهی مهمتر نداشتن امکان دستیابی به گزارشاتی تاریخچه ای با ماهیت زمان برای مشتریان کسب وکار بود. به این دلیل که همواره یک کپی از آخرین دادههای موجود در سیستم عملیاتی درون DW قرار میگرفت؛ که با بکارگیری Full Load اغلب قادر به ارائهی این نوع از گزارشات نبودیم، بدین ترتیب سازمانها به نسل دوم روی آورند که در این دیدگاه از مفهوم Incremental Load استفاده میشود. اشکال زیر مراحلی که در این روش انجام میشود را نمایان میسازد:
Incremental Load with an Extract In area
Incremental Load without an Extract In area
مراحل Incremental Load شامل:
تفاوتهای اصلی میان Full Load و Incremental Load در این است که در Incremental Load:
ترکیب این عوامل برای ساخت Incremental Load کارآمد تر، منجر به پیچیدهتر شدن پیاده سازی و نگهداری آن نیز میشود.
فرآیند لود افزایشی ETL، بایست قادر به شناسائی رکوردهای تغییریافته در مبداء باشد، که این عمل با استفاده از هر یک از تکنیکهای Push یا Pull انجام میشود.
- ایدهآل وجود داشتن یک ستون Last Changed در سیستم مبداء است؛ که از آن میتوان جهت انتخاب رکوردهای تغییر یافته استفاده نمود.
- چنانچه ستون Last Changed وجود نداشته باشد، تمامی رکوردهای مبداء باید با رکوردهای مقصد مقایسه شود.
تفاوت این دو روش به شرح زیر است:
مسئله ای که در هر دو مورد وجود دارد Load اضافه ای است؛ که روی سیستم مبداء وجود دارد و میتواند Performance سیستمهای OLTP را تحت تاثیر قرار دهد. به هر روی سناریو نخست معمولاً کاراتر از سناریویی است که از Trigger استفاده میکند.
پس از شناسائی رکوردهایی که در مبداء تغییر یافته اند، نیاز داریم تا این تغییرات در مقصد اعمال شود. در این قسمت به معرفی الگوهایی که برای اعمال این تغییرات وجود دارد میپردازیم.
تشخیص چگونگی اضافه نمودن تغییرات در مقصد تابع دو عامل زیر است:
فلوچارت زیر نشان میدهد، به چه شکل جداول مقصد متاثر از چگونگی پردازش رکوردهای مبداء قرار دارند. توجه داشته باشید که عمل بررسی بطور جداگانه و در یک لحظه صورت میگیرد.
Kimball Type II Slowly Changing Dimension نمونه ای از الگوی Versioned Insert است؛ که در آن نمونه ای از یک موجودیت دارای ورژنهای متعددی است. مطابق تصویر زیر؛ این الگو به ستونهای اضافه ای نیاز دارند که وضعیت نمونه ای از یک رکورد را نمایش دهد.
این ستونها به شرح زیر هستند:
برای مثال شکل زیر؛ بیانگر وضعیت اولیه رکوردی در این الگو است:
فرض کنید که این رکورد در تاریخ March 2 , 2010 در سیستم مبداء تغییر میکند. فرآیند ETL این تغییر را شناسائی میکند و همانند تصویر زیر؛ به شکل نمونه ای ثانویه از این رکورد، اقدام به درج آن میکند.
توجه داشته باشید زمانی که رکورد دوم در جدول درج میشود، به منظور بازتاب این تغییر؛ رکورد اول به شکل زیر بروزرسانی میگردد:
در برخی از پیاده سازیهای DW عمدتاً از الگوی Versioned Insert استفاده میشود و هرگز از الگوی Update استفاده نمیشود. مزیت این استراتژی در این است که تمامی تاریخچه تغییرات ردیابی و ثبت میشود. به هر روی غالباً هزینه ثبت کردن این تغییرات منجر به ایجاد نسخههای زیادی از تغییرات میشود. تیم DW برای مواردی که تغییرات متاثر از گزارشات تاریخچه ای نیستند، میتوانند الگوی Update را در نظر گیرند.
الگوی Update روی رکورد موجود، تغییرات سیستم مبداء را بروزرسانی میکند. مزیت این روش در این است که همواره یک رکورد وجود دارد و در نتیجه باعث ایجاد Queryهای کارآمدتر میشود. تصویر زیر بیانگر ستون هایی است که برای پشتیبانی از الگوی Update بایست ایجاد کرد.
این ستونها به شرح زیر هستند:
موارد اصلی الگوی Update عبارتند از:
یک روش دیگر برای در نظر گرفتن موارد فوق؛ اضافه کردن یک جدول برای درج ورژنها به الگوی Update است که در شکل زیر نشان داده شده است.
اضافه نمودن یک جدول تاریخچه، که تمامی تغییرات سیستم مبداء را ثبت میکند؛ نظارت و ممیزی دادهها را نیز فراهم میکند و همچنین بروزرسانیهای کارآمد مبتنی بر مجموعه را برای جداول DW به ارمغان میآورد.
این الگو غالباً در جداول حجیم Fact که بروزرسانی آنها پر هزینه است استفاده میشود. شکل زیر منطق استفاده شده در این الگو را نشان میدهد.
توجه داشته باشید در این الگو:
هم اکنون پس از آشنایی با مفاهیم و الگوهای توزیع دادهها به ارائه تعدادی نمونه میپردازیم؛ که بتوان این ایدهها و الگوها را در عمل پوشش داد.
هر یک از الگوهای Update Pattern و Versioned Insert Pattern میتوانند برای انواعی از جداول بکار روند که معروفترین آنها توسط Kimball ساخته شده اند.
مطابق تصویر زیر جدولی که تنها حاوی ورژن فعلی رکورد هاست؛ از Update Dataflow Pattern استفاده میکند.
مواردی که در مورد این گردش کاری باید در نظر داشت به شرح زیر است:
- راه دیگر فرستادن تغییرات رکوردها به یک جدول کاری است که پس از پایان یافتن فرآیند Update ، خالی (Truncate) میشود.
- مزیت نگهداری تمامی رکوردها در یک جدول تاریخچه؛ ایجاد یک دنباله ممیزی است که میتواند برای نظارت بر دادهها به منظور نمایان ساختن موارد مطرح شده توسط مصرف کنندههای کسب و کار استفاده شود.
شکل زیر نمایش دهنده چگونگی پیاده سازی Update Dataflow Pattern در یک SSIS میباشد:
این SSIS شامل عناصر زیر است:
به منظور تشخیص اینکه رکورد در جدول مقصد وجود دارد از “lkpPersonContact” استفاده میکنیم.
با استفاده از “DidRecordChange” مبداء و مقصد مقایسه میشوند. اگر تفاوتی بین مبداء و مقصد وجود نداشت؛ رکورد نادیده گرفته میشود. چنانچه بین مبداء و مقصد تفاوت وجود داشت؛ رکورد در جدول تاریخچه درج خواهد شد.
رکوردها در جدول مقصد درج خواهند شد در صورتیکه در آن وجود نداشته باشند.
رکوردها در جدول تاریخچه مقصد درج خواهند شد، در صورتیکه (در مقصد) وجود داشته باشند.
پس از اتمام Data Flow یک روال Post-processing مسئولیت بروزرسانی رکوردهای جدول اصلی و رکوردهای ذخیره شده در جدول تاریخچه را بر عهده دارد که میتواند مطابق تصویر زیر با استفاده از یک Execute Process Task پیاده سازی شود.
PostProcess مسئولیت اجرای تمامی فعالیتهای زیر را در این الگو برعهده دارد که شامل:
تصویر زیر بیانگر انجام این عملیات با استفاده از ابزارهای ETL است.
در نگاه نخستین ممکن است Data Flow از نوع اصلی خود پیچیدهتر به نظر آید؛ که در واقع این گونه نیز هست، زیرا در فاز توسعه بیشتر Frameworkها جهت پیاده سازی به یک زمان اضافهتری نیاز دارند. به هر روی این زمان جهت اجتناب از هزینه روزانه تطبیق دادهها گرفته خواهد شد.
مزایای حاصل شده از افزودن این منطق اضافی عبارت است از:
بهره برداران ETL و ناظران اطلاعات میتوانند با استفاده از خلاصه تعداد رکوردها درک بیشتری درباره فعالیتهای آن کسب کنند. پس از آنکه تعداد رکوردها، مشکوک به نظر آمد؛ تحقیقات بیشتری میتواند اتفاق افتد. (با عمیقتر شدن در جزئیات گزارشات)
جدولی که به صورت Versioned Insert پر شده است میتواند از Versioned Insert Dataflow Pattern استفاده کند. همانند شکل زیر که گردش کار در آن برای کارآئی بیشتر بازنگری شده است.
توجه داشته باشید Data Flow در این روش شامل:
شکل زیر SSIS versioned insert data flow pattern را نشان میدهد:
تعدادی نکته در Data Flow فوق وجود دارد که عبارتند از:
الگوی Versioned Insert نسبت الگوی Update دارای پیاده سازی سادهتر و فعالیتهای I/O کمتری است. از منظر دیگر، جدولی که از الگوی Update استفاده میکند، دارای تعداد رکوردهای کمتری است که میتواند به معنای Performance بهتر نیز تعبیر شود. ممکن است سوالی مطرح شود، اینکه چرا برای انجام کار به جدول تاریخچه نیاز است؛ این جدول را که نمیتوان Truncate نمود، پس چرا به منظور بروزرسانی از جدول اصلی استفاده میشود؟ پاسخ این پرسش در این است که جدول تاریخچه، ناظر اطلاعات و ممیزین داده را قادر میسازد، تغییرات در طول زمان را پیگیری نمایند.
بروزرسانی Dimension موارد زیر را شامل میشود:
چنانچه با یک Dimension کوچک مواجه هستید (با مقدار هزاران رکورد یا کمتر، که با صدها هزار رکورد یا بیشتر ضدیت دارد)، میتوانید از تبدیل “Slowly Changing Dimension” که بصورت Built-in در SSIS موجود است، استفاده نمائید. به هر روی با آنکه این تبدیل چندین ویژگی محدودکننده Performance دارد، اغلب کارآمدتر از پروسسه هایی که توسط خودتان ایجاد میشود. در واقع فرآیند بارگذاری در جداول Dimension با مقایسه دادهها بین مبداء و مقصد انجام میشود. به طور معمول مقایسه روی یک ورژن جدید و یا مجموعه ای از سطرهای جدید یک جدول با مجموعه دادههای موجود در جدول متناظرش صورت میگیرد. پس از تشخیص چگونگی تغییر در داده ها، یک سری عملیات درج و بروزرسانی انجام میشود. شکل زیر نمونه ای از پردازش سریع در Dimension را نمایش میدهد؛ که شامل مراحل اساسی زیر است:
با Merge Join ارتباطی بین رکوردهای مبداء و رکوردهای مقصد برقرار میشود. (در این مثال “CustomerAlternateKey”). هنگامی که از این دیدگاه استفاده میکنید، خاطر جمع شوید که نوع Join با مقدار “Left outer join” تنظیم شده است؛ بدین ترتیب قادر هستید تا رکوردهای جدید را از مبداء تشخیص دهید؛ از آنجا که هنوز در جدول Dimension قرار نگرفته اند.
گام پایانی به منظور تشخیص اینکه آیا رکورد، جدید یا تغییر یافته است (یا بلاتکلیف است)، مقایسه داده هاست. شکل زیر نمایش میدهد چگونه این ارزیابی با استفاده از تبدیل “Conditional Spilt” صورت میگیرد.
Conditional Spilt مستقیماً با استفاده از یک Adapter تعریف شده روی مقصد یا یک جدول کاری بروزرسانی که از یک Adapter تعریف شده روی مقصد استفاده میکند؛ توسط مجموعه دستور Update زیر، رکوردها را در جدول Dimension قرار میدهد. دستور Update زیر مستقیماً با استفاده از روش Join روی جدول Dimension و جدول کاری، مجموعه ای را بصورت انبوه بروزرسانی میکند.
UPDATE AdventureWorksDW2008R2.dbo.DimCustomer SET AddressLine1 = stgDimCustomerUpdates.AddressLine1 , AddressLine2 = stgDimCustomerUpdates.AddressLine2 , BirthDate = stgDimCustomerUpdates.BirthDate , CommuteDistance = stgDimCustomerUpdates.CommuteDistance , DateFirstPurchase = stgDimCustomerUpdates.DateFirstPurchase , EmailAddress = stgDimCustomerUpdates.EmailAddress , EnglishEducation = stgDimCustomerUpdates.EnglishEducation , EnglishOccupation = stgDimCustomerUpdates.EnglishOccupation , FirstName = stgDimCustomerUpdates.FirstName , Gender = stgDimCustomerUpdates.Gender , GeographyKey = stgDimCustomerUpdates.GeographyKey , HouseOwnerFlag = stgDimCustomerUpdates.HouseOwnerFlag , LastName = stgDimCustomerUpdates.LastName , MaritalStatus = stgDimCustomerUpdates.MaritalStatus , MiddleName = stgDimCustomerUpdates.MiddleName , NumberCarsOwned = stgDimCustomerUpdates.NumberCarsOwned , NumberChildrenAtHome = stgDimCustomerUpdates.NumberChildrenAtHome , Phone = stgDimCustomerUpdates.Phone , Suffix = stgDimCustomerUpdates.Suffix , Title = stgDimCustomerUpdates.Title , TotalChildren = stgDimCustomerUpdates.TotalChildren FROM AdventureWorksDW2008.dbo.DimCustomer DimCustomer INNER JOIN dbo.stgDimCustomerUpdates ON DimCustomer.CustomerAlternateKey = stgDimCustomerUpdates.CustomerAlternateKey
جداول Fact به پردازشهای منحصر به فردی نیازمند هستند، نخست به کلیدهای Surrogate جدول Dimension نیاز دارند تا Measureهای محاسبه شدنی را بدست آورند. این اعمال از طریق تبدیلات Lookup، Merge Join و Derived Column صورت میگیرد. با بروزرسانی ها، تفاضل رکوردها و یا Snapshot بیشتر این فرآیندهای دشوار انجام میشوند.
روی اغلب جداول Fact عمل درج صورت میگیرد؛ که کار متداولی در جدول Fact میباشد. شاید سادهترین کار که در فرآیند ساخت ETL صورت میگیرد، عملیات درج روی تنها تعدادی از جدول Fact میباشد. درج کردن در صورت لزوم بارگذاری انبوه داده ها، مدیریت شاخصها و مدیریت پارتیشنها را شامل میشود.
بروزرسانی روی جداول Fact معمولاً به یکی از سه طریق زیر انجام میگیرد:
در موردی که تغییرات با فرکانس کمی روی جدول Fact صورت میگیرد و یا فرآیند بروزرسانی قابل مدیریت است؛ سادهترین روش انجام یک دستور Update روی جدول Fact میباشد. نکته مهمی که هنگام انجام بروزرسانی باید به خاطر داشته باشید، استفاده از روش بروزرسانی مبتنی بر مجموعه است؛ به همان طریق که در قسمت الگوهای Dimension ذکر آن رفت.
در طریقی دیگر (درج compensating) میتوان اقدام به درج رکورد تغییر یافته نمود، تا ترجیحاً بروزرسانی روی آن صورت گیرد. این استراتژی به سادگی دادههای جدول Fact میان سیستم مبداء و مقصد را که تغییر یافته اند، به صورت یک رکورد جدید درج خواهد کرد. تصویر زیر مثالی از اجرای موارد فوق را نمایش میدهد.
در آخرین روش از یک دستور SQL MERGE استفاده میشود که در آن با استفاده از ادغام و مقایسه، تمامی دادههای جدید و تغییر یافته جدول Fact، درج و یا بروزرسانی میشوند. نمونه ای از استفاده دستور Merge به شرح زیر است:
MERGE dbo.FactSalesQuota AS T USING SSIS_PDS.dbo.stgFactSalesQuota AS S ON T.EmployeeKey = S.EmployeeKey AND T.DateKey = S.DateKey WHEN MATCHED AND BY target THEN INSERT(EmployeeKey, DateKey, CalendarYear, CalendarQuarter, SalesAmountQuota) VALUES(S.EmployeeKey, S.DateKey, S.CalendarYear, S.CalendarQuarter, S.SalesAmountQuota) WHEN MATCHED AND T.SalesAmountQuota != S.SalesAmountQuota THEN UPDATE SET T.SalesAmountQuota = S.SalesAmountQuota ;
زمانیکه یک ارجاع در جدول Fact به یک عضو Dimension که هنوز بارگذاری نشدهاست بوجود آید؛ یک Inferred Member تعبیر میشود. به سه طریق میتوان این Inferred Memberها را مدیریت نمود:
شکل زیر این موارد را نمایش میدهد:
CREATE VIEW GetData
as
SELECT * FROM tblTreeItems
using System;
namespace System.Web.Mvc
{
public abstract class WebViewPage<TModel> : WebViewPage
{
protected WebViewPage();
public AjaxHelper<TModel> Ajax { get; set; }
public HtmlHelper<TModel> Html { get; set; }
public TModel Model { get; }
public ViewDataDictionary<TModel> ViewData { get; set; }
public override void InitHelpers();
protected override void SetViewData(ViewDataDictionary viewData);
}
}
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
</head>
namespace MvcApplication18.Models
{
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
}
}
using System.Collections.Generic;
namespace MvcApplication18.Models
{
public static class EmployeeDataSource
{
public static IList<Employee> CreateEmployees()
{
var list = new List<Employee>();
for (int i = 0; i < 1000; i++)
{
list.Add(new Employee { Id = i + 1, Name = "name " + i });
}
return list;
}
}
}
using System.Linq;
using System.Web.Mvc;
using MvcApplication18.Models;
namespace MvcApplication18.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost] //for IE-8
public ActionResult EmployeeInfo(int? id)
{
if (!Request.IsAjaxRequest())
return View("Error");
if (!id.HasValue)
return View("Error");
var list = EmployeeDataSource.CreateEmployees();
var data = list.Where(x => x.Id == id.Value).FirstOrDefault();
if (data == null)
return View("Error");
return PartialView(viewName: "_EmployeeInfo", model: data);
}
}
}
@model MvcApplication18.Models.Employee
<strong>Name:</strong> @Model.Name
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<div id="EmployeeInfo">
@Ajax.ActionLink(
linkText: "Get Employee-1 info",
actionName: "EmployeeInfo",
controllerName: "Home",
routeValues: new { id = 1 },
ajaxOptions: new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EmployeeInfo",
LoadingElementId = "Progress"
})
</div>
<div id="Progress" style="display: none">
<img src="@Url.Content("~/Content/images/loading.gif")" alt="loading..." />
</div>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
base.OnActionExecuting(filterContext);
}
else
{
throw new InvalidOperationException("This operation can only be accessed via Ajax requests");
}
}
}
[AjaxOnly]
public ActionResult SomeAjaxAction()
{
return Content("Hello!");
}
<a data-ajax="true" data-ajax-loading="#Progress" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#EmployeeInfo"
href="/Home/EmployeeInfo/1">Get Employee-1 info</a>
<a href="#" onclick="LoadEmployeeInfo()">Get Employee-1 info</a>
@section javascript
{
<script type="text/javascript">
function LoadEmployeeInfo() {
showProgress();
$.ajax({
type: "POST",
url: "/Home/EmployeeInfo",
data: JSON.stringify({ id: 1 }),
contentType: "application/json; charset=utf-8",
dataType: "json",
// controller is returning a simple text, not json
complete: function (xhr, status) {
var data = xhr.responseText;
if (status === 'error' || !data) {
//handleError
}
else {
$('#EmployeeInfo').html(data);
}
hideProgress();
}
});
}
function showProgress() {
$('#Progress').css("display", "block");
}
function hideProgress() {
$('#Progress').css("display", "none");
}
</script>
}
@RenderSection("javascript", required: false)
[HttpPost] //for IE-8
public ActionResult EmployeeInfoData(int? id)
{
if (!Request.IsAjaxRequest())
return Json(false);
if (!id.HasValue)
return Json(false);
var list = EmployeeDataSource.CreateEmployees();
var data = list.Where(x => x.Id == id.Value).FirstOrDefault();
if (data == null)
return Json(false);
return Json(data);
}
<a href="#" onclick="LoadEmployeeInfoData()">Get Employee-2 info</a>
@section javascript
{
<script type="text/javascript">
function LoadEmployeeInfoData() {
showProgress();
$.ajax({
type: "POST",
url: "/Home/EmployeeInfoData",
data: JSON.stringify({ id: 1 }),
contentType: "application/json; charset=utf-8",
dataType: "json",
// controller is returning the json data
success: function (result) {
if (result) {
alert(result.Id + ' - ' + result.Name);
}
hideProgress();
},
error: function (result) {
alert(result.status + ' ' + result.statusText);
hideProgress();
}
});
}
function showProgress() {
$('#Progress').css("display", "block");
}
function hideProgress() {
$('#Progress').css("display", "none");
}
</script>
}
[HttpPost] //for IE-8
public ActionResult SearchEmployeeInfo(string data)
{
if (!Request.IsAjaxRequest())
return Content(string.Empty);
if (string.IsNullOrWhiteSpace(data))
return Content(string.Empty);
var employeesList = EmployeeDataSource.CreateEmployees();
var list = employeesList.Where(x => x.Name.Contains(data)).ToList();
if (list == null || !list.Any())
return Content(string.Empty);
return PartialView(viewName: "_SearchEmployeeInfo", model: list);
}
@model IEnumerable<MvcApplication18.Models.Employee>
<table>
<tr>
<th>
Name
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
</table>
@using (Ajax.BeginForm(actionName: "SearchEmployeeInfo",
controllerName: "Home",
ajaxOptions: new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EmployeeInfo",
LoadingElementId = "Progress"
}))
{
@Html.TextBox("data")
<input type="submit" value="Search" />
}
<form action="/Home/SearchEmployeeInfo" data-ajax="true"
data-ajax-loading="#Progress" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#EmployeeInfo"
id="form0" method="post">
<input id="data" name="data" type="text" value="" />
<input type="submit" value="Search" />
</form>
$.validator.unobtrusive.parse("#{form-id}");
$.ajax
({
url: "/{controller}/{action}/{id}",
type: "get",
success: function(data)
{
$.validator.unobtrusive.parse("#{form-id}");
}
});
//or
$.get('/{controller}/{action}/{id}', function (data) { $.validator.unobtrusive.parse("#{form-id}"); });
@using (Ajax.BeginForm(
"Action1",
"Controller",
null,
new AjaxOptions {
OnSuccess = "onSuccess",
UpdateTargetId = "result"
},
null)
)
{
<input type="submit" value="Save" />
}
var onSuccess = function(result) {
// enable unobtrusive validation for the contents
// that was injected into the <div id="result"></div> node
$.validator.unobtrusive.parse("#result");
};