1. 程式人生 > >ASP.NET Core 3.0 原生DI拓展實現IocManager

ASP.NET Core 3.0 原生DI拓展實現IocManager

昨天.NET Core 3.0 正式釋出,建立一個專案執行後發現:原來使用的Autofac在ConfigureServices返回IServiceProvider的這種寫法已經不再支援。當然Autofac官方也給出了示例。

.NET Core 本身內建DI,我決定不再使用Autofac,就使用原生DI,拓展IServiceCollection實現一個IocManager,

實現批量注入,靜態獲取例項功能。

一、Autofac官方文件

Program Class

Hosting changed in ASP.NET Core 3.0 and requires a slightly different integration. This is for ASP.NET Core 3+ and the .NET Core 3+ generic hosting support:

public class Program
{
  public static void Main(string[] args)
  {
    // ASP.NET Core 3.0+:
    // The UseServiceProviderFactory call attaches the
    // Autofac provider to the generic hosting mechanism.
    var host = Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureWebHostDefaults(webHostBuilder => {
          webHostBuilder
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>();
        })
        .Build();

    host.Run();
  }
}

Startup Class

In your Startup class (which is basically the same across all the versions of ASP.NET Core) you then use ConfigureContainer to access the Autofac container builder and register things directly with Autofac.

public class Startup
{
  public Startup(IHostingEnvironment env)
  {
    // In ASP.NET Core 3.0 env will be an IWebHostingEnvironment, not IHostingEnvironment.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
    this.Configuration = builder.Build();
  }

  public IConfigurationRoot Configuration { get; private set; }

  public ILifetimeScope AutofacContainer { get; private set; }

  // ConfigureServices is where you register dependencies. This gets
  // called by the runtime before the ConfigureContainer method, below.
  public void ConfigureServices(IServiceCollection services)
  {
    // Add services to the collection. Don't build or return
    // any IServiceProvider or the ConfigureContainer method
    // won't get called.
    services.AddOptions();
  }

  // ConfigureContainer is where you can register things directly
  // with Autofac. This runs after ConfigureServices so the things
  // here will override registrations made in ConfigureServices.
  // Don't build the container; that gets done for you. If you
  // need a reference to the container, you need to use the
  // "Without ConfigureContainer" mechanism shown later.
  public void ConfigureContainer(ContainerBuilder builder)
  {
      builder.RegisterModule(new AutofacModule());
  }

  // Configure is where you add middleware. This is called after
  // ConfigureContainer. You can use IApplicationBuilder.ApplicationServices
  // here if you need to resolve things from the container.
  public void Configure(
    IApplicationBuilder app,
    ILoggerFactory loggerFactory)
  {
    // If, for some reason, you need a reference to the built container, you
    // can use the convenience extension method GetAutofacRoot.
    this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();

    loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
    app.UseMvc();
  }
}

二、IocManager實現

1、建立IocManager

public interface IIocManager
{
    IServiceProvider ServiceProvider { get; set; }
}
public class IocManager : IIocManager
{
    static IocManager()
    {
        Instance = new IocManager();
    }
    public static IocManager Instance { get; private set; }
    public IServiceProvider ServiceProvider { get; set; }
}

2、建立生命週期介面

    /// <summary>
    ///    標記依賴項生命週期的介面
    ///     <see cref="ILifetimeScopeDependency" />,
    ///     <see cref="ITransientDependency" />,
    ///     <see cref="ISingletonDependency" />
    /// </summary>
    public interface ILifetime { }
    /// <summary>
    /// 確定介面或類的生存期
    /// 作用域模式,服務在每次請求時被建立,整個請求過程中都貫穿使用這個建立的服務。
    /// </summary>
    public interface ILifetimeScopeDependency : ILifetime { }
    /// <summary>
    /// 確定介面或類的生存期
    /// 作用域模式,服務在每次請求時被建立,整個請求過程中都貫穿使用這個建立的服務。
    /// </summary>
    public interface ILifetimeScopeDependency : ILifetime { }
    /// <summary>
    /// 確定介面或類的生存期
    /// 瞬態模式,每次請求時都會建立。
    /// </summary>
    public interface ITransientDependency : ILifetime { }

