نظرات مطالب
چه زمانی بهتر است از Silverlight استفاده شود؟
- بله. هدفگیری اصلی سیلورلایت 4 ، LOB‌ است یا به قولی line of business applications . اگر به کتاب‌های سال 2010 مراجعه کنید تعداد کتاب‌هایی که در مورد LOB و SL4 منتشر شده قابل توجه است:
Pro Business Applications with Silverlight 4 - APress
Silverlight 4 Data and Services Cookbook - Packt Publishing
Microsoft Silverlight 4 Business Application Development - Packt Publishing
و ...

با استفاده از WCF RIA Services یا حتی WCF Services و غیره دسترسی کامل برای مثال به entity framework خواهید داشت. همچنین کاربران شما مجددا به تجربه‌ی کار با برنامه‌های دسکتاپ باز خواهند گشت، هر چند برنامه تحت وب است. قابلیت نصب خارج از مرورگر را هم دارد (مثل یک برنامه دسکتاپ معمولی).

- برای خارج از سازمان هم مشکلی نیست. چون برنامه شما یکبار فقط باید دریافت شود. بعد کش می‌شود و افزونه‌ی سیلورلایت به صورت خودکار هربار چک می‌کند که آیا برنامه روی سرور تغییر کرده یا نه. اگر خیر از کش خوانده خواهد شد و کاربر راه دور معطل نخواهد شد. همچنین با استفاده از MEF (managed extensibility framework) می‌شود قسمت‌های مختلف برنامه را به صورت افزونه درآورد. یعنی کاربری که نیاز به تمام قسمت‌ها را ندارد خوب لزومی هم ندارد که همه‌ی آن‌ها را دریافت کند.
مطالب
بررسی سایز و پسوند فایل آپلود شده قبل از ارسال به سرور
می توان قبل از اینکه کاربر فایلی را سمت سرور ارسال کند پسوند فایل را چک کرد و از یک رفت و برگشت بیهوده به سرور جلوگیری کرد .
یک پیاده سازی ساده به کمک jQuery :
var ext = $('#my_file_field').val().split('.').pop().toLowerCase();
if($.inArray(ext, ['gif','png','jpg','jpeg']) == -1) {
    alert('invalid extension!');
}
 
 در کد بالا ابتدا پسوند فایل انتخاب شده توسط کاربر پیدا می‌شود ، سپس به کمک متد inArray با آرایه ای از پسوند‌های دلخواه ما مقایسه می‌شود و در صورت معتبر نبودن پیغامی به کاربر نشان می‌دهد.
کد بالا را می‌توان در رویداد Change کنترل فایل یا در هنگام Post شدن Form اطلاعات قرار داد.
کاملا واضح است که این روش را می‌توان به راحتی دور زد و نباید به آن اکتفا کرد.
مثال این روش را اینجا بررسی کنید.
بررسی سایز فایل :
در اکثر برنامه‌های تحت وب کاربرها محدود به Upload فایل تا سایز خاصی هستند ، این مورد را هم می‌توان قبل از Upload کنترل و اعتبارسنجی کرد : 
//binds to onchange event of your input field
$('#myFile').bind('change', function() {

  //this.files[0].size gets the size of your file.
  alert(this.files[0].size);

});
این روش تا زمانی که کاربر JavaScript را غیر فعال نکرده قابل اطمینان است.
مطالب
تزریق وابستگی‌ها در ASP.NET Core - بخش 5 - آشنایی با کلاس ServiceDescriptor
در بخش پنجم از سری نوشتار «تزریق وابستگی‌ها در ASP.NET Core»، می‌خواهیم به شرح کلاس ServiceDescriptor بپردازیم. اگر تعریف اینترفیس IServiceCollection را مشاهده کنیم، می‌بینیم که IServicecollection در واقع لیستی از اشیائی از نوع ServiceDescriptor را نگهداری می‌کند:
namespace Microsoft.Extensions.DependencyInjection
{
    public interface IServiceCollection : 
       ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>,
       IEnumerable, IList<ServiceDescriptor>
    {
    }
}

ServiceProvider و مؤلفه‌های درونی آن، از یک مجموعه از ServiceDescriptor‌ها برای برنامه‌ی شما بر اساس سرویس‌های ثبت شده‌ی توسط IServiceCollection استفاده می‌کنند. ServiceDescriptor حاوی اطلاعاتی در مورد سرویس‌های ثبت شده‌است. اگر به کد منبع این کلاس برویم، می‌بینیم پنج Property اصلی دارد که با استفاده از آن‌ها اطلاعات یک سرویس ثبت و نگهداری می‌شوند. با استفاده از این  اطلاعات در هنگام اجرا ، DI Container به واکشی و ساخت نمونه‌هایی از سرویس درخواستی اقدام می‌کند:

public Type ImplementationType { get; }
public object ImplementationInstance { get; }
public Func<IServiceProvider, object> ImplementationFactory { get; }
public ServiceLifetime Lifetime { get; }
public Type ServiceType { get; }

هر کدام از این Property ‌ها کاربرد خاص خود را دارند:

  • · ServiceType : نوع سرویسی را که می‌خواهیم ثبت شود، مشخص می‌کنیم ( مثلا اینترفیس IMessageService ) .  
  • · ImplementionType : نوع پیاده سازی سرویس مورد نظرمان را مشخص می‌کند ( مثلا کلاس MessageService ).  
  • · LifeTime : طول حیات سرویس را مشخص می‌کند. DI Container بر اساس این ویژگی، اقدام به ساخت و از بین بردن نمونه‌هایی از سرویس می‌کند.  
  • · ImplementionInstance : نمونه‌ی ساخته شده‌ی از سرویس است.  
  • · ImplementionFactory : یک Delegate است که چگونگی ساخته شدن یک نمونه از پیاده سازی سرویس را در خود نگه می‌دارد. این Delegate یک IServiceProvider را به عنوان ورودی دریافت می‌کند و یک object را بازگشت می‌دهد.

به صورت عادی، در سناریوهای معمول ثبت سرویس‌ها درون IServiceCollection، نیازی به استفاده از ServiceDescriptor نیست؛ ولی اگر بخواهیم سرویس‌ها را به روش‌های پیشرفته‌تری ثبت کنیم، مجبوریم که به صورت مستقیم با این کلاس کار کنیم.

 

می توانیم یک ServiceDesciriptor را به روش‌های زیر تعریف کنیم:

var serviceDescriptor1 = new ServiceDescriptor(
   typeof(IMessageServiceB),
   typeof(MessageServiceBB),
   ServiceLifetime.Scoped);

var serviceDescriptor2 = ServiceDescriptor.Describe(
   typeof(IMessageServiceB),
   typeof(MessageServiceBB),
   ServiceLifetime.Scoped);

var serviceDescriptor3 = ServiceDescriptor.Singleton(typeof(IMessageServiceB), typeof(MessageServiceBB));

var serviceDescriptor4 = ServiceDescriptor.Singleton<IMessageServiceB, MessageServiceBB>();
در بالا روش‌های تعریف یک ServiceDescriptor را می‌بینید. اولین متد و تعریف پارامترها در سازنده‌ها، روش پایه است؛ ولی برای راحتی کار، توسعه دهندگان تعدادی متد static نیز تعریف کرده‌اند که خروجی آنها یک نمونه از ServiceDescriptor است.

همانطور که دیدیم، IServiceCollection در واقع لیست و مجموعه‌ای از اشیاء است که از نمونه‌های جنریک IServiceCollection ، IList ، IEnumerable و Ienumberabl ارث بری می‌کند؛ بنابراین می‌توان از متدهای تعریف شده‌ی در این اینترفیس‌ها برای IServiceCollection نیز استفاده کرد. حالا ما برای اضافه کردن این سرویس‌های جدید، بدین طریق عمل می‌کنیم:

Services.Add(serviceDescriptor1);

استفاده از متدهای TryAdd() 

به کد زیر نگاه کنید :

services.AddScoped<IMessageServiceB, MessageServiceBA>();
services.AddScoped<IMessageServiceB, MessageServiceBB>();
همانطور که می‌بینید، در اینجا یک اینترفیس را دوبار ثبت کردیم. در این حالت موقع واکشی سرویس، DI Container آخرین نمونه‌ی ثبت شده‌ی برای اینترفیس را واکشی کرده و نمونه سازی می‌کند و به کلاس‌ها تزریق می‌کند. این یکی از مواردی است که ترتیب ثبت کردن سرویس‌های مهم است.

برای جلوگیری از این خطا می‌توانیم از متدهای TryAddSingleton() ، TryAddScoped() و TryAddTransient() استفاده کنیم. این متدها درون فضای نام Microsoft.Extionsion.DependencyInjection.Extension قرار دارند.

