اشتراک‌ها
فریم ورک Material UI

A CSS Framework and a Set of React Components that Implement Google's Material Design 

فریم ورک Material UI
اشتراک‌ها
Rider 2024.2 منتشر شد

Rider 2024.2: Full Line Code Completion, Reader Mode, Major Enhancements to Debugging, and More. 

Rider 2024.2 منتشر شد
اشتراک‌ها
ReSharper 2021.1 منتشر شد

ReSharper 2021.1: Updates in Code Analysis, Support for ASP.NET Route Templates, and Rename for Tuple Components 

ReSharper 2021.1 منتشر شد
مطالب
شروع به کار با DNTFrameworkCore - قسمت 4 - پیاده‌سازی CRUD API موجودیت‌ها
پس از معرفی DNTFrameworkCore، طراحی موجودیت‌های سیستم و پیاده‌سازی DTOها، اعتبارسنج‌ها و سرویس‌های متناظر آنها، در این مطلب روش پیاده سازی CRUD API یکسری موجودیت فرضی را با استفاده از امکانات این زیرساخت بررسی خواهیم کرد.

برای شروع لازم است بسته نیوگت زیر را نصب کنید:
PM> Install-Package DNTFrameworkCore.Web

همچنین برای اعمال خودکار مهاجرت‌های بانک اطلاعاتی، بسته نیوگت زیر را نصب کنید:
PM> Install-Package DNTFrameworkCore.Web.EntityFramework

سپس با استفاده از متد الحاقی MigrateDbContext به شکل زیر می‌توان فرآیند مذکور را خودکار کرد:
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build()
            .MigrateDbContext<ProjectDbContext>()
            .Run();
    }

//...
}

مثال اول: پیاده سازی CRUD API یک موجودیت ساده
[Route("api/[controller]")]
public class BlogsController : CrudController<IBlogService, int, BlogModel>
{
    public BlogsController(IBlogService service) : base(service)
    {
    }

    protected override string CreatePermissionName => PermissionNames.Blogs_Create;
    protected override string EditPermissionName => PermissionNames.Blogs_Edit;
    protected override string ViewPermissionName => PermissionNames.Blogs_View;
    protected override string DeletePermissionName => PermissionNames.Blogs_Delete;
}
کار با ارث‌بری از CrudController جنریک شروع می‌شود؛ سپس نیاز است نوع سرویس، نوع مدل و همچنین نوع شناسه مرتبط با موجودیت مورد‎‌نظر را از طریق Type Parameter مشخص کنید. این کنترلر پایه تعاریف مختلفی دارد که برحسب نیاز خود می‌توانید از آنها استفاده کنید. در ادامه نیز برای اعمال دسترسی خاصی برای عملیات CRUD، نیاز است نام دسترسی‌ها را مشخص کنید. کار تمام است؛ برای استفاده از آن می‌توانید با اجرای پروژه DNTFrameworkCore.TestAPI به شکل زیر عمل کنید:
ابتدا نیاز است با استفاده از افزونه‌ی Postman یک Environment جدید ایجاد کنید.

در اینجا دو متغیر endpoint و token ‌برای سرعت بخشیدن به فرآیند تست API تولیدی ایجاد شده‌اند. مقدار endpoint آن از ابتدا مشخص می‌باشد؛ ولی برای مقداردهی token، از ترفند زیر می‌توان استفاده کرد:

در برگه Tests آن می‌توان متغیر تعریف شده در Environment ایجاد شده را با قطعه کد زیر مقداردهی کرد:
 var data = JSON.parse(responseBody)
pm.environment.set("token", data.token);
و برای استفاده از این متغیر به شکل زیر عمل کنید:

حال برای ارسال درخواست‌های HTTP به BlogsController به شکل زیر عمل کنید:

پشت صحنه اکشن GET مربوط به BlogsController از متد سرویس ReadPagedListAsync استفاده می‌شود که خروجی آن در صورت مشخص نکردن TReadModel، برای یک موجودیت ساده مانند واحد سنجش، از همان TModel استفاده خواهد شد. در تصویر بالا لیست صفحه بندی شده موجودیت Blog را مشاهده می‌کنید. برای درخواست صفحه دیگر و جستجوی پویا می‌توان به شکل زیر عمل کرد:
query={"page":1,"pageSize":100,"filter":{"logic":"and","filters":[{"field":"title","value":"Blog1","operator":"startswith"}]}}
همانطور که در مطالب گذشته اشاره شد، ورودی متدهای Read موجود در سرویس‌ها از نوع IFilteredPagedQueryModel می‌باشد. یک ModelBinder سفارشی هم برای بایند خودکار این کوئری استرینک با محتوای یک شیء JSON، در زیرساخت طراحی شده است.

در پشت صحنه اکشن POST از متد CreateAsync سرویس مرتبط استفاده می‌شود و همانطور که در قسمت قبلی عنوان شد، Id و RowVersion مدل ارسالی، مقداردهی خواهد شد. 

در پشت صحنه اکشن ‎‎‎‎‎‎GET/{id}‎ از متد FindAsync سرویس مرتبط استفاده می‌شود و خروجی آن از نوع TModel می‌باشد. 

در پشت صحنه اکشن PUT از متد EditAsync سرویس مرتبط استفاده می‌شود که ورودی آن نوع TModel می‌باشد. همانطور که قبلا اشاره شده بود و در خروجی حاصل از درخواست ویرایش بالا مشخص می‎‌باشد، مکانیزم مدیریت استثناهای حاصل از مباحث همزمانی نیز به درستی انجام شده است.
برای حذف یک Blog می‌توان با ارسال درخواست DELETE به آدرس زیر به این هدف رسید:
{{endpoint}}/blogs/10
در پشت صحنه این اکشن نیز از متد DeleteAsync سرویس مرتبط استفاده می‌شود.
‌‌‌
مثال دوم: پیاده سازی و استفاده از CRUD API در سناریوهای Master-Detail
[Route("api/[controller]")]
public class UsersController : CrudController<IUserService, long, UserReadModel, UserModel>
{
    private readonly ILookupService _lookupService;

    public UsersController(IUserService service, ILookupService lookupService) : base(service)
    {
        _lookupService = lookupService ?? throw new ArgumentNullException(nameof(lookupService));
    }

    protected override string CreatePermissionName => PermissionNames.Users_Create;
    protected override string EditPermissionName => PermissionNames.Users_Edit;
    protected override string ViewPermissionName => PermissionNames.Users_View;
    protected override string DeletePermissionName => PermissionNames.Users_Delete;

    [HttpGet("[action]")]
    [PermissionAuthorize(PermissionNames.Users_Create, PermissionNames.Users_Edit)]
    public async Task<IActionResult> RoleList()
    {
        var result = await _lookupService.ReadRolesAsync();
        return Ok(result);
    }
}
‌‌
موجودیت User از جمله موجودیت‌هایی می‌باشد که نیاز است ReadModel مجزایی برای آن درنظر گرفت؛ چرا که در زمان نمایش لیستی کاربران، نیاز به واکشی گروه‌های کاربری متصل و دسترسی‌های خاص آن، نمی‌باشد. همچنین اکشن متد RoleList برای دریافت لیست گروه‌های کاربری موجود در سیستم نیز پیاده‌سازی شده است. باتوجه به اینکه نیاز است از این اکشن متد در عملیات ثبت و ویرایش استفاده کرد، بر روی آن با استفاده از فیلتر سفارشی PermissionAuthorize، بررسی شده است که کاربر جاری یکی از دسترسی‌های Users_Create یا Users_Edit را داشته باشد.
‎‎‎‎‎
درخواست‌های GET و DELETE مشابه مثال اول می‌باشد؛ برای درخواست‌های POST و PUT آن می‌توان به شکل زیر عمل کرد:

باتوجه به اینکه UserRole به عنوان یکی از وابستگی‌های موجودیت User محسوب می‌شود، در پاسخ درخواست GET مرتبط با کاربری با شناسه 2، roles آن، لیستی از UserRoleModel هستند که به عنوان یک DetailModel طراحی شده است. به عنوان مثال برای حذف اتصال یک گروه کاربری باید درخواست PUT را به شکل زیر ارسال کنید:

این‌بار اگر برای درخواست GET کاربر با شناسه 2 اقدام کنیم، به خروجی زیر خواهم رسید:

{
    "userName": "rabbal",
    "displayName": "غلامرضا ربال",
    "password": null,
    "isActive": false,
    "roles": [],
    "permissions": [],
    "ignoredPermissions": [],
    "rowVersion": "AAAAAAACGxI=",
    "id": 2
}


برای بررسی بیشتر، پیشنهاد می‌کنم پروژه  DNTFrameworkCore.TestAPI  موجود در مخزن این زیرساخت را بازبینی کنید.  
اشتراک‌ها
بررسی تغییرات ASP.NET Core در دات نت 8

ASP.NET Core in .NET 8 is your complete solution for modern web development. It handles all of your web development needs from the frontend to the backend. You can build beautiful, richly interactive web experiences with Blazor, and high-performance backend APIs and services that are reliable and secure. ASP.NET Core in .NET 8 is perfect for building cloud-native apps, and great tooling in Visual Studio and Visual Studio Code supercharges your productivity. With ASP.NET Core in .NET 8, every developer is a full stack developer! 

بررسی تغییرات ASP.NET Core در دات نت 8