مطالب
مرتب‌سازی، فیلتر کردن و صفحه‌بندی اطلاعات در ASP.NET Core

مقدمه

اگر با Apiها کار کرده باشید احتمالاً با این چالش که گاهی نیاز است منابعی (Resources) که به کاربر ارسال می‌شوند مرتب (Sort)، بر اساس درخواست کاربر فیلتر (Filter) و در صفحه‌بندی (Paging) مشخصی تحویل داده شوند، برخورد کرده‌اید. این نیاز خصوصاً در پاسخ (Response) با روش GET از استاندارد HTTP مشهود است. در این مطلب به معرفی کتابخانه‌ای می‌پردازیم که با استفاده از آن می‌توان عملیات فوق را پیاده‌سازی نمود. Sieve یک چارچوب (Framework) ساده، تمیز و قابل توسعه برای NET Core. است. در زمان نگارش این مقاله ویرایش ۲.۱.۳ از این کتابخانه در دسترس است و همانگونه که اشاره شد، این کتابخانه منبع باز (Open Source) بوده و می‌توانید آن را از مخزن گیت‌هاب در این پیوند دریافت نمایید.
  
سیستمی با یک موجودیت به نام "پست" (Post) مفروض است. با استفاده از کتابخانه Sieve عملیات مرتب‌سازی، فیلتر و صفحه‌بندی را هنگام درخواست (GET) تمامی پست‌ها اعمال خواهیم کرد.
// Post

public int Id { get; set; }

public string Title { get; set; }

public int LikeCount { get; set; }

public int CommentCount { get; set; }

public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;

۱. نصب کتابخانه

ابتدا لازم است از طریق Package Manager Console و اجرای دستور فوق اقدام به نصب این کتابخانه نمایید:  Install-Package Sieve -Version 2.1.3

۲. اضافه کردن سرویس‌

در فایل Startup.cs سرویس SieveProcessor را تزریق کنید:
services.AddScoped<SieveProcessor>();
 

۳. تعیین ویژگی‌هایی از کلاس برای اعمال مرتب‌سازی و فیلتر

باید ویژگی‌هایی (Properties) از کلاس را که می‌خواهید اعمال مرتب‌سازی و فیلتر بر روی آن‌ها انجام شوند، مشخص کنید. به دو روش این امر ممکن است:
 

۱.۳. از طریق اضافه کردن صفت (Attribute) به ویژگی‌ها

