Asp.mvc(三) ~ 使用 Autofac 实现依赖注入

Asp.mvc(三) ~ 使用 Autofac 实现依赖注入 #

在说 mvc 项目之前, 先看看下面一个依赖注入的例子, 新建一个名为 AutofacSample 的控制台程序,使用下面的指令获取 Atuofac :

Install-Package Autofac

创建一个 ILogger 接口, 其中定义了一个 void Log(string content)的方法:

namespace AutofacSample
{
    public partial interface ILogger
    {
        void Log(string content);
    }
}

定义 ConsoleLogger 与 TextLogger 均实现 ILogger 接口, 顾名思义: ConsoleLogger 表示使用控制台来写日志, TextLogger 表示使用文本的方式写日志:

ConsoleLogger:

using System;

namespace AutofacSample
{
    public partial class ConsoleLogger : ILogger
    {
        public void Log(string content)
        {
            Console.WriteLine("时间: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine("内容: " + content);
        }
    }


}

TextLogger:

using System;
using System.Configuration;
using System.IO;
using System.Text;

namespace AutofacSample
{
    public partial class TextLogger : ILogger
    {
        private string _logPath = ConfigurationManager.AppSettings["logpath"];

        public void Log(string content)
        {
            using (var writer = new StreamWriter(_logPath, true, Encoding.UTF8))
            {
                writer.WriteLine("-------------------------------------------------");
                writer.WriteLine("时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                writer.WriteLine("内容:" + content);
                writer.WriteLine("-------------------------------------------------");
            }
        }
    }
}

下面再来创建一个 LogManager, 其作用就是控制 ILogger 来进入写日志:

namespace AutofacSample
{
    public partial class LogManager
    {
        private ILogger _logger;

        public LogManager(ILogger logger)
        {
            this._logger = logger;
        }

        public void Log(string content)
        {
            this._logger.Log(content);
        }
    }
}

在此声明了一个 ILogger 类型的 _logger 字段, 使用带参构造函数来初始化 _logger, 然后定义 Log 方法进行写日志 。

在 Program.cs 中编写如下代码:

using Autofac;
using Autofac.Configuration;
using System;

namespace AutofacSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType(typeof(LogManager));
            builder.RegisterType(typeof(ConsoleLogger)).As(typeof(ILogger));
            //builder.RegisterType(typeof(TextLogger)).As(typeof(ILogger));

            using (var container = builder.Build())
            {
                var logManager = container.Resolve<LogManager>();
                logManager.Log("日志记录...");
            }
            Console.WriteLine("日志完毕");
            Console.ReadKey();
        }
    }
}

定义容器构建者对象:

var builder = new ContainerBuilder();

注册 LogManager 类, 使构建者与容器知道这个类的存在:

builder.RegisterType(typeof(LogManager));

注册 ConsoleLogger类, 将其指定为 ILogger 实例:

builder.RegisterType(typeof(ConsoleLogger)).As(typeof(ILogger));

下面注释的一行意思与上面的一样, 只不过注册的是 TextLogger 类。

创建容器:

var container = builder.Build();

通过容器创建 LogManager 实例, 调用 Log 方法来写日志:

var logManager = container.Resolve<LogManager>();
logManager.Log("日志记录...");

运行之后, 我们会在CMD窗口中看到下面的结果:

下面我们把上面注册 Logger的代码改为以下(注意:由于在 TextLogger 日志文件路径是获取 app.config文件中的 appSetting节, 所以大家自行配置):

//builder.RegisterType(typeof(ConsoleLogger)).As(typeof(ILogger));
builder.RegisterType(typeof(TextLogger)).As(typeof(ILogger));

再来看看结果:

打开自己配置好的日志文件, 我的由于运行了多次, 每次运行都会增加一条记录:

上述方式是直接修改源码, 但是有时候, 我们并不像重新编译程序, 这时候, 我们可以通过配置文件来完成这个工作: 首先在配置文件(app.config)中新增一个 section 节:

<configSections>
    <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
</configSections>

然后在下面在增加一些节点来注册我们的组件(Component),且制定我们的服务(Service) :

<autofac defaultAssembly="AutofacSample">
    <components>
      <component type="AutofacSample.TextLogger" service="AutofacSample.ILogger" />
    </components>
