مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت دوازدهم - توزیع برنامه
یکی از مشکلاتی را که حین کار با AngularJS 2.0 به کرات شاهدش خواهید بود، کش شدن تک اسکریپت‌های ماژول‌های آن است. برای مثال فایل ts ایی را تغییر می‌دهید؛ به فایل js معادل آن کامپایل می‌شود. چون برنامه ماژولار است و این ماژول پیشتر توسط مرورگر بارگذاری شده‌است، بار دیگر نسبت به دریافت مجدد آن اقدام نمی‌کند. همچنین با ارائه‌ی نگارش RC، دیگر خبری از فایل‌های bundle این مجموعه نیست و اینبار اگر تبادلات شبکه‌ی بین سرور و برنامه را مرور کنید، به چند صد رفت و برگشت، برای دریافت فایل‌های JS کتابخانه‌های مرتبط خواهید رسید که اصلا بهینه نیست. در این قسمت قصد داریم، یک Gulp Task را ایجاد کنیم تا تمام اسکریپت‌های موجود را با هم یکی کرده و توزیع برنامه را ساده‌تر کند؛ به همراه بالا رفتن سرعت کار با این سیستم، بدون نیازی به توزیع تک تک فایل‌های js نهایی، که شاید صدها فایل باشند.


نصب پیشنیازهای کار با Gulp و TypeScript

فایل package.json در قسمت اول این سری معرفی شد. دراینجا قسمت devDependencies آن‌را به نحو ذیل تکمیل کنید:
"devDependencies": {
        "typescript": "^1.8.10",
        "gulp": "^3.9.1",
        "path": "^0.12.7",
        "gulp-clean": "^0.3.2",
        "fs": "^0.0.2",
        "gulp-concat": "^2.6.0",
        "gulp-typescript": "^2.13.1",
        "gulp-tsc": "^1.1.5",
        "del": "^2.2.0",
        "gulp-autoprefixer": "^3.1.0",
        "gulp-cssnano": "^2.0.0",
        "gulp-html-replace": "^1.5.4",
        "gulp-htmlmin": "^1.0.5",
        "gulp-uglify": "^1.5.3",
        "merge-stream": "^1.0.0",
        "systemjs-builder": "^0.15.16",
        "typings": "^0.8.1"
    },
به این ترتیب، پس از ذخیره‌ی فایل و یا کلیک راست بر روی نام فایل و انتخاب گزینه‌ی restore packages، وابستگی‌هایی مانند gulp، gulp-typescript و یک سری فشرده ساز CSS و HTML دریافت خواهند شد.
نکته‌ی مهم آن systemjs-builder است. این کتابخانه کار کامپایل systemjs.config.js را به یک تک اسکریپت انجام می‌دهد. به این ترتیب مشکل صدها بار رفت و برگشت به سرور، برای دریافت وابستگی‌های AngularJS 2.0، به طور کامل برطرف می‌شود.


افزودن فایل gulpfile.js به پروژه

یا یک فایل جدید جاوا اسکریپتی را به نام gulpfile.js به ریشه‌ی پروژه اضافه کنید و یا از منوی project -> add new item نیز می‌توانید گزینه‌ی gulp configuration file را در VS 2015 انتخاب نمائید. محتوای این فایل را به نحو ذیل تغییر دهید:
var gulp = require("gulp"),
    concat = require("gulp-concat"),
    tsc = require("gulp-typescript"),
    jsMinify = require("gulp-uglify"),
    cssPrefixer = require("gulp-autoprefixer"),
    cssMinify = require("gulp-cssnano"),
    del = require("del"),
    merge = require("merge-stream"),
    minifyHTML = require('gulp-htmlmin'),
    SystemBuilder = require("systemjs-builder");
 
var appFolder = "./app";
var outFolder = "wwwroot";
 
gulp.task("clean", () => {
    return del(outFolder);
});
 
gulp.task("shims", () => {
    return gulp.src([
            "node_modules/es6-shim/es6-shim.js",
            "node_modules/zone.js/dist/zone.js",
            "node_modules/reflect-metadata/Reflect.js"
    ])
    .pipe(concat("shims.js"))
    .pipe(jsMinify())
    .pipe(gulp.dest(outFolder + "/js/"));
});
 