عملکرد کلی این متدها درست مثل متد‌های Add() است؛ با این تفاوت که این متد ابتدا IServiceCollection را جستجو می‌کند و اگر برای type مورد نظر سرویسی ثبت نشده بود، آن را ثبت می‌کند:

services.TryAddScoped<IMessageServiceB, MessageServiceBA>();
services.TryAddScoped<IMessageServiceB, MessageServiceBB>();

جایگذاری یک سرویس با نمونه‌ای دیگر

گاهی اوقات می‌خواهیم یک پیاده سازی دیگر را بجای پیاده سازی فعلی، در DI Container ثبت کنیم. در این حالت از متد Replace() بر روی IServiceCollection برای این کار استفاده می‌کنیم. این متد فقط یک ServiceDescriptor را به عنوان پارامتر ورودی می‌گیرد:

services.Replace(serviceDescriptor3);
ناگفته نماند که متد Replace() فقط اولین سرویس را با نمونه‌ی مورد نظر ما جایگذاری می‌کند. اگر می‌خواهید تمام نمونه سرویس‌های ثبت شده را برای یک نوع حذف کنید، می‌توانید از متد RemoveAll() استفاده کنید:
services.RemoveAll<IMessageServiceB>();

معمولا در پروژه‌های معمول خودمان نیازی به استفاده از Replace() و RemoveAll() نداریم؛ مگر اینکه بخواهیم پیاده سازی اختصاصی خودمان را برای سرویس‌های درونی فریم ورک یا کتابخانه‌های شخص ثالث، بجای پیاده سازی پیش فرض، ثبت و استفاده کنیم.  

 

AddEnumerable()

فرض کنید دارید برنامه‌ی نوبت دهی یک کلینیک را می‌نویسید و به صورت پیش فرض از شما خواسته‌اند که هنگام صدور نوبت، این قوانین را بررسی کنید:

  •   هر شخص در هفته نتواند بیش از 2 نوبت برای یک تخصص بگیرد.
  •   اگر شخص در ماه بیش از 3 نوبت رزرو شده داشته باشد ولی مراجعه نکرده باشد، تا پایان ماه، امکان رزرو نوبت را نداشته باشد .
  •   تعداد نوبت‌های ثبت شده‌ی برای پزشک در آن روز نباید بیش از تعدادی باشد که پزشک پذیرش می‌کند.
  •   و ...

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

  •   نوبت‌های ثبت شده برای یک شخص نباید دارای تداخل باشند.

در این حالت ما باید دوباره سرویس Register را باز کنیم و به متد بررسی کردن قوانین برویم و دوباره کدهایی را برای بررسی کردن قانون جدید بنویسیم و احتمالا کد ما به این صورت خواهد شد:

public class RegisterAppointmentService : RegisterAppointmentService
{
  public Task<Result> RegisterAsync(
    PatientInfoDTO patientIfno , DateTimeOffset requestedDateTime ,
    PhysicianId phusicianId )
  {
      CheckRegisterantionRule(patientInfo);
      // code here
  }

  private Task CheckRegisterationRule(PatientInfoDTO patientInfo)
  {
       CheckRule1(patientInfo);
       CheckRule2(patientInfo);
       CheckRule3(patientInfo);
  }
}  

در این حالت باید به ازای هر قانون جدید، به متد CheckRegisterationRule برویم و به ازای هر قانون، یک متد private جدید را بسازیم. مشکل این روش این است که در این حالت ما مجبوریم با هر کم و زیاد شدن قانون، این کلاس را باز کنیم و آن را تغییر دهیم و با هر تغییر دوباره، تست‌های واحد آن را دوباره نویسی کنیم. در یک کلام در کد بالا اصول Separation of Concern و  Open/Closed Principle را رعایت نمی‌شود.

یک راهکار این است که یک سرویس جداگانه را برای بررسی کردن قوانین بنویسیم و آن را به سرویس ثبت نوبت تزریق کنیم:

public class ICheckRegisterationRuleForAppointmentService : ICheckRegisterationRuleForAppointmentService
{
     public Task CheckRegisterantionRule(PatientInfoDTO patientInfo)
     {
                CheckRule1(patientInfo);
                CheckRule2(patientInfo);
                CheckRule3(patientInfo);
      }
}

public class RegisterAppointmentService : IRegisterAppointmentService
{
  private ICheckRegisterationRuleForAppointmentService  _ruleChecker;
 
  public RegisterAppointmentService (RegisterAppointmentService  ruleChecker)
  {
          _ruleChecker = ruleChecker;  
  }

  public Task<Result> RegisterAsync(
     PatientInfoDTO patientIfno , 
     DateTimeOffset requestedDateTime , 
     PhysicianId phusicianId )
  {
             _ruleChecker.CheckRegisterantionRule(patientInfo);
                // code here
  }
}

با این کار وظیفه‌ی چک کردن قوانین و وظیفه‌ی ثبت و ذخیره سازی قوانین را از یکدیگر جدا کردیم؛ ولی همچنان در سرویس بررسی کردن قوانین، اصل Open/Closed رعایت نشده‌است. خب راه حل چیست !؟

یکی از راه حل‌های موجود، استفاده از الگوی قوانین یا Rule Pattern است. برای اجرای این الگو، می‌توانیم با تعریف یک اینترفیس کلی برای بررسی کردن قانون، به ازای هر قانون یک پیاده سازی اختصاصی را داشته باشیم:


interface IAppointmentRegisterationRule
{
  Task CheckRule(PatientInfo patientIfno);
}

public class AppointmentRegisterationRule1 : IAppointmentRegisterationRule
{
      public Task CheckRule(PatientInfo patientIfno)
      {
          Console.WriteLine("Rule 1 is checked");
          return Task.CompletedTask;
      }
}

public class AppointmentRegisterationRule2 : IAppointmentRegisterationRule
{
     public Task CheckRule(PatientInfo patientIfno)
     {
Console.WriteLine("Rule 2 is checked"); return Task.CompletedTask; } } public class AppointmentRegisterationRule3 : IAppointmentRegisterationRule { public Task CheckRule(PatientInfo patientIfno) { Console.WriteLine("Rule 3 is checked"); return Task.CompletedTask; } } public class AppointmentRegisterationRule4 : IAppointmentRegisterationRule { public Task CheckRule(PatientInfo patientIfno) { Console.WriteLine("Rule 4 is checked"); return Task.CompletedTask; } }
حالا که ما قوانین خودمان را تعریف کردیم، به روش زیر می‌توانیم آن‌ها را درون سازنده ثبت کنیم:
services.AddScoped<IAppointmentRegisterationRule, AppointmentRegisterationRule1>();
services.AddScoped<IAppointmentRegisterationRule, AppointmentRegisterationRule2>();
services.AddScoped<IAppointmentRegisterationRule, AppointmentRegisterationRule3>();
services.AddScoped<IAppointmentRegisterationRule, AppointmentRegisterationRule4>();
حالا می‌توانیم درون سازنده‌ی سرویس مورد نظرمان، لیستی از سرویس‌های ثبت شده‌ی برای یک نوع خاص را به با استفاده از اینترفیس جنریک IEnumerable<T> دریافت کنیم که در اینجا T، برابر نوع سرویس مورد نظرمان است:
public class CheckRegisterationRuleForAppointmentService : ICheckRegisterationRuleForAppointmentService
{
       private IEnumerable<IAppointmentRegisterationRule> _rules ;

       public CheckRegisterationRuleForAppointmentService(IEnumerable<IAppointmentRegisterationRule> rules)
       {
           _rules = rules;
       }

      public Task CheckRegisterantionRule(PatientInfoDTO patientInfo)
      {
          foreach(var rule in rules)
          {
                rule.CheckRule(patientInfo);
          }
      }
}
با این تغییرات، هر زمانیکه خواستیم می‌توانیم با استفاده از DI Container، قوانین جدیدی را اضافه یا کم کنیم و با این کار، اصل Open/Closed را نیز رعایت کرده‌ایم.

 کد بالا به نظر کامل می‌آید ولی مشکلی دارد! اگر در DI Container برای IAppointmentRegisterationRule یک قانون را دو یا چند بار ثبت کنیم، در هر بار بررسی کردن قوانین، آن را به همان تعداد بررسی می‌کند و اگر این فرآیند منابع زیادی را به کار می‌گیرد، می‌تواند عملکرد برنامه‌ی ما را به هم بریزد.  برای جلوگیری از این مشکل، از متد TryAddEnumerabl() استفاده می‌کنیم که لیستی از ServiceDescriptor ‌ها را می‌گیرد و هر serviceDescriptor را فقط یکبار ثبت می‌کند:

