昨天.NET Core 3.0正式发布,创建一个项目运行后发现:原来使用的Autofac在ConfigureServices返回IServiceProvider的这种写法已经不再支持。

当然Autofac官方也给出了示例。.NET Core 本身内置DI,我决定不再使用Autofac,就使用原生DI,拓展IServiceCollection实现一个IocManager,

实现批量注入,静态获取实例能。末尾处含有Autofac 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

IIocManager接口

public interface IIocManager
{
IServiceProvider ServiceProvider { get; set; }
}

IocManager实现

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 ISingletonDependency: 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==null|assemblies.Count()==0)
{
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!=null)
{
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 class 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()
{
//通过IocManagerIocManager实例
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;
}
}

5、Autofac IocManager实现

5.1、安装 Autofac.Extensions.DependencyInjection包

5.2、 IocManager实现

IIocManager接口

public interface IIocManager
{
ILifetimeScope AutofacContainer { get; set; }
TService GetInstance<TService>();
}

IocManager实现

    public class IocManager : IIocManager
{
static IocManager()
{
Instance = new IocManager();
}
public static IocManager Instance { get; private set; }
/// <summary>
/// Autofac容器
/// </summary>
public ILifetimeScope AutofacContainer { get; set; } public TService GetInstance<TService>()
{
return AutofacContainer.Resolve<TService>();
}
}

静态类 DependencyInjectionExtensions 添加UseIocManager方法。使用Autofac时可以在ConfigureContaine中直接注册内容,ConfigureContainer在ConfigureServices之后运行,

所以不能使用在ConfigureServices里注入IocManager,要在Configure方法中引用IocManager。

    /// <summary>
/// .NET Core 依赖注入拓展
/// </summary>
public static class DependencyInjectionExtensions
{
/// <summary>
/// 注册程序集组件
/// </summary>
/// <param name="builder"></param>
/// <param name="assemblies"></param>
/// <returns></returns>
public static ContainerBuilder RegisterAssembly(this ContainerBuilder builder, params Assembly[] assemblies)
{
if (assemblies.IsNullOrEmpty())
{
throw new Exception("assemblies cannot be empty.");
}
foreach (var assembly in assemblies)
{
RegisterDependenciesByAssembly<ISingletonDependency>(builder, assembly);
RegisterDependenciesByAssembly<ITransientDependency>(builder, assembly);
RegisterDependenciesByAssembly<ILifetimeScopeDependency>(builder, assembly);
}
return builder;
} /// <summary>
/// 注册程序集
/// </summary>
/// <param name="builder"></param>
/// <param name="assembly">The assembly.</param>
private static void RegisterDependenciesByAssembly<TServiceLifetime>(ContainerBuilder builder, 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()) continue;
if (typeof(TServiceLifetime) == typeof(ISingletonDependency))
{
builder.RegisterType(type).As(itype).SingleInstance();
}
if (typeof(TServiceLifetime) == typeof(ITransientDependency))
{
builder.RegisterType(type).As(itype).InstancePerDependency();
}
if (typeof(TServiceLifetime) == typeof(ILifetimeScopeDependency))
{
builder.RegisterType(type).As(itype).InstancePerLifetimeScope();
}
}
} /// <summary>
/// 注册IocManager
/// </summary>
/// <param name="services"></param>
public static void UseIocManager(this IApplicationBuilder app)
{
IocManager.Instance.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
}
}

Service

    /// <summary>
/// Application拓展类
/// </summary>
public static class ServiceExtensions
{
/// <summary>
/// 注入Application容器
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static ContainerBuilder RegisterService(this ContainerBuilder builder)
{
var assembly = typeof(ApplicationExtensions).Assembly;
builder.RegisterAssembly(assembly);
return builder;
}
}