3、拓展IServiceCollection

/// <summary>
/// .NET Core 依賴注入拓展
/// </summary>
public static class DependencyInjectionExtensions
{
    /// <summary>
    /// 註冊程式集元件
    /// </summary>
    /// <param name="services"></param>
    /// <param name="assemblies"></param>
    /// <returns></returns>
    public static IServiceCollection AddAssembly(this IServiceCollection services, params Assembly[] assemblies)
    {
        if (assemblies.IsNullOrEmpty())
        {
            throw new Exception("assemblies cannot be empty.");
        }
        foreach (var assembly in assemblies)
        {
            RegisterDependenciesByAssembly<ISingletonDependency>(services, assembly);
            RegisterDependenciesByAssembly<ITransientDependency>(services, assembly);
            RegisterDependenciesByAssembly<ILifetimeScopeDependency>(services, assembly);
        }
        return services;
    }

    public static void RegisterDependenciesByAssembly<TServiceLifetime>(IServiceCollection services, Assembly assembly)
    {            
        var types = assembly.GetTypes().Where(x => typeof(TServiceLifetime).GetTypeInfo().IsAssignableFrom(x) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsSealed).ToList();
        foreach (var type in types)
        {
            var itype = type.GetTypeInfo().GetInterfaces().FirstOrDefault(x => x.Name.ToUpper().Contains(type.Name.ToUpper()));
            if (!itype.IsNull())
            {
                var serviceLifetime = FindServiceLifetime(typeof(TServiceLifetime));
                services.Add(new ServiceDescriptor(itype, type, serviceLifetime));
            }
        }
    }

    private static ServiceLifetime FindServiceLifetime(Type type)
    {
        if (type == typeof(ISingletonDependency))
        {
            return ServiceLifetime.Singleton;
        }
        if (type == typeof(ITransientDependency))
        {
            return ServiceLifetime.Singleton;
        }
        if (type == typeof(ILifetimeScopeDependency))
        {
            return ServiceLifetime.Singleton;
        }

        throw new ArgumentOutOfRangeException($"Provided ServiceLifetime type is invalid. Lifetime:{type.Name}");
    }

    /// <summary>
    /// 註冊IocManager
    /// 在ConfigureServices方法最後一行使用
    /// </summary>
    /// <param name="services"></param>
    public static void AddIocManager(this IServiceCollection services)
    {
        services.AddSingleton<IIocManager, IocManager>(provide =>
        {
            IocManager.Instance.ServiceProvider = provide;
            return IocManager.Instance;
        });
    }
}

4、IocManager使用例項:

4.1、示例程式集

namespace Service
{
    public interface IUserService
    {
        string GetUserNameById(string Id);
    }
    public interface UserService:IUserService,ISingletonDependency
    {
        public string GetUserNameById(string Id)
        {
         return "劉大大";
        }
    }
}

4.2、為程式集寫一個拓展類

public static class ServiceExtensions
{
    public static IServiceCollection UseService(this IServiceCollection services)
    {
        var assembly = typeof(ServiceExtensions).Assembly;
        services.AddAssembly(assembly);
        return services;
    }
}

4.3、Web層使用

Startup class
       public void ConfigureServices(IServiceCollection services)
        {
           services.UseService();
           
           services.AddControllersWithViews();
           
           services.AddIocManager();
        }
Controller

