AutoFac – 将 autofac 应用于MVC多层项目

C#

浏览数:1,001

2019-5-10

 一、前言

  AutoFac是.NET平台下的一款著名的IoC Container,它可以让我们很轻松的解除项目中服务类的接口与客户类的接口实现类之间的依赖关系,从而降低系统各模块之间耦合程度以提高系统的稳定性。最近在做毕业设计,在开发中采用了autofac来进行依赖注入,这里是对踩到的一些坑的解决方法,希望可以给同样不幸进入这些坑中的童鞋们提供一些解决思路。

  对于IOC、DI相关的概念由于自己也是一知半解的,推荐T2噬菌体的这篇 依赖注入那些事儿 写的很详细也很好理解。

  AutoFac文档地址:http://autofac.readthedocs.io/en/latest/getting-started/index.html

  使用AutoFac需要引用的类库dll:Autofac.dllAutofac.ConfigurationMicrosoft.Extensions.Configuration.Xml

  PS:我是采用xml进行配置的AutoFac,如果你采用json进行配置,则需要引用Microsoft.Extensions.Configuration.Xml,使用nuget即可获取到这些引用dll。

 二、实例

  项目结构如下图所示,autofac涉及到类库如下

  PSU.Factory:autofac配置相关信息

  PSU.Domain:功能接口的实现类

  PSU.IService:功能接口

  PSU.Controllers:控制器

  PSU.IService、PSU.Domain就是基本的接口与其实现类,也就没什么东西了,测试的代码如下:

 1 //-----------------------------------------------------------------------
 2 // <copyright file= "IIndex.cs">
 3 //     Copyright (c) Danvic712. All rights reserved.
 4 // </copyright>
 5 // Author: Danvic712
 6 // Date Created: 2018/1/9 星期二 16:37:48
 7 // Modified by:
 8 // Description: 管理员首页操作邻域
 9 //-----------------------------------------------------------------------
10 using PSU.Models.Area.Administrator.Home;
11 using System;
12 using System.Collections.Generic;
13 using System.Linq;
14 using System.Text;
15 using System.Threading.Tasks;
16 
17 namespace PSU.IService.Area.Administrator.Home
18 {
19     public interface IIndex
20     {
21         /// <summary>
22         /// 页面初始化加载
23         /// </summary>
24         /// <param name="webModel"></param>
25         /// <returns></returns>
26         IndexWebModel Init(IndexWebModel webModel);
27     }
28 }

接口定义

 1 //-----------------------------------------------------------------------
 2 // <copyright file= "IndexDomain.cs">
 3 //     Copyright (c) Danvic712. All rights reserved.
 4 // </copyright>
 5 // Author: Danvic712
 6 // Date Created: 2018/1/9 星期二 16:42:53
 7 // Modified by:
 8 // Description: 管理员首页操作邻域接口实现
 9 //-----------------------------------------------------------------------
10 using PSU.IService.Area.Administrator.Home;
11 using PSU.Models.Area.Administrator.Home;
12 using System;
13 
14 namespace PSU.Domain.Area.Administrator.Home
15 {
16     public class IndexDomain : IIndex
17     {
18         /// <summary>
19         /// 页面初始化加载
20         /// </summary>
21         /// <param name="webModel"></param>
22         /// <returns></returns>
23         public IndexWebModel Init(IndexWebModel webModel)
24         {
25             webModel = new IndexWebModel();
26             return webModel;
27         }
28     }
29 }

接口实现类

   PSU.Factory这个类库里写的是autofac的配置方法,在写之前让我们先看看官方的Demo:

   简单翻译一下

  1. 你需要在你的项目里加载Microsoft.Extensions.Configuration 这个dll,如果你使用json进行配置的话,你需要加载 Microsoft.Extensions.Configuration.Json 这个dll,而我是通过xml文件进行配置,则需要加载 Microsoft.Extensions.Configuration.Xml
  2. 通过实例化ConfigurationBuilder来加载配置文件
  3. 注册配置组件
  4. 在容器中注册配置模块

  因为我们会把所有的接口与实现类的映射放置于xml文件中,将所有的模块注册在容器中,通过对于官方方法的封装,创建一个静态方法去自由的选择加载需要接口与实现类,代码和配置文件如下:

 1 //-----------------------------------------------------------------------
 2 // <copyright file= "MAutoFac.cs">
 3 //     Copyright (c) Danvic712. All rights reserved.
 4 // </copyright>
 5 // Author: Danvic712
 6 // Date Created: 2018/1/8 星期一 13:23:04
 7 // Modified by:
 8 // Description: AutoFac帮助类
 9 //-----------------------------------------------------------------------