services.TryAddEnumerable(new[] {
  ServiceDescriptor.Scoped(typeof(IAppointmentRegisterationRule), typeof(AppointmentRegisterationRule1)),
  ServiceDescriptor.Scoped(typeof(IAppointmentRegisterationRule), typeof(AppointmentRegisterationRule2)),
  ServiceDescriptor.Scoped(typeof(IAppointmentRegisterationRule), typeof(AppointmentRegisterationRule3)),
  ServiceDescriptor.Scoped(typeof(IAppointmentRegisterationRule), typeof(AppointmentRegisterationRule4)),
});

مطالب
معرفی پروژه فروشگاهی Iris Store
پروژه IrisStore، یک سیستم فروشگاهی متن باز برای راه اندازی فروشگاه‌های اینترنتی کوچک است که سورس آن را می‌توانید از آدرس زیر دریافت کنید و برای اجرای آن نیاز به VS 2015 دارید (به دلیل استفاده‌ی از قابلیت‌های جدید زبان سی‌شارپ):
 
https://github.com/MehdiSaeedifar/IrisStore
 
همچنین نمونه‌ی آنلاین آن‌را می‌توانید در فروشگاه آیریس مشاهده کنید.
 

در ادامه برخی از قابلیت‌های این سیستم را مشاهده می‌کنید:
 

جست و جو با قابلیت دسته بندی نتایج

 
به هنگام جست و جو، لیستی از موارد پیشنهادی به صورت دسته بندی شده نمایش داده می‌شود.



جست و جوی پیشرفته کالا‌ها
 
جست و جو بر اساس قیمت، گروه، کلمات کلیدی و مرتب سازی نتایج انجام می‌گیرد. همچنین نتایج جست و جو بدون رفرش شدن صفحه و به صورت AJAX ای به همراه تغییر URL صفحه صورت می‌گیرد.



نمایش نمودار تغییرات قیمت
 
امکان نمایش نمودار تغییرات قیمت کالا در بازه‌ی زمانی نیز پیش بینی شده است.

   
ویرایش اطلاعات به صورت inline
 
امکان ویرایش قیمت و تاریخ به صورت inline وجود دارد.



   

مدیریت تصاویر کالا

 
در این قسمت امکان آپلود همزمان چندین فایل به همراه پیش نمایش آن‌ها وجود دارد. همچنین امکان کشیدن و رها کردن برای تغییر ترتیب چیدمان عکس‌ها نیز مهیا است.( تصویر اول به عنوان کاور کالا در نظر گرفته می‌شود.)


   

قابلیت‌های دیگر:

 
- مدیریت تصاویر اسلایدشو و تغییر ترتیب آن‌ها از طریق کشیدن و رها کردن (drag & drop)
- تعریف برگه و تغییر ترتیب نمایش آن‌ها از طریق کشیدن و رها کردن
- امکان ارسال پست
- تعریف دسته بندی
- مدیریت کاربران
- تعریف تنظیمات سایت
- نمایش کالا و پست‌های مشابه

کارهایی که باید انجام شود:

 
- پیاده سازی سبد خرید و خرید آنلاین
 

تصویر پنل مدیریت

 

تصویر صفحه‌ی اصلی:



همچنین به راحتی می‌توان با طراحی قالب جدیدی، از این سیستم برای کاری غیر از فروشگاه اینترنتی استفاده کرد؛ سایت‌های زیر نمونه‌های آنلاین دیگری از این سیستم هستند:

- http://www.petrapars.ir
- http://www.ava-tarh.ir
  
در نهایت فهرستی از کتاب خانه‌ها و فناوری‌های استفاده شده و همچنین مقالات مرتبط با این پروژه را قرار داده‌ام.

کتابخانه‌ها و فریم ورک‌های سمت سرور:

 فناوری یا کتابخانه   توضیحات  
مقالات مرتبط
 ASP.NET MVC 5.x
 فریم ورک و موتور اصلی سایت
-ASP.NET MVC
-How to handle repeating form fields in ASP MVC
-How to dynamically (via AJAX) add new items to a bound list model, in ASP MVC.NET  
 Entity Framework 6.x
 فریم ورک دسترسی به داده
-Entity framework code-first
-Update One-to-Many Entity using DBContext 
-مدیریت اطلاعات وابسته به زمان در بانک‌های اطلاعاتی رابطه‌ای
EFSecondLevelCache
کش سطح دوم EF 6
 -بازنویسی سطح دوم کش برای Entity framework 6  
 AutoMapper
 نگاشت اطلاعات یک شی به شی دیگر به صورت خودکار  - دوره AutoMapper
- خودکارسازی فرآیند نگاشت اشیاء در AutoMapper  
 StructureMap
 تزریق وابستگی‌ها
-EF Code First #12  
 MvcCheckBoxList
 اضافه کردن CheckBoxList  به HtmlHelper 

 DNTScheduler
 برای انجام کارهای زمان بندی شده
-انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
 Lucene.Net
 موتور جستجوی سایت  -جستجوی سریع و پیشرفته با لوسین Lucene.net  
 AspNet.Identity
 سیستم مدیریت کاربران
-اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity  
 ELMAH.MVC
 کتابخانه ثبت وقایع و خطا‌های سیستم  -معرفی ELMAH
 PagedList
 نمایش اطلاعات به صورت صفحه بندی شده

PersianDateTime
جایگزینی است برای System.DateTime برای تاریخ‌های شمسی
-PersianDateTime جایگزینی برای System.DateTime
T4MVC
تعاریف Strongly typed مسیرها 
-T4MVC : یکی از الزامات مدیریت پروژه‌های ASP.NET MVC
Dynamic LINQ
نوشتن کوئری‌های LINQ به صورت رشته ای
-انتخاب پویای فیلد‌ها در LINQ
-فعال سازی و پردازش جستجوی پویای jqGrid در ASP.NET MVC 

کتابخانه‌های جاوا اسکریپتی سمت کلاینت:
 
 فناوری یا کتابخانه  
  توضیحات     مقالات مرتبط 
 jQuery  کتاب خانه‌ی پایه جاوا اسکرپتی سایت
 -آموزش (jQuery) جی کوئری
-آموزش JQuery Plugin و مباحث پیشرفته جی کوئری  
 
 jQuery UI  ویجت‌های رابط کاربری
- نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC
- jQuery UI Sortable
-Categorized search result with jQuery UI Autocomplete
- jQuery UI Slider
-rtl jQuery UI Slider
-jquery UI Sortable with table and tr width  
jQuery Validation اعتبار سنجی سمت کلاینت
-مشکل اعتبار سنجی jQuery validator در Bootstrap tabs
-نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Popover به کمک Twitter bootstrap
toastr نمایش پیام و اطلاع رسانی

PersianDatePicker یک DatePicker شمسی کم حجم 
-PersianDatePicker یک DatePicker شمسی به زبان JavaScript که از تاریخ سرور استفاده می‌کند
CKEDITOR ادیتور متن
-استفاده از ادیتور CKEditor در صفحات ASP.NET
-یکپارچه سازی CKEditor با Lightbox
Roxy Fileman مدیریت فایل ها  -افزونه مدیریت فایل‌های رایگان Roxy FileMan برای TinyMce و CkEditor  
Magnific Popup نمایش عکس‌ها به صورت پاپ آپ

Select2 تغییر شکل drop down list‌ها برای انتخاب گزینه‌ها

jqGrid v4.6 نمایش اطلاعات در قالب جدول
- آموزش jqGrid
Bootstrap Star Rating امتیاز دهی ستاره ای
-پیاده سازی امتیاز دهی ستاره‌ای به مطالب به کمک jQuery در ASP.NET MVC
jQuery File Upload Plugin آپلود فایل به صورت AJAX ای

HIGHCHARTS نمایش نمودار

jQuery Number Plugin برای فرمت کردن اعداد

X-editable ویرایش اطلاعات به صورت inline
-قابل ویرایش کننده‌ی فوق العاده x-editable ؛ قسمت اول  
bootstrap-confirmation نمایش فرم تایید در قالب popover

PathJS برای تغییر URL صفحه برای اعمال Ajax ای 
-پیاده سازی دکمه «بیشتر» یا «اسکرول نامحدود» به کمک jQuery در ASP.NET MVC  

فریمورک‌های CSS:
 
فناوری یا کتابخانه
 توضیحات  
 مقالات مرتبط  
 Bootstrap 3.x 
 فریم ورک پایه ای css سایت
 - Bootstrap 3 RTL Theme
- Twitter Bootstrap
-سازگارسازی کلاس‌های اعتبارسنجی Twitter Bootstrap 3 با فرم‌های ASP.NET MVC 
-ساخت قالب‌های نمایشی و ادیتور دکمه سه وضعیتی سازگار با Twitter bootstrap در ASP.NET MVC
-نمایش اخطارها و پیام‌های بوت استرپ به کمک TempData در ASP.NET MVC
 AdminLTE 
 قالب مدیریت سایت
 - نسخه راستچین شده AdminLTE 2.2.1
