实现思想:每个页面打开的时候会在页面的隐藏控件自动生成一个值并将这个值赋值session,当提交方法的时候会在过滤器的时候进行获取session和页面传值过来的隐藏控件的值进行比较,如果值相同的话,重写session值。否则的话给出提示。

ActionFilter:

using System;
using System.Web;
using System.Web.Mvc;
using EwayFramework.Utils.Token;

namespace EwayFramework.BaseController.Filter
{

/// <summary>
/// 防止重复提交
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class CurrentApproveActionFilterAttribute : ActionFilterAttribute
{
/// <summary>
/// 审批页面的控制器+Action方法
/// </summary>
public string SessionMyToken { get; set; }
public string ID { get; set; }
public IPageTokenView PageTokenView { get; set; }

/// <summary>
/// Called when authorization is required.
/// </summary>
/// <param name="filterContext">The filter context.</param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
PageTokenView = new SessionPageTokenView(SessionMyToken + HttpContext.Current.Request.Params[ID]);
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}

if (!PageTokenView.TokensMatch)
{
filterContext.Result = new JsonResult
{
Data = new { Result =false, Message = "该单子已在其它地方打开,请在最新打开的页面审批或者刷新该页面!" }
};
}

}
}
}

定义生成随机码的接口和实现:

1、IPageTokenView.cs

namespace EwayFramework.Utils.Token
{
public interface IPageTokenView
{
/// <summary>
/// Generates the page token.
/// </summary>
string GeneratePageToken();

/// <summary>
/// Gets the get last page token from Form
/// </summary>
string GetLastPageToken { get; }

/// <summary>
/// Gets a value indicating whether [tokens match].
/// </summary>
/// <value>
/// <c>true</c> if [tokens match]; otherwise, <c>false</c>.
/// </value>
bool TokensMatch { get; }
}
}

2、PageTokenViewBase.cs

namespace EwayFramework.Utils.Token
{
public abstract class PageTokenViewBase : IPageTokenView
{
public static readonly string HiddenTokenName = "hiddenToken";
/// <summary>
/// Generates the page token.
/// </summary>
/// <returns></returns>
public abstract string GeneratePageToken();

/// <summary>
/// Gets the get last page token from Form
/// </summary>
public abstract string GetLastPageToken { get; }

/// <summary>
/// Gets a value indicating whether [tokens match].
/// </summary>
/// <value>
/// <c>true</c> if [tokens match]; otherwise, <c>false</c>.
/// </value>
public abstract bool TokensMatch { get; }

}
}

3、SessionPageTokenView.cs

using System;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace EwayFramework.Utils.Token
{
public class SessionPageTokenView : PageTokenViewBase
{
public string SessionMyToken { get; set; }

public SessionPageTokenView(string sessionmytoken)
{
SessionMyToken = sessionmytoken;
}

#region PageTokenViewBase

/// <summary>
/// Generates the page token.
/// </summary>
/// <returns></returns>
public override string GeneratePageToken()
{
if (HttpContext.Current.Session[SessionMyToken] != null)
{
return HttpContext.Current.Session[SessionMyToken].ToString();
}
else
{
var token = GenerateHashToken();
HttpContext.Current.Session[SessionMyToken] = token;
return token;
}
}

/// <summary>
/// Gets the get last page token from Form
/// </summary>
public override string GetLastPageToken
{
get { return HttpContext.Current.Request.Params[HiddenTokenName]; }
}

/// <summary>
/// Gets a value indicating whether [tokens match].
/// </summary>
/// <value>
/// <c>true</c> if [tokens match]; otherwise, <c>false</c>.
/// </value>
public override bool TokensMatch
{
get
{
string formToken = GetLastPageToken;
if (formToken != null)
{
if (formToken.Equals(GeneratePageToken()))
{
//Refresh token
HttpContext.Current.Session[SessionMyToken] = GenerateHashToken();
return true;
}
}
return false;
}
}

#endregion

#region Private Help Method

/// <summary>
/// Generates the hash token.
/// </summary>
/// <returns></returns>
private string GenerateHashToken()
{
return Encrypt(
HttpContext.Current.Session.SessionID + DateTime.Now.Ticks.ToString());
}

#endregion

public static string Encrypt(string plaintext)
{
string cl1 = plaintext;
string pwd = string.Empty;
MD5 md5 = MD5.Create();
byte[] s = md5.ComputeHash(Encoding.Unicode.GetBytes(cl1));
for (int i = 0; i < s.Length; i++)
{
pwd = pwd + s[i].ToString("X");
}
return pwd;
}
}
}

Htmlhelper:

using System;
using System.Web;
using System.Web.Mvc;

namespace EwayFramework.Utils.Token
{
public static class HtmlTokenHelper
{
/// <summary>
/// 自动生成隐藏控件
/// </summary>
/// <param name="htmlhelper"></param>
/// <param name="id">表单唯一标识ID</param>
/// <returns></returns>
public static MvcHtmlString GenerateVerficationToken(this HtmlHelper htmlhelper,dynamic id)
{
string formValue = SessionPageTokenView.Encrypt(HttpContext.Current.Session.SessionID + DateTime.Now.Ticks.ToString());
string sessionname = HttpContext.Current.Request.Path + htmlhelper.ViewData[id];
HttpContext.Current.Session[sessionname] = formValue;
string fieldName = PageTokenViewBase.HiddenTokenName;
TagBuilder builder = new TagBuilder("input");
builder.Attributes["type"] = "hidden";
builder.Attributes["name"] = fieldName;
builder.Attributes["value"] = formValue;
return new MvcHtmlString(builder.ToString(TagRenderMode.SelfClosing));
}
}
}