10 using Autofac;
11 using Autofac.Configuration;
12 using Microsoft.Extensions.Configuration;
13 
14 namespace PSU.Factory
15 {
16     public class MAutoFac
17     {
18         /// <summary>
19         /// 缓存注册容器
20         /// </summary>
21         private static IContainer _container = null;
22 
23         /// <summary>
24         /// 注册并创建实例
25         /// </summary>
26         /// <typeparam name="T"></typeparam>
27         /// <returns></returns>
28         public static T CreateInstance<T>()
29         {
30             if (_container == null)
31             {
32                 var builder = new ContainerBuilder();
33 
34                 //读取配置信息
35                 //
36                 IConfigurationBuilder config = new ConfigurationBuilder();
37                 config.AddXmlFile("autofac.config");
38 
39                 //注册组件
40                 var module = new ConfigurationModule(config.Build());
41 
42                 //注册模块
43                 builder.RegisterModule(module);
44 
45                 _container = builder.Build();
46             }
47 
48             return _container.Resolve<T>();
49         }
50     }
51 }

帮助类

1 <?xml version="1.0" encoding="utf-8" ?>
2 <autofac defaultAssembly="PSU.IService">
3   <!--Administrator:首页接口-->
4   <components name="0">
5     <type>PSU.Domain.Area.Administrator.Home.IndexDomain,PSU.Domain</type>
6     <services name="0" type="PSU.IService.Area.Administrator.Home.IIndex" />
7     <injectProperties>true</injectProperties>
8   </components>
9 </autofac>

配置文件

  创建一个返回类型是泛型的静态方法,通过 Resolve<T>() 用来解析容器中已经注册的实例T,并对给其进行赋值,这样,我们就可以通过传入指定的接口来获取对应的实现方法。

  对于XML配置文件,如果你是采用VS生成的配置文件模版,你需要移除 configuration 根节点,直接使用 autofac 作为XML文档的根节点,切记,否则你将无法读取到配置信息。同时,如果你是和我一样的直接写好配置文件的地址,你需要将配置文件放置在Web项目的根目录下,或者显示写好加载的配置文件的所在地址。

  配置相关解释:

  1、defaultAssembly 默认的命名空间;如果type节点或者services节点的属性type没有设置类所在命名空间的话,将默认在defaultAssembly下查找类,type节点和services节点的属性type设置格式为MyType,MyAssembly;

  2、多个接口时添加多个components节点,name 属性依次添加;

  3、type节点对应接口实现类所在的位置(命名空间.类名,命名空间) — 英文逗号;

  4、services节点对应接口所在的位置(命名空间.接口类名)

  5、injectProperties节点:是否启用组件的属性注入

       在控制器调用接口实例,我是采用的重写 Controller 类的 Inintalize 方法,实现接口的注入,这样我们就可以在控制器中调用接口里的方法了,实现方法如下图所示。

 1 //-----------------------------------------------------------------------
 2 // <copyright file= "HomeController.cs">
 3 //     Copyright (c) Danvic712. All rights reserved.
 4 // </copyright>
 5 // Author: Danvic712
 6 // Date Created: 2017/12/20 星期三 14:20:40
 7 // Modified by:
 8 // Description: Administrator-Home控制器
 9 //-----------------------------------------------------------------------
10 using PSU.Factory;
11 using PSU.IService.Area.Administrator.Home;
12 using PSU.Models.Area.Administrator.Home;
13 using System.Web.Mvc;
14 using System.Web.Routing;
15 
16 namespace PSU.Controllers.Areas.Administrator
17 {
18     public class HomeController : Controller
19     {
20         #region Initializes
21 
22         private IIndex _iService;
23 
24         protected override void Initialize(RequestContext requestContext)
25         {
26             base.Initialize(requestContext);
27 
28             if (_iService == null)
29             {
30                 _iService = MAutoFac.CreateInstance<IIndex>();
31             }
32         }
33 
34         #endregion
35 
36         #region Service
37 
38         public ActionResult Index(IndexWebModel webModel)
39         {
40             _iService.Init(webModel);
41             return View(webModel);
42         }
43 
44         #endregion
45     }
46 }

控制器

   至此,我们要完成的也就差不多了,运行项目看看,咦,发现报错,查看报错信息,提示我们找不到PSU.Domain这个类库dll

  Web项目,它所依赖的dll全部位于网站根目录下面的bin文件夹中,由于我们采用IOC加载接口实现层,Web层只引用接口,不引用接口实现层,所以autofac无法在项目中找到PSU.Domain这个dll,所以我们只要把这个dll给移动到Web项目的bin目录下面就可以了。编译生成后手动移动,繁琐、费事。这里我采用的是通过在PSU.Domain这里类库的属性上添加后期生成命令完成操作。重新生成下项目,预览这个视图页面,bingo,可以了。

 三、其它

  1、通过属性后期生成事件生成接口实现类库到bin文件夹里,有人说在release模式下,执行失败,我还没到这一步,所以就不得而知了,解决方案可以见链接 =》https://social.msdn.microsoft.com/Forums/zh-CN/caf363ec-e0f9-41da-ad24-60993e83f190/releasebindll?forum=adonetzhchs

  2、代码完成之后,才发现AutoFac有专门的一个在MVC项目如何使用的实例,如果有童鞋用过的话,可以说说这两种的优劣,示例见链接 =》http://autofac.readthedocs.io/en/latest/integration/mvc.html

  3、个人的一点使用实例,希望对你有点用处,如果中间有说的不对的地方,欢迎指点

  4、欢迎转载,注明出处即可

作者:墨墨墨墨小宇