Animate.css   انیمیشن‌های css3 سایت

Font Awesome   پک آیکون‌های برداری

Awesome Bootstrap Checkbox   زیبا سازی چک باکس ها

فونت فارسی وزیر   قلم فارسی



لطفا برای طرح سؤالات و پیشنهادات خود و جهت مدیریت بهتر آن‌ها، از قسمت اختصاصی این پروژه در سایت استفاده نمائید.
پروژه‌ها
فروشگاه IrisStore
پروژه IrisStore، یک سیستم فروشگاهی متن باز برای راه اندازی فروشگاه‌های اینترنتی کوچک است که سورس آن را می‌توانید از آدرس زیر دریافت کنید و برای اجرای آن نیاز به VS 2015 دارید: 

https://github.com/MehdiSaeedifar/IrisStore 

همچنین نمونه‌ی آنلاین آن‌را می‌توانید در فروشگاه آیریس مشاهده کنید.


در ادامه برخی از قابلیت‌های این سیستم را مشاهده می‌کنید: 
 

جست و جو با قابلیت دسته بندی نتایج
 

به هنگام جست و جو، لیستی از موارد پیشنهادی به صورت دسته بندی شده نمایش داده می‌شود. 



جست و جوی پیشرفته کالا‌ها 

جست و جو بر اساس قیمت، گروه، کلمات کلیدی و مرتب سازی نتایج انجام می‌گیرد. همچنین نتایج جست و جو بدون رفرش شدن صفحه و به صورت AJAX ای به همراه تغییر URL صفحه صورت می‌گیرد. 



نمایش نمودار تغییرات قیمت 
 
امکان نمایش نمودار تغییرات قیمت کالا در بازه‌ی زمانی نیز پیش بینی شده است. 


ویرایش اطلاعات به صورت inline 
 
امکان ویرایش قیمت و تاریخ به صورت inline وجود دارد.



 

مدیریت تصاویر کالا

  
در این قسمت امکان آپلود همزمان چندین فایل به همراه پیش نمایش آن‌ها وجود دارد. همچنین امکان کشیدن و رها کردن برای تغییر ترتیب چیدمان عکس‌ها نیز مهیا است.( تصویر اول به عنوان کاور کالا در نظر گرفته می‌شود.)


 

قابلیت‌های دیگر:

  
- مدیریت تصاویر اسلایدشو و تغییر ترتیب آن‌ها از طریق کشیدن و رها کردن (drag & drop)
- تعریف برگه و تغییر ترتیب نمایش آن‌ها از طریق کشیدن و رها کردن
- امکان ارسال پست
- تعریف دسته بندی
- مدیریت کاربران
- تعریف تنظیمات سایت
- نمایش کالا و پست‌های مشابه


تصویر پنل مدیریت


تصویر صفحه‌ی اصلی:



همچنین به راحتی می‌توان با طراحی قالب جدیدی، از این سیستم برای کاری غیر از فروشگاه اینترنتی استفاده کرد؛ سایت‌های زیر نمونه‌های آنلاین دیگری از این سیستم هستند:

http://www.petrapars.ir 
http://www.ava-tarh.ir 

در نهایت فهرستی از کتاب خانه‌ها و فناوری‌های استفاده شده و همچنین مقالات مرتبط با این پروژه را قرار داده‌ام.

کتابخانه‌ها و فریم ورک‌های سمت سرور:

 فناوری یا کتابخانه   توضیحات
مقالات مرتبط
 ASP.NET MVC 5.x 
 فریم ورک و موتور اصلی سایت
-ASP.NET MVC 
-How to handle repeating form fields in ASP MVC 
-How to dynamically (via AJAX) add new items to a bound list model, in ASP MVC.NET  
 Entity Framework 6.x 
 فریم ورک دسترسی به داده
-Entity framework code-first 
-Update One-to-Many Entity using DBContext
-مدیریت اطلاعات وابسته به زمان در بانک‌های اطلاعاتی رابطه‌ای 
EFSecondLevelCache 
کش سطح دوم EF 6
 -بازنویسی سطح دوم کش برای Entity framework 6
 AutoMapper 
 نگاشت اطلاعات یک شی به شی دیگر به صورت خودکار  دوره AutoMapper 
خودکارسازی فرآیند نگاشت اشیاء در AutoMapper
 StructureMap 
 تزریق وابستگی‌ها 
-EF Code First #12
 MvcCheckBoxList 
 اضافه کردن CheckBoxList  به HtmlHelper

 DNTScheduler 
 برای انجام کارهای زمان بندی شده
-انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
 Lucene.Net 
 موتور جستجوی سایت  -جستجوی سریع و پیشرفته با لوسین Lucene.net
 AspNet.Identity 
 سیستم مدیریت کاربران
-اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity
 ELMAH.MVC 
 کتابخانه ثبت وقایع و خطا‌های سیستم  -معرفی ELMAH
 PagedList 
 نمایش اطلاعات به صورت صفحه بندی شده

PersianDateTime 
جایگزینی است برای System.DateTime برای تاریخ‌های شمسی 
-PersianDateTime جایگزینی برای System.DateTime
T4MVC 
تعاریف Strongly typed مسیرها
-T4MVC : یکی از الزامات مدیریت پروژه‌های ASP.NET MVC
Dynamic LINQ 
نوشتن کوئری‌های LINQ به صورت رشته ای
-انتخاب پویای فیلد‌ها در LINQ 
-فعال سازی و پردازش جستجوی پویای jqGrid در ASP.NET MVC

کتابخانه‌های جاوا اسکریپتی سمت کلاینت:

 فناوری یا کتابخانه
  توضیحات     مقالات مرتبط
 jQuery  کتاب خانه‌ی پایه جاوا اسکرپتی سایت
 -آموزش (jQuery) جی کوئری 
-آموزش JQuery Plugin و مباحث پیشرفته جی کوئری

 jQuery UI  ویجت‌های رابط کاربری
نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC 
jQuery UI Sortable 
-Categorized search result with jQuery UI Autocomplete 
jQuery UI Slider 
-rtl jQuery UI Slider 
-jquery UI Sortable with table and tr width
jQuery Validation اعتبار سنجی سمت کلاینت
-مشکل اعتبار سنجی jQuery validator در Bootstrap tabs 
-نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Popover به کمک Twitter bootstrap
toastr نمایش پیام و اطلاع رسانی

PersianDatePicker یک DatePicker شمسی کم حجم
-PersianDatePicker یک DatePicker شمسی به زبان JavaScript که از تاریخ سرور استفاده می‌کند
CKEDITOR ادیتور متن
-استفاده از ادیتور CKEditor در صفحات ASP.NET 
-یکپارچه سازی CKEditor با Lightbox 
Roxy Fileman مدیریت فایل ها  -افزونه مدیریت فایل‌های رایگان Roxy FileMan برای TinyMce و CkEditor  
Magnific Popup نمایش عکس‌ها به صورت پاپ آپ

Select2 تغییر شکل drop down list‌ها برای انتخاب گزینه‌ها

jqGrid v4.6 نمایش اطلاعات در قالب جدول
آموزش jqGrid
Bootstrap Star Rating امتیاز دهی ستاره ای
-پیاده سازی امتیاز دهی ستاره‌ای به مطالب به کمک jQuery در ASP.NET MVC
jQuery File Upload Plugin آپلود فایل به صورت AJAX ای

HIGHCHARTS نمایش نمودار

jQuery Number Plugin برای فرمت کردن اعداد

X-editable ویرایش اطلاعات به صورت inline
-قابل ویرایش کننده‌ی فوق العاده x-editable ؛ قسمت اول
bootstrap-confirmation نمایش فرم تایید در قالب popover

PathJS برای تغییر URL صفحه برای اعمال Ajax ای
-پیاده سازی دکمه «بیشتر» یا «اسکرول نامحدود» به کمک jQuery در ASP.NET MVC

فریمورک‌های CSS:

فناوری یا کتابخانه 
 توضیحات
 مقالات مرتبط
 Bootstrap 3.x
 فریم ورک پایه ای css سایت
 - Bootstrap 3 RTL Theme 
Twitter Bootstrap 
-سازگارسازی کلاس‌های اعتبارسنجی Twitter Bootstrap 3 با فرم‌های ASP.NET MVC
-ساخت قالب‌های نمایشی و ادیتور دکمه سه وضعیتی سازگار با Twitter bootstrap در ASP.NET MVC 
-نمایش اخطارها و پیام‌های بوت استرپ به کمک TempData در ASP.NET MVC
 AdminLTE
 قالب مدیریت سایت
 - نسخه راستچین شده AdminLTE 2.2.1