gulp.task("tsc", () => {
    var tsProject = tsc.createProject("./tsconfig.json");
    var tsResult = gulp.src([
         appFolder + "/**/*.ts"
    ])
    .pipe(tsc(tsProject), undefined, tsc.reporter.fullReporter());
 
    return tsResult.js.pipe(gulp.dest("build/"));
});
 
gulp.task("system-build", ["tsc"], () => {
    var builder = new SystemBuilder();
 
    return builder.loadConfig("systemjs.config.js")
        .then(() => builder.buildStatic(appFolder, outFolder + "/js/bundle.js"))
        .then(() => del("build"));
});
 
 
gulp.task("buildAndMinify", ["system-build"], () => {
    var bundle = gulp.src(outFolder + "/js/bundle.js")
        .pipe(jsMinify())
        .pipe(gulp.dest(outFolder + "/js/"));
 
    var css = gulp.src(outFolder + "/css/styles.css")
        .pipe(cssMinify())
        .pipe(gulp.dest(outFolder + "/css/"));
 
    return merge(bundle, css);
}); 
 
gulp.task("favicon", function () {
    return gulp.src("./app/favicon.ico")
      .pipe(gulp.dest(outFolder));
});
 
gulp.task("css", function () {
    return gulp.src(appFolder + "/**/*.css")
      .pipe(cssPrefixer())
      .pipe(cssMinify())
      .pipe(gulp.dest(outFolder));
});
 
gulp.task("templates", function () {
    return gulp.src(appFolder + "/**/*.html")
        .pipe(minifyHTML())
        .pipe(gulp.dest(outFolder));
});
 
gulp.task("assets", ["templates", "css", "favicon"], function () {
    return gulp.src(appFolder + "/**/*.png")
      .pipe(gulp.dest(outFolder));
}); 
 
gulp.task("otherScriptsAndStyles", () => {
    gulp.src([
            "jquery/dist/jquery.*js",
            "bootstrap/dist/js/bootstrap*.js"
    ], {
        cwd: "node_modules/**"
    })
    .pipe(gulp.dest(outFolder + "/js/"));
 
    gulp.src([
        "node_modules/bootstrap/dist/css/bootstrap.css"
    ]).pipe(cssMinify()).pipe(gulp.dest(outFolder + "/css/"));
 
    gulp.src([
        "node_modules/bootstrap/fonts/*.*"
    ]).pipe(gulp.dest(outFolder + "/fonts/"));
}); 
 
//gulp.task("watch.tsc", ["tsc"], function () {
//    return gulp.watch(appFolder + "/**/*.ts", ["tsc"]);
//});
 
//gulp.task("watch", ["watch.tsc"]); 
 
gulp.task("default", [
    "shims",
    "buildAndMinify",
    "assets",
    "otherScriptsAndStyles"
    //,"watch"
]);
توضیحات

در این فایل فرض شده‌است که خروجی نهایی برنامه قرار است در پوشه‌ای به نام wwwroot کپی شود و پوشه‌ی اصلی برنامه، همان پوشه‌ای به نام app، در ریشه‌ی پروژه است.
 var appFolder = "./app";
