熟悉IoC容器的都知道,在開發過程中,最鬱悶的莫過於當你新增一個Service時,你需要對該Service進行註冊,有的是使用代碼注入,有的是XML配置注入,不管是哪種類型的注入,經常會出現開發人員忘記注入的情況,
如果你的頁面是直接發送請求的,那麼會得到類似於如下頁面的錯誤:
如果該服務是用於AJAX請求實用的,那麼你就悲劇了,因爲頁面只是沒反應,只有查看錯誤日誌了。
於是我試着去想辦法去避免每次的服務都需要注入,而是系統自動注入。
紅色線條框住的地方就是自動注入的代碼實現。很高興Autofac提供一個RegisterAssemblyTypes方法。它回去掃描所有的dll並把每個類註冊爲它所實現的接口。。。。
既然能夠自動注入,那麼接口和類的定義一定要有一定的規律。 從上面的代碼可以看到baseType這個變量,它是IDependency接口的類型。
IDependency接口如下:
其他任何的接口都需要繼承這個接口,例如我們定義一個接口IModelCar:
IModelCar的實現類:
自動注入原理說明:
首先我們去找到所有Dll,再去找到實現了IDependency接口的類,然後使用RegisterAssemblyTypes進行注入。
在Controller中調用試試:
可以看到_carmodel解析後爲ModelCar的實例。。
Demo下載: https://github.com/nicholaspei/MvcApplication5
Autofac是.net界一款輕量化的IOC組件,使用Autofac可以幫助完成代碼中很多依賴注入工作。在以前文章中,介紹過Autofac的配置過程(http://www.cnblogs.com/Jnw-qianxi/p/3450344.html),在我以往的配置過程中,接口與接口的實現類的註冊在一個靜態方法RegisterAutofac中實現:
01.
1
public
static
void
RegisterAutofac()
02.
2
{
03.
3
ContainerBuilder
builder =
new
ContainerBuilder();
04.
4
builder.RegisterControllers(Assembly.GetExecutingAssembly());
05.
5
06.
6
#region
IOC註冊區域
07.
7
08.
8
09.
9
//Admin
10.
10
builder.RegisterType<AdminService>().As<IAdminService>().InstancePerHttpRequest();
11.
11
12.
12
13.
13
#endregion
14.
14
//
then
15.
15
var
container = builder.Build();
16.
16
DependencyResolver.SetResolver(
new
AutofacDependencyResolver(container));
17.
17
18.
18
}
隨着系統開發的進行,IOC註冊區域中會不斷添加新的註冊,不同區域,不同模塊的類型註冊都會在這進行(數據倉儲層,業務邏輯層,基礎設施層等等不同層次的類型註冊都要在此方法中進行),同時系統不同開發人員都需要維護該方法,這樣帶來
1.
RegisterAutofac方法所在類的臃腫,且不符合類的職責單一原則。<br><br> 爲此我想到,能否根據註冊類型,將IOC註冊區域部分提取到不同的類中實現,將如這些類擁有一個共同的接口,不是就可以根據接口反射出獲取這些類了嗎?<br> <br>首先,定義反射類。用於獲取繼承接口的類型
01.
1
public
class
ContainerTypeFinder
: ITypeFinder
02.
2
{
03.
3
04.
4
public
IList<Assembly>
GetAssemblies()
05.
5
{
06.
6
//由於註冊文件可能分佈在不同類庫,爲此我們獲取所有程序集,而不是當前程序集
07.
7
return
AppDomain.CurrentDomain.GetAssemblies();
08.
8
09.
9
}
10.
10
11.
11
public
IEnumerable<Type>
FindClassesOfType(Type assignTypeFrom)
12.
12
{
13.
13
var
list =
new
List<Type>();
14.
14
foreach
(var item in GetAssemblies())
15.
15
{
16.
16
var
typesToRegister = item.GetTypes()
17.
17
.Where(type
=> !String.IsNullOrEmpty(type.Namespace))
18.
18
.Where(type
=> type.GetInterface(assignTypeFrom.Name) == assignTypeFrom)
19.
19
;
20.
20
if
(typesToRegister.Count()
>
0
)
21.
21
{
22.
22
list.AddRange(typesToRegister);
23.
23
}
24.
24
}
25.
25
return
list;
26.
26
}
27.
27
}
1.
然後,就是將IOC註冊區域移除到類當中
01.
1
public
interface
IDependencyRegistrar
02.
2
{
03.
3
void
Register(ContainerBuilder
builder);
04.
4
05.
5
int
Order
{ get; }
06.
6
}
07.
7
08.
8
09.
9
public
class
DependencyRegistrar
: IDependencyRegistrar
10.
10
{
11.
11
public
void
Register(ContainerBuilder
builder)
12.
12
{
13.
13
builder.RegisterType<EfRepository<Core.Domain.Customer.Customer>>().As<IRepository<Core.Domain.Customer.Customer>>().InstancePerHttpRequest();
14.
14
}
15.
15
16.
16
public
int
Order
17.
17
{
18.
18
get
{
return
1
;
}
19.
19
}
20.
20
}
1.
IDependencyRegistrar就是我們上面所說的接口,ContainerTypeFinder類當中的FindClassesOfType()方法會搜尋所有實現該接口的類。實現的註冊工作在Register()方法中完成。<br>接着,封裝一個方法完成所有的Autofac註冊工作,同時便於在Global中調用:<br>
01.
1
public
static
void
InitContainer()
02.
2
{
03.
3
//autofac
容器
04.
4
ContainerBuilder
builder =
new
ContainerBuilder();
05.
5
//註冊所有控制器
06.
6
builder.RegisterControllers(_typeFinder.GetAssemblies().ToArray());
07.
7
08.
8
#region
反射 核心
09.
9
//通過反射得到繼承IDependencyRegistrar該接口的類成員
10.
10
var
types = _typeFinder.FindClassesOfType(typeof(IDependencyRegistrar));
11.
11
var
drInstances =
new
List<IDependencyRegistrar>();
12.
12
//創建實例
13.
13
foreach
(var drType in types)
14.
14
drInstances.Add((IDependencyRegistrar)Activator.CreateInstance(drType));
15.
15
//sort
16.
16
drInstances
= drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
17.
17
//執行Register方法
18.
18
foreach
(var dependencyRegistrar in drInstances)
19.
19
dependencyRegistrar.Register(builder);
20.
20
#endregion
21.
21
22.
22
//then
23.
23
var
container = builder.Build();
24.
24
DependencyResolver.SetResolver(
new
AutofacDependencyResolver(container));
最後在Global文件Application_Start()方法中調用上述方法
1 ContainerManager.InitContainer();
1.
1.
1.