وبسایت شخصی حسن هاشمی

برنامه نویس. ایران. قم :))

یه سری shortcut برای شروع کار سریع در asp.net core

امسال فکر کنم 2و3 سالی میشه که با aspnet core کار می کنم.

یه سری نکات به مرور دستم اومد که بعضیاش هم تکراری هست ولی خب چون توی این 2و3 پروژه ای که الان کار می کنم، بروبچ کلا رعایت نمی کنن (از جمله خودم، حالا از روی تنبیله یا هرچی) گفتم یه جمع بندی کلی بزنم شاد یه نفر استفاده کرد. :))


Integration Test:

یکی از فوق العاده ترین امکانات جدیدی که توی asp.net core هست امکان تست integration هست. integration test یعنی تست کلی برنامه از بیرون به داخل به طوریکه تمام اجزای برنامه از جمله کنترلر/اکشن/validation/view همه با هم تست بشن.

asp.net این کارو با استفاده از یه تست سرور انجام میده.

یادتون باشه که برای تست حرفه ای حتما باید از xUnit استفاده کنید.

public class PrimeWebDefaultRequestShould
{
private readonly TestServer _server;
private readonly HttpClient _client;
public PrimeWebDefaultRequestShould()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnHelloWorld()
{
// Act
var response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();

var responseString = await response.Content.ReadAsStringAsync();

// Assert
Assert.Equal("Hello World!", responseString);
}
}


Configuration:

سیستم Configuration از Web.config قدیمی که خیلی وابسته به System.Configuration بود منتقل شده به سری کتابخونه های ساده Microsoft.*.Extension که یکی از Provider هاش میتونه xml یا json باشه.


بعد مقدارش رو از طریق سیستم DI تزریق کنید به کلاس های دلخواه، این سیستم بخشی از Configuration جدید توی net core هست و مختص aspnet نیست.

اطلاعات بیشتر


 Authorization Requirement:

یه بخشی هست که به سیستم Authorization توی Aspnet اضافه شده، (دقت کنید Authorization) برای زمانی که شما کنترل دسترسی فراتر از role های ساده توی سیستمتون دارید.

کارایی که قبلا توی AuthorizationFilter می کردین رو منتقل کنید توی AuthorizationRequirment با این تفاوت که سیستم جدید خیلی قابلیت های بیشتری داره که خودش رو توی پروژه های بزرگ نشون میده.

فرض کنید شما توی پروژه یه اکشن دارین که فقط کاربر لاگین شده باید بهش دسترسی داشته باشن. یه اکشن دیگه دارین که کاربر هم باید لاگین شده باشه و هم دارای شرایطی باشه که منطق پیچیده ای رو برای احرازش می طلبه. مثلا استان کاربر "قم" باشه و سنش هم بالای "21" باشه.

توی سیستم جدید می تونید دوتا Requirement بنویسید که یکی استان رو چک کنه (با توجه به دیتابیس مثلا) و یکی دیگه هم سنش رو (شاید با دیتابیس یا چیز دیگه)                                                                                                                      

services.AddAuthorization(options =>
{
options.AddPolicy("AgeReuirement", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));

options.AddPolicy("StateRequirment", policy =>
policy.Requirements.Add(new QomStateRequirement()));
});

class AgeAndStateAccess: IAuthorizationRequirement
{ }

class MinimumAgeRequirement: AuthorizationHandler<AgeAndStateAccess>
{
Task HandleRequirmentAsync(AuthorizationHandlerContext ctx)
{
if(ctx.User.Age > 21) ctx.Success();
}
}

class QomStateRequirement: AuthorizationHandler<AgeAndStateAccess>
{
Task HandleRequirmentAsync(AuthorizationHandlerContext ctx)
{
if(ctx.User.State == "Qom") ctx.Success();
}
}

توی این pipe اگه یکی از Requirement ها fail بشن کلا نتیجه fail میشه.
خوب اولین خوبیش اینه که شما توی این کلاس ها کلا به Container دسترسی دارین (چیزی که قبلا توی وب فرم که اصلا نبود و MVC هم فیلترهاش ساپورت نمی کرد).


ایمن سازی در مقال CSRF:

تابلوترین حمله ای که ممکنه به سایت بشه CSRF هست، قبلا هم توی aspnet 4 راه هایی برای حلش وجود داشت. توی asp.net core مثل قبل این امکان به عنوان بخشی از کتابخونه Data protection ارائه شده. و روش هندل کردنشون هم synchronization token هست.

در مورد CSRF توضیح نمیدم، چون به احتمال 100% همتون میدونید چیه.

اگه توی پروژه از cookie استفاده می کنید، یادتون باشه که حتما اینو فعال کنید. توی aspnet core امکان فعال سازیش به صورت global فراهم شده.

اطلاعات بیشتر


ModelBinding:

توی این بخش خیلی تغییرات نبوده فقط یه سری attribute هست که خودم خبر نداشتم تا چند روز از وجودشون :)

BindAttribute: وقتی به یه کلاس اعمال بشه، فقط property که توسط این attribute براش تعیین میشه بایند میشه و بقیه در نظر گرفته نمیشن.

BindNeverAttribute: وقتی به property اعمال بشه، از model binding حذف میشه.

نکته خیلی مهمی که از کثیفی کد جلوگیری می کنه اینه که model binding توی asp.net هم Dicationary رو bind میکنه و هم لیست رو، پس حتما ازین امکان استفاده کنید.

یه سود خیلی بزرگش اینه که از fat شدن کنترلرها جلوگیری می کنه.

همچنین می تونید محلی که مدل ازش bind میشه رو هم تعیین کنید (این امکان قبلا هم محدودتر بود)

FromBody, FromHeader, FromForm, FromQuery


همچنین Validation هم کما فی سابق در سرجاش هست، و برای پیاده سازی custom می تونید یه پیاده از IModelValidator رو مثل بقیه Validation Attr ها استفاده کنید.


یه مورد دیگه که جدید اضافه شده امکانی هست به نام RemoteValidation هست، و این امکان رو میده که دیتای روی کلاینت رو با استفاده از کد سمت سرور validate کنید.


اطلاعات بیشتر در اینجا


ExceptionHandling برای Api ها:

قالب api ها یه قالب Response متحد برای خطا ها نیاز دارن، توی asp.net core می تونید به راحتی با یه فیلتر اینکارو انجام بدید:



Caching:
مثل قبل دو روش برای کش کردن داریم:
1- InMemory
2- Destributed Caching

public class HomeController : Controller
{
    private IMemoryCache _cache;

    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }
}

استفاده ش هم خیلی ساده هست:
public IActionResult CacheTryGetValueSet()
{
    DateTime cacheEntry;

    // Look for cache key.
    if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
    {
        // Key not in cache, so get data.
        cacheEntry = DateTime.Now;

        // Set cache options.
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Keep in cache for this time, reset time if accessed.
            .SetSlidingExpiration(TimeSpan.FromSeconds(3));

        // Save data in cache.
        _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
    }

    return View("Cache", cacheEntry);
}
حواستون باشه اگه پشت لودبالانسر هستین، این روش جواب نمیده.

و مورد دوم هم Destributed Cache هست:
دو تا provider داریم: 
redis, sql server
استفاده ش هم مثل آب خوردن هست:

public class HomeController : Controller
{
    private IDistributedCache _cache;

    public HomeController(IDistributedCache cache)
    {
        _cache = cache;
    }
}
شما احتمالا توی برنامه تون باید یه wrapper روی اینا بنویسید
Loading