Animate.css انیمیشن‌های css3 سایت

Font Awesome پک آیکون‌های برداری

Awesome Bootstrap Checkbox زیبا سازی چک باکس ها

فونت فارسی وزیر قلم فارسی
 

مطالب
بلاگ‌ها و مطالب مطالعه شده در هفته قبل (هفته دوم آبان)

وبلاگ‌ها و سایت‌های ایرانی


Visual Studio


امنیت


ASP. Net


طراحی وب


اس‌کیوال سرور


به روز رسانی‌ها


ابزارها


سی‌شارپ

  • تازه‌های سی شارپ 4 ، واژه کلیدی dynamic ، قسمت‌های یک و دو و سه

عمومی دات نت


CPP


دلفی


ویندوز


Office

  • آشنایی با یک سری از اصطلاحات outlook 2007 برای برنامه نویس‌ها. (اگر قصد داشته باشید یک add-in را برای outlook 2007 با استفاده از امکانات VSTO توسعه دهید، آشنایی با این اصطلاحات بسیار ضروری خواهد بود)

متفرقه



نظرات مطالب
پیاده سازی JSON Web Token با ASP.NET Web API 2.x
- در مورد آدرس ویژه‌ی login این روش (نحوه‌ی تعیین، تغییر و پردازش ویژه‌ی آن)، هم در مطلب و هم در نظرات، بحث شده‌است. واژه‌ی login را در صفحه‌ی جاری جستجو کنید.
- مطلب و نظرات «امن سازی درخواست‌های ای‌جکسی برنامه‌های ASP.NET MVC 5.x در مقابل حملات CSRF» را در مورد نحوه‌ی ارسال RequestVerificationToken در برنامه‌های Ajax ایی مطالعه کنید.
- روش JWT عموما برای برنامه‌های تمام SPA (تمام تک صفحه‌ای وب مانند Angular) استفاده می‌شود (پیشنیاز بحث را که در ابتدای آن عنوان شده، مطالعه کنید). اگر برنامه‌ی شما تمام MVC است و از صفحات Razor استفاده می‌کنید، بهتر است از روش «اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity» استفاده کنید.
مطالب
تنظیمات CORS در ASP.NET Core
برنامه‌های امروزی، ممکن است به چندین Web API مستقل، تبدیل شده و سپس برنامه‌هایی (Front-ends) جدای از آن‌ها برای کار با آن‌ها ایجاد شوند. بنابراین این وظیفه‌ی برنامه‌‌های Web API است که مطمئن شوند کلاینت‌ها قادر به تعامل با آن‌ها هستند. CORS استانداردی است که یک چنین امکانی را مهیا می‌کند.



CORS چیست؟

CORS و یا cross origin resource sharing، یک مکانیزم امنیتی است که در تمام مرورگرهای جدید جهت جلوگیری از ارسال اطلاعات یک وب سایت، به وب سایتی دیگر، درنظر گرفته شده‌است. درخواست دسترسی به یک منبع (Resource) مانند تصویر، داده و غیره، خارج از سرآغاز آن، یک درخواست cross-origin نامیده می‌شود. برای مدیریت یک چنین درخواست‌هایی، استانداردی به نام CORS طراحی شده‌است. می‌توان به آن مانند نگهبانی یک ساختمان نگاه کرد که تا مجوز خاصی به آن‌ها ارائه نشود، امکان دسترسی به منابع ساختمان را صادر نخواهند کرد.


Origin چیست؟

سرآغاز یک درخواست از سه قسمت تشکیل می‌شود:
- Protocol/Scheme مانند HTTP/HTTPS
- Host مانند نام دومین
- شماره پورت مانند 443 برای پروتکل HTTPS  یا پورت 80 برای HTTP که عموما هر دو مورد به علت پیش‌فرض بودن، ذکر نمی‌شوند

بنابراین URLای مانند https://www.dntips.ir یک Origin را مشخص می‌کند. در اینجا به تمام منابعی که از این سرآغاز شروع می‌شوند و سه قسمت یاد شده‌ی آن‌ها یکی است، same-origin گفته می‌شود.
در این حالت اگر منابعی به URLهایی مانند https://www.dntips.ir (پروتکل متفاوت) و یا https://github.com (با host متفاوت) اشاره کنند، به آن‌ها Different-Origin گفته خواهد شد.


سیاست امنیتی Same-Origin چیست؟

سیاست امنیتی Same-Origin که به صورت توکار در تمام مرورگرهای امروزی تعبیه شده‌است، مانع تعامل سرآغازهایی متفاوت، جهت جلوگیری از حملات امنیتی مانند Cross-Site Request Forgery یا CSRF می‌شود. این سیاست امنیتی بسیار محدود کننده‌است و برای مثال مانع این می‌شود که بتوان توسط کدهای JavaScript ای، درخواستی را به سرآغاز دیگری ارسال کرد؛ حتی اگر بدانیم درخواست رسیده از منبعی مورد اطمینان صادر شده‌است. برای مثال اگر سایت جاری یک درخواست Ajax ای را به https://anotherwebsite.com/api/users ارسال کند، چون قسمت host مربوط به origin آن‌ها یکی نیست، این عملیات توسط مرورگر غیرمجاز شمرده شده و مسدود می‌شود.


چگونه می‌توان از تنظیمات CORS، برای رفع محدودیت‌های سیاست‌های دسترسی Same-Origin استفاده کرد؟

استاندارد CORS تعدادی header ویژه را جهت تبادل اطلاعات بین سرور و مرورگر مشخص کرده‌است تا توسط آن‌ها بتوان منابع را بین سرآغازهای متفاوتی به اشتراک گذاشت. در این حالت ابتدا کلاینت درخواستی را به سمت سرور ارسال می‌کند. سپس سرور پاسخی را به همراه هدرهای ویژه‌ای که مشخص می‌کنند به چه منابعی و چگونه می‌توان دسترسی یافت، به سمت کلاینت ارسال خواهد کرد. اکثر این هدرها با Access-Control-Allow شروع می‌شوند:
• Access-Control-Allow-Origin
در آن لیست سرآغازهایی را که سرور مایل است منابع خود را با آن‌ها به اشتراک بگذارد، مشخص می‌شوند. در حالت توسعه‌ی برنامه می‌توان از مقدار * نیز برای آن استفاده کرد تا هر سرآغازی بتواند به منابع سرور دسترسی پیدا کند. اما از استفاده‌ی این مقدار سراسری و کلی، در حالت انتشار برنامه خودداری کنید.
• Access-Control-Allow-Headers
• Access-Control-Allow-Methods
• Access-Control-Allow-Credentials


درخواست‌های ویژه‌ی Pre-Flight

در بسیاری از موارد، مرورگر زمانیکه تشخیص می‌دهد درخواست صادر شده‌ی از طرف برنامه، قرار است به یک Origin دیگر ارسال شود، خودش یک درخواست ویژه را به نام Pre-Flight و از نوع OPTIONS به سمت سرور ارسال می‌کند. علت آن این است که سرورهای قدیمی، مفهوم CORS را درک نمی‌کنند و در برابر درخواست‌های ویژه‌ای مانند Delete که از سرور جاری صادر نشده باشند، مقاومت می‌کنند (صرفا درخواست‌های Same-Origin را پردازش می‌کنند). به همین جهت است که اگر به برگه‌ی network ابزارهای توسعه دهندگان مرورگر خود دقت کنید، درخواست‌های cross-origin به نظر دوبار ارسال شده‌اند. بار اول درخواستی که method آن، options است و در خواست دوم که درخواست اصلی است و برای مثال method آن put است. این درخواست اول، Pre-Flight Request نام دارد. هدف آن این است که بررسی کند آیا سرور مقصد، استاندارد CORS را متوجه می‌شود یا خیر و آیا اینقدر قدیمی است که صرفا درخواست‌های Same-Origin را پردازش می‌کند و مابقی را مسدود خواهد کرد. اگر سرور درخواست Pre-Flight را درک نکند، مرورگر درخواست اصلی را صادر نخواهد کرد.



البته درخواست‌های pre-flight بیشتر در حالت‌های زیر توسط مرورگر صادر می‌شوند:
- اگر متد اجرایی مدنظر، متدی بجز GET/POST/HEAD باشد.
- اگر content type درخواست‌های از نوع POST، چیزی بجز application/x-www-form-urlencoded, multipart/form-data و یا text/plain باشند.
- اگر درخواست، به همراه یک هدر سفارشی باشد نیز سبب صدور یک pre-flight request خواهد شد.

