将数据传递到ASP.NET MVC中的母版页


Answers:


77

如果您希望视图具有强类型的视图数据类,则这可能对您有用。其他解决方案可能更正确,但这是设计和实用性恕我直言之间的良好平衡。

母版页采用强类型的视图数据类,该类仅包含与之相关的信息:

public class MasterViewData
{
    public ICollection<string> Navigation { get; set; }
}

使用该母版页的每个视图均采用强类型化的视图数据类,该类包含其信息并从母版页视图数据派生:

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
}

由于我不希望各个控制器了解将母版页数据放在一起的任何信息,因此将该逻辑封装到一个传递给每个控制器的工厂中:

public interface IViewDataFactory
{
    T Create<T>()
        where T : MasterViewData, new()
}

public class ProductController : Controller
{
    public ProductController(IViewDataFactory viewDataFactory)
    ...

    public ActionResult Index()
    {
        var viewData = viewDataFactory.Create<ProductViewData>();

        viewData.Name = "My product";
        viewData.Price = 9.95;

        return View("Index", viewData);
    }
}

继承与主视图之间的匹配关系很好,但是在渲染部分/用户控件时,我会将其视图数据组合到页面视图数据中,例如

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
    public SubViewData SubViewData { get; set; }
}

<% Html.RenderPartial("Sub", Model.SubViewData); %>

这只是示例代码,无意按原样编译。专为ASP.Net MVC 1.0设计。


4
这是Scott Gutherie推荐的方法,所以我必须同意。
西蒙·福克斯

@Simon Fox-是否有指向scottgu推荐的链接?找不到。
orip


抱歉。在理解这部分内容时遇到一些麻烦。控制器的构造函数会传递IViewDataFactory的实例,但系统需要无参数的构造函数。我也不熟悉该接口的C#语法(特别是“ MasterViewData,new()”)。有人可以解释一下还是给我指出一个好的资源。谢谢。
杰森

5
我喜欢使用强类型的模型,但是我不喜欢将主数据与所有其他模型和操作耦合在一起。跳到这个线程有点晚,但是我发布了我的主数据方法,使事情变得更加松散。
托德·梅尼尔

59

我更喜欢将主视图的数据驱动部分分解为多个部分,并使用Html.RenderAction进行渲染。与流行的视图模型继承方法相比,这具有几个明显的优点:

  1. 主视图数据与“常规”视图模型完全分离。这是继承而不是继承,导致了耦合更松散的系统,更易于更改。
  2. 主视图模型是通过完全独立的控制器操作建立的。“常规”操作无需为此担心,也不需要视图数据工厂,这对我来说似乎过于复杂。
  3. 如果您碰巧使用了AutoMapper之类的工具来将域映射到视图模型,则会发现配置起来更加容易,因为当视图模型不继承主视图数据时,它们将更像域模型。
  4. 使用针对主数据的单独操作方法,您可以轻松地将输出缓存应用于页面的某些区域。通常,主视图包含的数据更改频率少于主页内容。

3
+1。另一个优点是,可以根据当前的运行时状态,使同一视图使用不同的母版页。
StriplingWarrior

1
我非常喜欢这个答案-概述的其他方法似乎有点复杂。
Paddy

2
我认为这是最优雅的解决方案。
autonomatt

1
这个解决方案对我来说也是最好的。太感谢了!
JimDaniel 2011年

1
这是一种好方法,但是请记住,您仍然必须指定“部分操作”的路径。看到这个答案stackoverflow.com/a/3553617/56621
Alex

20

编辑

通用错误在下面提供了更好的答案。请阅读!

原始答案

Microsoft实际上已经发布了处理此问题的“官方”方式的条目。这提供了逐步解释,并解释了其原因。

简而言之,他们建议使用抽象控制器类,但请亲自看看。


谢谢!这个例子正是我正在做的...来自数据库的每个页面上的类别。
马丁

MVC的作者之一Scott Gutherie推荐以下@Generic Error提供的解决方案
Simon Fox

1
+1用于指示最佳答案,即使您的答案是正确的并已被OP接受为答案。
IsmailS 2011年

+1用于指示最佳答案,即使您的答案是正确的并已被OP接受为答案。
Dave Jellison

实际上,托德·梅尼尔(Todd Menier's)是目前最好的答案。
andreialecu 2011年

7

抽象控制器是一个好主意,但我还没有找到更好的方法。我也很想看看别人做了什么。



2

我发现,传递给视图的所有模型对象的共同父对象非常有用。

无论如何,页面之间总会有一些共同的模型属性。


0

Request.Params对象是可变的。在请求处理周期中,向其添加标量值非常容易。从视图的角度来看,该信息可能已在QueryString或FORM POST中提供。hth


0

我认为另一种好方法是为具有某些属性的视图(例如某些接口的ParentView)创建用于视图的接口,因此您可以将其用于需要引用页面的控件(父控件)和应从中访问的主视图。意见。


0

其他解决方案缺乏优雅感,并且花费的时间太长。我为将近整整一年的时间做这件非常悲伤和贫困的事情表示歉意:

<script runat="server" type="text/C#">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        MasterModel = SiteMasterViewData.Get(this.Context);
    }

    protected SiteMasterViewData MasterModel;
</script>

很明显,我在SiteMasterViewData上具有此静态方法Get(),该方法返回SiteMasterViewData。


对于许多人来说,这似乎有些骇人听闻或“肮脏”,但它很快就使工作
轻松

啊。如果您使用过Html.RenderAction(),则您的代码似乎很难维护。
Dan Esparza 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.