نظرات مطالب
ASP.NET MVC #2
بله. در کل هیچ قید خاصی نداره این قسمت.
مسیرراه‌ها
NHibernate
      مطالب
      فرمت کردن اطلاعات نمایش داده شده به کمک Kendo UI Grid
      پیشنیازهای بحث:
      - «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid »
      - «استفاده از Kendo UI templates»

      صورت مساله
      می‌خواهیم به یک چنین تصویری برسیم؛ که دارای گروه بندی اطلاعات است، فرمت شرطی روی ستون قیمت آن اعمال شده و تاریخ نمایش داده شده در آن نیز شمسی است. همچنین برای مثال ستون قیمت آن دارای ته جمع صفحه بوده و به علاوه یک دکمه‌ی سفارشی به نوار ابزار آن اضافه شده‌است.


      مباحث قسمت سمت سرور این مثال با مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» دقیقا یکی است. فقط یک خاصیت AddDate نیز در اینجا اضافه شده‌است.


      تغییر نحوه‌ی نمایش pager

      اگر به قسمت pager تصویر فوق دقت کنید، یک دکمه‌ی refresh، تعداد موارد هر صفحه و امکان وارد کردن دستی شماره صفحه، در آن پیش بینی شده‌است. این موارد را با تنظیمات ذیل می‌توان فعال کرد:
                  $("#report-grid").kendoGrid({
                      // ...
                      pageable: {
                          previousNext: true, // default true
                          numeric: true, // default true
                          buttonCount: 5, // default 10
                          refresh: true, // default false
                          input: true, // default false
                          pageSizes: true // default false
                      },


      بومی سازی پیغام‌های گرید

      پیغام‌های فارسی را که در تصویر فوق مشاهده می‌کنید، حاصل پیوست فایل kendo.fa-IR.js هستند:
       <!--https://github.com/loudenvier/kendo-global/blob/master/lang/kendo.fa-IR.js-->
      <script src="js/messages/kendo.fa-IR.js" type="text/javascript"></script>


      گروه بندی اطلاعات

      برای گروه بندی اطلاعات در Kendo UI Grid دو قسمت باید تغییر کنند.
      ابتدا باید فیلد پیش فرض گروه بندی در قسمت data source گرید تعریف شود:
                  var productsDataSource = new kendo.data.DataSource({
                      // ...
                      group: { field: "IsAvailable" },
                      // ...
                  });
      همین تنظیم، گروه بندی را فعال خواهد کرد. اگر علاقمند باشید که به کاربران امکان تغییر دستی گروه بندی را بدهید، خاصیت groupable را نیز true کنید.
      $("#report-grid").kendoGrid({
      // ...
      groupable: true, // allows the user to alter what field the grid is grouped by
      // ...
      در این حالت با کشیدن و رها کردن یک سرستون، به نوار ابزار مرتبط با گروه بندی، گروه بندی گرید بر اساس این فیلد انتخابی به صورت خودکار انجام می‌شود.


      اضافه کردن ته جمع‌های ستون‌ها

      این ته جمع‌ها که aggregate نام دارند باید در دو قسمت فعال شوند:
                  var productsDataSource = new kendo.data.DataSource({
                      //...
                      aggregate: [
                          { field: "Name", aggregate: "count" },
                          { field: "Price", aggregate: "sum" }
                      ]
                      //...
                  });
      ابتدا در قسمت data source مشخص می‌کنیم که چه تابع تجمعی قرار است به ازای یک فیلد خاص استفاده شود.
      سپس این متدها را می‌توان مطابق فرمت hash syntax قالب‌های Kendo UI در قسمت footerTemplate هر ستون تعریف کرد:
                  $("#report-grid").kendoGrid({
                      // ...
                      columns: [
                          {
                              field: "Name", title: "نام محصول",
                              footerTemplate: "تعداد: #=count#"
                          },
                          {
                              field: "Price", title: "قیمت",
                              footerTemplate: "جمع: #=kendo.toString(sum,'c0')#"
                          }
                      ]
                      // ...
                  });


      فرمت شرطی اطلاعات

      در ستون قیمت، می‌خواهیم اگر قیمتی بیش از 2490 بود، با پس زمینه‌ی قهوه‌ای و رنگ زرد نمایش داده شود. برای این منظور می‌توان یک قالب Kendo UI سفارشی را طراحی کرد:
          <script type="text/x-kendo-template" id="priceTemplate">
              #if( Price > 2490 ) {#
              <span style="background:brown; color:yellow;">#=kendo.toString(Price,'c0')#</span>
              #} else {#
              #= kendo.toString(Price,'c0')#
              #}#
          </script>
      سپس نحوه‌ی استفاده‌ی از آن به صورت ذیل خواهد بود:
                  $("#report-grid").kendoGrid({
                      //...
                      columns: [
                          {
                              field: "Price", title: "قیمت",
                              template: kendo.template($("#priceTemplate").html()),
                              footerTemplate: "جمع: #=kendo.toString(sum,'c0')#"
                          }
                      ]
                      //...
                  });
      توسط متد kendo.template امکان انتساب یک قالب سفارشی به خاصیت template یک ستون وجود دارد.


      فرمت تاریخ میلادی به شمسی در حین نمایش

      برای تبدیل سمت کلاینت تاریخ میلادی به شمسی از کتابخانه‌ی moment-jalaali.js کمک گرفته شده‌است:
       <!--https://github.com/moment/moment/-->
      <script src="js/cultures/moment.min.js" type="text/javascript"></script>
      <!--https://github.com/jalaali/moment-jalaali-->
      <script src="js/cultures/moment-jalaali.js" type="text/javascript"></script>
      پس از آن تنها کافی است متد فرمت این کتابخانه را در قسمت template ستون تاریخ و توسط hash syntax قالب‌های Kendo UI بکار برد:
                  $("#report-grid").kendoGrid({
                      //...
                      columns: [
                          {
                              field: "AddDate", title: "تاریخ ثبت",
                              template: "#=moment(AddDate).format('jYYYY/jMM/jDD')#"
                          }
                      ]
                      //...
                  });


      اضافه کردن یک دکمه به نوار ابزار گرید

      نوار ابزار Kendo UI Grid را نیز می‌توان توسط یک قالب سفارشی آن مقدار دهی کرد:
                  $("#report-grid").kendoGrid({
                      // ...
                      toolbar: [
                          { template: kendo.template($("#toolbarTemplate").html()) }
                      ]
                      // ...
                  });
      برای نمونه toolbarTemplate فوق را به نحو ذیل تعریف کرده‌ایم:
          <script>
              // این اطلاعات برای تهیه خروجی سمت سرور مناسب هستند
              function getCurrentGridFilters() {
                  var dataSource = $("#report-grid").data("kendoGrid").dataSource;
                  var gridState = {
                      page: dataSource.page(),
                      pageSize: dataSource.pageSize(),
                      sort: dataSource.sort(),
                      group: dataSource.group(),
                      filter: dataSource.filter()
                  };
                  return kendo.stringify(gridState);
              }
          </script>
      
          <script id="toolbarTemplate" type="text/x-kendo-template">
              <a class="k-button" href="\#" onclick="alert('gridState: ' + getCurrentGridFilters());">نوار ابزار سفارشی</a>
          </script>
      دکمه‌ی اضافه شده، وضعیت فیلتر data source متصل به گرید را بازگشت می‌دهد. برای مثال مشخص می‌کند که در چه صفحه‌ای با چه تعداد رکورد قرار داریم و همچنین وضعیت مرتب سازی، فیلتر و غیره چیست. از این اطلاعات می‌توان در سمت سرور برای تهیه‌ی خروجی‌های PDF یا اکسل استفاده کرد. وضعیت فیلتر اطلاعات مشخص است. بر همین مبنا کوئری گرفته و سپس می‌توان نتیجه‌ی آن‌را تبدیل به منبع داده تهیه خروجی مورد نظر کرد.



      کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
      KendoUI05.zip
      نظرات مطالب
      سفارشی سازی ASP.NET Core Identity - قسمت اول - موجودیت‌های پایه و DbContext برنامه
      رشته‌ی اتصالی پیش‌فرض این برنامه LocalDB است که نیازی به تعیین نام کاربری و غیره ندارد. مطلب «LocalDB FAQ» را در مورد نصب و به روز رسانی آن پیگیری کنید. اگر این رشته را تغییر دادید و قصد استفاده‌ی از SQL Server کامل را دارید، احتمالا رشته‌ی اتصالی شما از نوع windows authentication است (Integrated Security=true) که نام کاربری یوزر فعلی را که ویژوال استودیوی شما تحت آن اجرا می‌شود، عنوان کرده‌است. این کاربر باید در قسمت accounts/login مربوط به SQL Server دسترسی لازم را به بانک اطلاعاتی که مشخص کرده‌اید، پیدا کند یا ویژوال استودیو را با دسترسی ادمین اجرا کنید.
      مطالب
      آشنایی با M.A.F - قسمت دوم

      قسمت قبل بیشتر آشنایی با یک سری از اصطلاحات مرتبط با فریم ورک MAF بود و همچنین نحوه‌ی کلی استفاده از آن. در این قسمت یک مثال ساده را با آن پیاده سازی خواهیم کرد و فرض قسمت دوم بر این است که افزونه‌ی Visual Studio Pipeline Builder را نیز نصب کرده‌اید.

      یک نکته پیش از شروع:
      - اگر افزونه‌ی Visual Studio Pipeline Builder پس از نصب به منوی Tools اضافه نشده است، یک پوشه‌ی جدید را به نام Addins در مسیر Documents\Visual Studio 2008 ایجاد کرده و سپس فایل‌های آن‌را در این مسیر کپی کنید.

      ساختار اولیه یک پروژه MAF

      - پروژ‌ه‌هایی که از MAF استفاده می‌کنند، نیاز به ارجاعاتی به دو اسمبلی استاندارد System.AddIn.dll و System.AddIn.Contract.dll دارند (مطابق شکل زیر):



      - ساختار آغازین یک پروژه MAF از سه پروژه تشکیل می‌شود که توسط افزونه‌ی Visual Studio Pipeline Builder به 7 پروژه بسط خواهد یافت.
      این سه پروژه استاندارد آغازین شامل موارد زیر هستند:



      - هاست: همان برنامه‌ی اصلی که قرار است از افزونه استفاده کند.
      - قرار داد: نحو‌ه‌ی تعامل هاست و افزونه در این پروژه تعریف می‌شود. (یک پروژه از نوع class library)
      - افزونه: کار پیاده سازی قرار داد را عهده دار خواهد شد. (یک پروژه از نوع class library)

      - همچنین مرسوم است جهت مدیریت بهتر خروجی‌های حاصل شده یک پوشه Output را نیز به این solution اضافه کنند:



      اکنون با توجه به این محل خروجی، به خواص Build سه پروژه موجود مراجعه کرده و مسیر Build را اندکی اصلاح خواهیم کرد (هر سه مورد بهتر است اصلاح شوند)، برای مثال:



      نکته‌ی مهم هم اینجا است که خروجی host باید به ریشه این پوشه تنظیم شود و سایر پروژه‌ها هر کدام خروجی خاص خود را در پوشه‌ای داخل این ریشه باید ایجاد کنند.



      تا اینجا قالب اصلی کار آماده شده است. قرارداد ما هم به شکل زیر است (ویژگی AddInContract آن نیز نباید فراموش شود):

      using System.AddIn.Pipeline;
      using System.AddIn.Contract;

      namespace CalculatorConract
      {
      [AddInContract]
      public interface ICalculatorContract : IContract
      {
      double Operate(string operation, double a, double b);
      }
      }

      به عبارت دیگر برنامه‌ای محاسباتی داریم (هاست) که دو عدد double را در اختیار افزونه‌های خودش قرار می‌دهد و سپس این افزونه‌ها یک عملیات ریاضی را بر روی آن‌ها انجام داده و خروجی را بر می‌گردانند. نوع عملیات توسط آرگومان operation مشخص می‌شود. این آرگومان به کلیه افزونه‌های موجود ارسال خواهد شد و احتمالا یکی از آن‌ها این مورد را پیاده سازی کرده است. در غیر اینصورت یک استثنای عملیات پیاده سازی نشده صادر می‌شود.
      البته روش بهتر طراحی این افزونه، اضافه کردن متد یا خاصیتی جهت مشخص کردن نوع و یا انواع عملیات پشتیبانی شده توسط افزونه‌ است که جهت سادگی این مثال، به این طراحی ساده اکتفا می‌شود.

      ایجاد pipeline

      اگر قسمت قبل را مطالعه کرده باشید، یک راه حل مبتنی بر MAF از 7 پروژه تشکیل می‌شود که عمده‌ترین خاصیت آن‌ها مقاوم کردن سیستم در مقابل تغییرات نگارش قرارداد است. در این حالت اگر قرار داد تغییر کند، نه هاست و نه افزونه‌ی قدیمی، نیازی به تغییر در کدهای خود نخواهند داشت و این پروژه‌های میانی هستند که کار وفق دادن (adapters) نهایی را برعهده می‌گیرند.


      برای ایجاد خودکار View ها و همچنین Adapters ، از افزونه‌ی Visual Studio Pipeline Builder که پیشتر معرفی شد استفاده خواهیم کرد.



      سه گزینه‌ی آن هم مشخص هستند. نام پروژه‌ی قرارداد، مسیر پروژه‌ی هاست و مسیر خروجی نهایی معرفی شده. پیش از استفاده از این افزونه نیاز است تا یکبار solution مورد نظر کامپایل شود. پس از کلیک بر روی دکمه‌ی OK، پروژه‌های ذکر شده ایجاد خواهند شد:


      پس از ایجاد این پروژه‌ها، نیاز به اصلاحات مختصری در مورد نام اسمبلی و فضای نام هر کدام می‌باشد؛ زیرا به صورت پیش فرض هر کدام به نام template نامگذاری شده‌اند:



      پیاده سازی افزونه

      قالب کاری استفاده از این فریم ورک آماده است. اکنون نوبت به پیاده سازی یک افزونه می‌باشد. به پروژه AddIn مراجعه کرده و ارجاعی را به اسمبلی AddInView خواهیم افزود. به این صورت افزونه‌ی ما به صورت مستقیم با قرارداد سروکار نداشته و ارتباطات، در راستای همان pipeline تعریف شده، جهت مقاوم شدن در برابر تغییرات صورت می‌گیرد:
      using System;
      using CalculatorConract.AddInViews;
      using System.AddIn;

      namespace CalculatorAddIn
      {
      [AddIn]
      public class MyCalculatorAddIn : ICalculator
      {
      public double Operate(string operation, double a, double b)
      {
      throw new NotImplementedException();
      }
      }
      }

      در اینجا افزونه‌ی ما باید اینترفیس ICalculator مربوط به AddInView را پیاده سازی نماید که برای مثال خواهیم داشت:

      using System;
      using CalculatorConract.AddInViews;
      using System.AddIn;

      namespace CalculatorAddIn
      {
      [AddIn("افزونه یک", Description = "توضیحات", Publisher = "نویسنده", Version = "نگارش یک")]
      public class MyCalculatorAddIn : ICalculator
      {
      public double Operate(string operation, double a, double b)
      {
      switch (operation)
      {
      case "+":
      return a + b;
      case "-":
      return a - b;
      case "*":
      return a * b;
      default:
      throw new NotSupportedException("عملیات مورد نظر توسط این افزونه پشتیبانی نمی‌شود");
      }
      }
      }
      }

      همانطور که در قسمت قبل نیز ذکر شد، این کلاس باید با ویژگی AddIn مزین شود که توسط آن می‌توان توضیحاتی در مورد نام ، نویسنده و نگارش افزونه ارائه داد.


      استفاده از افزونه‌ی تولید شده

      هاست برای استفاده از افزونه‌هایی با قرارداد ذکر شده، مطابق pipeline پروژه، نیاز به ارجاعی به اسمبلی HostView دارد و در اینجا نیز هاست به صورت مستقیم با قرارداد کاری نخواهد داشت. همچنین هاست هیچ ارجاع مستقیمی به افزونه‌ها نداشته و بارگذاری و مدیریت آن‌ها به صورت پویا انجام خواهد شد.

      نکته‌ی مهم!
      در هر دو ارجاع به HostView و یا AddInView باید خاصیت Copy to local به false تنظیم شود، در غیر اینصورت افزونه‌ی شما بارگذاری نخواهد شد.



      پس از افزودن ارجاعی به HostView، نمونه‌ای از استفاده از افزونه‌ی تولید شده به صورت زیر می‌تواند باشد که توضیحات مربوطه به صورت کامنت آورده شده است:

      using System;
      using System.AddIn.Hosting;
      using CalculatorConract.HostViews;

      namespace Calculator
      {
      class Program
      {
      private static ICalculator _calculator;

      static void doOperation()
      {
      Console.WriteLine("1+2: {0}", _calculator.Operate("+", 1, 2));
      }

      static void Main(string[] args)
      {
      //مسیر پوشه ریشه مربوطه به خط لوله افزونه‌ها
      string path = Environment.CurrentDirectory;

      //مشخص سازی مسیر خواندن و کش کردن افزونه‌ها
      AddInStore.Update(path);

      //یافتن افزونه‌هایی سازگار با شرایط قرارداد پروژه
      //در اینجا هیچ افزونه‌ای بارگذاری نمی‌شود
      var addIns = AddInStore.FindAddIns(typeof(ICalculator), path);

      //اگر افزونه‌ای یافت شد
      if (addIns.Count > 0)
      {
      var addIn = addIns[0]; //استفاده از اولین افزونه
      Console.WriteLine("1st addIn: {0}", addIn.Name);

      //فعال سازی افزونه و همچنین مشخص سازی سطح دسترسی آن
      _calculator = addIn.Activate<ICalculator>(AddInSecurityLevel.Intranet);

      //یک نمونه از استفاده آن
      doOperation();
      }

      Console.WriteLine("Press a key...");
      Console.ReadKey();
      }
      }
      }

      چند نکته جالب توجه در مورد قابلیت‌های ارائه شده:
      - مدیریت load و unload پویا
      - امکان تعریف سطح دسترسی و ویژگی‌های امنیتی اجرای یک افزونه
      - امکان ایزوله سازی پروسه اجرای افزونه از هاست (در ادامه توضیح داده خواهد شد)
      - مقاوم بودن پروژه به نگارش‌های مختلف قرارداد


      اجرای افزونه در یک پروسه مجزا

      حتما با امکانات مرورگر کروم و یا IE8 در مورد اجرای هر tab آن‌ها در یک پروسه‌ی مجزا از پروسه اصلی هاست مطلع هستید. به این صورت پروسه‌ی هاست از رفتار tab ها محافظت می‌شود، همچنین پروسه‌ی هر tab نیز از tab دیگر ایزوله خواهد بود. یک چنین قابلیتی در این فریم ورک نیز پیش بینی شده است.

      //فعال سازی افزونه و همچنین مشخص سازی سطح دسترسی آن
      //همچنین جدا سازی پروسه اجرایی افزونه از هاست
      _calculator = addIn.Activate<ICalculator>(
      new AddInProcess(),
      AddInSecurityLevel.Intranet);

      در این حالت اگر پس از فعال شدن افزونه، یک break point قرار دهیم و به task manager ویندوز مراجعه نمائیم، پروسه‌ی مجزای افزونه قابل مشاهده است.



      برای مطالعه بیشتر + ، + ، + و +