Startup

        public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterService();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseIocManager();
}
Controller
public class HomeController : Controller
{
private readonly IIocManager _iocManager;
public HomeController(IIocManager iocManager)
{
_iocManager = iocManager;
}
public string test1()
{
//通过注入获取IocManager实例
var _userService=_iocManager.GetInstance<IUserService>();
var userName=_userService.GetUserNameById("1");
return userName;
} public string test2()
{
//通过IocManager获取IIocManager实例
var _userService=IocManager.Instance.GetInstance<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的更多相关文章

  1. ASP.NET CORE 学习之原生DI实现批量注册

    以前使用Autofac的时候,只需一句AsImplementInterfaces()就可以很轻松实现批量注册功能.而asp.net core内置的DI框架没有现成的批量注册方法,考虑到替换Autofa ...

  2. ASP.NET Core 3.0 入门

    原文:ASP.NET Core 3.0 入门 课程简介 与2.x相比发生的一些变化,项目结构.Blazor.SignalR.gRPC等 课程预计结构 ASP.NET Core 3.0项目架构简介 AS ...

  3. 从 MVC 到使用 ASP.NET Core 6.0 的最小 API

    从 MVC 到使用 ASP.NET Core 6.0 的最小 API https://benfoster.io/blog/mvc-to-minimal-apis-aspnet-6/ 2007 年,随着 ...

  4. ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介

    概述 ASP.NET Core 1.0是ASP.NET的一个重要的重新设计. 例如,在ASP.NET Core中,使用Middleware编写请求管道. ASP.NET Core中间件对HttpCon ...

  5. #ASP.NET Core 1.0 Key Features

    Cross platform support and flexible runtime engine(跨平台支持和灵活的运行时引擎) ASP.NET Core 1.0 offers support f ...

  6. .NET Core 1.0、ASP.NET Core 1.0和EF Core 1.0简介

    .NET Core 1.0.ASP.NET Core 1.0和EF Core 1.0简介 英文原文:Reintroducing .NET Core 1.0, ASP.NET Core 1.0, and ...

  7. ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置

    在 ASP.NET Core 里扩展 Razor 查找视图目录不是什么新鲜和困难的事情,但 _ViewStart 和 _ViewImports 这2个视图比较特殊,如果想让 Razor 在我们指定的目 ...

  8. 从头编写 asp.net core 2.0 web api 基础框架 (3)

    第一部分:http://www.cnblogs.com/cgzl/p/7637250.html 第二部分:http://www.cnblogs.com/cgzl/p/7640077.html 之前我介 ...

  9. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (3)

    Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-template-from-scratc ...

随机推荐

  1. JavaScript数组方法大全(第二篇)

    数组方法大全(第二篇) 注意:如有错误欢迎指出,如有雷同纯属巧合,本博客参考书籍JavaScript权威指南,有兴趣的小伙伴可以去翻阅一下哦 forEach()方法 遍历数组,里面可以传递一个方法 v ...

  2. C#中的扩展方法(向已有类添加方法,但无需创建新的派生类型)

    C#中的扩展方法 扩展方法使你能够向现有类型"添加"方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样 ...

  3. 随笔编号-15 重构--改善既有代码的设计--Day01--学习笔记

    最近公司开发的系统在进行大批量数据查询的时候发现响应速度变得让人无法忍受,so 老大安排我进行代码重构的工作,主要目的就是为提高代码的执行效率.减小方法之间的响应时间.降低方法之间的耦合度.= =! ...

  4. C#使用iTextSharp给PDF文件加水印

    给PDF添加水印,可以用iTextSharp. 步骤1:下载iTextSharp 步骤2:在项目中添加引用itextsharp.dll 步骤3:在程序中使用iTextSharp.text.pdf us ...

  5. Delphi - Windows自动计划任务与ParamStr详解

    Windows自动计划任务与ParamStr详解 ParamStr函数: ParamStr(1),..ParamStr(N) ParamStr(1)代表程序入口的第一个参数,同理,ParamStr(N ...

  6. C#开发学习人工智能的第一步

    前言 作为一个软件开发者,我们除了要学会复制,黏贴,还要学会调用API和优秀的开源类库. 也许,有人说C#做不了人工智能,如果你相信了,那只能说明你的思想还是狭隘的. 做不了人工智能的不是C#这种语言 ...

  7. 深入浅出TypeScript(3)- 函数重载和泛型

    面向对象特性中,最根本的就是面向对象的三大基本特征:封装.继承.多态.同时,TypeScript中也存在多态的使用,比如函数重载,今天我们先看一下函数重载以及泛型的概念. 什么是函数重载 简单来说,函 ...

  8. 五月月赛 寻宝 exkmp + 主席树

    : 寻宝 时间限制: Sec 内存限制: MB 提交: 解决: [提交] [状态] [讨论版] [命题人:admin] 题目描述 采蘑菇的小西佬找到了一张上古年间的藏宝图,上面画着m座连绵不断的山,他 ...

  9. 洛谷- P1306 斐波那契公约数 - 矩阵快速幂 斐波那契性质

    P1306 斐波那契公约数:https://www.luogu.org/problemnew/show/P1306 这道题目就是求第n项和第m项的斐波那契数字,然后让这两个数求GCD,输出答案的后8位 ...

  10. poj - 1860 Currency Exchange Bellman-Ford 判断正环

    Currency Exchange POJ - 1860 题意: 有许多货币兑换点,每个兑换点仅支持两种货币的兑换,兑换有相应的汇率和手续费.你有s这个货币 V 个,问是否能通过合理地兑换货币,使得你 ...