使用特性和反射在 ASP.NET Web API 中进行依赖注入






3.05/5 (8投票s)
通过特性和反射解析依赖
引言
在本文中,我们将了解如何创建一个依赖注入特性并在整个应用程序中使用它,从而消除冗余代码。
我将使用 AutoFac WebApi 容器作为我的依赖注入解析器。
问题
当我们开始在项目中为依赖项使用任何容器时,我们会编写大量的冗余代码,如下所示。
builder.RegisterType<<wbr />EmployeeManager>().As<<wbr />IEmployeeManager>();
builder.RegisterType<<wbr />CustomerManager>().As<<wbr />ICustomerManager>();
builder.RegisterType<<wbr />EmployeeRepository>().As<<wbr />IEmployeeRepository>();
builder.RegisterType<<wbr />CustomerRepository>().As<<wbr />ICustomerRepository>();
...
...
builder.RegisterType<<wbr />CustomerManager>().As<<wbr />ICustomerManager>();
builder.RegisterType<<wbr />EmployeeRepository>().As<<wbr />IEmployeeRepository>();
builder.RegisterType<<wbr />CustomerRepository>().As<<wbr />ICustomerRepository>();
随着项目规模的增长,依赖构建器的行数也会增加。
这其中存在多个问题。
1. 每次想要添加依赖项时,都需要进入依赖类并添加相关的依赖项。
2. 在合并代码时,开发人员可能会覆盖一些依赖项。
3. 该类会不断增长,并且在某个时候你会觉得它难以维护。
4. 这将违反 SOLID 原则的开放/封闭原则
解决方案
现在我们将看到如何通过特性和反射解决这些冗余代码。
步骤 1
我们将在此项目中创建一个公共库,并创建一个继承 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(<wbr />IEmployeeRepository employeeRepository)
{
_employeeRepository = employeeRepository;
}
public IList<Employee> GetAllEmployess()
{
var employeeData = _employeeRepository.<wbr />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] 特性装饰的类时,这意味着该类已准备好被注入。无论何时需要该类,都可以注入。
步骤 3
现在让我们在 WebApi 控制器中注入这个类,如下所示。
public class EmployeeController : ApiController
{
private readonly IEmployeeManager _employeeManager;
public EmployeeController(<wbr />IEmployeeManager employeeManager)
{
_employeeManager = employeeManager;
}
[AllowAnonymous]
[ResponseType(typeof(Employee)<wbr />)]
public IHttpActionResult GetEmployees()
{
var employeeData = _employeeManager.<wbr />GetAllEmployess();
return Ok(employeeData);
}
}
当您从 swagger 或 postman 运行上述代码时,它会起作用吗? 不,我们是否告诉 CLR 解析依赖项? 到目前为止,我们还没有做任何事情。
现在我们来做吧。
步骤 4
您需要从 NuGet 包管理器下载 Autofac.WebApi2 和 AutoFac。
我们将构建一个名为 Static AutoFacDependencyBuilder 的静态类,如下所示。
public static class AutofacDependecyBuilder
{
public static void DependencyBuilder()
{
// Create the builder with which components/services are registered.
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.<wbr />RegisterApiControllers(<wbr />Assembly.GetExecutingAssembly(<wbr />));
builder.RegisterAssemblyTypes(<wbr />AppDomain.CurrentDomain.<wbr />GetAssemblies())
.Where(t => t.GetCustomAttribute<<wbr />InjectableAttribute>() != null)
.AsImplementedInterfaces()
.InstancePerRequest();
builder.<wbr />RegisterWebApiFilterProvider(<wbr />GlobalConfiguration.<wbr />Configuration);
//Build the Container
var container = builder.Build();
//Create the Dependency Resolver
var resolver = new AutofacWebApiDependencyResolve<wbr />r(container);
//Configuring WebApi with Dependency Resolver
GlobalConfiguration.<wbr />Configuration.<wbr />DependencyResolver = resolver;
}
}
上述加粗的代码是会将所有部分组合在一起的关键。
这段代码将在项目首次加载时加载所有程序集。它将使用反射获取所有自定义特性并创建按请求实例化的对象。 在我们的例子中,它是 Injectable 自定义特性。
步骤 5
好的,经过所有的努力工作,我们需要在 Global.asax 或 App.Start 文件中初始化 AutoFac 依赖构建器类,如下所示。
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configure(<wbr />WebApiConfig.Register); AutofacDependecyBuilder.<wbr />DependencyBuilder(); } }
现在我们可以说它会完美地工作。
如果您不想经历所有的努力工作,可以访问下面的存储库链接。它应该可以帮助您入门。