C# MVC-向视图传递附加信息

C# MVC-向视图传递附加信息,c#,asp.net-mvc,asp.net-mvc-2,C#,Asp.net Mvc,Asp.net Mvc 2,我正在使用Asp.NETMVC框架开发一个网站。我们需要跨多个页面添加一般用户信息,方法与堆栈顶部的信誉栏类似 我认为重要的是,在创建控制器方法时不应该添加任何开销,以便将额外的信息添加到视图中。这排除了在ViewData对象中传递此信息的选项,或修改ViewModels以接受信誉字段的选项,因为这将导致每个控制器的外观如下所示: public ActionResult Index() { ViewData["reputationScore"] = GetUsersReputation(

我正在使用Asp.NETMVC框架开发一个网站。我们需要跨多个页面添加一般用户信息,方法与堆栈顶部的信誉栏类似

我认为重要的是,在创建控制器方法时不应该添加任何开销,以便将额外的信息添加到视图中。这排除了在ViewData对象中传递此信息的选项,或修改ViewModels以接受信誉字段的选项,因为这将导致每个控制器的外观如下所示:

public ActionResult Index()
{
    ViewData["reputationScore"] = GetUsersReputation(userId);

    // main controller logic here
}
如果一个站点上90%的页面都使用了这种方法,那么如果我们还想显示用户的徽章数量,那么修改它可能会非常耗时

我可以想出4种解决方案

使用母版页 在母版页代码中检索用户信誉,并在母版页标记中标记信誉

缺点:

  • 这似乎正在远离MVC所代表的一切
  • 我一直在考虑使用替代视图引擎(如razor),我不确定这些引擎的混合效果如何
  • 它倾向于限制版面的布局——很难把它放在页面的中间。 扩展HtmlHelper以添加GetUsers计算方法 这似乎有点违背了Html对象的用途——它不仅仅是渲染输出,而是访问数据库。除了违反隐喻之外,我想不出还有什么其他重要的问题

    覆盖System.Web.Mvc.ViewPage 重写Viewpage以公开Html之外的对象,该对象可用于调用访问数据库的方法选择。确保扩展方法可以以与HtmlHelper相同的方式添加,以便在需要新方法时可以适当扩展。这可以让我们写下如下内容:

    <% DataAccess.GetUsersReputation() %>
    
    
    
    创建基本通用视图模型 与其将视图模型直接传递给视图,不如将其包装在可以容纳所有所需方法的基础视图模型中:

    public ActionResult Index()
    {
        MyViewModel viewCoreInfo = model.GetData();
    
        return View(new BaseViewModel<MyViewModel>(viewCoreInfo));
    }
    
    public ActionResult Index()
    {
    MyViewModel viewCoreInfo=model.GetData();
    返回视图(新的BaseViewModel(viewCoreInfo));
    }
    
    BaseViewModel可以公开网页上需要的额外信息所需的所有属性。e、 g.用户计算(它可以在构造函数中查询数据库,也可以在访问属性时加载数据)。我认为这更好地保持了MVC的比喻,但有点麻烦

  • 是否有其他人提出了更好的解决方案
  • 哪一个是最好的-如果您使用过它们,它们是否有效/有问题?

  • 我已经完成了这项工作,并创建了一个基本模型类,其中包含所有共同的信息。我的所有其他viewmodel类都继承自此类。但是您必须在每个控制器中填充这些信息。这就是我选择的解决方案。

    为什么不让
    MyViewModel
    继承
    BaseViewModel

    您可以使用
    BaseController.OnResultExecuting
    填充公共值:

    protected override void OnResultExecuting(ResultExecutingContext ctx) {
        base.OnResultExecuting(ctx);
        var baseView = ctx.Result as BaseViewModel;
        if (baseView != null)
        {
            //assign values here
        }
    }
    

    既然您提到了使用razor视图引擎的可能性,我想ScottGu的博客文章可能会引起兴趣

    他讨论了如何在razor中使用“sections”,这将允许您在布局(“母版页”)上创建一个可以加载附加内容的部分。以这种方式创建SO样式信息栏将是干净而简单的

    编辑:

    至于根据下面的评论呈现局部视图…新的有一些例子

    在本例中,他们使用的是Html.RenderAction。Html.RenderPartial是另一个选项。 在这一点上,差异是显而易见的,但我确信网络上还有其他资源

    控制器只会返回部分视图,如下所示:

     return PartialView();
    

    您可以使用代码隐藏文件创建局部视图,并在其中使用数据填充局部视图。这是一种有点非mvc的方式,但它会起作用。

    您可以创建操作筛选器,覆盖OnResultExecuting,填充公共值并将其添加到操作/控制器:

    public class AddCommonData : ActionFilterAttribute 
    {
      public override void OnResultExecuting(ResultExecutingContext filterContext)
      {
        ViewResult viewResult = filterContext.Result as ViewResult;
        if (viewResult != null)
        {
          //...
        } 
      }
    }
    

    节与Webforms引擎中的内容占位符一样。这并不能真正解决OP的问题。OP想知道如何从控制器传输视图/分区/任何内容中的信息。谢谢您的回答。我认为这仍然存在同样的问题,尽管razor允许您使用母版页创建标记,但通常认为在视图(而不是显示逻辑)中编写代码是不好的做法。它当然不是放置数据访问方法的地方——这实际上是模型/控制器的责任。但是,为了防止重复,我希望避免在每个控制器中调用声誉方法。@Giles我明白你的意思。如果该部分呈现一个partialview,调用自己的控制器/操作或类似的东西,会怎么样?@Stephen776如果可能的话,这听起来是一个不错的解决方案。可以从局部视图中调用控制器吗?你在任何地方见过这样的例子吗?@Giles是的,我相信它就像Html.RenderPartial(“动作”、“控制器”、“其他参数(可选)”)一样简单。我知道我的开发机器上有一个这样的示例。当我找到答案时,我可以贴一个例子。我喜欢重写OnResultExecuting方法的想法。我担心的是让MyViewModel继承BaseViewModel,然后在这两个类之间引入耦合。如果您后来决定需要另一组页面来显示好友数,但您仍然使用MyViewModel作为主要数据,则需要允许BaseViewModel同时实现好友和信誉方法。与我的解决方案一样,您只需更改FriendDataBaseVie的BaseViewModel