第一种方法,我们知道,在ASP.NET MVC中,要从一个Action跳转到另一个Action,通常是用一系列以“Redirect”开头的方法
- Redirect
- RedirectToAction
- RedirectToRoute
之类的。
但是使用Redirect系列的方法进行跳转时,默认是使用GET方法的,也就是说,如果你的跳转请求带有参数,那么这些参数将全部暴露在跳转后的url中,增加了不安全性(特别是如果参数中包含密码、密钥等等敏感数据)
于是就想到了用POST方法传递数据,这样至少一般的访问者无法从url中获取敏感信息。但是仔细查阅了MSDN和StackOverflow,得到的答案是“Redirect方法不支持POST”。
好在StackOverflow上找到一个回答 点我 ,倒是给我一些启发。直接POST不行,那就间接POST,先通过一个GET方法获取某个页面,然后以这个页面为中介将数据POST给真正要处理请求的页面。
下面给出一个示例代码。在这个示例代码中,有两个页面Login和AfterLogin,要求在Login中输入用户名和密码后跳转到AfterLogin,并携带一个由UserAppModel定义的数据列表
public class UserAppModel { public string UserId { get; set; } public string ClientId { get; set; } public string RedirectUri { get; set; } }
这些信息将在使用GET方法加载Login页面时获取。
public ActionResult Login(string client_id, string redirect_uri) { HttpCookie cookie = new HttpCookie("app"); cookie["client_id"] = client_id; cookie["redirect_uri"] = redirect_uri; Response.Cookies.Add(cookie); return View(); }
界面设计就省略了,无非是两个文本框和一个submit按钮。
之后对Login要有个HttpPost方法来接收登录数据,并构造UserAppModel的数据发到新的AfterLogin页面。
[HttpPost] public ActionResult Login(UserModel model) { if (ModelState.IsValid) { HttpCookie cookie = Request.Cookies["app"]; if (cookie != null) { if (model.UserId == "AAA" && model.Password == "aaa") { UserAppModel newModel = new UserAppModel(); newModel.UserId = model.UserId; newModel.ClientId = cookie["client_id"]; newModel.RedirectUri = cookie["redirect_uri"]; TempData["model"] = newModel; return RedirectToAction("AfterLogin", "Home"); } ViewBag.Message = "Login error! Invalid user ID or password."; } } return View(); }
AfterLogin需要两个方法,一个采用GET方式,一个采用POST方式,通过GET方式的页面去调用POST方式的页面,就实现了使用POST的重定向
// // POST: /Home/AfterLogin [AcceptVerbs(HttpVerbs.Post)] public ActionResult AfterLogin(UserAppModel model) { ViewData["model"] = model; return View(model); } [AcceptVerbs(HttpVerbs.Get)] public ActionResult AfterLogin() { return AfterLogin(TempData["model"] as UserAppModel); }
结论:Redirect系列方法不支持POST,但是可以通过间接的做法实现POST方式的重定向。
第二种方法:
当我们在使用ASP.NET MVC实现页面跳转的时候,常用的应该是:
① Redirect
② RedirectToAction
③RedirectToRoute
④或者在前台使用脚本跳转。
但这几种跳转方式都是基于Get请求的,在某些特定场景下可能并不适用。例如需要传递大数据量参数、或者复杂对象类型参数的场景,get方式肯定是有限制的。在webform里面,有一种服务器端跳转方式:Server.Transfer,相信大家一定都还记得。这种方式是中止当前页面执行,并将执行流程转入一个新的页面,并使用上一个页面创建的应答流。 这种方式具有如下的特点:
①地址栏URL不会发生变化。
②上一个页面后台产生的参数和对象可以直接传递到新的页面。
③减少客户端对服务器的请求。
我们知道,ASP.NET MVC有一个核心思想,就是“约定胜于配置” ,例如在执行完一个action后,会到view目录下根据controller名称查找对应的view来进行渲染,但是 约定的做法并不意味着不能改变。
对于ASP.NET MVC而言,可以通过动态改变当前Action所渲染的view路径,来实现类似的效果。
渲染非常规路径的View
先实现一个自定义的ViewEngine:
{
public ChangeViewEngine( string controllerPathName, string viewName)
{
this.ViewLocationFormats = new [] { " ~/Views/ " + controllerPathName + " / " + viewName + " .cshtml " };
}
}
再实现一个ActionAttribute
{
private string _controllerPath; private string _viewName;
public ChangeViewPathAttribute( string controllerPath, string viewName)
{
this._controllerPath = controllerPath;
this._viewName = viewName;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
// base.OnResultExecuting(filterContext);
// ViewEngines.Engines.Clear();
ViewEngines.Engines.Add( new ChangeViewEngine(_controllerPath,_viewName));
}
}
在该段代码里面,ChangeViewPathAttribute类继承于ActionFilter,并重写其中的OnResultExecuting方法,将自定义的ViewEngine加入到全局ViewEngine集合里面来。
最后,在需要渲染不同路径的action加上Attribute
[ Filter .ChangeViewPath( " Invoice " , " Create " )]
public ActionResult PreInvoice( string strIds,bool flag)
在做完以上步骤后,我们就可以随意指定action所要渲染的view,在服务器端进行跳转,实现类似Server.Transfer的效果。 当然,以上只是一个简单的示例,你完全可以做的更优雅一点,实现更灵活的路径配置:)