在.Net Framwework MVC5的環境下使用autofac,直接上代碼
1.我的環境是.Net Framework4.5,MVC5,VS2017
nuget安裝autofac:
Install-Package Autofac -version 4.6.2
MVC安裝:
Install-Package Autofac.Mvc5 -version 4.0.2
WebApi安裝:
Install-Package Autofac.WebApi2 -version 4.3.0
基礎準備:
標識類:IBaseFlagService(實現該接口的類我們都需要注入進去)
用戶接口:
public interface IUserService : IBaseFlagService
{
string GetCurrentUserId();
string FormatDate(DateTime? date, bool isBegin);
}
用戶實現類:
public class UserService : IUserService
{
public string FormatDate(DateTime? date, bool isBegin)
{
if (date.HasValue)
{
string a = "yyyy-MM-dd ";
string b = isBegin ? "00:00:00.000" : "23:59:59.999";
return date.Value.ToString(a + b);
}
return null;
}
public string GetCurrentUserId()
{
return Guid.NewGuid().ToString();
}
}
動作接口:
public interface IActionService:IBaseFlagService
{
string SayHi();
string Action();
}
動作實現類一:貓
public class CatService : IActionService
{
public string Action()
{
return "貓咪賣萌!";
}
public string SayHi()
{
return "喵~";
}
}
動作實現類二:狗
public class DogService : IActionService
{
public string Action()
{
return "憨憨的柯基賣萌!";
}
public string SayHi()
{
return "汪汪汪~";
}
}
在global程序啓動時注入autofac:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
IocService.InitAutofac();
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
IocService:
public class IocService
{
public static IContainer Container;
public static void InitAutofac()
{
string dllNameStr = "WebMvcUseAutofac,WebMvcUseAutofacServices";
string a = ",";
var assList = dllNameStr.Split(new string[] { a }, StringSplitOptions.RemoveEmptyEntries).Select(r => Assembly.Load(r)).ToArray();
var baseType = typeof(IBaseFlagService);
var builder = new ContainerBuilder();
//RegisterAuto(builder, assList, baseType);
RegisterCustom(builder, assList, baseType);
RegisterWithMultipleImplements(builder);
builder.RegisterControllers(assList).PropertiesAutowired();//Mvc使用 注意:控制器無法單例注入,必須一次請求,一個實例,無法單例
//builder.RegisterApiControllers(assList).PropertiesAutowired();//WebApi使用,同樣,控制器無法單例注入
IocService.Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(IocService.Container));//Mvc使用
//GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(IocService.Container);//WebApi使用
}
/// <summary>
/// 通過注入,將實現IBaseFlagService接口的所有服務類注入到類本身所實現的接口中
/// </summary>
/// <param name="builder"></param>
/// <param name="assList"></param>
/// <param name="baseType"></param>
private static void RegisterAuto(ContainerBuilder builder, Assembly[] assList, Type baseType)
{
builder.RegisterAssemblyTypes(assList).Where(r => baseType.IsAssignableFrom(r) && r.IsInterface == false)//找到程序集中符合條件的類
.AsSelf().AsImplementedInterfaces()//注入到自己實現的接口中
.SingleInstance()//生命週期:單例
.PropertiesAutowired();//支持屬性注入
}
/// <summary>
/// 自己寫邏輯注入
/// </summary>
/// <param name="builder"></param>
/// <param name="assList"></param>
/// <param name="baseType"></param>
private static void RegisterCustom(ContainerBuilder builder, Assembly[] assList, Type baseType)
{
//程序集下所有的類
var allTypeList = assList.SelectMany(r => r.GetTypes()).ToList();
var groupTypeList = allTypeList.ToLookup(r => r.Name).Select(r => new { Name = r.Key, Count = r.Count(), List = r.ToArray() }).OrderBy(r => r.Count).ToArray();
//實現了指定接口的類
var allServiceTypeList = allTypeList.FindAll(r => baseType.IsAssignableFrom(r));
//服務類
var serviceTypes = allServiceTypeList.FindAll(r => r.IsInterface == false);
//服務接口(排除掉標籤接口)
var iServiceTypes = allServiceTypeList.FindAll(r => r.IsInterface && IsSameType(r, baseType) == false);
string a = ",";
foreach (var serviceType in serviceTypes)
{
//該服務類所實現的接口
var interfaceList = serviceType.GetInterfaces();
var useInterfaceList = interfaceList.Intersect(iServiceTypes).ToArray();
//校驗
if (useInterfaceList.Length == 0)
throw new Exception($"服務類{serviceType.Name}沒有實現任何接口!");
else if (useInterfaceList.Length > 1)
throw new Exception($"服務類{serviceType.Name}實現的接口數量大於1個:{string.Join(a, useInterfaceList.Select(r => r.Name))}");
//注入操作
builder.RegisterType(serviceType).As(useInterfaceList[0])
.SingleInstance()//單例注入
.PropertiesAutowired();//支持屬性注入
}
}
/// <summary>
/// 一個接口多個實現,手動注入(也可以自動注入,通過增加特性來標識,然後讀取注入,我這裏就不做演示)
/// </summary>
/// <param name="builder"></param>
private static void RegisterWithMultipleImplements(ContainerBuilder builder)
{
builder.RegisterType<CatService>().Named<IActionService>("Cat").PropertiesAutowired();//Named參數只能是string
builder.RegisterType<DogService>().Keyed<IActionService>("Dog").PropertiesAutowired();//這裏只是使用Keyed,因爲Keyed參數是object,可以使用枚舉
}
public static bool IsSameType(Type type1, Type type2)
{
return type1.FullName == type2.FullName;
}
}
測試代碼:
public class HomeController : Controller
{
//構造函數注入
public IUserService _UserServiceForConstructor;
public HomeController(IUserService userService)
{
this._UserServiceForConstructor = userService;
}
public IUserService _UserServiceForProperty { get; set; }
public ActionResult Index()
{
//使用構造函數注入的接口
string dateStr = _UserServiceForConstructor.FormatDate(DateTime.Now, false);
//使用屬性函數注入的接口
string userId = _UserServiceForProperty.GetCurrentUserId();
var catService = IocService.Container.ResolveNamed<IActionService>("Cat");
string catStr = catService.SayHi();
var dogService = IocService.Container.ResolveKeyed<IActionService>("Dog");
string dogStr = dogService.SayHi();
string a = ";";
ViewBag.PageData = string.Join(a, new List<string>() { dateStr, userId, catStr, dogStr });
return View();
}
}
前端:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
@ViewBag.PageData
</div>
</body>
</html>
運行結果:
Ending~