如何避免在MVC4中使用ViewBag在控制器和视图之间传递查询值

时间:2013-03-17 23:03:48

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

我已经读过它generally a bad practice to use ViewBags并且混合ViewBag和ViewModel也不好,但是我使用一些ViewBags在我的控制器和视图之间传递sort order参数,虽然我可以创建属性在视图ViewModel上我需要的值才能在第一时间创建模型,所以无法看到如何解决这个问题。

控制器

public ActionResult Index(string sortOrder, string searchString, 
                          string currentFilter, int? page, 
                          bool? includeComplete)
{

 ViewBag.CurrentSort = sortOrder;
 ViewBag.NameSortParam = string.IsNullOrWhiteSpace(sortOrder) ? "Name desc" : "";
 ViewBag.DateSortParam = sortOrder == "Date" ? "Date desc" : "Date";

 if (Request.HttpMethod == "GET")
     searchString = currentFilter;
 else
     page = 1;

 ViewBag.CurrentFilter = searchString;
 bool showCompleted = (includeComplete == null || includeComplete == false)
                        ? false : true;
 ViewBag.IncludeCompleted = showCompleted;

 int pageNumber = (page ?? 1);

 var query = Session.QueryOver<ToDo>();

 if (!string.IsNullOrWhiteSpace(searchString))
     query = query.WhereRestrictionOn(td => td.TaskName)
                      .IsInsensitiveLike(string.Format("%{0}%", searchString));

 if (!showCompleted)
     query.And(td => td.IsComplete == false);

 switch (sortOrder)
 {
    case "Name desc":
      query = query.OrderBy(td => td.TaskName).Desc;
      break;
        case "Date":
      query = query.OrderBy(td => td.DueDate).Asc;
      break;
    case "Date desc":
      query = query.OrderBy(td => td.DueDate).Desc;
      break;
    default:
      query = query.OrderBy(td => td.TaskName).Asc;
      break;
 }

 var result = query.Fetch(p=>p.Priority).Eager
           .Fetch(s=>s.Staff).Eager
           .List();

 var viewModel = AutoMapper.Mapper.Map<IEnumerable<ToDo>, 
                     IEnumerable<IndexToDoViewModel>>(result)
                     .ToPagedList(pageNumber, PageSize);
 return View(viewModel);

}

然后在我的视图中,我将使用ViewBag将值传递回控制器,例如我需要的sortOrder,然后才能将其应用到构成我的NHibernate查询中大部分方法,例如:

@Html.ActionLink("Name", "Index", new {sortOrder=ViewBag.NameSortParam, 
                                      includeComplete = ViewBag.IncludeCompleted})

我的ViewModel

public class IndexToDoViewModel
{
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd MMM yyyy}")]
    [DisplayName("Date Due")]
    public DateTime? DueDate { get; set; }

    public Guid Id { get; set; }

    [DisplayName("Is Complete")]
    public bool IsComplete { get; set; }

    [DataType(DataType.MultilineText)]
    public String Notes { get; set; }

    public string Priority { get; set; }

    public string Staff {get; set;}

    [DisplayName("Name")]
    public String TaskName { get; set; }

    // These would potentially replace my ViewBag?
    public string CurrentSort { get; set; }
    public string CurrentFilter { get; set; }
    public string NameSortParam { get; set; }
    public string DateSortParam { get; set; }
    public bool IncludeCompleted { get; set; }

}

2 个答案:

答案 0 :(得分:3)

  

然后在我看来,我将使用ViewBag将值传递回   控制器

不,您将值传递给下一个控制器。当浏览器的新实例将处理请求时,(可能)在浏览器往返之后使用这些值。

由于您没有将任何内容传递回当前的控制器,因此无需使用ViewBag。如果您愿意,可以将值放在模型中。


即使您将视图中的数据发送到控制器(这是非常不寻常的),使用该模型仍然可以实现。例如:

MyModel viewModel = new MyModel();
ActionResult result = View(viewModel);

// here you can access anything that the view would put in the model

return result;

当然,您不能使用控制器视图中的任何值来创建模型,因为您必须在视图之前创建模型。如果您需要视图中的任何数据来获取数据,您可以将其作为方法放在模型中而不是控制器中。

答案 1 :(得分:1)

我建议为您创建的每个视图创建一个ViewModel,因为您可能需要将更多信息传递给视图。

在这种情况下,您将拥有一个ViewModel,它具有分页列表数据的属性,您可以为SortOrder添加另一个属性。

例如:

public class MyViewModel
{
    public IEnumerable<ToDo> TodoList { get; set; }
    public string SortOrder { get; set; }
}

请参阅问题:ViewModel Best Practices