asp.net core 2.1 ioc 依赖注入
net core 中的依赖注入
Package
Microsoft.Extensions.DependencyInjection
ServiceCollection
用来构造容器对象 IServiceProvider
调用 ServiceCollection 的 BuildServiceProvider() 创建 SerivceProvider, 可以获取 BuildServiceProvider() 之前 ServiceCollection 的对象
public class ServiceCollection : IServiceCollection, ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable, IList<ServiceDescriptor>
{
public ServiceCollection();
public ServiceDescriptor this[int index] { get; set; }
public int Count { get; }
public bool IsReadOnly { get; }
public void Clear();
public bool Contains(ServiceDescriptor item);
public void CopyTo(ServiceDescriptor[] array, int arrayIndex);
public IEnumerator<ServiceDescriptor> GetEnumerator();
public int IndexOf(ServiceDescriptor item);
public void Insert(int index, ServiceDescriptor item);
public void MakeReadOnly();
public bool Remove(ServiceDescriptor item);
public void RemoveAt(int index);
}
例子1:类的注入,一个简单的例子
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
using (ServiceProvider servicePorvider = services.BuildServiceProvider())
{
TestServiceImpl testTemplpm = servicePorvider.GetService<TestServiceImpl>();
testTemplpm.Name = "Tom";
testTemplpm.SayHi();
}
public class TestServiceImpl
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"Hi, I'm {Name}");
}
}
ServiceProvider
实现了 IDisposable
接口, 所以需要用到 using
.
例子2:接口注入
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new ServiceCollection();
services.AddTransient<ITestService, TestServiceImpl>();
using (ServiceProvider servicePorvider = services.BuildServiceProvider())
{
var testTemplpm = servicePorvider.GetService<ITestService>();
testTemplpm.Name = "Tom";
testTemplpm.SayHi();
}
public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
public class TestServiceImpl : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"Hi, I'm {Name}");
}
}
IServiceProvider 的服务器定位方法
-
GetService
:此方法用于获取与给定类型匹配的第一个服务实例。如果容器中没有该类型的服务,它将返回null
。因此,它被用于在没有明确要求的情况下获取可能存在的依赖项。 -
GetRequiredService
:此方法用于获取单一的,类型匹配的服务实例。如果容器中没有该类型的服务,它将抛出一个异常
。因此,它被用于确保始终获得所需的依赖项。 -
GetRequiredKeyedService
:此方法用于获取与给定键关联的单一服务实例。如果容器中没有与该键匹配的服务,它将抛出一个异常
。它被用于在有键的服务中获取所需的依赖项。 -
GetServices
:此方法用于获取与给定类型匹配的所有服务实例。如果容器中没有该类型的服务,它将返回一个空数组
。因此,它被用于获取可能存在的依赖项集合。
生命周期
内置的IOC有三种生命周期:
Transient: Transient服务在每次被请求时都会被创建。这种生命周期比较适用于轻量级的无状态服务。
Scoped: Scoped生命周期的服务是每次web请求被创建。
Singleton: Singleton生命能够周期服务在第一被请求时创建,在后续的每个请求都会使用同一个实例。如果你的应用需要单例服务,推荐的做法是交给服务容器来负责单例的创建和生命周期管理,而不是自己来走这些事情。
在Startup的ConfigureServices方法中
调用方法
services.AddSingleton(typeof(IMyService),new MyService());
也可以services.AddSingleton(typeof(IMyService),typeof(MyService));
最好还是services.AddSingleton<IMyService, MyService>();
因为这样的话可以在MyService中通过构造函数注入其他服务。
注册程序集的所有类
//通过反射把所有服务接口进行了注入:
var serviceAsm = Assembly.Load(new AssemblyName("Service"));
foreach (Type serviceType in serviceAsm.GetTypes()
.Where(t => typeof(IServiceTag).IsAssignableFrom(t) && !t.GetTypeInfo().IsAbstract))
{
var interfaceTypes = serviceType.GetInterfaces();
foreach (var interfaceType in interfaceTypes)
{
services.AddSingleton(interfaceType, serviceType);
}
}
其他类注入
在其他类怎么使用注入?假如在ExceptionFilter
中想调用IUserService怎么办?要确保ExceptionFilter不是new出来的,而是IOC创建出来
services.AddSingleton<ExceptionFilter>();
//mvc core中注册filter要在AddMvc的回调方法中注册。
services.AddMvc(options =>
{
var serviceProvider = services.BuildServiceProvider();
var filter = serviceProvider.GetService<ExceptionFilter>();
options.Filters.Add(filter);
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
手动获取注入
在HttpContext可用的时候,也可以通过这种方法来解析服务:
public IActionResult Index()
{
IMyDependency idService = (IMyDependency)HttpContext.RequestServices.GetService(typeof(IMyDependency));
return View();
}
内置服务
asp.net mvc core中架注入了很多服务:
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1
最有用的就是IHostingEnvironment
,其中主要成员有:WebRootPath属性(wwwroot文件夹的物理路径);ContentRootPath属性(网站根目录的物理路径)。
Microsoft.AspNetCore.Hosting下的HostingEnvironmentExtensions下还提供了一些扩展方法:
IsDevelopment()是否是开发环境、IsProduction()是否是生产环境。
asp.net mvc core中没有Server.MapPath()
方法,根据你要定位的文件是不是在wwwroot下,你可以使用IHostingEnvironment. WebRootPath或者IHostingEnvironment. ContentRootPath来进行拼接。
public class HomeController : Controller
{
private IHostingEnvironment iHostingEnvironment;
public HomeController(IHostingEnvironment iHostingEnvironment)
{
this.iHostingEnvironment = iHostingEnvironment;
}
public IActionResult Index()
{
IHostingEnvironment host = new HostingEnvironment();
host.WebRootPath = iHostingEnvironment.WebRootPath;
host.ContentRootPath = iHostingEnvironment.ContentRootPath;
host.ApplicationName = iHostingEnvironment.ApplicationName;
host.EnvironmentName = iHostingEnvironment.EnvironmentName;
// host.ContentRootFileProvider = iHostingEnvironment.ContentRootFileProvider;
// host.WebRootFileProvider = iHostingEnvironment.WebRootFileProvider;
return View(host);
}
...
}
指定要由 web 主机使用的环境
Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseEnvironment("Development") //指定要由 web 主机使用的环境。
.UseStartup<Startup>();