ASP.NET Core中注入方式默认为构造器注入,不支持属性注入以及其他更高级的注入.参考下面的说明:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#default-service-container-replacement
但是对于习惯了属性注入的开发人员来说比较头疼,为了实现自动注入,需要额外加一个构造函数,还需要把需要提供的服务一一对应,这种操作兼职逼死强迫症.当然官方也给出解决方案,就是使用第三方的容器,比如Autofac,Unity.但是为了一个属性注入而抛弃内置的容器引入第三方容器,感觉也得不偿失.所以如果能在内置容器的基础上突破构造器的限制,则是两全其美.
属性注入就细节也有两种方式:1. 通过名称,2. 通过特性. 为了可以控制哪些属性需要注入,哪些属性不需要注入,同时在不能提供服务时给出异常提醒,我们选择第二种方式.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace OneSmart.Store.Admin.Web.Extensions
{
[AttributeUsage(AttributeTargets.Property)]
public class RequiredServiceAttribute : Attribute
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Resources;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace OneSmart.Store.Admin.Web.Extensions
{
public class AutoBindProControllerActivator : IControllerActivator
{
private readonly ITypeActivatorCache _typeActivatorCache;
private static IDictionary> _publicPropertyCache = new Dictionary>();
public AutoBindProControllerActivator(ITypeActivatorCache typeActivatorCache)
{
if (typeActivatorCache == null)
{
throw new ArgumentNullException(nameof(typeActivatorCache));
}
_typeActivatorCache = typeActivatorCache;
}
public object Create(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException(nameof(controllerContext));
}
if (controllerContext.ActionDescriptor == null)
{
throw new ArgumentException(nameof(ControllerContext.ActionDescriptor));
}
var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo;
if (controllerTypeInfo == null)
{
throw new ArgumentException(nameof(controllerContext.ActionDescriptor.ControllerTypeInfo));
}
var serviceProvider = controllerContext.HttpContext.RequestServices;
var instance = _typeActivatorCache.CreateInstance
在Startup类中找出DefaultControllerActivator,Remove,并注入AutoBindProControllerActivator.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(typeof(GlobalExceptionFilterAttribute));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// 必须要在AddMvc之后删除DefaultActivator =
var defaultActivator = services.FirstOrDefault(c => c.ServiceType == typeof(IControllerActivator));
if (defaultActivator != null)
{
services.Remove(defaultActivator);
services.AddSingleton();
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using OneSmart.Core;
using OneSmart.Store.Admin.Web.Interfaces;
using OneSmart.Store.Admin.Web.Models;
namespace OneSmart.Store.Admin.Web.Controllers
{
public class HomeController : Controller
{
[RequiredService]
public IService MyService{get;set;}
public IActionResult Index()
{
// MyService.dosomething...
return View();
}
}
}
因为我们的切入点是Activator,所以只能解决控制器内的属性注入,服务内部的注入还不能解决.目前服务的实例化是通过一个静态类ActivatorUtilities来实现,这个静态类并没有注入到容器中,所以不能通过服务替换的方式解决.如果有其他方法解决,不妨在下方留言,谢谢.