调用和实现:

控制器:

在对应的Action方法上加上下述:

SessionMyToken :触发该Action方法的页面路由

ID:该单子的唯一标识ID(Action方法的参数必须有对应的值)

  [CurrentApproveActionFilter(SessionMyToken = "/PPHVPM_SecondForecastBOM/SecondForecastBOMPending_P", ID = "MainId")]

页面:

参数值为:该页面的唯一标识的 ViewBag.MainId不为空

 @Html.GenerateVerficationToken("MainId")

ASP.NET MVC 通过ActionFilterAttribute来实现防止重复提交的更多相关文章

  1. 创建一个ASP.NET MVC OutputCache ActionFilterAttribute

    在每一个web应用程序中, 有的情况下,你想在一段时间内缓存一个具体的页面HTML输出,因为相关的数据和处理并不是总是变化.这种缓存的响应是储存在服务器的内存中.因为没有必要的额外处理,它提供了非常快 ...

  2. ASP.NET MVC 利用ActionFilterAttribute来做权限等

    ActionFilterAttribute是Action过滤类,该属于会在执行一个action之前先执行.而ActionFilterAttribute是 MVC的一个专门处理action过滤的类.基于 ...

  3. ASP.NET MVC下Ajax.BeginForm方式无刷新提交表单

    有时候,不得不考虑到以下场景问题: 数据库表字段会频繁更改扩展,而流行的重业务的js框架过于依赖json数据接口,导致的问题是,数据库表更改 -> 数据接口更改 -> 前段框架逻辑更改.. ...

  4. asp.net 防止页面刷新或后退引起重复提交

     项目中经常遇到刷新后重复的向数据库增加一条相同的记录,造成数据重复,如何规避这些问题呢?下面我们就一起讨论一下在asp.net怎样防止页面刷新或后退引起重复提交数据的问题: 其实asp.net防止刷 ...

  5. asp.net mvc 模型验证注解,表单提交

    一.添加模型 public class Account { public int ID { get; set; } [Display(Name = "姓名")] //设置要显示的字 ...

  6. asp.net mvc Partial OutputCache 在SpaceBuilder中的应用实践

    最近给SpaceBuilder增加OutputCache 时发现了一些问题,贴在这做个备忘,也方便遇到类似问题的朋友查阅. 目前SpaceBuilder表现层使用是asp.net mvc v1.0,使 ...

  7. Asp.Net MVC 实用视频教程

    [北盟学习BaMn.Cn] Asp.Net MVC 第01课--创建第一个项目.avi [北盟学习BaMn.Cn] Asp.Net MVC 第02课--自己建一个controller view.avi ...

  8. Asp.net Mvc 中的模型绑定

    asp.net mvc中的模型绑定可以在提交http请求的时候,进行数据的映射. 1.没有模型绑定的时候 public ActionResult Example0() { ) { string id ...

  9. ASP.NET MVC中实现多个button提交的几种方法

    有时候会遇到这样的情况:在一个表单上须要多个button来完毕不同的功能,比方一个简单的审批功能. 假设是用webform那不须要讨论,但asp.net mvc中一个表单仅仅能提交到一个Action处 ...

随机推荐

  1. sorl 6.6.0 定时更新索引

    solr 定时更新索引 – solr 6.6.0 – dataimport.scheduler 这里先重点说下,定时更新引用的org.apache.solr.handler.dataimport.sc ...

  2. Eclipse apk 签名

    Eclipse apk 签名 project>right mouse click>android tool>Export signed Application package cre ...

  3. ehlib 用法记录

    点列头排序 1.add  ehlibado.pas  to project. 2.grideh>ColumnDefValues>Title>TitleButton=true; 3.g ...

  4. YII 自带验证码实现

    共三步,分别controllers,models,views各一层添置一行代码即可实现 第一步在controllers添加 public function actions() { return arr ...

  5. Java里的堆(heap)栈(stack)和方法区(method)

    基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法 ...

  6. X264编码流程详解(转)

    http://blog.csdn.net/xingyu19871124/article/details/7671634 对H.264编码标准一直停留在理解原理的基础上,对于一个实际投入使用的编码器是如 ...

  7. Halcon中二维码解析函数解码率和时长的优化方法

    Halcon中条码解析函数包容多种条码类型且简单强大.现有的‘Data Matrix ECC 200’.‘QR Code’和‘PDF417’等广泛使用的条码均能解析.简单是通过默认参数即可对多种条码进 ...

  8. U3D 场景切换时 脚本对象,GO对象,资源对象的问题

    脚本对象:在LUA中写了一个actor类,它封装了角色逻辑,引用了一个GO. GO对象:通过 GameObject.Instantiate(资源对象)生成的. 资源对象:制作好的模型prefab. 在 ...

  9. Jboss:The LogManager was not properly installed (you must set the "java.util.logging.manager" system prop

    可能是jboss的服务器版本选择不对 ,比如我本地的Jboss服务器版本是  jboss-as-web-7.0.2.Final,选择的服务器版本是JBOOS  V7.1  Runtime ,就会报上面 ...

  10. maven使用阿里云maven库

    在maven\conf\settings.xml中的mirrors添加 <mirror> <id>nexus-aliyun</id> <name>Nex ...