9

我们正在使用 ASP.NET MVC 技术开发某种云 CMS,并在此过程中发现了一些障碍。用户可以通过控制面板更改许多参数,我们需要在视图中结束这些参数。例如,用于初始化 Facebook JS API 的 Facebook 应用程序 ID。或要在页面上显示的附加文本。或背景图片。现在我们没有使用 DI 来传输这些参数,而是将它们添加到 ViewModel,但这破坏了 ASP.NET MVC 处理模型的方式(例如表单验证、绑定等)

看起来使用 DI 注入提供参数、文本和图片的服务可以使我的视图减少对特定控制器的依赖,甚至还有一些微软技术可以做到这一点http://www.asp.net/mvc/tutorials/动手实验室/aspnet-mvc-4-dependency-injection#Exercise2。但是,论坛上有很多反对使用 DI 将服务注入视图的答案。

所以问题是:将一些服务注入视图的正确方法是什么?或者我根本不应该这样做并且应用程序设计有问题?

更新:一些真实的代码示例(现在我们使用模型来注入服务)

从数据库中注入文本(它们必须是用户可编辑的,因为它是 CMS):

<div class="steps">@Html.Raw(Model.Texts["Main", "Step2"]</div>

从数据库中注入翻译(实际上是本地化):

<div class="gonfalon">@Model.Translations["Title_Winners"]</div>

注入参数(来自数据库,可能是特定于请求的;例如,如果站点具有不同的域,则 facebook 应用程序应该是每个域的):

Facebook.Initialize(Model.Parameters["FbApplicationId"], Model.Parameters["FbApplicationSecret"]);

当前方法的问题是该代码取自竞赛机制。处理自定义文本、翻译或 facebook 应用程序 ID 绝对超出竞争业务范围。它还破坏了模型,因为模型模型不是实际的业务领域,而是处理很多实际上属于视图的东西(比如翻译和自定义文本)

更新 2:已将以下答案中的代码段修改为更通用:

public static class WebViewPageExtensions 
{ 
    public static I ResolveService<I>(this WebViewPage page) 
    { 
         return DependencyResolver.Current.GetService<I>(); 
    } 
} 
4

3 回答 3

8

不,您不应该将服务注入视图,但是...

对于想要赋予主题开发者更多权力的主题化等场景,仅一种模型是不够的。例如,如果您的模型包含当前帖子,主题设计师如何要求侧边栏的类别列表?还是小部件?

在 asp.net mvc 中,您可以使用扩展方法来提供该功能。扩展方法将使用依赖解析器来获取服务。这样,您可以在视图中拥有所需的功能,而无需实际注入服务。

请注意,调用业务层更新模型仍然违反了关注点分离。视图可用的服务应该只包含读取模型或通用实用程序功能。

一个例子

 public static IMyViewServices MyServices(this WebViewPage view)
     {
         return DependencyResolver.Current.GetService<IMyViewServices>();
     }

在 DI 容器中配置的IMyViewServices生命周期应该是每个 http(范围)请求

于 2013-04-19T10:28:56.143 回答
4

不,故事结束。为什么?原因如下:

您的视图只需要知道它将使用什么视图模型来呈现该模型。这有几个原因,但最大的一个是关注点分离。保持你的观点尽可能愚蠢。您将看到这种分离将在整个过程中为您提供一个干净的应用程序结构。

用户可以通过控制面板更改许多参数,我们需要在视图中结束这些参数。

我不确定你在这里的确切意思,但这就是为什么会有视图模型。您的业​​务层将塑造模型,您的控制器将简单地将它们映射到您的视图模型并将它们传递到视图(表示层)。

于 2013-04-19T17:45:43.197 回答
2

这实际上取决于您希望控制器执行多少操作以及您想要达到何种程度的分离。

在我的世界中,MVC 应用程序中的“控制器”做得尽可能少,因为我有一个处理所有业务逻辑的服务层和一个处理所有数据库交互的数据层。

在 GET 上,控制器将简单地调用一个服务方法,该方法将构建视图模型并将其交还给控制器,然后控制器将其传递给视图。在 POST 上,视图将数据发布到控制器,控制器将其发送到服务层进行验证、保存到数据库等。服务被注入到控制器的构造函数中。

如果您想查看代码示例,我将非常乐意发布它们。

于 2013-04-19T10:14:10.630 回答