var outFolder = "wwwroot";
سپس در اینجا یک سری task کامپایل و کپی کردن فایل‌ها تهیه شده‌اند:
 1) وظیفه‌ی clean، کار تمیز کردن پوشه‌ی نهایی خروجی برنامه را انجام می‌دهد (حذف تمام فایل‌های آن).
 2) وظیفه‌ی shims، کار بسته بندی، یکی کردن و فشرده کردن سه اسکریپت es6-shim.js، zone.js و Reflect.js را انجام می‌دهد. سپس تک فایل حاصل را به نام shims.js، در پوشه‌ی wwwroot/js کپی می‌کند.
 3) وظیفه‌ی tsc، یکبار دیگر کامپایلر TypeScript را اجرا می‌کند تا مطمئن شویم با آخرین نگارش فایل‌های js برنامه کار می‌کنیم.
 4) وظیفه‌ی system-build، کار پردازش خودکار مداخل فایل systemjs.config.js را انجام می‌دهد. در آخرین نگارش ارائه شده‌ی AngularJS 2.0، بجای ذکر مداخل مورد نیاز آن، این  تک فایل systemjs.config.js را به صفحه پیوست می‌کنیم تا اسکریپت‌های لازم را (چند صد عدد)، به صورت خودکار بارگذاری کند. برای یکی کردن این چند صد عدد اسکریپت، از کتابخانه‌ی SystemBuilder  آن کمک گرفته و کار کامپایل نهایی را انجام می‌دهیم. خروجی تمام این فایل‌ها، به همراه کلیه فایل‌های js حاصل از کامپایل فایل‌های TypeScript برنامه، در فایلی به نام bundle.js کپی شده‌ی در پوشه‌ی wwwroot/js نوشته می‌شود. بنابراین دیگر نیازی نیست تا فایل‌های js پوشه‌ی app و همچنین فایل‌های js وابستگی‌های AngularJS 2.0 را توزیع کنیم. تک فایل bundle.js، حاوی تمام این‌ها است.
 5) وظیفه‌ی buildAndMinify کار اجرای وظیفه‌ی system-bulder را به همراه فشرده سازی تک فایل bundle.js، به عهده دارد. به علاوه اگر در پوشه‌ی css آن نیز فایل styles.css موجود باشد، آن را فشرده می‌کند.
 6) در ادامه یک سری وظیفه‌ی کپی کردن منابع برنامه را مشاهده می‌کنید. مانند favicon که کار کپی کردن این آیکن را به پوشه‌ی wwwroot انجام می‌دهد. وظیفه‌ی css، فایل‌های css موجود در پوشه‌های برنامه را به wwwroot و زیر پوشه‌های آن کپی می‌کند. وظیفه‌ی templates، کار کپی کردن فایل‌های html قالب‌های کامپوننت‌ها را بر عهده دارد. وظیفه‌ی assets، کار کپی کردن فایل‌های png را انجام می‌دهد.
 7) وظیفه‌ی otherScriptsAndStyles یک سری css و js ثالث را به پوشه‌ی wwwroot کپی می‌کند؛ مانند فایل‌های بوت استرپ و جی‌کوئری.
 8) وظیفه‌ی default، کار اجرای تمام این وظایف را با هم به عهده دارد.

اکنون اگر بر روی gulpfile.js کلیک راست کنید، گزینه‌ی task runner explorer ظاهر خواهد شد. آن‌را انتخاب کنید:


بر روی وظیفه‌ی default کلیک راست کرده و آن‌را اجرا کنید. پس از مدتی پوشه‌ی جدید wwwroot ساخته شده و فایل‌های نهایی برنامه به آن کپی می‌شوند.
 

اصلاح فایل index.html و یا Views\Shared\_Layout.cshtml

اکنون که تمام فایل‌های مورد نیاز پروژه در پوشه‌ی wwwroot کپی شده‌اند، نیاز است فایل index.html را به نحو ذیل تغییر داد:
<!DOCTYPE html>
<html>
<head>
    <base href="/">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
 
    <link href="~/wwwroot/css/bootstrap.css" rel="stylesheet" />
    <link href="~/wwwroot/app.component.css" rel="stylesheet" />
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
 
    <script src="~/wwwroot/js/shims.js"></script>
</head>
 
<body>
    <div>
        @RenderBody()
        <pm-app>Loading App...</pm-app>
    </div>
 
    <script src="~/wwwroot/js/jquery/dist/jquery.min.js"></script>
    <script src="~/wwwroot/js/bootstrap/dist/js/bootstrap.min.js"></script>
    <script src="~/wwwroot/js/bundle.js"></script>
 
    @RenderSection("Scripts", required: false)
</body>
</html>
همانطور که مشاهده می‌کنید، اینبار دیگر خبری از systemjs.config.js و وابستگی‌های آن نیست.
اسکریپت‌های shims که برای مرورگرهای قدیمی‌تر درنظر گرفته شده‌اند، به تک فایل wwwroot/js/shims.js منتقل شده‌اند.
تمام اسکریپت‌های AngularJS 2.0 و وابستگی‌های آن به همراه تمام اسکریپت‌های برنامه‌ی خودمان، به تک فایل wwwroot/js/bundle.js منتقل شده‌اند.