IIocManager實現了單例模式,可以通過構造器注入獲取例項,也可以通過通過IocManager.Instance獲取例項

    public class HomeController : Controller
    {
        private readonly IIocManager _iocManager;
        public HomeController(IIocManager iocManager)
        {
            _iocManager = iocManager;
        }
        public string test1()
        {
         //通過注入獲取IocManager例項
         var _userService=_iocManager.ServiceProvider.GetService<IUserService>(); 
         var userName=_userService.GetUserNameById("1");
         return userName;
        }
        
        public string test2()
        {
         //通過IocManager獲取IIocManager例項
         var _userService=IocManager.Instance.ServiceProvider.GetService<IUserService>(); 
         var userName=_userService.GetUserNameById("1");
         return userName;
        }
        
        public string test3([FromServices]IUserService _userService)
        {
         //通過注入獲取Service例項
         var userName=_userService.GetUserNameById("1");
         return userName;
        }
}

相關推薦

ASP.NET Core 3.0 原生DI拓展實現IocManager

昨天.NET Core 3.0 正式釋出,建立一個專案執行後發現:原來使用的Autofac在ConfigureServices返回IServiceProvider的這種寫法已經不再支援。當然Autofac官方也給出了示例。 .NET Core 本身內建DI,我決定不再使用Autofac,就使用原生DI,拓展I

ASP.NET Core 3.0 實戰:構建多版本 API 介面

第一次在部落格寫分享,請多多捧場,如有歧義請多多包含! 因為業務需求發展需要,所以API介面的變更升級是必不可少的事情,而原有的介面是不可能馬上停止使用的。例如:Login介面為例,1.0版本之返回使用者的基本資訊,而2.0版本的迭代下,要把使用者祖宗十八代資訊都要返回到客戶端,這時候1.

ASP.NET Core 3.0 實戰:構建多版本 API 接口

版本信息 include swaggerui 各類 val 業務 oca head sem 第一次在博客寫分享,請多多捧場,如有歧義請多多包含! 因為業務需求發展需要,所以API接口的變更升級是必不可少的事情,而原有的接口是不可能馬上停止使用的。例如:Login接口為例,

ASP.NET Core 3.0:將會擁有更少的依賴

在ASP.NET Core專案中,我們使用一個叫做Microsoft.AspNetCore.App的綜合包。它也被稱為ASP.NET Core Shared Framework,在ASP.NET Core Shared Framework之中包含了很多依賴項,它能滿足一般應用的需求。但是如果你檢視它的依賴項,

ASP.NET Core 3.0 上的gRPC服務模板初體驗(多圖)

XML 代碼管理 grpc 文件內容 作者 發送 需要 web 應用 創建 原文:ASP.NET Core 3.0 上的gRPC服務模板初體驗(多圖)早就聽說ASP.NET Core 3.0中引入了gRPC的服務模板,正好趁著家裏電腦剛做了新系統,然後裝了VS2019的功夫

自動擋換手動擋:在 ASP.NET Core 3.0 Middleware 中手動執行 Controller Action

由於遭遇 System.Data.SqlClient 的效能問題(詳見之前的博文),向 .NET Core 3.0 的升級工作被迫提前了。在升級過程中遇到了一個問題,我們在 Razor Class Library 中實現的自定義錯誤頁面無法在 ASP.NET Core 3.0 Preview 5 中

ASP.NET Core 3.0 preview 特性,瞭解CLR的Garbage Collection

前言 在閱讀這篇文章:Announcing Net Core 3 Preview3的時候,我看到了這樣一個特性: Docker and cgroup memory Limits We concluded that the primary fix is to set a GC heap maximum s

gRPC in ASP.NET Core 3.0 -- Protocol Buffer(1)

現如今微服務很流行,而微服務很有可能是使用不同語言進行構建的。而微服務之間通常需要相互通訊,所以微服務之間必須在以下幾個方面達成共識: 需要使用某種API 資料格式 錯誤的模式 負載均衡 。。。 現在最流行的一種API風格可能是REST,它主要是通過HTTP協議來傳輸JSON資料。 但是

ASP.NET Core 3.0中使用動態控制器路由

原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 譯文:https://www.cnblogs.com/lwqlun/p/11461657.html 譯者:Lamond Lu 譯者注 今天在網上看到了這篇關於ASP.NET Cor

