1. 程式人生 > >.Net Core中依賴註入服務使用總結

.Net Core中依賴註入服務使用總結

ces sin 其他 logs color 調用 pop com int

一、依賴註入

  引入依賴註入的目的是為了解耦和。說白了就是面向接口編程,通過調用接口的方法,而不直接實例化對象去調用。這樣做的好處就是如果添加了另一個種實現類,不需要修改之前代碼,只需要修改註入的地方將實現類替換。上面的說的通過接口調用方法,實際上還是需要去實例化接口的實現類,只不過不需要我們手動new 構造實現類,而是交給如微軟的DI、Autofac這些工具去構建實現類。我們只需要告訴它們,某個類是某個接口的實現類,當用到的時候,工具會自動通過構造函數實例化類。

二、.Net Core中自帶的DI

  本來想寫依賴註入源碼的講解的,看到網上有篇文章關於源碼講解的,很詳細、清楚,就不再寫了。地址:http://www.cnblogs.com/bill-shooting/p/5540665.html。我在這裏就說說使用吧。

  依賴註入有三種生命周期,每種生命周期的註入方式大同小異,下面我以作用域生命周期舉例,其他兩種跟這個不同,我會特別說明。

下面為用到的兩個服務。

public class UserService : IUserService
{
    public string GetName()
    {
        return "UserName";
    }
}

public interface IUserService
{
    string GetName();
}
public class ConfigReader : IConfigReader
{
    
private string configFilePath;//需要傳一個路徑,去讀取路徑下文件的內容 public ConfigReader(string configFileName) { this.configFilePath = configFileName; } public string Reader() { return File.ReadAllText(configFilePath); } } public interface IConfigReader { string
Reader(); }

 1、最常用的註入方式,以接口形式暴露服務

services.AddScoped(typeof(IUserService), typeof(UserService));
services.AddScoped
<IUserService, UserService>();

兩種註入方式是一個意思,這種方式適合實現類為無參構造函數或者有參構造函數中參數已經被註入過了。

  2、自己註入自己,以實現形式暴露服務

services.AddScoped<UserService>();


services.AddScoped(typeof(UserService));

這種註入方式適合只有實現類,沒有借口類的註冊。

  3、需要傳參的構造函數的類的註入

services.AddScoped<IConfigReader, ConfigReader>(x => { return new ConfigReader("c:/a.txt"); });
services.AddScoped
<IConfigReader>(x => { return new ConfigReader("c:/a.txt"); });
services.AddScoped(
typeof(IConfigReader), x => { return new ConfigReader("c:/a.txt"); });

前兩個匿名方法參數是IServiceProvider,返回值為一個實例,第三個返回值是Object。上面舉的例子沒有用到IServiceProvider ,下面再舉一個例子。修改上面的UserService類,將構造方法需要一個IConfigReader參數。

public class UserService : IUserService
{private IConfigReader configReader;

    public UserService(IConfigReader configReader)
    {
        this.configReader = configReader;
    }
    public string GetName()
    {
        return "UserName" + configReader.Reader();
    }
}

註冊的時候,如下:

services.AddScoped<IConfigReader, ConfigReader>(x => { return new ConfigReader("c:/a.txt"); });
//通過ServiceProvider獲取已經註冊的IConfigReader services.AddScoped
<IUserService, UserService>(x => { return new UserService(x.GetService<IConfigReader>()); });
//或者
services.AddScoped<IUserService, UserService>(x => { return new UserService(new ConfigReader("c:/a.txt")); });

單例類型的生命周期多了兩種註入方式:

services.AddSingleton<IConfigReader>(new ConfigReader("c:/a.txt"));

services.AddSingleton(typeof(IConfigReader), new ConfigReader("C:/a.txt"));

自帶的依賴註入工具也可以批量註入

var assembly = Assembly.GetExecutingAssembly()
                        .DefinedTypes
                        .Where(a => a.Name.EndsWith("Service") && !a.Name.StartsWith("I"));

foreach (var item in assembly)
{
    services.AddTransient(item.GetInterfaces().FirstOrDefault(), item);
}

註意:當一個服務有多個實現時,調用的時候通過 IEnumerable<IPayService> PayServices 獲取所有的實現服務。

services.AddTransient<IPayService, AliPayService>();
services.AddTransient<IPayService, WeChatPayService>();

使用的時候:

技術分享圖片

三、Autofac

  1、以接口形式暴露服務

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    var builder = new ContainerBuilder();
    builder.Populate(services);

    builder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();

    var container = builder.Build();
    return new AutofacServiceProvider(container);
}

  2、通過實現類暴露服務

builder.RegisterType<UserService>();

  3、需要傳參的構造函數的類的註入

 builder.Register(c => new ConfigReader("c:/a.txt")).As<IConfigReader>();

  4、通過程序集註入

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(c => c.Name.EndsWith("Service"))
.AsImplementedInterfaces();

總結:

不論是微軟的依賴註入組件還是Autofac 原理都是先將接口和對應的實現類註入到容器中,當要使用的時候,組件會自動通過構造函數創建實例。這裏有個問題如果有個實現類有多個構造函數,組件會找滿足參數最多的那個構造函數。

.Net Core中依賴註入服務使用總結