اکنون اگر برنامه را اجرا کنید، سرعت آن با قبل قابل مقایسه نیست! اینبار دیگر نه نیازی به بارگذاری تمام وابستگی‌های AngularJS 2.0 به صورت مجزا توسط systemjs.config.js وجود دارد و نه به ازای مشاهده‌ی هر صفحه‌ای، یکبار قرار است فایل js کامپوننت آن بارگذاری شود. تمام این‌ها داخل فایل wwwroot/js/bundle.js قرار گرفته‌اند و تنها یکبار بارگذاری می‌شوند.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MVC5Angular2.part12.zip


خلاصه‌ی بحث

با نوشتن یک Gulp Task جدید می‌توان بر اساس فایل systemjs.config.js، تمام اسکریپت‌های دخیل در اجرای برنامه را به صورت خودکار یافته و به صورت یک تک فایل نهایی، بسته بندی و توزیع کرد.
مطالب
آشنایی با LibMan در پروژه‌های ASP.NET Core
مدیریت پکیج‌های سمت کلاینت
پروژه‌های جدیدی که با استفاده از قالب پیش‌فرض ایجاد می‌شوند، شامل یک پوشه با نام lib، در شاخه‌ی wwwroot هستند که حاوی این فایل‌ها می‌باشند:


اینها به عنوان حداقل‌های ایجاد یک وب اپلیکیشن، برای قالب انتخاب شده در نظر گرفته شده‌اند. اما فرض کنید بعد از مدتی می‌خواهیم ورژن bootstrap استفاده شده در پروژه را ارتقاء دهیم؛ در این حالت چندین انتخاب داریم:

  • دانلود مستقیم فایل موردنیاز و جایگزین کردن آن با نسخه‌ی فعلی
  • حذف پوشه‌ی wwwroot/lib و نصب مجدد پوشه‌ها از طریق NPM یا Yarn
  • استفاده از bower و سفارشی‌سازی مسیر قرار گرفتن فایل‌ها توسط browerrc.

روش اول، به نسبت ساده‌تر است؛ اما مشکل اینجاست که همه چیز به صورت دستی انجام خواهد گرفت. یعنی برای نسخه‌های بعدی همین روال باید مجدداً انجام شود. در روش دوم نیز مشکل اینجاست که مسیر قرار گرفتن پکیج‌های پروژه، از این به بعد node_modules خواهند بود و نیاز به یک تنظیم اضافی در فایل Startup.cs و مطلع کردن ASP.NET Core برای serve کردن فایل‌های سمت کلاینت است همچنین نیاز خواهد بود که تمامی ارجاعات داخل فایل Layout.cshtmlـ نیز از lib به node_modules تغییر پیدا کنند. در نهایت روش آخر نیز به دلیل منسوخ شدن bower پیشنهاد نمی‌شود.

استفاده از LibMan 
LibMan یک قابلیت جدید است که از نسخه‌ی Visual Studio 2017 برای مدیریت پکیج‌های سمت کلاینت اضافه شده است. این ابزار به صورت cross platform تهیه شده است؛ یعنی در خارج از Visual Studio نیز قابل استفاده می‌باشد. در واقع این ابزار را می‌توانیم به صورت Globally روی سیستم خود نصب کنیم و از طریق خط فرمان همانند NPM از آن استفاده کنیم.  

نصب و استفاده از LibMan
این ابزار ابتدا توسط Mads Kristensen با عنوان Client-Side Library Installer به صورت یک افزونه برای Visual Studio 2015 توسعه داده شد که در نهایت تیم ASP.NET این ابزار را  به صورت توکار به Visual Studio 2017 اضافه کرد. در نتیجه اگر از نسخه‌ی 2017 ویژوال استودیو استفاده می‌کنید، برای استفاده از این ابزار نیاز به نصب پکیج خاصی نخواهید داشت. برای استفاده از این ابزار در سیستم‌عامل‌های به غیر از ویندوز نیز یک CLI تهیه شده است که از طریق خط فرمان قابل استفاده می‌باشد. برای نصب این ابزار کافی است ابتدا آن را به صورت سراسری نصب کنید:
dotnet tool install -g Microsoft.Web.LibraryManager.Cli

