Autofac یک ابزار برای مدیریت وابستگی بین کلاسهاست که توسعه برنامه را در هنگام بزرگ شدن چه از نظر اندازه و پیچیدگی ساده میکند. Asp.Net Core بر خلاف Asp.Net کلاسیک Dependency Injection را به صورت توکار پشتیبانی میکند اما با استفاده از Autofac توسعه پروژه آسان تر و سریع تر انجام میشود. به عنوان مثال اگر یک اینترفیس به نام IUserService داشته باشیم و یک کلاس به نام UserService که این اینترفیس را  پیاده سازی کرده باشد, طبیعتا باید هردوی این اینترفیس و کلاس را به DI معرفی کنیم مانند زیر:

services.AddScoped<IUserService, UserService>();

که این کار را باید برای تمامی اینترفیس های استفاده شده انجام دهیم و زمانی که اندازه پروژه بزرگ میشود این کار کمی وقت گیر میشود و اکثرا فراموش میکنیم که اینترفیس ها رو رجیستر کنیم. اما با استفاده از Autofac نیازی به این کار نیست و عملیات رجیستر کردن اینترفیس ها به صورت خودکار انجام میشود. پیاده سازی Autofac در Asp.Net Core 3 با سایر ورژن های قدیمی کمی Net Core. متفاوت است. 

ابتدا باید پکیج های زیر را از طریق Nuget نصب کنید.

  • Autofac ورژن 5.1.2
  • Autofac.Extensions.DependencyInjection ورژن 6.0.0

سپس اولین تغییر در کلاس Program است که باید به صورت زیر تغییر یابد.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory()) // <--NOTE THIS
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

در Net Core. سه نوع Life time برای ثبت رجیسترها داریم

  1. Scoped
  2. Transient
  3. Singleton

Scoped : اگر سرویسی با این نوع لایف تایم رجیستر شود به ازای هر ریکوست یک شی از کلاس مورد نظر ساخته شده.

Transient : اگر سرویسی با این نوع لایف تایم رجیستر شود به ازای هر سرویس یک شی از کلاس مورد نظر ساخته شده.

Singleton : اگر سرویسی با این نوع لایف تایم رجیستر شود در مرحله اول بررسی میشود که آیا شی ای از این کلاس در سیستم وجود دارد یا نه. اگر وجود نداشت یک نمونه از شی ایجاد میشود و دراختیار DI قرار میگیرد, اگر شی درون سیستم بود شی فعلی را بر میگرداند و از ایجاد شی های جدید جلوگیری میکند. این لایف تایم که از نامش پیداست الگوی Singleton را پیاده سازی میکند.

در ادامه سه اینترفیس را فقط برای نشانه گذاری ایجاد میکنیم. با این کار مشخص میکنیم که هر سرویس باید به چه روشی رجیستر شود.

public interface IScopeDependency { }
public interface ISingletoneDependency { }
public interface ITransientDependency { }

در ادامه هنگام ساخت کلاس ها باید مشخص کنیم که این کلاس باید به چه روشی رجیستر شود. این کار را با ارث بری کردن اینترفیس های بالا انجام میدهیم به صورت زیر:

public interface IUserService
{
    string DoSomething();
}
public class UserService : IUserService, IScopeDependency
{
    public string DoSomething()
    {
        return "Hi ;)";
    }
}

اگر بخواهیم کلاس UserService از نوع Singleton رجیستر شود میتوانیم به جای IScopeDependency از ISingletoneDependency ارث بری کنیم. در ادامه با استفاده از ContainerBuilder مشخص میکنیم کلاس هایی که از اینترفیس IScopeDependency ارث بری کرده اند باید از نوع InstancePerLifetimeScope ( همان Scoped قبلی ) رجیستر شوند و ... .

نکته : Autofac با استفاده از نام سرویس ها مشخص میکند که در ازای درخواست برای اینترفیس IUserService باید کلاس UserService داده شود. یعنی دقیقا نام کلاس باید دقیقا همنام اینترفیس باشد و فقط حرف "I" را نداشته باشد.

 در این قسمت از یک اکستنشن متد استفاده کرده ایم جهت جلوگیری از شلوغ شدن کلاس Startup و فقط متد را فراخوانی میکنیم.

public static void AutofacConfig(this ContainerBuilder builder)
{
    var assembly = typeof(Startup).Assembly;
    builder.RegisterAssemblyTypes(assembly)
                    .AssignableTo<IScopeDependency>()
                    .AsImplementedInterfaces()
                    .InstancePerLifetimeScope();

    builder.RegisterAssemblyTypes(assembly)
                    .AssignableTo<ITransientDependency>()
                    .AsImplementedInterfaces()
                    .InstancePerDependency();

    builder.RegisterAssemblyTypes(assembly)
                    .AssignableTo<ISingletoneDependency>()
                    .AsImplementedInterfaces()
                    .SingleInstance();
}

اگر پروژه شما شامل چند لایه است و هر لایه وابستگی مربوط به خود را دارد میتوانید Assembly سایر لایه هارا به عنوان پارامتر به متد RegisterAssemblyTypes ارسال کنید چون ورودی این متد از نوع params است و میتوانید چندین Assembly را پاس دهید. در ادامه باید یک متد به نام ConfigureContainer مانند زیر در کلاس Startup ایجاد کنیم و پیکربندی لازم برای راه اندازی Autofac انجام دهیم.

public void ConfigureContainer(ContainerBuilder containerBuilder)
{
    containerBuilder.AutofacConfig();
}

و در آخر درخواست IUserService از طریق Constructor کنترلر User

public class UserController : Controller
{
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    public IActionResult Index()
    {
        return Ok(_userService.DoSomething());
    }
}


Powered by Froala Editor