依赖注入与代码整洁性

在软件开发中,依赖注入(Dependency Injection,简称DI)是一种设计模式,用于实现控制反转(Inversion of Control,简称IoC),它允许程序在运行时动态地将依赖项注入到对象中。这种方式可以提高代码的可测试性和可维护性,但随着项目的增长,依赖项的注册可能会变得冗长且难以管理。本文将探讨如何使用AutoFacWebApi容器作为依赖注入解析器来减少代码冗余,并遵循SOLID原则。

问题

当开始使用任何容器来解析项目中的依赖时,通常会编写大量的冗余代码,如下所示:

builder.RegisterType<EmployeeManager>().As<IEmployeeManager>(); builder.RegisterType<CustomerManager>().As<ICustomerManager>(); builder.RegisterType<EmployeeRepository>().As<IEmployeeRepository>(); builder.RegisterType<CustomerRepository>().As<ICustomerRepository>();

随着项目的增长,依赖构建器中的代码行数也会增加,这会带来多个问题:

  • 每次添加依赖时,都需要来到依赖类并添加相应的依赖。
  • 在合并代码时,开发者可能会覆盖掉一些依赖。
  • 类不断增长,最终会变得难以维护。
  • 这违反了SOLID原则中的开闭原则。

解决方案

将通过属性和反射来解决代码冗余问题。

首先,将在项目中创建一个公共库,并在System命名空间下创建一个继承自Attribute类的InjectableAttribute类。

using System; namespace AutoFacCommon { public class InjectableAttribute : Attribute { } }

这里使用了"InjectableAttribute"作为名称,因为Angular2有一个名为Injectable的依赖注入,希望客户端和服务端能够同步。

接下来,需要使用Injectable属性来装饰类。

[Injectable] public class EmployeeManager : IEmployeeManager { private readonly IEmployeeRepository _employeeRepository; public EmployeeManager(IEmployeeRepository employeeRepository) { _employeeRepository = employeeRepository; } public IList<Employee> GetAllEmployess() { var employeeData = _employeeRepository.GetAllEmployees(); var employeeList = new List<Employee>(); foreach (var employee in employeeData) { var employ = new Employee(); employ.EmployeeDesignation = employee.EmployeeDesignation; employ.EmployeeId = employee.EmployeeId; employ.EmployeeName = employee.EmployeeName; employeeList.Add(employ); } return employeeList; } }

注意:当看到类上装饰了[Injectable]属性时,这意味着这个类已经准备好被注入了。在需要这个类的地方都可以使用。

现在让在WebApi控制器中注入这个类。

public class EmployeeController : ApiController { private readonly IEmployeeManager _employeeManager; public EmployeeController(IEmployeeManager employeeManager) { _employeeManager = employeeManager; } [AllowAnonymous] [ResponseType(typeof(Employee))] public IHttpActionResult GetEmployees() { var employeeData = _employeeManager.GetAllEmployess(); return Ok(employeeData); } }

运行上述代码时,可能会发现它不会工作,因为还没有告诉CLR来解析依赖。现在来做这件事。

需要有Autofac.WebApi2和AutoFac。可以从Nuget包管理器下载。

public static class AutofacDependencyBuilder { public static void DependencyBuilder() { var builder = new ContainerBuilder(); builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies()) .Where(t => t.GetCustomAttribute<InjectableAttribute>() != null) .AsImplementedInterfaces().InstancePerRequest(); builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration); var container = builder.Build(); var resolver = new AutofacWebApiDependencyResolver(container); GlobalConfiguration.Configuration.DependencyResolver = resolver; } }

上述代码将把所有部分整合在一起。这段代码将在项目首次加载时加载所有程序集。它将使用反射获取所有自定义属性,并为每个请求创建实例。在例子中,它是Injectable自定义属性。

public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); AutofacDependencyBuilder.DependencyBuilder(); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485