ASP.NET MVC Clean从操作中注入部分视图的方法

时间:2016-02-06 22:10:30

标签: asp.net-mvc asp.net-mvc-4

我有一个包含许多小部件的应用,其内容取决于请求特定路由的用户。简单地说:如果请求小部件操作,则必须呈现其内容,否则它是空的。考虑这样的路线/行动:

  • 〜/ MyApp / Index - >没有模特;应用HTML,没有任何小部件
  • 〜/ MyApp / Foo / {id} - >使用FooModel;如果ModelState有效,则返回 索引HTML,将Foo的小部件的部分视图注入div#foo; 否则重定向到索引。
  • 〜/ MyApp / Bar / {id} - >与Foo相同,但不同的模型和小部件

我的foo动作:

public ActionResult Foo(string id) {
    if (ModelState.IsValid) {
        var response = FooService.GetData(id);
        // Inject Foo widget to Index
    }
    return RedirectToAction("Index");
}

我知道可以使用ViewBag或其他方法发送变量并使用条件来决定是否渲染部分视图。但是......应该有更好的方法来做到这一点,对吗?

2 个答案:

答案 0 :(得分:3)

当我想用非平凡的绑定逻辑(调用数据库,组合复杂对象等)构建共享视图时,我使用MVC的Html.RenderActionResult。每个窗口小部件的绑定逻辑包含在PartialViewResult方法中,该方法使用Html.RenderAction()从* .cshtml文件调用。

<强> ContentController:

    public ActionResult Index(int id)
    {
        var indexViewModel = new IndexViewModel
        {
            Id = id,
            Title = "My Title",
            SubHeader = "Wow its 2016"
        };

        return View(indexViewModel);
    }

    public PartialViewResult PopularContent(int id)
    {
        var popularContentViewModel = new List<PopularContentViewModel>();
        // query by id to get popular content items

        return PartialView("_PopularContent", popularContentViewModel);
    }

    public PartialViewResult Widget2(int id)
    {
        return PartialView("_Widget2Partial");
    }

<强> Index.cshtml:

@model StackOverflow.RenderAction.ViewModels.IndexViewModel

<h1>@Model.Title</h1>
<h2>@Model.SubHeader</h2>
--RenderAction will call out to the specified route.
--Note the use of the Id parameter from the viewmodel.
@{Html.RenderAction("PopularContent", "Content", new {Model.Id});}

答案 1 :(得分:0)

ASP.NET MVC属性路由可以是一个很好的解决方案:

在您的控制器中:

public class WidgetController : Controller
{
     [Route("myapp/foowidget", Name = "FooWidget")]
     public ActionResult FooWidget()
     {
          //create any model and return any view or partial or redirect
     }

     [Route("myapp/boowidget/{id:int}", Name = "BooWidget")]
     public ActionResult BooWidget(int id)
     {
          //create any model and return any view or partial or redirect
     }
}

然后在视图中,您可以按名称调用路径:

@Url.RouteUrl("FooWidget")

@Url.RouteUrl("BooWidget")

@Html.RenderPartial("FooWidget")
如果url是/ myapp / something / id,

@Url.RouteUrl("BooWidget")将呈现或连接当前url中的id,因为你的Route属性定义:&#34; myapp / boowidget / {id:int} &#34 ;.事实上,@Url.RouteUrl("BooWidget")可能会从格式/ controllerName / action / id的任何当前url中提取id,但您必须进行测试。

并注意如何将您的WidgetController和您的url分开关注点路由不以任何方式依赖于该控制器的名称。这是属性路由的一个很好的功能,您可以声明自定义路由以及组织控制器,并从控制名称的名称约定依赖性中断,该控件名称是用户在浏览器中看到的url controllerName / action的一部分。

关于Html.RenderPartial ,我不确定RenderPartial&#34;是否连接&#34;或者将能够像#34; FooWidget&#34;一样路由到您的RouteName。如果它确实很棒。

如果不是你的解决方案:

public class WidgetController : Controller
{
     public ActionResult FooWidget()
     {
          //model, you choose, return a partial
     }

     public ActionResult RedirectUser()
     {
          //do a redirect
     }

     public ActionResult BooWidget()
     {
          //any model, any partial
     }

     public ActionResult BooWidget(int id)
     {
          //any model, any partial
     }
}

控制器中的每个方法都是单一目的,具有独特的签名并且做一件事,没有条件可以传入,也没有必要的决定。