قدم بعدی اضافه کردن فایلی با عنوان libman.json درون پروژه است. برای افزودن این فایل کافی است دستور زیر را در خطر فرمان وارد کنید:
libman init

با صدور فرمان فوق فایل مربوطه درون پروژه ایجاد می‌شود که در واقع یک فایل json ساده برای مدیریت پکیج‌های سمت کلاینت است:
{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": []
}

همانطور که مشاهده می‌کنید، می‌توانیم منبع دریافت پکیج‌‌ها را نیز تعیین کنیم که در حالت پیش‌فرض بر روی cdnjs تنظیم شده‌است و در واقع یک Content Delivery Network برای تعداد بیشماری پکیج سمت کلاینت است. درون آرایه‌ی libraries نیز می‌توانیم پکیج‌های موردنیاز خود را وارد کنیم. حتی برای هر پکیج هم می‌توانیم provider را override نمائیم. فرض کنید می‌خواهیم کتابخانه‌ی bootstrap را به پروژه اضافه کنیم. در اینحالت کافی است دستور زیر را برای نصب پکیج مربوطه صادر نمائیم:
libman install bootstrap@4.3.1 --provider unpkg --destination wwwroot/lib/bootstrap

در نهایت فایل libman.json چنین ساختاری پیدا خواهد کرد:
{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "provider": "unpkg",
      "library": "bootstrap@4.3.1",
      "destination": "wwwroot/lib/bootstrap"
    }
  ]
}

برای نصب مجدد پکیج هم می‌توانید از دستور libman restore استفاده کنید؛ در این حالت دقیقا مانند Nuget، پکیج‌ها از روی فایل libman.json از provider مربوطه دانلود و به پروژه اضافه خواهند شد. در ادامه لیست دستورات موجود را مشاهده می‌کنید:

نظرات مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت پنجم - پیاده سازی ورود و خروج از سیستم
آن بسته برای این است که خودتان UI مدیریتی برای آن طراحی کنید و در این بین پایه‌ای هم در اختیارتان باشد. البته ترکیب بسته‌ی EF آن با بسته‌ی IdentityServer4.AspNetIdentity امکان استفاده‌ی از ASP.NET Core Identity مایکروسافت را به عنوان UI مدیریتی این IDP میسر می‌کند که بررسی آن نیاز به بحثی جداگانه دارد.
نظرات مطالب
صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid
- اسکریپت‌های کامل این مثال را در این پوشه می‌توانید مشاهده کنید. برای مثال اگر به فایل kendo.all.min.js مراجعه کنید، ابتدای آن ذکر شده‌است: Kendo UI v2014.2.1008 . به احتمال زیاد شما از یک نگارش قدیمی استفاده می‌کنید.
نکته‌ای در مورد دریافت آخرین نگارش‌های Kendo UI  
نظرات مطالب
پیاده سازی InstanceProvider برای سرویس های WCF
با سلام؛ اگر یک برنامه چند لایه داشته باشیم (UI- DomainLayer-DataAccess- Service ) و مثلا یک پروژه‌ای هم از نوع webapi  یا wcf در آن معماری قرار داشت، می‌خواهم در web api یا wcf هم برای اعمال dependency Injection  با آن mapping ‌ها که در لایه ui قرار دادم هم استفاده کنم. با تشکر.
نظرات مطالب
MVC vs 3-Tier Pattern
منم یه مدت دچار این ابهام بودم. ولی الان اینطور نتیجه می‌گیرم:

