[英]Dependency Injection / Constructor Injection Help
我有以下类/接口:
public interface IProjectRepository
{
IQueryably<Project> GetProjects();
}
// Depends on my EF Context
public ProjectRepository : IProjectRepository
{
private MyDbEntities context;
public ProjectRepository(MyDbEntities context)
{
this.context = context;
}
public IQueryable<Project> GetProjects()
{
return context.Projects;
}
}
我的 controller:
// Depends on IProjectRepository
public class ProjectsController : Controller
{
private IProjectRepository projectRepository;
public ProjectsController(IProjectRepository projectRepository)
{
this.projectRepository = projectRepository;
}
public ActionResult Index()
{
return View(projectRepository.GetProjects());
}
}
我需要设置我的依赖注入,以便它在 ProjectRepository 中传递到我的 Controller并且它需要在我的实体框架上下文中传递到项目存储库中。 我需要实体上下文是 HTTP 请求范围。
我不确定应该将所有映射代码放在哪里以使依赖注入工作。 我也不明白没有默认构造函数的 MVC 将如何工作。
有人可以帮我把所有的部分放在一起吗? 我正在使用 StructureMap 但我可以轻松切换到其他东西,因为我不知道我在做什么。
如果您使用的是 MVC 3,为了正确地做事,您应该使用内置的依赖解析位。 我强烈建议您阅读Brad Wilson(ASP.NET MVC 团队成员)的系列博客文章。
至于特定于 StructureMap 的实现,我发现以下博客文章很有帮助。
StructureMap 和 ASP.NET MVC 3 – 入门
StructureMap、Model ASP.NET MVC 3 中的绑定器和依赖注入
ASP.NET MVC 3 中的 StructureMap、动作过滤器和依赖注入
ASP.NET MVC 3 中的 StructureMap、全局操作过滤器和依赖注入
无论如何,这里有一些代码。 首先,我建议您安装StructureMap-MVC3 NuGet package 。
我不记得它究竟以文件的方式创建了什么,但这就是基本上涉及的内容。
/App_Start/StructuremapMvc.cs - 这挂钩到 Application_Start 并设置您的容器( SmIoC.Initialize()
),然后将 MVC 3 DependencyResolver 设置为您的SmDependencyResolver
using System.Web.Mvc;
using YourAppNamespace.Website.IoC;
using StructureMap;
[assembly: WebActivator.PreApplicationStartMethod(typeof(YourAppNamespace.App_Start.StructuremapMvc), "Start")]
namespace YourAppNamespace.Website.App_Start {
public static class StructuremapMvc {
public static void Start() {
var container = SmIoC.Initialize();
DependencyResolver.SetResolver(new SmDependencyResolver(container));
}
}
}
/IoC/SmDependencyResolver.cs - 这是您的 MVC 3 IDependencyResolver 实现。 它在上面的 App_Start 代码中使用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace YourAppNamespace.Website.IoC
{
public class SmDependencyResolver : IDependencyResolver
{
private readonly IContainer _container;
public SmDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType == null)
{
return null;
}
try
{
return _container.GetInstance(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType).Cast<object>(); ;
}
}
}
/IoC/SmIoC.cs - 这是您设置容器的地方...也用于 App_Start 代码。
namespace YourAppNamespace.Website.IoC
{
public static class SmIoC
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
//etc...
});
return ObjectFactory.Container;
}
}
}
现在一切都已连接...(我认为;-)但您还有最后一件事要做。 在您的Global.asax
中,我们需要确保您处理 HttpContext 范围内的所有内容。
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
所以你应该可以通过构造函数注入来实现依赖注入,这是go关于处事的正确方法。
如果您准备使用 StructureMap, 这里有一个您可能需要的设置教程。
其他一些依赖注入框架带有自定义的 controller 工厂,它们将为您完成这些工作。 例如, Ninject (开源依赖注入)有一个您可以使用的扩展,其中包含此行为。 例如,请参见此处。 在这里扩展。
您还可以使用Unity IOC ,它是另一个流行的依赖注入框架,据我所知,您必须创建一个自定义 controller 工厂(如结构图)来实现此行为。 有关示例,请参见此处。
您还可以研究所有其他依赖注入框架,看看您可以获得哪些支持。
编辑:我希望我能正确解释这一点,但这里有一些背景信息。
MVC 使用 controller 工厂,该工厂负责在发出请求时实例化所需的相应控制器。 默认情况下,它将通过调用其无参数构造函数来初始化 controller。
要为构造函数参数注入创建基础结构,您需要创建一个可以解析构造函数参数的自定义工厂。 这就是依赖注入容器的用武之地:本质上,DI 容器(如果配置正确)知道如何解决这些依赖关系,您的自定义工厂将利用它来请求注册的依赖关系并将其传递给 controller 构造函数。
所有的工作都差不多。 从历史上看,所有人都有设置器注入器(设置一个然后填充的属性),但现在大多数都有构造器注入。 在结构 map 中,最简单的方法是使用属性:[StructureMap.DefaultConstructor]。
添加属性后,您放置在“地图”中的对象应该无需任何额外工作即可注入。 如果不能使用属性,请考虑使用 setter。
结构上有一个文件 map 站点: http://structuremap.net/structuremap/ConstructorAndSetterInjection.htm
使用 StructureMap 时,我的 controller 通常会有这样的内容:
private static IProjectRepository GetProjectRepository()
{
var retVal = ObjectFactory.TryGetInstance<IProjectRepository>()
?? new ProjectRepository();
return retVal;
}
如果 TryGetInstance 返回 null(因为没有为该类型设置任何内容),它将默认为您指定的具体类型。
现在你有一个像这样的引导程序:
public static class StructureMapBootStrapper
{
public static void InitializeStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
}
}
}
现在您在 Global.asax Application_Start 事件中调用此引导程序:
protected void Application_Start()
{
StructureMapBootStrapper.InitializeStructureMap();
}
现在在一个测试项目中,当你想注入一个模拟存储库时,你可以这样做:
[TestMethod]
public void SomeControllerTest()
{
StructureMap.ObjectFactory.Inject(
typeof(IProjectRepository),
new MockProjectRepository());
// ... do some test of your controller with the mock
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.