【问题标题】:Access to container of Simple Injector MVC views访问 Simple Injector MVC 视图的容器
【发布时间】:2017-02-27 17:08:35
【问题描述】:

在一个 Sitecore 项目中,我使用 this article 集成了 Simple Injector

它使用sitecore管道,然后使用App_start中的方法

namespace BBC.App_Start
{
    public class SimpleInjector : IPackage
    {
        public void RegisterServices(Container container)
        {
            GetContainer.RegisterServices(container);

            container.Register(() => new SitecoreContext(), Lifestyle.Scoped);
            container.Register(() => new Container(), Lifestyle.Singleton);
        }
    }
}

我可以将容器注入控制器构造函数,但不能在视图文件中包含容器。

我尝试在 App-start 中声明一个静态属性并将容器保存到其中。但我仍然没有在视图中获得注册类型

在视图中拥有容器对象的最佳方式是什么?

【问题讨论】:

  • 您的视图中不应有任何依赖项。视图应该是普通的 DTO,控制器(或其他一些组件)应该创建它们。您也不应该将 Container 本身放入类中;这也是一种反模式。
  • 第三,你应该Register(() => new Container(), ...)。这将注册一个空容器。

标签: asp.net-mvc-4 dependency-injection sitecore inversion-of-control simple-injector


【解决方案1】:

正如Stephen 在他的评论中所建议的那样,你的问题的字面答案是“你不应该那样做——因为这不是 MVC 和 DI 真正应该工作的方式”。更详细的答案是这样的:

您的视图的工作是呈现已通过模型传递的数据。视图不应该真正包含逻辑。非常简单的东西,比如“如果标志为假,隐藏这个标记块”是可以的,但更复杂的代码来计算标志的值不应该出现在视图中。

MVC 鼓励您将呈现(视图)与数据(模型)和逻辑(控制器)。这应该使我们的代码更易于使用 - 因此,如果您有需要执行的处理,那么它应该在您的控制器方法运行时真正发生。

如果您的视图需要一些特殊数据,最佳实践建议它应该在控制器方法中解决它并将其传递给模型中的视图。代码可能看起来更像这样:

public class MyModel
{
    public string SpecialData { get; set; }
}

public class MyController : Controller
{
    public ActionResult DoSomething()
    {
        // do whatever processing is needed
        var somethingCalculate = resultFromYourOtherObject();
        // do other stuff

        var model = new MyModel() { SpecialData = somethingCalculated };

        return View(model);
    }
}

然后 View 只需要接受 MyModel 类作为它的模型,并渲染 SpecialData 属性 - 不需要逻辑。

我认为,让从 DI 容器中获取对象的调用传播到您的代码库中也是一个坏主意。对于 MVC 应用程序,通常您的 DI 容器会在应用程序启动时连接到为请求创建控制器的过程。 DI 框架不是将 DI 容器传递给控制器​​,而是扩展了控制器的创建过程,并且容器不会暴露在此之外。当 MVC 运行时需要创建控制器时,控制器创建逻辑使用 DI 框架为所有控制器的依赖项获取对象。

如果不详细说明您实际想要实现的目标,很难说在这里创建对象的“正确”方法是什么,但两种最常见的模式可能是:

1) 构造函数注入:您的控制器有一个参数,它接受所需的对象。 DI 容器在创建控制器时为您创建此对象,因此您的控制器在创建时获取其所有依赖项。适用于:您知道如何在请求开始时创建对象的场景。

public interface IMySpecialObject
{
    string DoSomething();
}

public class MyController : Controller
{
    private IMySpecialObject _specialObject;

    public MyController(IMySpecialObject specialObject)
    {
        _specialObject = specialObject;
    }

    public ActionResult RenderAView()
    {
        // do some stuff
        var data = _specialObject.DoSomething();

        return View(data);
    }
}

只要在您的应用启动时将IMySpecialObject 及其具体实现注册到您的 DI 容器中,一切都很好。

2) 工厂类: 然而,有时,有问题的对象可能是可选的,或者它可能需要在控制器创建时不可用的数据来创建它。在这种情况下,您的 DI 框架可以将 Factory 对象传递给您的控制器,这将用于稍后构建特殊对象。

public interface ISpecialFactory
{
    ISpecialObject CreateSpecialObject(object data);
}

public class MyController : Controller
{
    private IMySpecialFactory _specialFactory;

    public MyController(IMySpecialFactory specialFactory)
    {
        _specialFactory = specialFactory;
    }

    public ActionResult RenderAView()
    {
        // do some stuff
        if( requireSpecialObject )
        {
            var data = getSomeData();
            var specialObject = _specialFactory.CreateSpecialObject(data);
            var data = _specialObject.DoSomething();
            return View(data);
        }

        return View("someOtherView");
    }
}

但是一本关于使用 DI 的好书可能会建议其他更适合您的特定问题的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 2019-05-01
    • 1970-01-01
    相关资源
    最近更新 更多