mvc کلا در لایه UI قرار داره. یعنی اگر شما لایه BL و DAL رو داشته باشید، حالا میتونید لایه UI رو با یکی از روش ها، مثلا سیلورلایت، asp.net mvc یا asp.net web form پیاده کنید. 
پاسخ به بازخورد‌های پروژه‌ها
حق دسترسی UI به Model
یک سیستم از همکاری قسمت‌های مختلف اون جهت رسیدن به یک مقصود مشخص، تعریف و تشکیل میشه. قسمت آغازین برنامه که لایه UI هم در آن هست (و به اون لایه UI نمی‌گن؛ راه انداز یا بوتسترپر هست)، تمام قسمت‌های دیگر رو باید جهت تشکیل و راه اندازی سیستم هماهنگ و آغاز کنه.
مطالب
صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid
پس از آشنایی مقدماتی با Kendo UI DataSource، اکنون می‌خواهیم از آن جهت صفحه بندی، مرتب سازی و جستجوی پویای سمت سرور استفاده کنیم. در مثال قبلی، هر چند صفحه بندی فعال بود، اما پس از دریافت تمام اطلاعات، این اعمال در سمت کاربر انجام و مدیریت می‌شد.



مدل برنامه

در اینجا قصد داریم لیستی را با ساختار کلاس Product در اختیار Kendo UI گرید قرار دهیم:
namespace KendoUI03.Models
{
    public class Product
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public decimal Price { set; get; }
        public bool IsAvailable { set; get; }
    }
}


پیشنیاز تامین داده مخصوص Kendo UI Grid

برای ارائه اطلاعات مخصوص Kendo UI Grid، ابتدا باید درنظر داشت که این گرید، درخواست‌های صفحه بندی خود را با فرمت ذیل ارسال می‌کند. همانطور که مشاهده می‌کنید، صرفا یک کوئری استرینگ با فرمت JSON را دریافت خواهیم کرد:
 /api/products?{"take":10,"skip":0,"page":1,"pageSize":10,"sort":[{"field":"Id","dir":"desc"}]}
سپس این گرید نیاز به سه فیلد، در خروجی JSON نهایی خواهد داشت:
{
"Data":
[
{"Id":1500,"Name":"نام 1500","Price":2499.0,"IsAvailable":false},
{"Id":1499,"Name":"نام 1499","Price":2498.0,"IsAvailable":true}
],
"Total":1500,
"Aggregates":null
}
فیلد Data که رکوردهای گرید را تامین می‌کنند. فیلد Total که بیانگر تعداد کل رکوردها است و Aggregates که برای گروه بندی بکار می‌رود.

می‌توان برای تمام این‌ها، کلاس و Parser تهیه کرد و یا ... پروژه‌ی سورس بازی به نام  Kendo.DynamicLinq نیز چنین کاری را میسر می‌سازد که در ادامه از آن استفاده خواهیم کرد. برای نصب آن تنها کافی است دستور ذیل را صادر کنید:
 PM> Install-Package Kendo.DynamicLinq
Kendo.DynamicLinq به صورت خودکار System.Linq.Dynamic را نیز نصب می‌کند که از آن جهت صفحه بندی پویا استفاده خواهد شد.


تامین کننده‌ی داده سمت سرور

همانند مطلب کار با Kendo UI DataSource ، یک ASP.NET Web API Controller جدید را به پروژه اضافه کنید و همچنین مسیریابی‌های مخصوص آن‌را به فایل global.asax.cs نیز اضافه نمائید.
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Kendo.DynamicLinq;
using KendoUI03.Models;
using Newtonsoft.Json;

namespace KendoUI03.Controllers
{
    public class ProductsController : ApiController
    {
        public DataSourceResult Get(HttpRequestMessage requestMessage)
        {
            var request = JsonConvert.DeserializeObject<DataSourceRequest>(
                requestMessage.RequestUri.ParseQueryString().GetKey(0)
            );

            var list = ProductDataSource.LatestProducts;
            return list.AsQueryable()
                       .ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter);
        }
    }
}
تمام کدهای این کنترلر همین چند سطر فوق هستند. با توجه به ساختار کوئری استرینگی که در ابتدای بحث عنوان شد، نیاز است آن‌را توسط کتابخانه‌ی JSON.NET تبدیل به یک نمونه از DataSourceRequest نمائیم. این کلاس در Kendo.DynamicLinq تعریف شده‌است و حاوی اطلاعاتی مانند take و skip کوئری LINQ نهایی است.
ProductDataSource.LatestProducts صرفا یک لیست جنریک تهیه شده از کلاس Product است. در نهایت با استفاده از متد الحاقی جدید ToDataSourceResult، به صورت خودکار مباحث صفحه بندی سمت سرور به همراه مرتب سازی اطلاعات، صورت گرفته و اطلاعات نهایی با فرمت DataSourceResult بازگشت داده می‌شود. DataSourceResult نیز در Kendo.DynamicLinq تعریف شده و سه فیلد یاد شده‌ی Data، Total و Aggregates را تولید می‌کند.

تا اینجا کارهای سمت سرور این مثال به پایان می‌رسد.


تهیه View نمایش اطلاعات ارسالی از سمت سرور

اعمال مباحث بومی سازی
<head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Language" content="fa" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>Kendo UI: Implemeting the Grid</title>

    <link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
    <!--شیوه نامه‌ی مخصوص راست به چپ سازی-->
    <link href="styles/kendo.rtl.min.css" rel="stylesheet" />
    <link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
    <script src="js/jquery.min.js" type="text/javascript"></script>
    <script src="js/kendo.all.min.js" type="text/javascript"></script>

    <!--محل سفارشی سازی پیام‌ها و مسایل بومی-->
    <script src="js/cultures/kendo.culture.fa-IR.js" type="text/javascript"></script>
    <script src="js/cultures/kendo.culture.fa.js" type="text/javascript"></script>
    <script src="js/messages/kendo.messages.en-US.js" type="text/javascript"></script>

    <style type="text/css">
        body {
            font-family: tahoma;
            font-size: 9pt;
        }
    </style>

    <script type="text/javascript">
        // جهت استفاده از فایل: kendo.culture.fa-IR.js
        kendo.culture("fa-IR");
    </script>
</head>
- در اینجا چند فایل js و css جدید اضافه شده‌اند. فایل kendo.rtl.min.css جهت تامین مباحث RTL توکار Kendo UI کاربرد دارد.
- سپس سه فایل kendo.culture.fa-IR.js، kendo.culture.fa.js و kendo.messages.en-US.js نیز اضافه شده‌اند. فایل‌های fa و fa-Ir آن هر چند به ظاهر برای ایران طراحی شده‌اند، اما نام ماه‌های موجود در آن عربی است که نیاز به ویرایش دارد. به همین جهت به سورس این فایل‌ها، جهت ویرایش نهایی نیاز خواهد بود که در پوشه‌ی src\js\cultures مجموعه‌ی اصلی Kendo UI موجود هستند (ر.ک. فایل پیوست).
- فایل kendo.messages.en-US.js حاوی تمام پیام‌های مرتبط با Kendo UI است. برای مثال«رکوردهای 10 تا 15 از 1000 ردیف» را در اینجا می‌توانید به فارسی ترجمه کنید.
- متد kendo.culture کار مشخص سازی فرهنگ بومی برنامه را به عهده دارد. برای مثال در اینجا به fa-IR تنظیم شده‌است. این مورد سبب خواهد شد تا از فایل kendo.culture.fa-IR.js استفاده گردد. اگر مقدار آن‌را به fa تنظیم کنید، از فایل kendo.culture.fa.js کمک گرفته خواهد شد.

راست به چپ سازی گرید
تنها کاری که برای راست به چپ سازی Kendo UI Grid باید صورت گیرد، محصور سازی div آن در یک div با کلاس مساوی k-rtl است:
    <div class="k-rtl">
        <div id="report-grid"></div>
    </div>
k-rtl و تنظیمات آن در فایل kendo.rtl.min.css قرار دارند که در ابتدای head صفحه تعریف شده‌است.

تامین داده و نمایش گرید

در ادامه کدهای کامل DataSource و Kendo UI Grid را ملاحظه می‌کنید:
    <script type="text/javascript">
        $(function () {
            var productsDataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "api/products",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    },
                    parameterMap: function (options) {
                        return kendo.stringify(options);
                    }
                },
                schema: {
                    data: "Data",
                    total: "Total",
                    model: {
                        fields: {
                            "Id": { type: "number" }, //تعیین نوع فیلد برای جستجوی پویا مهم است
                            "Name": { type: "string" },
                            "IsAvailable": { type: "boolean" },
                            "Price": { type: "number" }
                        }
                    }
                },
                error: function (e) {
                    alert(e.errorThrown);
                },
                pageSize: 10,
                sort: { field: "Id", dir: "desc" },
                serverPaging: true,
                serverFiltering: true,
                serverSorting: true
            });

            $("#report-grid").kendoGrid({
                dataSource: productsDataSource,
                autoBind: true,
                scrollable: false,
                pageable: true,
                sortable: true,
                filterable: true,
                reorderable: true,
                columnMenu: true,
                columns: [
                    { field: "Id", title: "شماره", width: "130px" },
                    { field: "Name", title: "نام محصول" },
                    {
                        field: "IsAvailable", title: "موجود است",
                        template: '<input type="checkbox" #= IsAvailable ? checked="checked" : "" # disabled="disabled" ></input>'
                    },
                    { field: "Price", title: "قیمت", format: "{0:c}" }
                ]
            });
        });
    </script>
- با تعاریف مقدماتی Kendo UI DataSource پیشتر آشنا شده‌ایم و قسمت read آن جهت دریافت اطلاعات از سمت سرور کاربرد دارد.
- در اینجا ذکر contentType الزامی است. زیرا ASP.NET Web API بر این اساس است که تصمیم می‌گیرد، خروجی را به صورت JSON ارائه دهد یا XML.
- با استفاده از parameterMap، سبب خواهیم شد تا پارامترهای ارسالی به سرور، با فرمت صحیحی تبدیل به JSON شده و بدون مشکل به سرور ارسال گردند.
- در قسمت schema باید نام فیلدهای موجود در DataSourceResult دقیقا مشخص شوند تا گرید بداند که data را باید از چه فیلدی استخراج کند و تعداد کل ردیف‌ها در کدام فیلد قرار گرفته‌است.
- نحوه‌ی تعریف model را نیز در اینجا ملاحظه می‌کنید. ذکر نوع فیلدها در اینجا بسیار مهم است و اگر قید نشوند، در حین جستجوی پویا به مشکل برخواهیم خورد. زیرا پیش فرض نوع تمام فیلدها string است و در این حالت نمی‌توان عدد 1 رشته‌ای را با یک فیلد از نوع int در سمت سرور مقایسه کرد.
- در اینجا serverPaging، serverFiltering و serverSorting نیز به true تنظیم شده‌اند. اگر این مقدار دهی‌ها صورت نگیرد، این اعمال در سمت کلاینت انجام خواهند شد.

پس از تعریف DataSource، تنها کافی است آن‌را به خاصیت dataSource یک kendoGrid نسبت دهیم.
- autoBind: true سبب می‌شود تا اطلاعات DataSource بدون نیاز به فراخوانی متد read آن به صورت خودکار دریافت شوند.
- با تنظیم scrollable: false، اعلام می‌کنیم که قرار است تمام رکوردها در معرض دید قرارگیرند و اسکرول پیدا نکنند.
- pageable: true صفحه بندی را فعال می‌کند. این مورد نیاز به تنظیم pageSize: 10 در قسمت DataSource نیز دارد.
- با sortable: true مرتب سازی ستون‌ها با کلیک بر روی سرستون‌ها فعال می‌گردد.
- filterable: true به معنای فعال شدن جستجوی خودکار بر روی فیلدها است. کتابخانه‌ی Kendo.DynamicLinq حاصل آن‌را در سمت سرور مدیریت می‌کند.
- reorderable: true سبب می‌شود تا کاربر بتواند محل قرارگیری ستون‌ها را تغییر دهد.
- ذکر columnMenu: true اختیاری است. اگر ذکر شود، امکان مخفی سازی انتخابی ستون‌ها نیز مسیر خواهد شد.
- در آخر ستون‌های گرید مشخص شده‌اند. با تعیین "{format: "{0:c سبب نمایش فیلدهای قیمت با سه رقم جدا کننده خواهیم شد. مقدار ریال آن از فایل فرهنگ جاری تنظیم شده دریافت می‌گردد. با استفاده از template تعریف شده نیز سبب نمایش فیلد bool به صورت یک checkbox خواهیم شد.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
KendoUI03.zip