昨天 .NET Core 3.0 正式發佈,創建一個項目運行後發現:原來使用的Autofac在ConfigureServices返回IServiceProvider的這種寫法已經不再支持。 當然Autofac官方也給出了示例。.NET Core 本身內置DI,我決定不再使用Autofac,就使用原生 ...
昨天.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 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==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 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;
}
}
5、Autofac IocManager實現
5.1、安裝 Autofac.Extensions.DependencyInjection包
5.2、 IocManager實現
IIocManager介面
public interface IIocManager
{
ILifetimeScope ServiceProvider { get; set; }
}
IocManager實現
public class IocManager : IIocManager
{
static IocManager()
{
Instance = new IocManager();
}
public static IocManager Instance { get; private set; }
public ILifetimeScope ServiceProvider { get; set; }
}
靜態類 DependencyInjectionExtensions 添加UseIocManager方法。使用Autofac時可以在ConfigureContaine中直接註冊內容,ConfigureContainer在ConfigureServices之後運行,
所以不能使用在ConfigureServices里註入IocManager,要在Configure方法中引用IocManager。
/// <summary>
/// 註冊IocManager
/// 在Configure方法使用
/// </summary>
/// <param name="services"></param>
public static IApplicationBuilder UseIocManager(this IApplicationBuilder app)
{
services.AddSingleton<IIocManager, IocManager>(provide =>
{
IocManager.Instance.ServiceProvider = app.ApplicationServices.GetAutofacRoot();
return app;
});
}
使用示例:
Startup class
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacModule());
}
public void Configure(IApplicationBuilder app,ILoggerFactory loggerFactory)
{
app.UseIocManager();
}
Controller
public class HomeController : Controller
{
private readonly IIocManager _iocManager;
public HomeController(IIocManager iocManager)
{
_iocManager = iocManager;
}
public string test1()
{
//通過註入獲取IocManager實例
var _userService=_iocManager.ServiceProvider.Resolve<IUserService>();
var userName=_userService.GetUserNameById("1");
return userName;
}
public string test2()
{
//通過IocManager獲取IIocManager實例
var _userService=IocManager.Instance.ServiceProvider.Resolve<IUserService>();
var userName=_userService.GetUserNameById("1");
return userName;
}
public string test3([FromServices]IUserService _userService)
{
//通過註入獲取Service實例
var userName=_userService.GetUserNameById("1");
return userName;
}
}