繁体   English   中英

依赖注入/构造函数注入帮助

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM