Asp.net mvc 从MVC中的控制器确定局部视图的模型
我目前的问题是,我有一个局部视图,我想确定它正在使用什么模型 我不得不为我的项目处理一些奇怪的场景,所以我将尝试在这里概述它,也许有人可以提供一个更好的方法来做到这一点 我正在设计类似谷歌iGoogle页面的东西。包含多个小部件的主页,这些小部件可以移动或根据需要进行配置。当前系统异步加载实际小部件的数据,并在我的应用程序中查看控制器的帖子。该控制器要么将部分视图呈现为可以返回的HTML(然后加载到页面视图JQUERY中),要么仅呈现存储在数据库中的纯HTML/JavaScript 这对我来说很好,我有一个小部件模型,它包含一个通过数据库描述的选项字典,然后被部分视图使用。当我想将数据传递给局部视图时,问题就出现了。我能想到的最好的解决方案是让控制器确定所讨论的部分视图使用的模型,使用一些函数填充模型,然后将其与部分视图一起传递给将在控制器内将其呈现为HTML的函数 我意识到这对于MVC来说是一个奇怪的场景(层正在混合…),任何关于基本设计或实现的建议都将不胜感激Asp.net mvc 从MVC中的控制器确定局部视图的模型,asp.net-mvc,model-view-controller,asp.net-mvc-3,Asp.net Mvc,Model View Controller,Asp.net Mvc 3,我目前的问题是,我有一个局部视图,我想确定它正在使用什么模型 我不得不为我的项目处理一些奇怪的场景,所以我将尝试在这里概述它,也许有人可以提供一个更好的方法来做到这一点 我正在设计类似谷歌iGoogle页面的东西。包含多个小部件的主页,这些小部件可以移动或根据需要进行配置。当前系统异步加载实际小部件的数据,并在我的应用程序中查看控制器的帖子。该控制器要么将部分视图呈现为可以返回的HTML(然后加载到页面视图JQUERY中),要么仅呈现存储在数据库中的纯HTML/JavaScript 这对我来说很
我目前正在使用MVC3/Razor。请随意询问任何其他问题。一个选项是在应用程序中扩展部分请求的概念。史蒂夫·桑德森(Steve Sanderson)有,尽管这篇文章与MVC 1和MVC 2有关。我认为这对v3仍然有帮助,但我还没有调查v3,看看MVC团队是否实现了自己的版本。在异步场景中,您需要稍微玩弄一下实现,也许可以更改PartialRequest定义以根据需要接受不同的信息,但我认为这可能是一个好的开始。最终的结果将是更好地隔离关注点,允许单个控制器管理特定类型的分部,从而更好地了解您想要使用的模型类型 我不能100%确定这是您想要的,但是可以将
[ChildActionOnly]
属性添加到控制器中的方法中。这要求只能从部分视图调用该方法。然后,您可以为该方法设置部分视图,该方法基本上类似于您的一个小部件。在此处查看MVC音乐商店示例:
动态视图模型怎么样?MVC3中的布局使用它们,也许您可以使用类似的东西:
我为这个问题设计了一个可能的解决方案,因为它看起来像一个有趣的问题。我希望它对你有用
模型
首先是模型。我决定创建两个“小部件”,一个用于新闻,一个用于时钟
public class NewsModel
{
public string[] Headlines { get; set; }
public NewsModel(params string[] headlines)
{
Headlines = headlines;
}
}
public class ClockModel
{
public DateTime Now { get; set; }
public ClockModel(DateTime now)
{
Now = now;
}
}
控制器
我的控制器对视图一无所知。它所做的是返回单个模型,但该模型能够根据视图的需要动态获取正确的模型
public ActionResult Show(string widgetName)
{
var selector = new ModelSelector();
selector.WhenRendering<ClockModel>(() => new ClockModel(DateTime.Now));
selector.WhenRendering<NewsModel>(() => new NewsModel("Headline 1", "Headline 2", "Headline 3"));
return PartialView(widgetName, selector);
}
通过将其放入Global.asax.cs中来注册视图引擎:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new ModelSelectorEnabledRazorViewEngine());
翻译
“我的主视图”包括以下几行内容来全面测试它:
@Html.Action("Show", "Widget", new { widgetName = "Clock" })
@Html.Action("Show", "Widget", new { widgetName = "News" })
我在博客上写的就是这样做的。请看
基本上,我构建了一个类似的小部件系统。文章还介绍了如何处理这些小部件的配置。这利用了Mvc3中的动态支持,因此任何模型对象都可以从单个控制器操作传递到视图
默认情况下,所有小部件都有一个KVP属性集合(我相信这就是OP所拥有的)。因此,对于一个简单的小部件,我们可以从视图中访问这些属性。我使用了一个小部件来显示一些html(html存储在其中一个属性中)
然而,对于更复杂的小部件,我们实现了IWidgetWithDisplayModel
。这告诉我们,在将加载的小部件传递回视图之前,我们需要“构建”显示模型
下面是控制器的操作,它可以做到这一点。查看帖子的详细信息
[HttpGet]
public ActionResult Get(string name)
{
var widget = widgetService.GetWidgetBySystemName(name, true);
if (widget == null)
return Content(string.Format("Widget [{0}] not found!", name));
if (!this.ViewExists(widget.WidgetName))
return Content(string.Format("A template for widget [{0}] was not found.", widget.WidgetName));
if (widget is IWidgetWithDisplayModel) {
(widget as IWidgetWithDisplayModel).CreateDisplayModel();
}
return PartialView(widget.WidgetName, widget);
}
我正在研究这一点,尽管我不确定它是否完全适用于我的场景。我的设计目前是针对不同的小部件的数据库驱动。这意味着对于任何特定的小部件,我都没有单独的控制器。有很多小部件甚至不需要局部视图,只需要存储在服务器端的HTML。它还使用JSON返回呈现的HTML,这是异步方面所需要的。我会继续检查它,看看是否有什么可以帮助的。谢谢。我理解,并且不认为直接的应用程序会起作用,但我认为底层机制(尤其是RenderPartial的修改)可能会为其他想法埋下种子。因此,如果我理解正确,您有一个来自客户端的javascript类型调用,该调用假定它将从控制器接收HTML。控制器直接从数据库或部分视图检索html。在这两种情况下,控制器都通过JSON返回纯html。当您专门处理需要模型的局部视图,而不知道要使用哪个模型时,会遇到麻烦,对吗?对。现在我有一个全局的“widget”模型,它有一些ID和一个适用于任何模型的偏好字典(并且是从数据库构建的)。这很好,而且非常灵活,当我引入希望直接访问数据库的小部件时,问题就出现了。我最终不得不为每个小部件创建一个新模型,本质上是一个case语句,用于确定小部件需要传递给它的模型(基于小部件的数据库定义)。我的想法是有一些方法来确定小部件的模型,然后为每个模型编写通用代码
@model MvcApplication2.Models.NewsModel
<h2>News Widget</h2>
@foreach (var headline in Model.Headlines)
{
<h3>@headline</h3>
}
public class ModelSelectorEnabledRazorViewEngine : RazorViewEngine
{
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var result = base.CreateView(controllerContext, viewPath, masterPath);
if (result == null)
return null;
return new CustomRazorView((RazorView) result);
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
var result = base.CreatePartialView(controllerContext, partialPath);
if (result == null)
return null;
return new CustomRazorView((RazorView)result);
}
public class CustomRazorView : IView
{
private readonly RazorView view;
public CustomRazorView(RazorView view)
{
this.view = view;
}
public void Render(ViewContext viewContext, TextWriter writer)
{
var modelSelector = viewContext.ViewData.Model as ModelSelector;
if (modelSelector == null)
{
// This is not a widget, so fall back to stock-standard MVC/Razor rendering
view.Render(viewContext, writer);
return;
}
// We need to work out what @model is on the view, so that we can pass the correct model to it.
// We can do this by using reflection over the compiled views, since Razor views implement a
// ViewPage<T>, where T is the @model value.
var compiledViewType = BuildManager.GetCompiledType(view.ViewPath);
var baseType = compiledViewType.BaseType;
if (baseType == null || !baseType.IsGenericType)
{
throw new Exception(string.Format("When the view '{0}' was compiled, the resulting type was '{1}', with base type '{2}'. I expected a base type with a single generic argument; I don't know how to handle this type.", view.ViewPath, compiledViewType, baseType));
}
// This will be the value of @model
var modelType = baseType.GetGenericArguments()[0];
if (modelType == typeof(object))
{
// When no @model is set, the result is a ViewPage<object>
throw new Exception(string.Format("The view '{0}' needs to include the @model directive to specify the model type. Did you forget to include an @model line?", view.ViewPath));
}
var model = modelSelector.GetModel(modelType);
// Switch the current model from the ModelSelector to the value of @model
viewContext.ViewData.Model = model;
view.Render(viewContext, writer);
}
}
}
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new ModelSelectorEnabledRazorViewEngine());
@Html.Action("Show", "Widget", new { widgetName = "Clock" })
@Html.Action("Show", "Widget", new { widgetName = "News" })
[HttpGet]
public ActionResult Get(string name)
{
var widget = widgetService.GetWidgetBySystemName(name, true);
if (widget == null)
return Content(string.Format("Widget [{0}] not found!", name));
if (!this.ViewExists(widget.WidgetName))
return Content(string.Format("A template for widget [{0}] was not found.", widget.WidgetName));
if (widget is IWidgetWithDisplayModel) {
(widget as IWidgetWithDisplayModel).CreateDisplayModel();
}
return PartialView(widget.WidgetName, widget);
}