</autofac>

需要注意的是: AutofacSample 是我们程序的命名空间, 无论是组件还是服务, 写的都是 FullName。 同样将其中的 type 改为 AutofacSample.ConsoleLogger 的话, 就表示指定控制台日志作为日志对象, 大家可以自行尝试。

好, 基本概念有了, 那下面就来说一说在 asp.net mvc 项目中如何使用 Autofac:

在 MonggodbSample 的 Services 层中(如果对此不清楚的请移步: http://blog.csdn.net/zhanxueguang/article/details/46994813

private IRepository<M.User> _userRepository;

public UserService()
{
    this._userRepository = new MongoRepository<M.User>();
}

在 UserService 中定义了

private IRepository<M.User> _userRepository

这个私有字段, 主要作用是为了获取操作数据库的相关对象, 在构造函数中, 将其实例成为

MongoRepository<M.User>

, 根据设计模式六大原则之一: 依赖倒置原则高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。 我们直接将 _userRepository 字段实例成为

MongoRepository

, 自然是违反了这个原则, 所以我们需要这样修改:

private IRepository<M.User> _userRepository;

public UserService(IRepository<M.User> userRepository)
{
    this._userRepository = userRepository;
} 

将构造函数更改为接收一个

IRepository<M.User>

参数的构造函数, 下面再看 Web 层, 创建一个 UserController 控制器:

using System.Web.Mvc;
using Services.User;
using System.Threading.Tasks;
using M = Core.Domain;
using Web.Models.User;
using System.Collections.Generic;

namespace Web.Controllers
{
    public class UserController : Controller
    {
        private IUserService _userService;

        public UserController(IUserService userService)
        {
            _userService = userService;
        }
    }
}

同样,根据依赖倒置原则, 我们在 UserController 中定义了一个类型为 IUserService, 名为 _userService 的私有字段, 构造函数含义一个 IUserService userService 参数,用于初始化 _userService 字段, 但是我们仔细一想, 貌似 UserController 的父类 Controller 中并不包含带参的构造函数吧! 这个时候, Autofac 的强大之处就体现出来了, 我们首先通过 Nuget 包控制台键入以下命令获取 Autofac :

Install-Package Autofac.Mvc5

安装成功之后, 打开 Web 项目下的 Global.asax 应用程序文件:

using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace Web
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

将 Application_Start 函数更改为:

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        //获取容器建立者
        var builder = new ContainerBuilder();
        //注册泛型 Repository<>
        builder.RegisterGeneric(typeof(MongoRepository<>)).As(typeof(IRepository<>))
            .InstancePerLifetimeScope();
        //注册 Service
        builder.RegisterType(typeof(UserService)).As(typeof(IUserService));
        //注册 Controller 
        builder.RegisterControllers(typeof(MvcApplication).Assembly);

        //创建容器
        var container = builder.Build();
        //将上面的容器设置为一个新的依赖解析器
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

注释中对代码的作用解释的很清楚, 下面我们在 UserController 中添加一个名为 Index 的 Action :

public async Task<ActionResult> Index()
{
    var result = await this._userService.FindManyAsync(x => true, 10, 0);
    return View(result);
}

即调用 IUserService 中定义的 FindManyAsync 方法来获取相对应条件的数据, 我们再来创建一个以 Core.Domain.User为强类型的 Index 视图:

@model IEnumerable<Core.Domain.User>

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.LoginName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LoginPwd)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.NickName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.PhoneNo)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Birthday)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Email)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Address)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.RegisterTime)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.LoginName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LoginPwd)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.NickName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.PhoneNo)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Birthday)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Email)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Address)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.RegisterTime)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
        </td>
    </tr>
}

</table>

界面效果:

上面所演示的仅仅只是 Autofac 的冰山一角, 仅仅针对 mvc, 就有注册 Controller , 设置依赖解析器, 注册模型绑定者, 注册 Web 抽象, 启用 View Pages 的属性注入, 启用动作过滤器的属性注入等等, 简直不要太多… 后续再专门抽出一个系列来说 IOC (Inversion of Conotrol) 控制反转。 好了好了,该睡觉了,时间有点晚了…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值