我们正在使用ASP.NET MVC技术开发某种云CMS,并且在途中遇到了一些障碍。用户可以通过控制面板更改许多参数,我们需要在视图中结束这些参数。例如,Facebook应用程序ID初始化Facebook JS API。或者在页面上显示其他文本。或背景图片。目前我们没有使用DI来传输这些参数,而是将它们添加到ViewModel中,但这会破坏ASP.NET MVC处理模型的方式(例如表单验证,绑定等)。
看起来使用DI注入提供参数,文本和图片的服务可能会使我的视图更少依赖于特定于控制器,甚至还有一些Microsoft技术可以做到这一点http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-dependency-injection#Exercise2。但是,在论坛上有很多答案反对使用DI将服务注入到视图中。
所以问题是:将一些服务注入视图的正确方法是什么?或者我根本不应该这样做,应用程序设计出了什么问题?
UPDATE :一些真实的代码示例(现在我们使用Model来注入服务)
从数据库中注入文本(它们必须是用户可编辑的,因为它是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绝对不在竞争业务范围之内。它也破坏了模型作为模型模型而不是实际的业务领域,但处理了许多实际属于View的东西(如翻译和自定义文本)
更新2 :修改了以下答案中的代码段,使其更具通用性:
public static class WebViewPageExtensions
{
public static I ResolveService<I>(this WebViewPage page)
{
return DependencyResolver.Current.GetService<I>();
}
}
答案 0 :(得分:7)
不,你不应该将服务注入视图,但是......
对于诸如主题的场景,您希望为主题开发人员提供更多功能,仅仅一个模型是不够的。例如,如果您的模型包含当前帖子,主题设计师如何请求侧边栏的类别列表?或者对于小部件?
在asp.net mvc中,您可以使用扩展方法来提供该功能。扩展方法将使用依赖项解析程序来获取服务。这样,您可以在视图中拥有所需的功能,而无需实际注入服务。
请注意,调用业务层更新模型仍然违反了“关注点分离”。视图可用的服务应仅包含读取模型或一般实用程序功能。
一个例子
public static IMyViewServices MyServices(this WebViewPage view)
{
return DependencyResolver.Current.GetService<IMyViewServices>();
}
DI容器中配置的IMyViewServices 生命周期应该是每个http(范围)请求
答案 1 :(得分:3)
不,故事结束。为什么?原因如下:
您的视图只需要知道它将用于呈现该模型的视图模型。这有几个原因,但最大的原因是关注点的分离。保持你的观点尽可能愚蠢。您将看到这一分离将在整个过程中为您提供干净的应用程序结构。
用户可以通过控制面板更改许多参数,我们需要在视图中进行更改。
我不确定你在这里究竟是什么意思,但这就是视图模型的原因。您的业务层将塑造模型,您的控制器将简单地将它们映射到您的视图模型并将它们传递到视图(表示层)。
答案 2 :(得分:2)
这实际上取决于您希望控制器做多少,以及您希望实现的分离程度。
在我的世界中,MVC应用程序中的“控制器”尽可能少,因为我有一个处理所有业务逻辑的服务层和一个处理所有数据库交互的数据层。
在GET上,控制器将简单地调用一个服务方法,该方法将构建视图模型并将其交还给控制器,然后控制器将其传递给视图。在POST上,视图将数据发布到控制器,控制器将其发送到服务层进行验证,保存到DB等。服务被注入控制器的构造函数。
如果你想看到它们,我会非常乐意发布代码示例。