‫۱۰ ماه قبل، چهارشنبه ۱۵ آذر ۱۴۰۲، ساعت ۱۷:۲۷
در ASP.NET Core 8.0 نیز امکان مدیریت استثناءها به صورت سراسری با پیاده‌سازی اینترفیس  IExceptionHandler مسیر شده است:
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;

internal sealed class GlobalExceptionHandler : IExceptionHandler
{
    private readonly ILogger<GlobalExceptionHandler> _logger;

    public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
    {
        _logger = logger;
    }

    public async ValueTask<bool> TryHandleAsync(
        HttpContext context,
        Exception exception,
        CancellationToken cancellationToken = default)
    {
        _logger.LogError(exception, "An unhandled exception has occurred while executing the request.");
        var problemDetails = new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Title = "Server Error",
        };

        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        await context.Response.WriteAsJsonAsync(problemDetails);

        return true;
    }
}

برای ریجستر کردن آن نیز:
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
// other code
app.UseExceptionHandler();
‫۱۰ ماه قبل، یکشنبه ۵ آذر ۱۴۰۲، ساعت ۲۱:۴۶
نکته تکمیلی: Collection literalها اصطلاحاً target-typed هستند مثلاً در شرایطی که نیاز باشد از Ternary Operator درون [] استفاده شود نیازی به Cast کردن آن نیست و خود کامپایلر آن را تشخیص خواهد داد:

‫۱۱ ماه قبل، جمعه ۲۸ مهر ۱۴۰۲، ساعت ۰۴:۰۴
نکته تکمیلی:

از NET 6. به بعد نیز میتوانیم مقدار Timeout را به صورت سراسری تنظیم کنیم:
AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromMicroseconds(50));
مقدار پیش‌فرض آن  Regex.InfiniteMatchTimeout میباشد یعنی تا زمان اتمام تطبیق ادامه خواهد داشت و اگر در حال نگارش کتابخانه‌ای هستید، بهتر است از روش زیر استفاده کنید:
Regex.IsMatch("abc", "a", RegexOptions.None, TimeSpan.FromSeconds(5));
این قابلیت از زمان دات‌نت 4.5 اضافه شده‌است.
‫۱ سال قبل، پنجشنبه ۱۳ مهر ۱۴۰۲، ساعت ۲۰:۵۱
پشتیبانی از انواع داده‌ایی DateOnly, TimeOnly در EF8 اضافه شده است (برای پروایدر SQL Server):
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;


await using var context = new MyDbContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Users.Add(new User
{
    Name = "John Doe",
    Birthday = new(1980, 1, 20),
    ShiftStart = new (8, 0),
    ShiftLength = TimeSpan.FromHours(8)
});
await context.SaveChangesAsync();

public class MyDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"...")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
    }
    public DbSet<User> Users { get; set; }
}

public class User
{
    public int Id { get; set; }
    public required string Name { get; set; }
    public DateOnly Birthday { get; set; }
    public TimeOnly ShiftStart { get; set; }
    public TimeSpan ShiftLength { get; set; }
}
با این DDL:
CREATE TABLE [Users] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [Birthday] date NOT NULL,
    [ShiftStart] time NOT NULL,
    [ShiftLength] time NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY ([Id])
);

‫۱ سال قبل، دوشنبه ۳ مهر ۱۴۰۲، ساعت ۱۷:۵۸
یک نکته تکمیلی
حین استفاده از ControllerBase میتوانیم از یک تعداد helper برای خروجی اکشن‌ها استفاده کنیم؛ به عنوان مثال میتوانیم بعد از ساخت یک resource جدید از CreatedAtAction استفاده کنیم که به صورت خودکار خروجی 201 را برمیگرداند و همچنین هدر Location را نیز برایمان تنظیم خواهد کرد؛ 
[ApiController]
[Route("api/users")]
public class UserController : ControllerBase
{
    [HttpGet("{id:int}")]
    public ActionResult GetUserById(int id)
    {
        var user = new { Id = 1, Name = "Sirwan Afifi" };
        return Ok(user);
    }

    [HttpPost]
    public ActionResult CreateUser(CreateUserDto user)
    {
        return CreatedAtAction(nameof(GetUserById), new { user.Id }, user);
    }
}

اطلاعات بیشتر (+)

‫۱ سال قبل، جمعه ۳۱ شهریور ۱۴۰۲، ساعت ۲۰:۵۰
در NET 8. نیز یک مفهومی اضافه شده تحت عنوان Keyed DI Services؛ با کمک این قابلیت میتوانیم سرویس‌ها را توسط یک کلید ثبت یا استفاده کنیم؛ برای استفاده از یک سرویس که با کلید هم ذخیره شده میتوانیم از پراپرتی FromKeyedServices استفاده کنیم:
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<BigCacheConsumer>();
builder.Services.AddSingleton<SmallCacheConsumer>();

builder.Services.AddKeyedSingleton<IMemoryCache, BigCache>("big");
builder.Services.AddKeyedSingleton<IMemoryCache, SmallCache>("small");

var app = builder.Build();

app.MapGet("/big", (BigCacheConsumer data) => data.GetData());
app.MapGet("/small", (SmallCacheConsumer data) => data.GetData());

app.Run();

class BigCacheConsumer([FromKeyedServices("big")] IMemoryCache cache)
{
    public object? GetData() => cache.Get("data");
}

class SmallCacheConsumer(IKeyedServiceProvider keyedServiceProvider)
{
    public object? GetData() => keyedServiceProvider.GetRequiredKeyedService<IMemoryCache>("small");
}