在下面的
RedirectToAction
中,我想传递一个viewmodel
。如何将模型传递给重定向?
我设置了一个断点来检查模型的值,以验证模型是否正确创建。这是正确的,但生成的视图不包含模型属性中找到的值。
//
// model created up here...
//
return RedirectToAction("actionName", "controllerName", model);
ASP.NET MVC 4 RC
RedirectToAction
向客户端浏览器返回 302 响应,因此浏览器将向浏览器响应的位置标头值中的 url 发出新的 GET 请求。
如果您尝试将简单的精益扁平视图模型传递给第二个操作方法,您可以使用 RedirectToAction
方法的
this 重载。
protected internal RedirectToRouteResult RedirectToAction(
string actionName,
string controllerName,
object routeValues
)
RedirectToAction
会将传递的对象(routeValues)转换为查询字符串,并将其附加到 url(根据我们传递的前 2 个参数生成),并将生成的 url 嵌入到响应的 location 标头中。
假设你的视图模型是这样的
public class StoreVm
{
public int StoreId { get; set; }
public string Name { get; set; }
public string Code { set; get; }
}
在第一个操作方法中,您可以将 this 的对象传递给
RedirectToAction
方法,如下所示
var m = new Store { StoreId =101, Name = "Kroger", Code = "KRO"};
return RedirectToAction("Details","Store", m);
此代码将向浏览器发送 302 响应,其位置标头值为
Store/Details?StoreId=101&Name=Kroger&Code=KRO
假设您的
Details
操作方法的参数为 StoreVm
类型,查询字符串参数值将正确映射到参数的属性。
public ActionResult Details(StoreVm model)
{
// model.Name & model.Id will have values mapped from the request querystring
// to do : Return something.
}
以上内容适用于传递小型扁平视图模型。但如果你想传递一个复杂的对象,你应该尝试遵循 PRG 模式。
PRG 代表POST - REDIRECT - GET。通过这种方法,您将在查询字符串中发出带有唯一 id 的重定向响应,使用第二个 GET 操作方法可以再次查询资源并将某些内容返回到视图。
int newStoreId=101;
return RedirectToAction("Details", "Store", new { storeId=newStoreId} );
这将创建网址
Store/Details?storeId=101
在您的详细信息 GET
操作中,使用传入的 storeId,您将从某处(从服务或查询数据库等)获取/构建 StoreVm
对象
public ActionResult Details(string storeId)
{
// from the storeId value, get the entity/object/resource
var store = yourRepo.GetStore(storeId);
if(store!=null)
{
// Map the the view model
var storeVm = new StoreVm { Id=storeId, Name=store.Name,Code=store.Code};
return View(storeVm);
}
return View("StoreNotFound"); // view to render when we get invalid store id
}
遵循 PRG 模式 是处理此用例的更好解决方案。但如果您不想这样做并且确实想通过 Stateless HTTP 请求传递一些复杂的数据,您可以使用一些临时存储机制,例如
TempData
TempData["NewCustomer"] = model;
return RedirectToAction("Index", "Users");
并再次在您的
GET
操作方法中阅读它。
public ActionResult Index()
{
var model=TempData["NewCustomer"] as Customer
return View(model);
}
TempData
使用场景背后的 Session
对象来存储数据。但一旦读取数据,数据就会终止。
Rachel 写了一篇不错的博客 post 解释了何时使用 TempData /ViewData。值得一读。
在 Asp.Net core 中,不能在 TempData 中传递复杂类型。您可以传递简单类型,如
string
、int
、Guid
等。
如果您绝对想通过 TempData 传递复杂类型对象,您有 2 个选择。
1)将对象序列化为字符串并传递。
这是一个使用 Json.NET 将对象序列化为字符串的示例
var s = Newtonsoft.Json.JsonConvert.SerializeObject(createUserVm);
TempData["newuser"] = s;
return RedirectToAction("Index", "Users");
现在在您的
Index
操作方法中,从 TempData 读取此值并将其反序列化到您的 CreateUserViewModel
类对象。
public IActionResult Index()
{
if (TempData["newuser"] is string s)
{
var newUser = JsonConvert.DeserializeObject<CreateUserViewModel>(s);
// use newUser object now as needed
}
// to do : return something
}
2) 将简单类型的字典设置为 TempData
var d = new Dictionary<string, string>
{
["FullName"] = rvm.FullName,
["Email"] = rvm.Email;
};
TempData["MyModelDict"] = d;
return RedirectToAction("Index", "Users");
稍后阅读
public IActionResult Index()
{
if (TempData["MyModelDict"] is Dictionary<string,string> dict)
{
var name = dict["Name"];
var email = dict["Email"];
}
// to do : return something
}
另一种方法是将其存储在会话中。
var s = JsonConvert.SerializeObject(myView);
HttpContext.Session.SetString("myView", s);
并把它拿回来
string s = HttpContext.Session.GetString("myView");
myView = JsonConvert.DeserializeObject<MyView>(s);
您也可以像执行任何方法一样直接调用操作,而不是重定向
return actionName(model);
但是,如果你这样做,那么在actionName方法中,不要返回像这样的简单视图
return View(model);
但是
return View("actionName", model);
您需要指定要使用哪个视图。否则,调用方法的视图将被调用。
如果您关心从不同的控制器调用,那么您可以首先实例化 [new nameController().actionName(model)]