实现思想:每个页面打开的时候会在页面的隐藏控件自动生成一个值并将这个值赋值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. uva-11111-栈

    注意输入和输出的结果 -9 -7 -2 2 -3 -2 -1 1 2 3 7 9 -9 -7 -2 2 -3 -1 -2 2 1 3 7 9-9 -7 -2 2 -3 -1 -2 3 2 1 7 9- ...

  2. snmp获取设备相关管理信息

    在本文中,作者将向我们展示如何用snmp代理监视网络设备,甚至发送软件警告. 网络上很多代理在为我们服务.只要我们开启UDP/161,162端口,这些代理就会以Management Informati ...

  3. js阻止冒泡和默认事件(默认行为)详解- jquery DefaultPrevented 函数

    <!DOCTYPE html> <html>     <head>     <meta charset="UTF-8">     & ...

  4. U3D+SVN: 两份相同资源放在不同目录下导致META的更改

    U3D+SVN: 两份相同资源放在不同目录下导致META的更改. 实际情形:将地图文件map拷一份放在其它目录,回到UNITY编辑器,载入完成后加到磁盘,看到map文件夹下的所有meta都变红了. r ...

  5. MySQL 触发器示例

    简介: MySQL 触发器 这次实验是在一台 MySQL Slave 上进行的,事实证明:从库添加数据库.表.插入.删除数据等,不会导致主从失败. 一.创建实验数据库.表 mysql > cre ...

  6. SOAP 版本可能不匹配: 出现意外的 Envelope 命名空间 http://schemas.xmlsoap.org/wsdl/

    原错误描述:SOAP 版本可能不匹配: 出现意外的 Envelope 命名空间 http://schemas.xmlsoap.org/wsdl/.应为 http://schemas.xmlsoap.o ...

  7. 解决virtualbox共享文件夹没有访问权限的问题

    Virtualbox是一款免费试用的虚拟机软件.基本功能完全可替代需要购买或crack的VMware. 在Windows主机上用Virtualbox搭建Linux虚拟机,虚拟机和主机之间传递文件最方便 ...

  8. 一篇很好的关于mysqld_safe脚本源码解读的文章,收藏了!!

    #!/bin/sh # 一些状态变量的定义 KILL_MYSQLD=; # 试图kill多余的mysqld_safe程序,1表示需要kill MYSQLD= # mysqld二进制可执行文件的名称 n ...

  9. 用Hash Table(哈希散列表)实现统计文本每个单词重复次数(频率)

    哈希表在查找方面有非常大应用价值,本文记录一下利用哈希散列表来统计文本文件中每个单词出现的重复次数,这个需求当然用NLP技术也很容易实现. 一.基本介绍 1.Hash Key值:将每个单词按照字母组成 ...

  10. 动态执行SQL语句,接收返回值

    一.exec和sp_executesql介绍 当需要根据外部输入的参数来决定要执行的SQL语句时,常常需要动态来构造SQL查询语句.比如,一个比较通用的分页存储过程,可能需要传入表名,字段,过滤条件, ...