Razor 无论站点的入口点是什么,都希望用列表初始化每个视图

Razor 无论站点的入口点是什么,都希望用列表初始化每个视图,razor,asp.net-mvc-4,shopping-cart,Razor,Asp.net Mvc 4,Shopping Cart,我有一个购物篮,它容纳用户选择的项目,并存储在会话变量中。我希望它能在关于basket状态的每个视图上显示不同的值,即basket:1,但我只能看到如何在单个入口点将其传递给视图。如何使用此列表初始化每个视图?您可以在布局中渲染。子操作的概念是,它可以与主操作并行执行某些逻辑 例如,您可以使用以下控制器: public class ShoppingBasketInfoController: Controller { [ChildActionOnly] public ActionR

我有一个购物篮,它容纳用户选择的项目,并存储在会话变量中。我希望它能在关于basket状态的每个视图上显示不同的值,即basket:1,但我只能看到如何在单个入口点将其传递给视图。如何使用此列表初始化每个视图?

您可以在布局中渲染。子操作的概念是,它可以与主操作并行执行某些逻辑

例如,您可以使用以下控制器:

public class ShoppingBasketInfoController: Controller
{
    [ChildActionOnly]
    public ActionResult Index()
    {
        var model = Session["info"] as ShoppingInfoViewModel;
        return PartialView(model);
    }
}
然后您将有一个相应的局部视图(
~/Views/ShoppingBasketInfo/Index.cshtml
):

现在,所有视图都将在指定位置显示此信息,而不必担心此信息来自何处、如何存储或使用何种视图模型。主要动作是完全独立的


我已经用
[ChildActionOnly]
属性修饰了子操作,以确保此操作永远不会通过客户端的正常HTTP请求访问,例如使用
/ShoppingBasketInfo/Index
。它只能在主执行操作的上下文中使用。

您的最佳选择可能是基本控制器、基本视图模型、接口和操作过滤器的组合

// Interface.  To be implemented by model and controller.
public interface IHoldABasket 
{
    Basket Basket { get; set; };
}

// Base view model.  Has a basket as public property.
public BaseBasketViewModel : IHoldABasket 
{
      public Basket Basket { get; set; }
}

// Base controller model.  Also has a basket.
public BaseController : Controller, IHoldABasket 
{
   public Basket Basket { get; set; }

   public BaseController() 
   {
       AttemptBasketLoad();
   }

   private void AttemptBasketLoad()
   {
       // Replace the SomeMethodToLoadBasket with whatever method you use
       // to retrieve a basket.
       Basket = SomeMethodToLoadBasket();
   }
}

// Action Filter
public class BasketAwareAttribute : ActionFilterAttribute 
{
   public override void OnActionExecuted(ActionExecutedContext filterContext)
   {
        // If controller can hold basket AND model can hold basket
        if (filterContext.Controller is IHoldABasket 
            && filterContext.Controller.ViewData.Model is IHoldABasket)
        {
            // Copy basket from controller into model.
            // Will now be accessible through Basket property on model.
            ((IHoldABasket)filterContext.Controller.ViewData.Model)
               .LoggedInUser
                = ((IHoldABasket)filterContext.Controller).LoggedInUser;

        }

        base.OnActionExecuted(filterContext);
   }
}
这就是基础设施的分类。让我们看一个实际的例子。您可能有一个ProductListViewModel。应该从基本视图模型类继承的

首先,确保ProductListViewModel继承自BaseBasketViewModel

public class ProductListViewModel : BaseBasketViewModel 
{
}
由于继承,视图模型包含一个basket对象并实现IHoldABasket接口

您的控制器将从BaseController继承

public class ProductController : BaseController 
{

}
控制器方法如下所示

[BasketAware]
public ViewResult Products(int page = 1) 
{
   // Load VM that implements IHoldABasket
   // Really contrived, I know... :P

   var vm = new ProductListViewModel() { Results = productServices.Search() };

   return View(vm);
}
应该是这样。引擎盖下发生的事情是

  • 基本控制器尝试加载一个篮子,如果找到,则将其存储
  • 控制器和模型继承了一个公共接口,使得从控制器到模型的自动复制更容易实现
  • 动作过滤器在最后一分钟加载。如果控制器和模型都可以容纳一个篮子(例如,两个机具
    IHoldABasket
    ),则篮子将从控制器复制到模型
  • 所有从BaseBasketViewModel派生的视图模型都将有一个名为Basket的公共属性

我最终决定走另一条路,但你的答案似乎简单易行。
public class ProductController : BaseController 
{

}
[BasketAware]
public ViewResult Products(int page = 1) 
{
   // Load VM that implements IHoldABasket
   // Really contrived, I know... :P

   var vm = new ProductListViewModel() { Results = productServices.Search() };

   return View(vm);
}