Asp.net MVC - 使用PRG模式(附源码)

简介:

阅读目录:

一、 传统的Asp.net页面问题

二、Asp.net MVC中也存在同样的问题

三、使用PRG模式

四、PRG模式在MVC上的实现

 

一. 传统的Asp.net页面问题

一个传统的Asp.net页面的请求会是这样的:
    HTTP GET 请求"Register.aspx"
    HTTP POST 请求 "Register.aspx"(点击按钮等触发服务器端事件)
    数据检验失败, 重新返回到"Register.aspx"
    在HTTP POST到"Register.aspx"
    数据创建成功, 重新返回到"Register.aspx",提示创建成功
 
看看好像没有什么问题呀, 但是如果在标记为红色的这步之后,你在浏览器上点击"刷新"按钮, 就会弹出下面的对话框。


 
这个对话框的意思是, 为了显示你点击"刷新"按钮的页面, 浏览器需要发送你上次提交的数据到服务器端, 之所以会这样的原因是浏览器记录的是上次你的Post请求, 所以你点击"刷新"按钮, 也是重复执行一次Post请求, 而用户其实是想得到初始的页面,也就是GET请求"Register.aspx"页面. 对于大多数不清楚原理的普通用户来说,这样的对话框会让用户会非常困扰.
 
web系统应当是以URL为标记的资源, 一个URL最好代表的一种资源. 当你收藏一个网页,分享一个网页给你朋友的时候, 你用的是网页的URL, 那是因为网页的URL就对应了你想分享的资源.
所以上面方式带来的另外一个问题就是, Get, POST, 以及POST成功后的页面实际上代表了3中不同的资源,但是这三种资源的URL是同一个URL.
 

二. Asp.net MVC中也存在同样的问题

假如我们在完成一个注册页面, Controller中的代码是这样的:
 

复制代码
 //
        // GET: /Home/
        [HttpGet]
        public ActionResult Register()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Register(Models.RegisterModel registerModel)
        {
            return View();
        }
复制代码

View中的代码是:

复制代码
@using(Html.BeginForm()){
    <fieldset>
        <legend>Register</legend>
        @Html.ValidationSummary(true)
        <ol>
            <li>
                @Html.LabelFor(m => m.NickName)
                @Html.TextBoxFor(m => m.NickName)
                @Html.ValidationMessageFor(m => m.NickName)
            </li>
            <li>
                @Html.LabelFor(m => m.Email)
                @Html.TextBoxFor(m => m.Email)
                @Html.ValidationMessageFor(m => m.Email)
            </li>
        </ol>
        <input type="submit" value="Sumbit" />
    </fieldset>
}
复制代码

运行以后,当你提交表单的时候,你会发现出现了同样的问题.
 

三. 使用PRG模式

PRG模式是Post/Redirect/Get的简称.
当一个Post请求过来的时候, 服务端会处理Post请求后,再发送Redirect(HTTP 303状态码)到浏览器,浏览器之后再发送Get请求到其它页面.
这样做, 浏览器的上一个操作就总是Http Get操作, 而不是Post操作, 也就解决了刷新弹出框的问题.


 

四. PRG模式在MVC上的实现

针对上面的例子,我们的修改思路是:
创建3个不同的Action对应, Post请求到"RegisterProcess"之后,无论成功还是失败, 都会转换成Get请求, 成功转向"RegisterSuccess", 失败转向"Register"
 
 
修改之后的Controller代码如下:

复制代码
 //
        // GET: /Home/
        [HttpGet, ImportModelStateFromTempData]
        public ActionResult Register()
        {
            return View();
        }
        [HttpPost, ExportModelStateToTempData]
        public ActionResult RegisterProcess(Models.RegisterModel registerModel)
        {
            if (ModelState.IsValid)
            {
                return RedirectToAction("RegisterSuccess");
            }
            return RedirectToAction("Register");
        }
        [HttpGet]
        public ActionResult RegisterSuccess()
        {
            return View();
        }
复制代码

上面的ImportModelStateFromTempData和ExportModelStateToTempData是ActionFilter, 是为了解决Redirect不能保存Model的验证错误的问题.
实现的基本原理是通过ExportModelStateToTempData把Model的验证错误存放到TempData中, 通过ImportModelStateFromTempData从TempData中把验证错误导入.


View代码是:

复制代码
@using (Html.BeginForm("RegisterProcess", "Home"))
{
    <fieldset>
        <legend>Register</legend>
        @Html.ValidationSummary(true)
        <ol>
            <li>
                @Html.LabelFor(m => m.NickName)
                @Html.TextBoxFor(m => m.NickName)
                @Html.ValidationMessageFor(m => m.NickName)
            </li>
            <li>
                @Html.LabelFor(m => m.Email)
                @Html.TextBoxFor(m => m.Email)
                @Html.ValidationMessageFor(m => m.Email)
            </li>
        </ol>
        <input type="submit" value="Sumbit" />
    </fieldset>
}
复制代码


ImportModelStateFromTempData和ExportModelStateToTempData的实现代码如下:

复制代码
 public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
    {
        protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
    }
    public class ExportModelStateToTempData : ModelStateTempDataTransfer
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            //Only export when ModelState is not valid
            if (!filterContext.Controller.ViewData.ModelState.IsValid)
            {
                //Export if we are redirecting
                if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
                {
                    filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
                }
            }
            base.OnActionExecuted(filterContext);
        }
    }
    public class ImportModelStateFromTempData : ModelStateTempDataTransfer
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;
            if (modelState != null)
            {
                //Only Import if we are viewing
                if (filterContext.Result is ViewResult)
                {
                    filterContext.Controller.ViewData.ModelState.Merge(modelState);
                }
                else
                {
                    //Otherwise remove it.
                    filterContext.Controller.TempData.Remove(Key);
                }
            }
            base.OnActionExecuted(filterContext);
        }
    }
复制代码

 最后,附上本文相关源代码 MVCFormValiation.zip



本文转自JustRun博客园博客,原文链接:http://www.cnblogs.com/JustRun1983/archive/2013/04/18/3027861.html,如需转载请自行联系原作者


目录
相关文章
|
17天前
|
SQL 开发框架 数据可视化
企业应用开发中.NET EF常用哪种模式?
企业应用开发中.NET EF常用哪种模式?
|
17天前
|
前端开发 数据安全/隐私保护
什么是mvvm,mvp、mvc和mvvm模式有什么区别?
什么是mvvm,mvp、mvc和mvvm模式有什么区别?
50 0
|
17天前
|
设计模式 存储 前端开发
MVC(模型-视图-控制器)是一种在Web应用程序开发中广泛使用的软件设计模式
【5月更文挑战第12天】MVC模式是Web应用开发中的常见设计模式,将逻辑、数据和界面分离,提升代码可维护性和重用性。模型处理数据逻辑,视图展示数据,控制器协调用户输入与模型视图交互。优点包括代码分离、易维护、可扩展和组件重用,促进高效灵活的开发。
15 2
|
8天前
|
前端开发 JavaScript 中间件
基于最新koa的Node.js后端API架构与MVC模式
基于最新koa的Node.js后端API架构与MVC模式
20 1
|
17天前
|
设计模式 前端开发 Java
19:Web开发模式与MVC设计模式-Java Web
19:Web开发模式与MVC设计模式-Java Web
27 4
|
17天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
27 0
|
17天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
34 0
|
17天前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
6 0
|
17天前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
128 5
|
17天前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
75 0

相关实验场景

更多