`
feiliboos
  • 浏览: 663640 次
文章分类
社区版块
存档分类
最新评论

Asp.net MVC 2 中解决页面提交数据并发问题

 
阅读更多

在 Asp.net MVC 2 中解决页面提交数据并发问题

通过本篇,你能了解到 Asp.net MVC 模型绑定处理过程,一种解决并发颗粒度到一条数据的方法.

* 如何解决互联网中某条数据的并发问题
在一个页面提交数据库前把从数据库取出的数据和提交时数据库中的数据比较,不同则给出提示.
在和其他童鞋的讨论中,都明确的指出了采用HashCode的方案,HashCode作为区分对象不同的一种方案,确实可行,但也有反对的声音.采用HashCode难免会涉及到对于实体对象的HashCode生成的问题,而实体对象的Hash又是根据自身属性生成,而属性又包含了其他关系,这种连带作用十分可观,也想过采用对于所有值属性采用Hash生成,对于关系对象着获取ID后再生成,但表数量也不少,如果考虑反射则每次提交都要遍历所有属性,性能客观,这还仅仅只是一次修改呢,折腾再三有了这样的方法.
在每张表中加入一个新的DateTime字段,每次修改赋最新值.
对,就是这么简单,每次读取时获得DateTime对象,返回到客户端页面,提交时再和数据库中对象比较.DateTime对象精确到毫秒,这种程度已经足够应付需求中所定义的并发.


通过Ticks构造的DateTime对象

*如何在Asp.net MVC中使用DateTime对象作为验证数据是否已过期依据

Asp.net MVC 的模型肩负着承载数据的责任.同时又很容易配置,使用.下面这张图介绍了Asp.net MVC如何处理实体对象模型的(截自Pro Asp.net MVC 2 Framework.

模型作为.net对象传递给视图后经过渲染后,呈现在HTML中.这就是回应客户端响应的流程.

同样的,作为客户端,以单纯的字符串是无法直接在.net中使用的,又需要进行模型绑定.才能转换为.net对象,继而使用他.

知道了整个模型的整个流程后,我们有了几个对策,思考再三决定传递DateTime对象的Ticks作为依据,因为直接输出DateTime最多也就精确到秒,不能和数据库中的原始数据DateTime匹配.所以获得其Ticks,作为字符串传输,然后返回的时候再解析.有了解决思路后就好做了.

这是我们的模型,注意其中的HashTime可空属性. 注意他标上了一个UIHint Attribute,能够绑定指定的用户控件,继而单独的渲染该属性.

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1publicpartialclassModelSimpleChangeUser:IHashTime
2{
3[HiddenInput]
4[DisplayName("用户编号")]
5[Required]
6publicintUserId{get;set;}
7
8[Required(ErrorMessage="名称必须不为空")]
9[DisplayName("用户名")]
10[DataType(System.ComponentModel.DataAnnotations.DataType.Text)]
11publicstringUserName{get;set;}
12[Required(ErrorMessage="Email必须存在")]
13[DisplayName("电子邮件")]
14[DataType(System.ComponentModel.DataAnnotations.DataType.EmailAddress)]
15publicstringEmail{get;set;}
16
17[HiddenInput(DisplayValue=false)]
18[UIHint("HiddenDateTime")]
19[Required(ErrorMessage="HashTime必须存在")]
20publicDateTime?HashTime{get;set;}
21
22
23
24publicModelSimpleChangeUser(){}
25publicModelSimpleChangeUser(ES.DAL.Useru)
26{
27this.UserId=u.UserId;
28this.Email=u.Email;
29this.HashTime=u.HashTime;
30this.UserName=u.UserName;
31}
32
33publicES.DAL.UserChangeTo(ES.DAL.Useruser)
34{
35if(UserId==user.UserId&&user.HashTime.HasValue)
36{
37user.UserName=UserName;
38user.Email=Email;
39}
40returnuser;
41}
42}

整个编辑视图也就一行起作用的代码.之所以能够这样是因为Asp.net MVC 2强大的模型特性标记功能,他能够在模型中声明如何显示,这就使得视图和模型完全分离,在视图里我都没有内联ViewPage的泛型类.使得页面可以编写完全独立的效果,而不必纠缠于和模型属性配对的问题中.

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><%=Html.EditorForModel()%>

在HiddenDateTime控件实现了一个简单的从当前实体模型对象读取Ticks的功能,由于是可空DateTime,所以处理了为null情况(标记字段在测试的时候有些是Null,所以这里给处理了一下,如果在真实的环境中这是不存在的,因为在建立和修改时都已经自动赋值了)

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1<%@ControlLanguage="C#"Inherits="System.Web.Mvc.ViewUserControl<DateTime?>"%>
2
3<%
4Dictionary<string,object>others=newDictionary<string,object>();
5//others.Add("Oth","ccc");
6%>
7<%=Html.Hidden("",Model.HasValue?Model.Value.Ticks:-1,others)%>

效果如下:

然后是绑定从客户端发来的数据问题.在这个点上费了很久,后来还是在书上找到了解决办法.
首先要知道Asp.net MVC是从那些地方以怎样的顺序获取了数据,下面是获取的顺序.

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1.Request.Form
2.RouteData.Values
3.Request.QueryString
4.Request.Files
5.null

前台输出的是DateTime的Ticks而不是默认的DateTime输出,所以还需要自己解析下.这里有一段ValueProviderFactroy的代码是截自书中的,在Global.asax的Appcation_Start事件注册后,就能截获所有参数的传递了.

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1protectedvoidApplication_Start()
2{
3AreaRegistration.RegisterAllAreas();
4
5RegisterRoutes(RouteTable.Routes);
6
7ValueProviderFactories.Factories.Insert(0,newES.WEB.Models.HiddentTimeValueProviderFactory());
8}

下面是那个解析工厂

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->publicclassHiddentTimeValueProviderFactory:ValueProviderFactory
{
publicoverrideIValueProviderGetValueProvider(ControllerContextctx)
{
returnnewHiddentTimeValueProvider(ctx.HttpContext.Request);
}

privateclassHiddentTimeValueProvider:IValueProvider
{
privateHttpRequestBaserequest;
publicHiddentTimeValueProvider(HttpRequestBaseRequest)
{
request
=Request;
}

publicboolContainsPrefix(stringprefix)
{
return"HashTime".Equals(prefix,StringComparison.OrdinalIgnoreCase);
}

publicValueProviderResultGetValue(stringkey)
{
varresult
=ContainsPrefix(key)
?newValueProviderResult(newDateTime(long.Parse(request["HashTime"])),null,CultureInfo.CurrentCulture)
:
null;
returnresult;
}
}
}

自此我们的代码已经完全可以跑起来了,在控制器里对传过来的数据直接分析,看Ticks是否相等就能判断有并发情况了.当然在返回错误的视图中我们也做了一些改善用户体验的处理.

下面是我们的控制器:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1publicActionResultEdit(Models.ModelSimpleChangeUserusers)
2{
3returnDoSafe(()=>
4{
5varu=UserManager.FindById(users.UserId);
6if(u.HashTime!=null)
7if(users.HashTime!=null&&
8users.HashTime.Value.Ticks==u.HashTime.Value.Ticks)
9{
10u.UserName=users.UserName;
11u.Email=users.Email;
12UserManager.Update(u);
13returnRedirectToAction("Index")asActionResult;
14}
15ViewData["lastAction"]="Edit";
16ViewData["lastController"]="User";
17returnView(RetiredPage,users);
18});
19}

注意15,16行,他将当前处理的Controller和Action的名称都保存了起来,以备在视图中使用,同样将用户输入的数据返回了出去.

下面是视图页面:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1<asp:ContentID="RetiredMain"ContentPlaceHolderID="MainContent"runat="server">
2
3<h2>对不起,您访问的页面已过期!</h2>
4<p>
5您所操作的原始数据可能被更改,请您返回获取最新数据.
6</p>
7<%=Html.ActionLink("返回",
8ViewData[BaseController.LastAction].ToString(),
9ViewData[BaseController.LastController].ToString(),
10Model,new{id="PostBackLink"})%>
11<scripttype="text/javascript">
12setTimeout(function(){
13varg=document.getElementById("PostBackLink");
14try{g.click();}catch(ex){}
15},2000);
16</script>
17</asp:Content>

用HtmlHelper生成了一个超链接,使用了我们之前保存的控制器数据,从而得知是在哪里引发了错误,并且还保存了用户输入的数据模型,最后给这个超链接赋值了一个id属性,供我们在客户端脚本上使用.

在客户端脚本里我们触发了一个延迟脚本,两秒后触发返回超链接的click事件,由于在FireFox下没有该对象,所以只是简单的容错了一下,还有更多FireFox下的超链接的脚本触发请移步JavaScript模拟用户单击事件.

整个过程还是相当简单的,不过条条大路通罗马,不一定都要坐技术含量高的飞机嘛.
前些天分享了一个封装了EntityFramework的操作的类,这里又拓展了他,将HashTime自动写入,这里就没考虑泛型,因为数据的读写实在太频繁了,就将所有实体继承一个IHashTime接口,接口只有一个HashTime属性,然后封装了一个方法,在每次数据创建或者改写的时候调用.从而整个并发问题迎刃而解.

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1privatevoidsetHashTime(object o)
2{
3(oasIHashTime).HashTime=DateTime.Now;
4}
分享到:
评论

相关推荐

    [ASP.NET MVC 小牛之路] 文章系列

    asp.net mvc系列教程,转载于博客园 一、[ASP.NET MVC 小牛之路]01 - 理解MVC模式 二、[ASP.NET MVC 小牛之路]02 - C#知识点提要 ...二一、[ASP.NET MVC 大牛之路]03 - C#高级知识点概要(2) - 线程和并发

    asp.net的MVC框架

    Taurus.MVC是一个简单的asp.net的MVC框架。 适合场景:对性能和并发有较高要求的电商、站点、WebAPI等系统,支持.Net Core

    .NET MVC Redis 实现简单的抢购队列

    .NET MVC Redis 实现简单的抢购队列,RPush LPop 实现高并发抢购队列

    ASP.NET MVC+EF仿博客园网站开发

    ASP.NET MVC+EF仿博客园网站开发 使用ASP.NET MVC5 基于.NET 4.5 开发一个大型的博客系统。包括全站首页 个人博客园 后台系统 博客系统四大部分。同时也适合在校学生。进行毕业设计。同学们可以对着学习和仿照开发...

    asp.net 中使用oracle数据库事务

    如何创建 OracleTransaction 对象并用它们将事务提交给数据库,如何使用保存点部分回滚一个事务,以及 Oracle 数据库如何分离并发事务。同时分别提供了vb.net和c#两种开发工具提供了具体实例代码

    ASP.NET网络在线考试系统(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    ASP.NET图书馆管理信息系统(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net知识库

    SubmitOncePage:解决刷新页面造成的数据重复提交问题 SharpRewriter:javascript + xml技术利用#实现url重定向 采用XHTML和CSS设计可重用可换肤的WEB站点 asp.net的网址重定向方法的比较:面向搜索引擎友好 也谈 ...

    Contoso大学MVC示例应用2012523

    为 ASP.NET MVC 应用程序创建 EF 数据模型 使用 EF 在 MVC 中实现基本的增、删、改、查功能 排序、过滤与分页 创建更加复杂的数据模型 读取关联的数据 更新关联的数据 处理并发 实现继承 实现仓储和操作...

    ASP.NET在线毕业thesis提交系统的设计与实现(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net作业在线提交系统的设计与实现(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net数据存储与交换系统设计(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    另外,还专门介绍了ASP.NET4 新增的功能,如MVC 和动态数据等。  《ASP.NET 4高级程序设计(第4版)》适合各层次的ASP.NET程序员阅读。 =================== 第一部分 核心概念 第1章 ASP.NET简介 1.1 ASP.NET的...

    ASP.NET4高级程序设计(第4版) 3/3

    另外,还专门介绍了ASP.NET4 新增的功能,如MVC 和动态数据等。  《ASP.NET 4高级程序设计(第4版)》适合各层次的ASP.NET程序员阅读。 作者简介 作者:(美)麦克唐纳 目录 第一部分 核心概念 第1章 ASP.NET简介 ...

    asp.net通讯录管理系统课程设计.zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net医药进销存系统.zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net企业客户管理系统cms系统.zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    asp.net+sql2008在线论坛系统.zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

    ASP.NET中小企业OA系统的设计与实现(源代码+thesis).zip

    缓存管理:为了提高应用程序的性能,我们将使用ASP.NET提供的缓存机制来缓存常用的数据和页面。这将减少对数据库和服务器的访问次数,提高应用程序的响应速度和吞吐量。 异步编程:我们将使用ASP.NET提供的异步编程...

Global site tag (gtag.js) - Google Analytics