بنابراین در برنامه‌های SPA خود که اطلاعات را با فرمت JSON به سمت یک Web API ارسال می‌کنند (و Origin آن‌ها یکی نیست)، حتما شاهد درخواست‌های Pre-Flight نیز خواهید بود.


تنظیمات CORS در ASP.NET Core

اکنون که با مفهوم CORS آشنا شدیم، در ادامه به نحوه‌ی انجام تنظیمات آن در برنامه‌های ASP.NET Core خواهیم پرداخت.
تنظیمات ابتدایی CORS در فایل Startup.cs و متد ConfigureServices آن انجام می‌شوند:
public void ConfigureServices(IServiceCollection services) 
{ 
    // Add service and create Policy with options 
    services.AddCors(options => 
    { 
        options.AddPolicy("CorsPolicy", 
            builder => builder.AllowAnyOrigin() 
            .AllowAnyMethod() 
            .AllowAnyHeader() 
            .AllowCredentials() ); 
    }); 
     
    // Make sure MVC is added AFTER CORS 
    services.AddMvc(); 
}
ابتدا توسط متد AddCors، سرویس‌های مرتبط، به سیستم تزریق وابستگی‌های ASP.NET Core اضافه خواهند شد و سپس در قسمت تنظیمات آن می‌توان همان هدرهای Access-Control-Allow را که پیشتر در مورد آن‌ها بحث کردیم، تعریف و مقدار دهی کرد. برای مثال تنظیم AllowAnyOrigin، همان استفاده‌ی از مقدار * در هدر Access-Control-Allow-Origin تولیدی است. باید دقت داشت که تنظیمات این سرویس‌ها باید پیش از افزودن سرویس‌های MVC انجام شوند.
در اینجا CorsPolicy که به عنوان پارامتر مشخص شده‌است، نام این سیاست دسترسی سفارشی است و در قسمت‌های مختلف برنامه می‌توان ارجاعاتی را به این نام تعریف کرد.

و برای تعریف سرآغازی خاص و یا متدی مشخص، می‌توان به صورت زیر عمل کرد (ذکر صریح WithOrigins برای حالت توزیع برنامه مناسب است و از دیدگاه امنیتی، استفاده‌ی از AllowAnyOrigin کار صحیحی نیست ):
services.AddCors(options =>
{
    options.AddPolicy("AllowOrigin",
            builder => builder.WithOrigins("http://localhost:55294")
                              .WithMethods("GET", "POST", "HEAD"));
});

پس از تنظیم سیاست دسترسی مدنظر، اکنون نوبت به اعمال آن است. اینکار در متد Configure فایل Startup.cs انجام می‌شود:
public void Configure(IApplicationBuilder app) 
{ 
    // ... 
 
    app.UseCors("CorsPolicy"); 
     
    // ... 
     
    app.UseMvc(routes => 
    { 
        routes.MapRoute( 
            name: "default", 
            template: "{controller=Home}/{action=Index}/{id?}"); 
    }); 
}
در اینجا متد UseCors که میان‌افزار CORS را فعال می‌کند، باید پیش‌از میان‌افزار Mvc تعریف شود تا بتواند هدرها را اعمال کند. همچنین نامی که در اینجا به عنوان پارامتر آن استفاده شده، دقیقا به همان نامی که برای تنظیمات سیاست دسترسی درنظر گرفته شد، اشاره می‌کند.
متد app.UseCors، یک متد سراسری است و کل سیستم را داخل این سیاست دسترسی CORS قرار می‌دهد. اگر می‌خواهید صرفا به کنترلر خاصی این تنظیمات اعمال شوند، می‌توان از فیلتر EnableCors با ذکر نام سیاست دسترسی تعریف شده، استفاده کرد (در این حالت ذکر services.AddCors ضروری است و از ذکر app.UseCors صرفنظر می‌شود):
[EnableCors("CorsPolicy")]
public class MyApiController : Controller

و یا اگر می‌خواهید از app.UseCors سراسری استفاده کنید، اما آن‌را برای کنترلر و یا حتی اکشن متد خاصی غیرفعال نمائید، می‌توان از فیلتر [DisableCors] استفاده کرد.

چند نکته:
- به نام رشته‌ای سیاست دسترسی تعریف شده، دقت داشته باشید. اگر این نام را درست ذکر نکنید، هدری تولید نخواهد شد.
- میان‌افزار CORS، برای درخواست‌های same-origin نیز هدری را تولید نمی‌کند.


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

در هر دو روش فوق که یکی بر اساس app.UseCors سراسری و دیگری بر اساس فیلتر EnableCors اختصاصی کار می‌کنند، ذکر نام سیاست دسترسی options.AddPolicy ضروری است. اگر علاقه‌ای به ذکر این نام ندارید، می‌توان به طور کامل از تنظیم services.AddCors صرفنظر کرد (قسمت پارامتر و تنظیمات آن‌را ذکر نکرد) و متد app.UseCors را به صورت زیر تنظیم نمود که قابلیت داشتن تنظیمات خاص خود را نیز دارا است:
public void ConfigureServices(IServiceCollection services)
{
      services.AddCors();
      services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseCors(policyBuilder =>
    {
        string[] origins = new string[] { "http://localhost:2000", "http://localhost:2001" };
 
        policyBuilder
            .AllowAnyHeader()
            .AllowAnyMethod()
            .WithOrigins(origins);
    });
 
    app.UseMvc();
}

روش دیگر انجام اینکار، تعریف یک DefaultPolicy است:
public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(
            builder =>
            {
            builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            });
          options.AddPolicy("MyCORSPolicy",
            builder =>
            {
                builder.WithOrigins("http://localhost:49373")
                                    .AllowAnyHeader()
                                    .AllowAnyMethod();
            });
     });
    services.AddMvc().AddNewtonsoftJson();
}
در اینجا در متد AddCors می‌توان چندین AddPolicy نامدار را داشت، به همراه یک AddDefaultPolicy بدون نام. استفاده‌ی از سیاست نام‌دار تعریف شده، یا توسط متد سراسری app.UseCors("MyCORSPolicy") انجام می‌شود و یا توسط فیلتر [EnableCors("MyCORSPolicy")]. اما اگر فیلتر [EnableCors] را بدون ذکر نامی قید کنیم، از همان تنظیمات AddDefaultPolicy استفاده خواهد کرد.


خطاهای متداول حین کار با CORS

خطای کار با SignalR و ارسال اطلاعات اعتبارسنجی کاربر

Access to XMLHttpRequest at 'http://localhost:22135/chat/negotiate?jwt=<removed the jwt key>' 
from origin 'http://localhost:53150' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. 
The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
برای رفع این مشکل کافی است متد AllowCredentials نیز قید شود:
services.AddCors(options =>
{
     options.AddPolicy("AllowAllOrigins",
         builder =>
          {
              builder
                 .AllowAnyOrigin()
                 .AllowAnyHeader()
                 .AllowAnyMethod()
                 .AllowCredentials();
          });
    });

تمام اعتبارسنجی‌ها و اطلاعات کوکی‌ها در سمت سرور قابل دسترسی نیستند

CORS به صورت پیش‌فرض اطلاعات کوکی‌ها را به دومینی دیگر ارسال نمی‌کند. در این حالت اگر حتما نیاز به انجام اینکار است، باید در درخواست Ajax ای ارسالی، خاصیت withCredentials به true تنظیم شود. همچنین سمت سرور نیز هدر Access-Control-Allow-Credentials را تنظیم کند (همان متد AllowCredentials فوق). در اینجا Credentials به کوکی‌ها، هدرهای اعتبارسنجی (مانند هدرهای JWT) کاربران و یا مجوزهای TLS کلاینت‌ها اشاره می‌کند.
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;

