65.9K
CodeProject 正在变化。 阅读更多。
Home

依赖注入模式与 Autofac

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (21投票s)

2013 年 12 月 1 日

CPOL

3分钟阅读

viewsIcon

77660

downloadIcon

9

依赖注入 (DI) 如何帮助我们构建松散耦合的软件架构,以及如何使用 Autofac 实现 DI。

引言

依赖注入模式,也称为控制反转,是当今最流行的设计范例之一。它使我们能够编写松散耦合的代码,消除对象之间的紧密耦合,使对象和使用它们的应用程序更灵活、可重用、更易于测试,并使其能够在运行时和编译时更改。 

在本文中,我们将讨论依赖注入 (DI) 如何帮助我们构建松散耦合的软件架构,以及如何使用 Autofac 实现 DI。在文章的最后,我们应该清楚这个模式以及如何在 ASP.NET MVC4 应用程序中应用它。 

技术: Visual Studio 2012, .NET Framework 4.5, ASP.NET MVC4, Entity Framework 5 和 C#。 

背景 

我们可以通过四种主要方式将依赖项注入到类中,例如构造函数注入、Setter 注入、属性注入和方法注入。在本文中,我将讨论构造函数注入以及如何使用 Autofac 实现 DI。

构造函数注入:这是最常见的 DI。在这种方法中,我们在构造函数本身中传递对象引用。因此,当客户端创建对象时,它会将对象传递给构造函数。依赖注入是通过在实例化该类时通过类的构造函数提供依赖项来完成的。注入的组件可以在类的任何地方使用。 

public class Customer     
{
    DIDbContext dbContext = new DIDbContext();
    public int Create(Customer customer)
    {
        if (customer != null)
        {
            dbContext.Customers.Add(customer);
            dbContext.SaveChanges();
            return 1;
        }
        return 0;
    }
    public IEnumerable<customer> GetAllCustomers()
    {
        return dbContext.Customers.ToList();
    }
}

public class CustomerController : Controller
{
    Customer customer = null;
    public CustomerController()
    {
        Customer=new Customer();
    }
    public ActionResult Index()
    {
       var customers= customer.GetAllCustomers();
       return View(customers);
    }
    public ActionResult Create()
    {           
        return View();
    }
    [HttpPost]
    public ActionResult Create(Customer customer)
    {
         customer.Create(customer);
        return RedirectToAction("Index"); 
    }
}

CustomerController 类依赖于 Customer 类。在这种情况下,CustomerControllerCustomerController 构造函数内部直接创建一个 Customer 的实例,并且确切地知道它正在创建和使用的客户类。这确实违反了 DIP(依赖倒置原则)。

为了减少依赖,我们必须执行几个步骤。首先,我们引入 Repository 层,在那里我们可以保留与数据库相关的功能,例如数据插入、修改和获取。然后我们引入 Service 层,在那里我们可以保留额外的逻辑,如果我们有需要的话。例如,如果我们需要向客户发送邮件,或者我们需要计算来自客户的总利润。在这种情况下,我们可以将邮件发送和计算功能保留在 Service 层中。我们可以在 CustomerCustomerController 之间创建两个抽象层。我们可以使用接口/抽象类来表示 CustomerCustomerController 之间的抽象。

public interface IRepository
{
    int Create(T t);
    IEnumerable FindAll();
    T FindById(int id);
}

public class CustomerRepository : IRepository<customer>
{
    DIDbContext dbContext = new DIDbContext();

    public int Create(Customer customer)
    {
        if (customer != null)
        {
            dbContext.Customers.Add(customer);
            dbContext.SaveChanges();
            return 1;
        }
        return 0;
    }
    public IEnumerable<customer> FindAll()
    {
        return dbContext.Customers.ToList();
    }
    public Customer FindById(int id)
    {
        return dbContext.Customers.Find(id);
    }
}

public interface IService<t>
{
    int Create(T t);
    IEnumerable<t> FindAll();
    T FindById(int id);	
    void SendMail();
    void CalculateTotalProfit();
}

public class CustomerService : IService<customer>
{
    private readonly IRepository<customer> _iCustomerRepository;
    public CustomerService(IRepository<customer> customerRepository)
    {
        _iCustomerRepository = customerRepository;
    }
    public int Create(Customer customer)
    {
        return _iCustomerRepository.Create(customer);
    }
    public IEnumerable<customer> FindAll()
    {
        return _iCustomerRepository.FindAll();
    }
    public Customer FindById(int id)
    {
        return _iCustomerRepository.FindById(id);
    }
    public void SendMail()
    { 
    //implement here..
    }
    public void void CalculateTotalProfit()
    {
    //implement here..
    }
}

public class CustomerController : Controller
{
    private readonly IService<customer> _customerService = null;
    public CustomerController(IService<customer> customerService)
    {
        _customerService = customerService;
    }
    public ActionResult Index()
    {
        var customers = _customerService.FindAll();
       return View(customers);
    }
    public ActionResult Create()
    {           
        return View();
    }
    [HttpPost]
    public ActionResult Create(Customer customer)
    {
        _customerService.Create(customer);
        return RedirectToAction("Index"); 
    }
}

在这里,我们引入了两个接口,IRepositoryIService,以表示抽象并确保 CustomerContrller 类仅调用来自 IService 接口的方法或属性,因为 CustomerController依赖于 Service 类,并且 Customer 类调用来自 IRepository 接口的方法或属性,因为 Customer依赖于 Repository 类。 

为了编写松散耦合的代码,我们可以应用这些注入中的任何一个,应用哪个注入将取决于具体场景。 

现在我们将看到如何将 AutofacASP.NET MVC4 集成和实现。 

Autofac 是一个 IoC 容器,它为 ASP.NET MVC 框架提供了更好的集成,并管理类之间的依赖关系,以便 应用程序保持易于更改。我们可以轻松地将 Autofac 集成到我们的应用程序中;为此,首先,我们必须 获取 NuGet 包。 如果你不用 NuGet,你可以 从这个网站下载 Autofac。  

使用 Autofac 注册组件:首先,我们必须将 Autofac 程序集(Autofac.dll, Autofac.Configuration.dll, 和 Autofac.Integration.Mvc.dll)添加到我们的项目中。然后,我们在 Global.asax.csApplication_Start() 中编写以下代码块,它将使用 ASP.NET MVC 4 配置 Autofac。

var builder = new ContainerBuilder(); 
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType(typeof(CustomerService)).AsImplementedInterfaces();
builder.RegisterType(typeof(CustomerRepository)).AsImplementedInterfaces();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

致谢:感谢 Rubayat Asirul Bari 审阅本文并提供了许多有用的建议。 

结论

希望您能够将此应用于您的应用程序,并且它将使在您的应用程序中应用依赖注入设计模式变得更容易一些。

© . All rights reserved.