实现思想:每个页面打开的时候会在页面的隐藏控件自动生成一个值并将这个值赋值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. 利用MessageFormat实现短信模板的匹配

    其实没什么技术含量,因为老是想不起来,所以在此文做下记录. 通常我们的应用系统中都会有很多短信的发送,或者是信息邮件等的推送,而这些信息却有着相同的共性,比如只是用户名换了下. 像下面这条,除了红色字 ...

  2. Hyberledger-Fabric 1.00 RPC学习(2)尝试建立一个network

    本文参考:http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html 这里我们学习建立第一个Hyperledger Fa ...

  3. git/github基本命令

    Git与项目 git的使用,主要包括: 本地仓库的命令 远程仓库的命令 项目需求.页面.模型类的设计,及页面的使用 sudo apt-get install git 安装成功后,运行如下命令 git ...

  4. 【转】iOS9适配 之 关于info.plist 第三方登录 添加URL Schemes白名单

    近期苹果公司iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装. 受此影响,当你的应用在 ...

  5. django2.0表的ORM字段类型和展示

    django2.0表的ORM字段类型和展示 思路整理 今天想给博客的文章添加增加一个分类字段 但是不知道这种后台字段生成的字段,样式怎么处理 后来找到了,就是在定义模型的字段定义的时候 决定样式 mo ...

  6. DevExpress GridView 整理

    1:去除 GridView 头上的 "Drag a column header here to group by that column" -->  点击 Run Desig ...

  7. 34.TokenInterceptor防止表单重复提交

    转自:https://wenku.baidu.com/view/84fa86ae360cba1aa911da02.html 由于某些原因,用户在进行类似表单提交的操作后,以为表单未被提交,会进行多次的 ...

  8. 11 MySQL--Navicat与pymysql模块

    1.Navicat的安装下载 一.Navicat 在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时, 可以使用可视化工具Navicat,以图形界面的形式操作My ...

  9. 基于jquery-ui及bootstrap的可拖拽模态框

    可直接使用代码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t ...

  10. win7局域网内共享文件夹及安全设置

    右键想要共享的文件夹,选择属性. 在文件夹属性对话框中选择共享标签,如图: 点击共享按钮,弹出文件共享对话框. 添加 Everyone ,并根据实际需要修改权限.权限可以是读取 或 读取/写入. 到此 ...