//In jQuery:
$.ajax({
  type: 'get',
  url: 'http://www.example.com/home',
  xhrFields: {
    withCredentials: true
}

//ES6 fetch API:
fetch(
   'http://remote-url.com/users',
   {
     'PUT',
     headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
     },
     mode: 'cors',
     credentials: 'include',
     body: JSON.stringify(body)
   }
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((error) => console.error(error));

CORS حساس به حروف کوچک و بزرگ است

روش دیگر تنظیم فیلتر EnableCors را در اینجا مشاهده می‌کنید:
[EnableCors(origins: "http://MyWebsite.com", headers: "*", methods: "*")]
//is not the same as this:
[EnableCors(origins:"http://mywebsite.com", headers: "*", methods: "*")]
اگر بجای * دقیقا origins را مشخص کردید، بخاطر داشته باشید که این تنظیم به کوچکی و بزرگی حروف حساس است و در صورت اشتباهی (مانند ذکر MyWebSite بجای mywebsite متداول با حروف کوچک)، درخواست‌های رسیده مسدود خواهند شد. همچنین همانطور که ذکر شد، بین HTTP و HTTPS نیز تفاوت وجود دارد و origin این‌ها یکی درنظر گرفته نمی‌شود و حتی اگر تمام حروف را هم کوچک وارد کرده باشید، باز هم تنظیمات جداگانه‌ای را نیاز خواهند داشت.


در حالت بروز خطای مدیریت نشده‌ای در سمت سرور، ASP.NET Core هدرهای CORS را ارسال نمی‌کند
اطلاعات بیشتر 
نظرات مطالب
inject$ در AngularJs
 به صورت کلی با استفاده از watch$  می‌توان تمامی تغییراتی را که به خواص ViewModel اعمال می‌شوند مشاهده کرد.
تعریف کلی آن به صورت زیر است:
$watch(watchExpression, listener, objectEquality)
»watchExpression : می‌توان نام خاصیت مورد نظر در ViewModel یا یک تابع را که قصد مشاهده تغییرات آن را داریم تعیین کنیم.
»Listener : با تغییر در مقدار watchExpression  اگر  مقدار قبلی این عبارت با مقدار فعلی آن برابر نباشد این تابع فراخوانی می‌شود.
» objectEquality : به صورت پیش فرض Angular مقادیر مورد نظر برای تغییرات را فقط از نظر Reference Equal بودن چک می‌کند. اگر بخواهیم که Angular به صورت عمقی و درختی مقادیر ابجکت‌ها را بررسی کند مقدار این پارامتر باید true شود.
در فریم ورک Angular هر زمان که عمل مقید سازی خواص ViewModel به عناصر DOM انجام می‌گیرد در واقع یک نمونه از watch$ به لیستی به نام watch list $ اضافه می‌شود. دقت کنید که صرفا تعریف در محدوده کنترلر کافی نیست بلکه باید خاصیت مورد نظر حتما مقید شود. برای مثال
app.controller('MainCtrl', function($scope) {
  $scope.foo = "Foo";
  $scope.world = "World";
});
در View نیز
Hello, {{ World }}
در کنترلر بالا دو خاصیت تعریف شده است، در حالی که در View فقط یک خاصیت مقید شده است. درنتیجه فقط یک watch$ به لیست مورد نظر اضافه شده است.
و به عنوان نکته آخر، در Angular نسخه 1.1.4 تابعی به نام watchCollection اضافه شده است که برای ردیابی تغییرات یک مجموعه مورد استفاده قرار می‌گیرد.
یک مثال در این مورد
مطالب
مقدمه‌ای بر Docker
Docker به صورت ساده، پلتفرمی است که به سادگی قابلیت ساخت، انتقال و اجرا کردن Image‌ها را در اختیار دارد و همچنین به صورت native درون سرور‌های لینوکسی و ویندوزی اجرا میشود؛ به علاوه اینکه در محیط محلی، برای تست نیز بر روی ماشین‌های ویندوزی و مک از طریق virtual machine قابل اجراست.

دو مفهوم اساسی در محیط Docker وجود دارند که دانستن آن‌ها ضروری است: Image و Container
image عملا چیزی است که از آن برای Build یک Container استفاده می‌شود. image دارای یک سری فایل‌های لازم و اساسی است که باعث می‌شود بر روی یک Operation System اجرا شود؛ مثل Ubuntu یا Windows. بنابراین شما Application Framework خود را خواهید داشت و همچنین Databaseی که با آن کار میکند. بنابراین قابلیت استفاده از زبان‌ها و فریم ورک‌های مختلف چون Asp.net Core, Nodejs, Python و غیره را خواهد داشت. یک image به خودی خود غیر قابل استفاده است تا زمانیکه بر روی یک Container توزیع شده باشد، تا قابلیت اجرا پیدا کند. بنابراین نقطه‌ی شروع اصلی اجرایی یک برنامه با Container مربوط به آن میباشد.
به صورت خلاصه Image یک template از نوع Readonly است که ترکیبی از لایه‌های File System می‌باشد، به همراه فایل‌های share شده‌ی دیگر (از قبیل فریم ورک‌ها و ...) که میتوانند یک Docker Container Instance را تولید نمایند.
Container یک محیط امن و ایزوله است که به وسیله‌ی image ساخته شده است و میتواند اجرا، متوقف، منتقل و یا حذف شود (بطور قابل ملاحظه‌ای اجرا کردن و متوقف کردن آن سریع میباشد).


تفاوت Docker Containers و Virtual Machines

Virtual Machines همیشه بر روی Host Operation System اجرا میشوند (که می‌تواند بر روی ویندوز یا لینوکس باشد) و بعد از آن اجرای Guest OS بر روی سطحی به نام Hypervisor. پس میتوان گفت یک کپی کامل از سیستم عامل است که که بر روی hypervisor اجرا میشود و خودش نیز بر روی سخت افزار اجرا میشود. بنابراین میتوان مثل شکل زیر، یک App داشت که عملا یک سری باینری و کتابخانه است و اگر قرار باشد بر روی سیستم عامل‌های مختلفی کار کند، احتیاج به کپی کردن کل آن می‌باشد و بطور واضحی زمان و هزینه‌ی بیشتری برای بالا آوردن آن لازم است.
اما بر خلاف آن، داکر با استفاده از ابزاری به نام Docker Engine کار میکند که میتواند Container‌های مختلفی از OS‌های مختلف را اجرا نماید و نیازی به کپی گرفتن از کل سیستم عامل برای اجرای هر container نخواهد بود.


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


چطور Docker میتواند سریعتر از Virtual Machine‌ها عمل کند ؟

داکر از چیزی به نام Copy On Write استفاده میکند؛ به معنای کپی کردن همزمان با نوشتن. همانطور که گفته شد هر Container از یک Image ساخته میشود و عملا Imageها همان FileSystem‌های از قبل تولید شده هستند و هر کدام از لایه‌ای از کتابخانه‌ها استفاده میکنند که برای اجرای برنامه‌های کاربردی مورد استفاده قرار می‌گیرند. سرور آپاچی را در نظر بگیرید، به عنوان یک فایل image که FileSystem بر روی آن ذخیره شده‌است. با نصب Php یک لایه بر روی لایه دیگر ایجاد شده و فقط تغییرات جدید به آن اضافه خواهند شد و حال اگر بخواهید تغییری را بر روی source code خود بدهید، عملا فقط آن تغییر به Image و FileSystem اضافه خواهد شد. این معماری لایه لایه باعث تولید یک FileSystem بصورت read-only میشود که شامل لایه‌های متفاوتی است و سبب کم حجم شدن آن، بالا رفتن سرعت آن می‌شود و همچنین با استفاده از Caching، قدرت زیادی را بدان می‌بخشد.


پس همانطور که در شکل فوق مشاهده میکنید، هر image از لایه‌های مختلفی تشکیل شده است و توانایی به اشتراک گذاشتن این لایه‌های متمایز از یکدیگر در Container‌ها وجود دارد.


بنابراین طبق شکل فوق، بحث را اینگونه خلاصه میکنیم که هر Image از ترکیبی از لایه‌هایی از نوع read-only تشکیل شده است و با اضافه شدن Container، عملا یک لایه‌ی دیگری که قابلیت read/write را دارد بر روی آن اضافه میشود و درون آن source code میتواند قرار گیرد و اینکه بر مبنای شکل زیر میبینید که قابلیت به اشتراک گذاری Image layer‌ها به Container‌های مختلف تعبیه شده است که باعث میشود لایه‌ی نصب شده بر روی سیستم، بصورت اشتراکی قابل استفاده‌ی مجدد باشد و فضای دیسک کمتری، به علاوه سرعت اجرای بالاتری را داشته باشد. هر لایه یک مقدار هش شده‌ی یکتایی را در اختیار دارد تا از لایه‌های دیگر تمیز داده شود و قابل شناسایی باشد.




داکر در شبکه چگونه کار میکند؟

ضمنا نکته‌ی قابل توجه که در مقاله‌های بعدی به صورت عملی به آن میپردازیم این است که با استفاده از داکر میتوانیم وب سرورهایی را بر روی Container‌های مختلفی داشته باشیم که همگی بر روی پورت بطور مثال 80 هستند؛ طوری که درون هر Container بدلیل ایزوله بودن پروسس‌های مخصوص Container مربوط به خود، به پورت‌های باز داخل آن شبکه دسترسی دارند و میتوانند پورت در نظر گرفته شده‌ی درون Container را با پورت دیگری بیرون Container به اصطلاح Expose نمایند.
ضمن اینکه نکته‌ی دیگری که وجود دارد، ارتباط Container‌ها با یکدیگر است. برای مثال یک Container برای Database و دیگری برای WebApp میباشد که باید به همدیگر link شده تا قابل استفاده گردند و عملا نیازی به نوشتن ip یکدیگر در این حالت وجود ندارد. البته راه‌های دیگری از قبیل Compose کردن نیز وجود دارد که در ادامه بیشتر با آن‌ها آشنا خواهیم شد.


Docker Volume چیست؟

بحث دیگری که وجود دارد، Volumeها هستند که قسمتی از FileSystem‌ها میباشند و بصورت ساده، مثال کاربردی‌اش میتواند قسمتی از یک سیستم و دایرکتوری خاصی را بر روی Container خاصی Map کردن باشد و عملا داخل آن دایرکتوری میتواند source code بوده باشد (یکی از راه‌های ممکن برای map کردن source code به container) و بر روی Container ایجاد شود.
فوایدی که با استفاده از Volume‌ها میتوان به آن رسید از قبیل موارد زیر میباشند:
قابلیت به اشتراک گذاری یک Volume بین Container‌های مختلف که به شدت میتواند قابل استفاده باشد.
Data Volume‌ها ماندگار هستند. یعنی حتی بعد از اینکه Container مربوطه را حذف نمایید، volume مربوط به آن بطور اتوماتیک حذف نمیشود (مگر اینکه خودتان دستور حذف کردن آن را وارد نمایید). پس عملا قابلیت استفاده‌ی مجدد را نیز خواهد داشت.

طبق شکل فوق ما میتوانیم درون یک container یک volume داشته باشیم. وقتی ما چیزی را درون آن مینویسیم عملا داریم در قسمت خاصی به نام Docker Host عمل write کردن را انجام میدهیم که باعث میشود داکر متوجه آن شود. وقتی اسمی را به یک Volume انتساب میدهیم همانند /var/www، در واقع یک اسم مستعار (alias) میباشد که اشاره میکند به این Docker host موجود. در ادامه بیشتر با Volume‌ها آشنا خواهیم شد. 


DockerFile و ساخت image‌ها چگونه است؟

روش دیگر برای اجرای source code در داکر، ساخت یک image اختصاصی از آن و اجرا کردن آن بر روی یک container مجزا است.  با استفاده از DockerFile میتوانید image‌های خود را build کرده که عملا هر image در آخر باید به یک سیستم عامل برسد و همانطور که گفته شد به صورت لایه‌ای کار میکنند و مراتب اجرای آن از قبیل working directory و expose کردن بر روی پورتی خاص، همچنین استفاده از Environment Variable‌ها میباشد و همچنین با استفاده از DockerHub (که نسخه‌ی enterprise نیز دارد) میتوان image‌های ساخته شده را بر روی cloud نگه داشت و همه‌ی اعضای تیم از یک image بخصوص استفاده کنند؛ برای مثال همه‌ی اعضای تیم از یک نسخه‌ی Nodejs استفاده کنند و اشتباها بر روی ماشین‌های توسعه‌ی مختلف برنامه نویسان، از نسخه‌های مختلفی استفاده نشود و همچنین روند به‌روز رسانی به سادگی انجام گیرد.


مزایای Docker برای برنامه نویسان

فرض کنید که یک App Service از Azure تهیه کرده باشید. تست‌های unit, integration, acceptance را انجام داده و با خیال راحت Container خود را از طریق برای مثال Visual studio team service بر روی App service به صورت انتشار از طریق مدل Continuous Integration و  Continuous Deployment داشته باشید. پس عملا داکر به Devops بودن محیط و چابک بودن تیم توسعه کمک شایانی کرده و فرآیند‌های سخت و زمانبر انتقال Codeها از محیط توسعه به محیط انتشار را تسریع میبخشد.
بنابراین از داکر به راحتی میتوان در محیط Production نیز استفاده کرد و مزایای فوق العاده ای را برای برنامه نویسان ارائه کرده است. بطور مثال فرض کنید در تولید نرم‌افزار یک Web server ، تعدادی Database و یک Caching server که کانفیگ کردن، اجرا و ... به صورت عادی بسیار صعب و مشکل ساز بوده را به راحتی میتوان اجرا نمود. ضمن اینکه ممکن است هر کدام از ابزارهایی که استفاده شده، فقط مخصوص سیستم عاملی خاص باشد که قاعدتا احتیاج به بالا آوردن Virtual Machine خواهید بود و در سناریو‌های خاصی مثل سیستم هایی با معماری Microservice که هر کدام از این ریز سرویس‌ها ممکن است زبان، فریم ورک، دیتابیس و ... مخصوص به خود را داشته باشند، عملا کار بسیار سخت و پر هزینه خواهد بود (ضمن اینکه استفاده‌ی همزمان از چند Virtual Machine در کنار هم در محیط توسعه، حجم زیادی از memory و disk سیستم شما را خواهد گرفت و شما را مجبور به ارتقای سیستم خود خواهد کرد!).

مشکل دیگری که Docker آن را حل کرده، Conflict‌های ورژن‌های مختلف ابزار‌های مورد استفاده است. به راحتی میتوان Containerی از Image‌ها را به صورت ایزوله با ورژن‌های مختلفی ایجاد کرد تا بطور کامل برنامه نویسان را از مشکل همیشگی به‌روزرسانی‌ها و Role-back کردن‌ها آسوده خاطر نماید. 

از آنجایی که داکر قابلیت اجرای در محیط production را نیز دارد، عملا محیط Development با محیط Production تفاوتی ندارد و این جمله‌ی معروف که «در سیستم من کار میکند اما در نسخه‌ی انتشار داده شده خیر» دیگر اتفاق نخواهد افتاد.

به راحتی میتوانید از یک Image خاص، Containerهای ایزوله‌ی متفاوتی را ساخته و همگی آنها را در کنار هم اجرا نمود و مورد تست و ارزیابی قرار داد.


Dokcer hub

مخرنی است از هزاران Image آماده از قبیل سیستم عامل، فریم ورک و... که قابلیت استفاده‌ی مجدد خواهد داشت. همچنین شما میتوانید Image‌های خود را نیز بدان اضافه نموده تا دیگران از آن استفاده نمایند. استفاده از مخزن‌های public آن رایگان میباشد. از آنجایی که Docker یک محصول متن باز و رایگان است، یک بخش از درآمد‌های آن از فروش اختصاصی مخزن‌ها در DokcerHub میباشد (چیزی شبیه به Private Repository در Github).
بیشتر از این به مفاهیم نمیپردازیم. برای مطالعه‌ی بیشتر، کتاب فوق العاده‌ی Mastering Docker را پیشنهاد میکنم. 


شروع به کار با Docker

بعد از نصب کردن نسخه‌ی رسمی Docker و باز کردن ترمینال مربوطه، اولین دستوراتی را که باید با آن آشنا باشیم، شامل موارد زیر میباشد:

لیست Image‌های کش شده‌ی بر روی سیستم:
 docker images
لیست container‌های در حال اجرای بر روی ماشین محلی:
 docker ps
بعد از تست کردن دو دستور فوق مشاهده میکنید که هیچ image و containerی بر روی سیستم شما وجود ندارد.

برای آزمایش کردن و نصب اولین image، دستور زیر را وارد میکنیم (میتوانید اطلاعات بیشتری از imageها را در dockerHub پیدا کنید). من در اینجا  kitematic/hello-world-nginx را به عنوان image از مخزن dokcerhub، بر روی سیستم خود pull کرده‌ام (این یک نسخه‌ی بسیار سبک از کانتینر nginx میباشد).
 docker pull kitematic/hello-world-nginx
بعد از اجرای دوباره‌ی دستور docker images مشاهده میکنید که image مربوطه بر روی سیستم شما نصب شده است.
حال وقت اجرای این image و توزیع آن بر روی container میباشد که با استفاده از دستور زیر است:
 docker run -p 80:80 kitematic/hello-world-nginx
پرچم p- برای مقدار دهی پورت خارجی و داخلی میباشد و بعد از آن هم که نام image مربوطه برای اجرای container میباشد (فلگ‌های خیلی بیشتر و تخصصی‌تری در رابطه با اجرا وجود دارند که در ادامه بیشتر مورد بحث قرار می‌گیرند) .

بعد از اجرای این دستور میتوانید با وارد کردن ip مربوط به virtual machine ساخته شده بر روی سیستم خود (اگر از مک یا ویندوز استفاده میکنید احتمالا 192.168.99.100 خواهد بود) که البته با دستور docker-machine ip میتوانید آن را پیدا کنید و وارد کردن آن بر روی مرورگر خود، تصویری مثل زیر را مشاهده کنید:

بدین معناست که container شما اجرا شده و قابلیت مورد استفاده قرار گرفتن را خواهد داشت. حال اگر دستور docker ps را مجددا وارد نمایید، اطلاعات این container را از نوع id, status port و غیره، مشاهده خواهید کرد.