تنها ویژگی‌هایی از کلاس که دارای صفت [(Sieve(CanSort = true, CanFilter = true] باشند، می‌توانند مرتب و یا فیلتر شوند (می‌توان تنها از یکی از آن‌ها نیز استفاده نمود).
لذا کلاس پست به صورت زیر ویرایش می‌شود:
// Post

public int Id { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public string Title { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public int LikeCount { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public int CommentCount { get; set; }

[Sieve(CanFilter = true, CanSort = true, Name = "created")]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;

 

۲.۳. از طریق Fluent API

برای استفاده از این روش، ابتدا کلاسی را ایجاد و از کلاس SieveProcessor مشتق کنید. سپس تابع MapProperties موجود در کلاس والد را override کنید.
// ApplicationSieveProcessor

public class ApplicationSieveProcessor : SieveProcessor
{
    public ApplicationSieveProcessor(
        IOptions<SieveOptions> options, 
        ISieveCustomSortMethods customSortMethods, 
        ISieveCustomFilterMethods customFilterMethods) 
        : base(options, customSortMethods, customFilterMethods)
    {
    }

    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        mapper.Property<Post>(p => p.Title)
            .CanFilter()
            .HasName("a_different_query_name_here");

        mapper.Property<Post>(p => p.CommentCount)
            .CanSort();

        mapper.Property<Post>(p => p.DateCreated)
            .CanSort()
            .CanFilter()
            .HasName("created_on");

        return mapper;
    }
}
حال باید کلاس جدید را تزریق نمایید:
services.AddScoped<ISieveProcessor, ApplicationSieveProcessor>();
در هر دو روش پارامتری دیگر با نام "Name" نیز وجود دارد که می‌توانید با استفاده از آن برای هر ویژگی، نامی غیر از نام اصلی آن را اتخاذ نمایید.
 

۴. دریافت پرس‌و‌جوهای (Queries) مرتب/فیلتر/صفحه‌بندی با اضافه کردن SieveModel به کنترلر (Controller)

برای دریافت پرس‌و‌جوهای مرتب/فیلتر/صفحه‌بندی، SieveModel را به اکشنی (Action) که پست‌ها را برگشت می‌دهد به عنوان پارامتر اضافه کنید. سپس با فراخوانی تابع Apply با استفاده از تزریق SieveProcessor در کنترلر خود، پرس‌و‌جوها را به منابع خود اعمال کنید.
[HttpGet]
public JsonResult GetPosts(SieveModel sieveModel) 
{
    var result = _dbContext.Posts;
    result = _sieveProcessor.Apply(sieveModel, result);
    return Json(result.ToList());
}
توجه داشته باشید مقادیر پرس‌و‌جوها اختیاری است و هر کدام می‌توانند به تنهایی و یا با هم مورد استفاده قرار گیرند.
 

۵. ارسال درخواست

با تمام موارد گفته شده، اکنون می‌توانید درخواستی را برای دریافت (GET) شامل پرس‌و‌جوهای مرتب/فیلتر/صفحه‌بندی ارسال نمایید. برای مثال:
GET /GetPosts

?sorts=     LikeCount,CommentCount,-created         // sort by likes, then comments, then descendingly by date created 
&filters=   LikeCount>10,Title@=awesome title,      // filter to posts with more than 10 likes, and a title that contains the phrase "awesome title"
&page=      1                                       // get the first page...
&pageSize=  10                                      // ...which contains 10 posts
sorts= LikeCount,CommentCount,-created ?: مرتب‌سازی بر اساس تعداد محبوبیت، سپس تعداد نظرات و در آخر تاریخ ثبت پست به صورت نزولی.
filters= LikeCount>10,Title@=awesome title &: فیلتر بر اساس پست‌هایی که تعداد محبوبیت آن‌ها بیش از ۱۰ است و در عنوان خود شامل عبارت "awesome title" می‌باشند.
page=1 &: صفحه اول ...
pageSize=10 &: ... که شامل ۱۰ پست است.

به صورت رسمی‌تر:
sorts: فهرست دستورالعمل‌هایی شامل نام ویژگی‌هایی است که مرتب‌سازی بر روی آن‌ها اعمال می‌شود و از طریق کاما (,) از یکدیگر تمایز داده می‌شوند. با اضافه کردن - قبل از نام ویژگی، آن را به صورت نزولی مرتب نمایید.
  • filters: دستورالعمل‌های جدا شده توسط کاما (,) به صورت {Name}{Operator}{Value} که در آن:
    • {Name} نام ویژگی‌ای است که صفت Sieve بر روی آن تعریف شده و یا نام سفارشی‌ای است که کاربر تعیین کرده است.
      • همچنین می‌توانید بیش از یک نام (برای یای منطقی (OR)) در درون جفت پرانتز باز و بسته و جداکننده یای منطقی (|) داشته باشید. برای مثال: LikeCount|CommentCount)>10) مشخص می‌کند مقدار LikeCount و یا CommentCount بیش از ۱۰ باشد.
    • {Operator} یکی از عملگرهای ممکن است.
    • {Value} مقداری است که در عمل فیلتر مورد استفاده قرار می‌گیرد.
  • page: شماره صفحه‌ای است که برگشت داده می‌شود.
  • pageSize: تعداد مواردی است که در هر صفحه برگردانده خواهد شد.
 

۶. عملگرها (Operators)

عملگر
توضیحات
عملگر
توضیحات
== برابر =@  شامل
=! مخالف
=_  شروع شود با
< بزرگ‌تر
*=@  شامل (حساس به حروف)*
> کوچک‌تر
*=_  شروع شود با (حساس به حروف)
=< بزرگ‌تر مساوی
*==  برابر (حساس به حروف)
=> کوچک‌تر مساوی

 
* حساس به بزرگی و کوچکی حروف

۷. پیکربندی

برای پیکربندی شامل مواردی چون حساس به بزرگ و کوچک بودن نام ویژگی، تعداد صفحات پیشفرض، حداکثر تعداد صفحه مجاز و نحوه برخورد با نام ویژگی ناموجود در ویژگی‌های کلاس ابتدا قطعه زیر را به appsettings اضافه کنید.
{
    "Sieve": {
        "CaseSensitive": "boolean: should property names be case-sensitive? Defaults to false",
        "DefaultPageSize": "int number: optional number to fallback to when no page argument is given. Set <=0 to disable paging if no pageSize is specified (default).",
        "MaxPageSize": "int number: maximum allowed page size. Set <=0 to make infinite (default)",
        "ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false"
    }
}

 سپس سرویس فوق را در Startup.cs اضافه کنید:
services.Configure<SieveOptions>(Configuration.GetSection("Sieve"));

نظرات مطالب
دو خبر در مورد برنامه Reflector
ولی واقعا این نسخه ارزش پرداخت 35 دلار رو داره.
اشتراک‌ها
کتابخانه HTML5 Scratch Card

Scratch.js is a standalone library with no external dependencies which brings interactivity to your website by allowing you to generate scratch cards for your visitors.
Based on HTML5, scratch.js generate canvas on the fly and is optimized for all modern browsers and has touch support for mobile devices. You can use it to make scratch cards, coupons, promotionnal game and even advertisement.

کتابخانه HTML5 Scratch Card
نظرات مطالب
معرفی کتابخانه Postal برای ASP.NET MVC
با سلام من وقتی برنامه و اجرا میکنم خطای زیر رو بهم میده
No default Instance is registered and cannot be automatically determined for type 'Postal.IEmailViewRenderer'

There is no configuration specified for Postal.IEmailViewRenderer

1.) new EmailService(*Default of IEmailViewRenderer*, *Default of IEmailParser*, *Default of Func<SmtpClient>*)
2.) Postal.EmailService
3.) Instance of Postal.IEmailService (Postal.EmailService)
4.) new AccountController(*Default of IApplicationUserManager*, *Default of IApplicationSignInManager*, *Default of IAuthenticationManager*, *Default of IProfileService*, *Default of IUserService*, *Default of IIdentityMessageService*, *Default of IEmailService*, *Default of IUnitOfWork*)
5.) Annual_faculty_promotions.WebUI.Controllers.AccountController
6.) Instance of Annual_faculty_promotions.WebUI.Controllers.AccountController
7.) Container.GetInstance(Annual_faculty_promotions.WebUI.Controllers.AccountController)

حتی به StructureMap هم اینترفیس IEmailService رو معرفی کردم.
ioc.For<IEmailService>().Use<EmailService>();

ممنون میشم کمک کنید
اشتراک‌ها
بررسی کارآیی کدهای NET. با BenchmarkDotNet و افزونه‌ی EtwProfiler آن

EtwProfiler is the new diagnoser for BenchmarkDotNet that I have just finished. It’s going to be released as part of 0.11.2. Soon! It allows to profile the benchmarked .NET code on Windows and exports the data to a trace file which can be opened with PerfView or Windows Performance Analyzer. 

بررسی کارآیی کدهای NET. با BenchmarkDotNet و افزونه‌ی EtwProfiler آن
اشتراک‌ها
ارائه‌ی MapKit JS از اپل

Use of the library does involve having an Apple Developer account at $99 a year , and to use the beta, developers will need to set up core Maps identifiers, keys, and tokens via their developer account. The beta version limits usage to  250,000 instantiations and 25,000 service calls, per API key per day, compared to Google's limit of 100,000 map instantiations per month on the free tier. 

ارائه‌ی MapKit JS از اپل