.NET Core 3.0ASP.NET Core 3.0 前瞻

前幾天微軟釋出了 .NET Core 3.0 Preview 9 ,這是.NET Core 3.0 最後一個預覽版。 .NET Core 3.0 正式釋出將在.NET Conf 上釋出,.NET Conf 時間是9月23日至25日。 Visual Studio 2019 16.3

[翻譯] ASP.NET Core 3.0 的新增功能

目錄 ASP.NET Core 3.0 的新增功能 Blazor Blazor Server Blazor WebAssembly (預覽) Razor 元件

ASP.NET Core 3.0 使用gRPC

一.簡介 gRPC 是一個由Google開源的,跨語言的,高效能的遠端過程呼叫(RPC)框架。 gRPC使客戶端和服務端應用程式可以透明地進行通訊,並簡化了連線系統的構建。它使用HTTP/2作為通訊協議,使用 Protocol Buffers 作為序列化協議。 它的主要優點: 現代高效能輕量級 RPC 框架

ASP.NET Core 3.0 : 二十五. TagHelper

  什麼是TagHelper?這是ASP.NET Core 中新出現的一個名詞,它的作用是使伺服器端程式碼可以在Razor 檔案中參與建立和呈現HTML 元素。(ASP.NET Core 系列目錄) 一、概述   上面的解釋有點拗口?那麼換一個名詞,HtmlHelper大家都

ASP.NET Core 3.0 gRPC 雙向流

目錄 ASP.NET Core 3.0 使用gRPC ASP.NET Core 3.0 gRPC 雙向流 ASP.NET Core 3.0 gRPC 認證授權 一.前言 在前一文 《ASP.NET Core 3.0 使用gRPC》中有提到 gRPC 支援雙向流呼叫,支援實時推送訊息,這也是 gRPC的一大

ASP.NET Core 3.0 : 二十四. 配置的Options模式

上一章講到了配置的用法及內部處理機制,對於配置,ASP.NET Core還提供了一種Options模式。(ASP.NET Core 系列目錄) 一、Options的使用 上一章有個配置的繫結的例子,可以將配置繫結到一個Theme例項中。也就是在使用對應配置的時候,需要進行一次繫結操作。而Options模式

asp.net core 3.0 更新簡記

asp.net core 3.0 更新簡記 Intro 最近把活動室預約專案從 asp.net core 2.2 更新到了 asp.net core 3.0,記錄一下,升級踩過的坑以及經驗總結,包括但不限於 TargetFramework (netcoreapp2.2 需要更新為 netcoreapp3.0

開發一個帶UI的庫(asp.net core 3.0

在GitHub上有個專案,本來是作為自己研究學習.net core的Demo,沒想到很多同學在看,還給了很多星,所以覺得應該升成3.0,整理一下,寫成博分享給學習.net core的同學們。 專案名稱:Asp.NetCoreExperiment 專案地址:https://github.com/axzxs2

asp.net core 3.0 中使用 swagger

asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 簡單的記錄了一下 swagger 的使用,那個專案的 api 比較簡單,都是匿名介面不涉及到認證以及 api 版本控制,最近把另外一個 api 專案升級到了 3.0,還是遇到了一些問題,這裡單獨

ASP.NET Core 3.0 一個 jwt 的輕量角色/使用者、單個API控制的授權認證庫

目錄 說明 一、定義角色、API、使用者 二、新增自定義事件 三、注入授權服務和中介軟體 三、如何設定API的授權 四、新增登入頒發 Token 五、部分說明

ASP.NET Core 3.0 : 二十八. 在Docker中的部署以及docker-compose的使用

本文簡要說一下ASP.NET Core 在Docker中部署以及docker-compose的使用  (ASP.NET Core 系列目錄)。 系統環境為CentOS 8 。  先打個廣告:求職中,求坑,求推薦 一、概述 簡單說一下Docker的幾個概念: 記得