熟悉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.