[转载]在MVC2.0 中 进行 LINQTOSQL 实体统一验证方法(上)

mikel阅读(967)

[转载]在MVC2.0 中 进行 LINQTOSQL 实体统一验证方法(上) – RyanDing – 博客园.

场景

当我把项目从 MVC1.0 升级到 MVC2.0 时,原以为可以方便的使用 System.ComponentModel.DataAnnotations 结合 MVC2.O 的

ModelState.IsValid 进行数据有效验证。比如以下验证:

1 public class SystemUserMetaData 2 { 3 [Required(ErrorMessage = "不能为空!")] 4 [StringLength(6, ErrorMessage = "用户名长度不能超过6!")] 5 public string UserName { get; set; } 6 [Required(ErrorMessage = "IsValid is required.")] 7 public string ChineseName { get; set; } 8 [Required(ErrorMessage = "IsValid is required.")] 9 public bool IsValid { get; set; } 10 [Required(ErrorMessage = "Department is required.")] 11 public int DepartmentID { get; set; } 12 [Required(ErrorMessage = "Password is required.")] 13 public string Password { get; set; } 14 [Required(ErrorMessage = "Rank is required.")] 15 public int RankID { get; set; } 16 [PhoneAttribute(ErrorMessage = "电话号码不正确")] 17 public string MobilePhone { get; set; } 18 public int UserID { get; set; } 19 }
代码1

这些Annotation特性验证可以很轻松通过 mvc2.0  ViewData.ModelState.Values 获取到验证错误的提示信息。但是当我们的验证条件变得更加

复杂时,比如在修改一个LinqToSQL 实体时需通过该实体的主键和唯一索引进行验证实体是否唯一性时,此时需要两个字段同时验证,当这种验证出现时我

发现无法简单的使用 DataAnnotaion 进行同一实体的多字段验证。自定义 ValidationAttribute 特性重写 IsValid 时 无法根据当前的属性获取到其他属性

的值。因为ValidationAttribute 特性是附加在一个类的属性上的。可能聪明的你此刻已想到了将验证特性直接加载 LinqToSQL 的 类上。当你为这个特性

编写验证方法时就可以通过反射得到 LinqToSQL 实体的所有属性的值,或许单一的 ValidationAttribute 属性验证特性不能完成的任务就可以得到解决。

当我把LINQTOSQL 类的验证特性写完后附加到 LinqTOSQL partial 类上代码如下:

[UniqueName("UserID", "UserName", typeof(SystemUser), ErrorMessage = "该用户已存在。")] [MetadataType(typeof(SystemUserMetaData))] public partial class SystemUser { }

在MVC2.0 中当我们使用 TryUpdateModel 方法时 发现 UniqueName 的 IsValid 方法始终没有被调用。但是当 MetadataType 移除除掉,我们再调用

TyUpdateaModel方法时UniqueName 特性的 IsValid 验证方法就被正常调用了。此时我明白了问题应该是由 MVC  TryUpdateModel 方法引起,将该方

法换成 UpdateModel 后问题依旧。MetadataType 特性覆盖了 UniqueName 特性,当然了如果想知道具体的原因,可以 Reflect 出 TryUpdateModel

的方法找到到答案。为了解决这个问题,我决定使用自定义的方法进行实体验证,代码如下:

代码3

public class Validation { public static void ValidateAttributes<TEntity>(TEntity entity) { var validationInstance = new Validation(); validationInstance.ValidateAttributesInternal(entity); } public virtual void ValidateAttributesInternal<TEntity>(TEntity entity) { var validationIssues = new List<ValidationIssue>(); var props = typeof(TEntity).GetProperties(); var metatype = typeof(TEntity).GetCustomAttributes(typeof(MetadataTypeAttribute), false).FirstOrDefault(); var type = ((System.ComponentModel.DataAnnotations.MetadataTypeAttribute)(metatype)).MetadataClassType; var s = type.GetProperties(); var customAttrs = typeof(TEntity).GetCustomAttributes(true).Where(t => t.GetType().Namespace.Contains("ValidationMeta")); foreach (var attr in customAttrs) { var validate = (ValidationAttribute)attr; //执行 附加在 linqtosql partial 类 上的 ValidationAttribute 验证方法 bool valid = validate.IsValid(entity); if (!valid) { validationIssues.Add(new ValidationIssue(null, null, validate.ErrorMessage)); } } //执行附加在 linqtosql partial 类 属性上的 ValidationAttribute 验证方法 foreach (var prop in s) ValidateProperty(validationIssues, entity, prop); // throw exception? if (validationIssues.Count > 0) throw new ValidationIssueException(validationIssues); } protected virtual void ValidateProperty<TEntity>(List<ValidationIssue> validationIssues, TEntity entity, PropertyInfo property) { //得到验证特性的集合 var validators = property.GetCustomAttributes(typeof(ValidationAttribute), false); foreach (ValidationAttribute validator in validators) ValidateValidator(validationIssues, entity, property, validator); } protected virtual void ValidateValidator<TEntity>(List<ValidationIssue> validationIssues, TEntity entity, PropertyInfo property, ValidationAttribute validator) { var dataEntityProperty = typeof(TEntity).GetProperties().FirstOrDefault(p => p.Name == property.Name); var value = dataEntityProperty.GetValue(entity, null); if (!validator.IsValid(value)) { validationIssues.Add(new ValidationIssue(property.Name, value, validator.ErrorMessage)); } } }

大家留意一下代码3 中的注释,这样 Validation 这个类就就可以替代MVC TryUpdateModel 的验证功能同时让代码1的 UniqueName 和 MetaDataType 两个特性 “共存”。

MetadataType 的职责:验证实体的单一属性值的有效性。

LINQ实体类上的其他的自定义特性:如代码1中的 UniqueName 则可以进行复杂的属性验证如多属性值同时验证等。

这样我们就彻底的解决了开发过程中验证代码统一的编码规范。而不是同一个数据有效性验证的代码满天飞的局面。

小结

当我完成了以上代码似乎已经达到了预期的目的,但测试代码时候发现如果使用TryUpdateModel 更新另外一个LINQTOSQL 模型(Order表),这个被

更新的模型从数据库上来看它属于 SystemUser 的外键表。通过Order表中的UserID 字段关联到 SystemUser。当Order实体被MVC TryUpdateModel 时会同时把SystemUser 的 自定义的 [UniqueName] 特性的方法 IsValid() 也调用了,很显然这不是我们想要的。该问题我会在下一篇文章提出解决方案。

[转载]C#调试心经续

mikel阅读(1301)

[转载]C#调试心经续 – Alexis – 博客园.

由于上篇文章漏了一些比较重要的知识,在此文中补充。

断点篇

命中次数(Hit Counts)

右击断点,可以设置Hit Counts(命中次数),会弹出如下的对话框

当条件满足的时候断点会被命中(即即将被执行),这个命中次数是断点被命中的次数。默认是始终break,选项有如下的几种:始终break;当命中次数达到多少次时break;当命中次数是多少的倍数时break;当命中次数大于等于多少的时候break

于是在上篇中的条件也可以这样实现,设置命中次数等于50的时候break,按F5后,断点被触发,此时i=50

点过滤器

我们可以限制断点在特定的处理器和进程中。可以设置机器名、进程id、进程名、线程id、线程名中的某些条件来过滤一些断点。

注意:ThreadId需要特别说明一下,ThreadId并不是托管程序中,.NET 框架中System.Threading.Thread.ManagedThreadId,两者不能等同。简单来说,ManagedThreadId是线程在CLR中的标识符,而ThreadId却是线程在操作系统中的标识符。因此ThreadId需要从调试器中的“Threads”窗口中获取。

断点条件

我们可以设置断点达到的条件,如下图,我们设置表达式为i==5注意是判相等,而不是赋值的等于),按F5,断点再次被触发,此时i=50

还有一个选项是已经被改变,则里面条件是具体的变量,如我们的代码如下

private void ConditionDebug()
{
int hitCount = 0;
for (int i = 0; i < 100; i++)
{
if (i==49)
{
hitCount = 1;
}
}
Console.Write(“Hit Count={0}”, hitCount);
}

我们在代码里如果i==49,就将hitCount的值改变,同时设置断点的条件为

则当断点再次被触发的时候此时i=50。这个通常被用在找变量的时在什么时候发生改变。

断点的位置

可以设置断点的位置,如下图,设置程序到达那个文件的第几行第几个字符时触发断点。

断点触发时

我们可以设置断点到达时做一些其他的事情,如打印消息,运行一个宏。

自定义调用堆栈

堆栈跟踪时vs一步步执行你的程序是对当前的方法调用继承关系的直观显示。在调试程序时,我们会经过一个又一个方法,包括方法的嵌套调用。堆栈跟踪会对这当中的每一层方法作出记录。选择“调试–>窗口–>调用堆栈”,或者是快捷键Ctrl+Alt+C就可以看到当前的堆栈跟踪状态。这里会将每个方法单独显示为一行,并且带有行号和参数值。每一个新的方法调用被称为堆栈帧。

堆栈跟踪是广为人知的调试工具,它的优点在于你可以双击任意一行跳转到程序中该层调用方法的代码。于是你可以看到程序是如何执行到这一位置的,同时可以看到方法接受的参数值。并且可以使用Ctrl+C将一个或者全部堆栈帧复制到剪贴板,并将这个方法的调用信息发送给工作伙伴。

项目属性中的Debug选项卡

如果你的项目是Console项目(控制台应用程序)或者是WinForm项目,则右击项目解决方案,选择属性,会出来如下的项目属性窗体。

我们可以设置“启动动作”、“启动选项”和“是否启用调试”。

Start Action有三个选择项:

Start Project:默认选项,设置为启动项目

Start external program:调试的时候启动内部程序

Start browser with URL:调试的时候打开URL地址

使用Trace.axd调试ASP.NET

在以前asp时候,我们为了查看某个变量的值,通常会使用Response.Write方法。可能现在许多ASP.NET程序员也习惯在后台使用Response.Write方法将变量的值写出来,其实微软提供了很好的调试工具,即Trace.axd。它的功能主要是:配置 ASP.NET 代码跟踪服务以控制如何收集、存储和显示跟踪结果。

关键的几个选项:

1localOnly 默认为false。这个很好理解。如果为true,只在本地输出跟踪信息。

2enabled 是否启用跟踪。

3pageOutput 指定在每一页的结尾是否呈现跟踪输出。如果是 false ,则只能通过跟踪实用工具访问跟踪输出。

4requestLimit 指定在服务器上存储的跟踪请求的数目。最大为10000,默认为10

5traceMode 指定显示跟踪信息的顺序。SortByCategory SortByTime(默认)

关于更多可以参考

http://msdn.microsoft.com/zh-cn/library/6915t83k%28VS.80%29.aspx

下面以一个小Demo来说明怎么使用Trace.axd来调试ASP.NET

1. 建立一个Web项目,取名为WebTraceTest

2. 编辑web.config文件,添加trace节点(在)

内容如下:

<trace enabled=”true” localOnly=”true”

pageOutput=”true”

requestLimit=”15″

mostRecent=”true” />

3. 新建一个页面,取名为Test.aspx,在里面增加一个文本框和一个按钮(都是服务器端的控件)

按下F5,开始调试,会发现出现如下界面

5. 在文本框中输入文字,如Alexis,点击按钮,会发现Form Collection中会有详细的信息,如下:

说明:使用Trace.axd我们可以获得以下信息:

Request Details:请求的详细信息

Trace Information:跟踪信息

Control Tree:控件树

Session State:会话状态

Application State:应用程序状态

Request Cookies Collection:请求Cookie集合

Response Cookies Collection:响应Cookie集合

Headers Collection:标头集合

Response Headers Collection:响应标头集合

Form Collection:窗体集合

Querystring CollectionQueryString集合(即Url中?后面的字符串的信息)

Server Variables:服务器变量

Visual Studio与一个运行中的进程连接

当你按下F5对程序开始调试时,VS.NET会对项目进行生成(如果有必要的话)并以调试模式启动程序。也就是说,只要项目位于Debug版本的程序集中,VS.NET就与运行得程序之间建立了连接,以便对断点等与调试相关的方法作出反应。

不过有些时候,我们需要或者想要对正在运行得Visual Studio之外启动的进程进行调试。当进程位于debug版本的程序集中,这是可以做到的。

1. 选择“工具—>调试进程”列出所有正在运行得程序,如下图

2. 选择自己感兴趣的进程,点击连接,此时Visual Studio自动切换到了调试模式。

3. 打开Progress窗口,发现我们刚刚选择的进程在列表中,如下图

这一技巧可以让你对Windows服务进程进行调试。编写Windows服务进程时,你无法按F5启动调试,因为它们必须先通过管理工具安装后启动才能运行。如果你在调试模式下生成并安装服务程序,就可以使用这一技巧进行调试。

而且你可以对SQL存储过程使用同样的方式进行调试。如果你安装了SQL Server调试组件,并且有足够的权限,就可以连接到SQL Server的进程,并在服务器中为存储过程设置断点来一步步执行。

调试Visual Studio中的多个项目

在实际开发中,我们往往分了许多层,有许多的项目集合在一个解决方案下。我们可以右击要调试的项目选择“调试–> 运行新实例”来实现调试这个项目。我也可以右击解决方案,选择多项目调试,如下图

我们还可以设置项目的期待顺序。在客户端/服务器(CS结构)程序中,我们可以使用这一方法来确保服务器端程序在客户端程序之前运行。

只在特定类型的异常时中断

一个健壮的程序会在运行时处理所有可能出现的异常。不过开发者在调试复杂的程序时会觉得这样有些麻烦。因为所有的异常都被处理掉了。在出现任何异常时,Visual Studio不会再进行处理,或者中断代码来对用户作出提示。

幸运的是Visual Studio有个选项可以让开发者指定他们关心的异常类型。选择菜单栏à调试à异常,或者使用快捷键Ctrl+Alt+E。如下图

我们可以看到一个树状结构列出所有VS可以监视到的异常。

后面的两个勾选框的意思分别为是否被抛出和用户是否不处理。

参考:

Visual Studio.NET使用技巧手册》

http://msdn.microsoft.com/

[转载]C#调试心经

mikel阅读(1241)

[转载]C#调试心经 – Alexis – 博客园.

我们在做程序开发时,难免会遇到错误异常。如何快速地找到出错的地方、分析错误的原因以及找到解决问题的方案,是许多初级程序员困扰的问题,这也正是经验的宝贵之处。 下面我将简单介绍在Visual Studio中调试以及一些高级的调试和常见的错误。

PS:如无特别说明Visual Studio均指Dev10Visual Studio 2010

入门篇

假设你是有着.Net平台的程序员,并且使用Visual Studio 做为开发工具。

断点:最简单的一种,设置一个断点,程序执行到那一句就自动中断进入调试状态。设置断点,在你觉得有问题的代码行,左侧单击,会出现红色的红点即断点。

启动调式:按F5,或者菜单栏调式开始调试,或者工具栏的图标

快速监视:快速查看变量或者表达式的值,也可以自定义表达式进行计算

单步执行

有三种,一种是每次执行一行(F10);一种是每次执行一行,但遇到函数调用就会跳到被调用的函数里(F11);一种是直接执行当前函数里剩下的指令,返回上一级函数(Shift+F11)。

还有一种后悔药,设为下一句(Set Next Statement),即下一句会被执行的语句(右击设置或者快捷键:Ctrl+Shift+F10),但要注意在调试与数据有关的时候,设置下一句有可能会报异常。如在调试向DataTable中添加行的时候,已经存在的行不能重复被添加到DataTable中。

监视

调试器可能会自动列出一些相关变量的值,但是你可能还关心其它变量的值,可以添加对这些变量的监视。还可以监视一个表达式的值,比如a+b。但是,这个表达式最好不要修改变量的值,比如监视a++都会导致监视时修改了a的值,影响了程序的运行结果。

调试技巧篇

使用快捷键会大大提升我们的调试效率,常用的调试快捷键:

F5 启动调试

F10 执行下一行代码,但不执行任何函数调用。

F11 在执行进入函数调用后,逐条语句执行代码。

Shift + F11 执行当前执行点所处函数的剩余行。

Shift + F5 停止运行程序中的当前应用程序。可用于“中断”模式和“运行”模式。

拖动断点(感谢 圣殿骑士的提醒)

在调试中,我们可以拖动断点,使得程序运行到我们想要运行的地方。通常是用来验证这段代码对程序的运行结果有没有影响的。因为我们拖动代码,则被过滤的代码就不会执行,将它跟原来的相比,可以看出去掉这段代码有什么影响

条件中断

假如你写了个for循环,而且循环的次数比较多,如下代码,现在我们知道在i=50的时候会有异常,那我们不可能按50F5去调试这代码,不然这效率….

private void ConditionDebug()
{
for
(int i = 0; i < 100; i++)
{
if
(i==50)
{
//some error code here
Console
.WriteLine(“i=50 here”);
}
}
}

我们可以直接利用vs提供的功能修改变量i的值,一开i=0,即刚进入for循环中,我们设置将i改为49并回车,再调试一次,会发现i=50 如下图

当然我们也可以直接在代码里写代码以达到这个目的,代码如下

private void ConditionDebug()
{
for (int i = 0; i < 100; i++)
{
System.Diagnostics.Debug.Assert(i != 50);
if (i==50)
{
//some error code here
Console.WriteLine(“i=50 here”);
}
}
}

使用了调试中的Assert(断言),当执行程序后会弹出如下的提示框,点击Ingore(忽略)即可,会发现此时i已经为50了,有兴趣的朋友可以看看Assert的其他用法。

Immediate Window

Immediate window在调试的时候计算表达式的值、执行语句、打印变量的值等。我们输入命令(注意一定要以“>”开头),会有智能提示,而且命名都是自解释型。

如,我们现在想要知道i的值,可以输入命名>Debug.Print i(也可以简单的使用>? i),如下图

Immediate window还有更强大的用法,计算方法的返回值(如果有的话)

如果有这个的函数

int MethodValue(int a)

{

if (a==1)

{

return 1;

}

else

{

return 0;

}

}

我们可以使用Immediate命令 >? class.Method(args) 去调用这个方法,如下图

其中p是当前类的实例(因为MethodValue是类的方法,注意?和表达式之间要有空格)


对于一些实时性很高的程序(如socket)使用 Debug.Write()把错误写到日志文件中,.Net可以将Debug信息写到你指定的文件中,记住,写进出的信息不一定是出错的信息,也可以是你的程序的运行的一些重要信息,当你调试过程中发现某个模块出了问题,但是不能决定位置,那你就可以使用这个方法,如果是一天才出一个错误,那你就更要使用这个方法。

实例篇

涉及到WSWebServices)的调试

在基于WinForm的实际开始开发中,我们往往采用WS用做数据的传递,我们在前台获取收集数据,通过WS将数据传递给后台,后台做相应的业务逻辑处理后,会持久到数据库中。而往往我们又会在WS中写一些相关的代码,如身份验证、日志记录、提示信息等,怎样去调试这些代码呢。

涉及到JavaScript的调试

许多程序员为调试JavaScript感到困惑不已,因为没有一款很好的调试工具。一些人喜欢使用FireBug来调试JavaScript,确实是一个不错的选择,Firebug提供了许多的JavaScript信息,是一款不错的调试JavaScript的工具。下面我将会介绍如何使用Visual Studio调试JavaScript,Visual Studio中调试JS跟调试C#差不多,都是设置断点,不同的是我们在查看元素值的时候需要注意点。

涉及到Ajax的调试

现在ajax已经十分的流行,但是随之而来的即调试困难,大部分初级程序员不知道如何有效地从前台调试到后台代码,以至出了很多不完善的ajax应用。

下面以一个简单的实例来介绍如何使用Visual Studio调试JavaScript。实例是使用Ajax验证用户登录,如果验证通过,则提示“登录成功”,否则提示“登录失败”。

下面是主要的代码,我们使用JQuery来实现ajax,并且在后台文件中故意出错。

正确的用户名和密码是admin1

调试方法如下,在后台入口处设置断点,然后在前台js中调用后台的方法处设置断点,然后按F5启动调试,当我们输入用户名、密码后,点击登录后会发现,前台断点被触发了。

F5继续调试,有时候会跳到JQuery的源码中,不管他,继续F5,会发现执行到后台中的断点中,如下图

而后台代码的调试是十分简单的。(PS:有时候无需在前台设置断点也可直接进入后台的调试,如何不行的话,在前台html文件或者aspx文件中认为有可能出错的地方设置断点,一步步调试)

一些调试中出现的常见错误(会陆续更新):

1. 我们调试到某一句代码的时候,突然莫名奇妙的跳出来了,其实是刚刚执行的这一句话有异常,我们可以使用try…catch进行异常捕获,看看异常原因是什么,然后做相应的处理

2. ADO.NET,我们会使用ds.Merge()方法进行合并内存表,如果有异常的话,一般有以下三种情况:

A.其中一张表中有两行一模一样的数据,包括主键

B.这两张表的结构不一致

C.两张表中某个字段的类型不匹配,如字段ageA表中式string,而在B表中确是Decimal

[转载]汇编开发环境搭建

mikel阅读(701)

引子

由于这些日子一直都在研究底层的技术,从 Windows 驱动程序,到 Windows 内核等等技术的学习,

让我对底层的技术越发有兴趣了,而刚好,在研究 WRK 时,

对内存管理,寄存器,地址总线,数据总线,控制总线等的理解不够透彻,

所以越发的想学习汇编程序设计来提升功力,

而由于近来在公司里一直都有项目压着,所以在公司里也实在不好拿本汇编程序设计看,

所以只好晚上回来学习了, 汇编看了几个晚上,也算是蛮有感觉的。

今天就先来搭个开发环境再说吧。

开发环境搭配

我介绍四种开发汇编程序的方式:

第一种:直接在 Dos 环境下使用 Edit 命令调出源码编辑框,

生成源码后,可以使用由微软提供的 masm 汇编编译器来对源码进行编译,

编译完后再使用 Linker 连接器即可得到可执行文件,

这种方式现在几乎被灭绝了(当然使用 masm 汇编编译器还是很普遍的),

除非你真要在 DOS 环境下运行汇编程序;

第二种:通过简化第一种方式而来;

第三种:直接使用 Masm for Windows 集成实验环境,这个开发环境呢,非常适合汇编语言的初学者,

因为这个 IDE 本身就是由一些从事汇编程序教学的大学老师开发的出来用于汇编初学者进行学习和实验的,

所以使用简单,方便,这里可以对这个 IDE 稍加推荐;

第四种:则是通过 Visual  Studio 这个强大的 IDE 来实现汇编程序的编译,运行和调试,

至于 Visual  Studio 就不多做介绍了,.Net 用了这么多年,这东西强大到什么程度那是总所周知的;

第一种方式:使用 Edit + MASM 5.0 编译器 + Linker 连接器

其实这种方式是很简单的,只是很麻烦,因为简单而且麻烦,

所以我采用尽可能的将截图传上来,然后稍加注解的方式进行介绍,

软件准备:

需要 MASM 5.0 或者以上的汇编编译器

首先,是要编辑汇编源代码:

其实对于源码的编辑根本不需要向如下这么麻烦,直接拿个记事本就 OK 了

运行 cmd 命令

image

输入 Edit 命令从而弹出汇编源码编辑框

image

image

在源码输入框中输入汇编源码

image

将编辑好的汇编源码保存到 xx.asm 文件中

image

image

image

然后就是要编译编辑好的汇编源代码

在 Dos 环境下进入到  MASM 5.0  汇编编译器所在的目录

image

然后运行 masm.exe

image

image

可以从上面的截图中看到  [. ASM]  的标记,这个标记代表的是需要在这里输入要编译的源程序文件名,

这里有一点特别的是,由于默认的文件扩展名为 .asm ,所以在编译 .asm 的汇编源程序时可以不用指定源程序所在文件的扩展名。

我们将一开始编辑好的汇编源程序所在的文件输入以进行编译

image

指定文件所在路径后按  Enter  键

image

此时可以看到编译器提示需要输入要编译出的目标文件的名称,由于在一开始已经指定了 BoyXiao. asm ,

所以编译器自动指定了目标文件的名称为 BoyXiao. obj 的名称,如果在这里不做修改的话,

则编译器会以默认目标文件名称 BoyXiao. obj 进行输出,在这里我并不改变名称,所以直接按 Enter 键即可

image

此时又提示需要输入列表文件的名称,其实是完全可以不要让编译器生成这个 LST 文件的,所以也不需要进行输入,

直接按 Enter 键即可

image

此时又提示需要输入交叉引用文件的名称,这里也完全可以不要让编译器生成这个 CRF 文件,

所以也不需要进行输入,直接按 Enter 键即可

image

至此,汇编源程序编译成功,

编译得到的结果就是在我的 E:\Tools\MASM\MASM 5.0 目录下生成了一个 BoyXiao.obj 文件

image

下面就是要实现对目标文件的连接

经过编译操作后,我们得到了一个 .obj 的目标文件,但很显然,这还并不是一个可执行文件,

下面就需要对目标文件进行连接,从而得到一个可执行文件。

一般来说,需要准备一个连接器,这里我使用的是微软提供的 Linker 连接器,即 LINK.EXE ,

image

进入 LINK.EXE 文件所在目录,直接运行 LINK.EXE

image

image

此时提示需要输入被连接的目标文件的名称,这里也就是  BoyXiao.obj  ,

由于我的 BoyXiao.obj 和 Link.exe 在同一目录下,所以不需要指定路径,直接给出 .obj 的名称即可,

image

按  Enter  键

image

这里提示需要输入要生成的可执行文件的名称,此时如果想要将可执行文件输入到指定目录下,

则需要指定目录,否则只需要指定名称即可,并且可以看到名称已有默认值:BOYXIAO.EXE

在这里我选择默认值,所以直接按 Enter 键即可

image

按  Enter  键

image

又继续提示需要输入映像文件的名称,在这里,不需要生成这个文件,所以直接按 Enter 键即可

image

此时又提示需要输入库文件的名称,由于我们的这个程序中没有使用任何的子程序,

也就是根本没有调用什么库文件,所以这里也可以直接按 Enter  键处理

image

至此,整个目标文件的连接工作结束,得到的结果是一个 EXE 文件

image

执行汇编程序

image

其实执行起来是看不到什么结果的,因为上面的汇编代码没有输出任何内容,而只是改变了几个寄存器的值而已,

自然也就看不到任何的输出了。

第二种方式:使用 Edit + MASM 5.0 编译器 + Linker 连接器 (简化版)

这种方式其实和第一种方式说不上有什么区别,只不过在编译和连接过程中使用了很多编译器和连接器的默认设置而已

软件准备:

和第一种方式一样

编辑汇编源代码:

和第一种方式一样,也可以是直接使用文本编辑器编辑即可

编译编辑好的汇编源代码

直接到 MASM.EXE 文件目录,然后直接使用 masm 编译指定路径的文件即可

特别注意的是,需要在目录的后面加上 “;”

image

image

同样在 E:\Tools\MASM\MASM 5.0 目录下生成了  BoyXiao.obj 目标文件

image

实现目标文件的连接

同样,直接下到连接器 LINK.EXE 文件所在的目录,然后直接使用 LINK 连接指定的目标文件即可

同样需要注意在目录或文件名的后面加上 “;”

image

image

可以看到连接成功了,从而生成了可执行文件,当然这个可执行文件运行的效果和第一种方式中一样,

即看不到任何输出

image

第三种方式:MASM For Windows 集成开发环境

上面的两种方式都显得非常麻烦,编译了还要连接,谁有那么多时间去浪费啊,

所以,下面介绍的这个 MASM For Windows 集成开发环境就显得非常有优势了,

软件准备:

MASM For Windows 集成开发环境,我这里使用的是 2010 版本,大小 15.5 MB

实现 HelloWorld

直接打开 MASM For Windows 集成开发环境,然后找到范例程序,然后直接运行即可

image

image

可以看出,使用这个东东确实会方便很多很多

第四种方式:使用 Visual  Studio 来实现开发汇编程序

软件准备:

既然是使用  Visual  Studio  来开发了,自然就需要  Visual  Studio  IDE 了,

在这里呢,我使用的是  Visual  Studio  2010 ,当然 2008 和 2005 都是可以的,

只不过在一些设置上有些许区别而已,在这里,我也不做区分,大家感兴趣的可以去网上淘一大把,

然后就是<<Intel  汇编语言程序设计>>中的 Irvine 包,这个在网上也有一大把

VS 2010 设置:

在  VC++  中新建一个空项目,取名为  Test

image

定制  VC++  工程构建规则

image

image

设置完  VC++  生成自定义项文件后,再添加一个  C++  文件,并注意取名时后缀名记为  .asm

image

设置  VC++  工程的项目属性

image

需要添加库路径,这里的库路径指的是 <<Intel  汇编语言程序设计>> 中的 Irvine 库

image

设置包含路径

image

设置依赖库文件,添加 Irvine32.lib

image

设置项目输出

image

设置生成汇编代码列表,添加  $(ProjectName).lst  属性

image

Hello World 程序:

image

直接运行即可

image

结束语

花了这么多的截图来介绍这四种汇编程序开发方式,也算是良苦用心了,事实上呢,这四种方式,

我们并没有必要全部掌握,我们只需找到适合自己的方式即可,

比如,初学的话,我觉得  MASM  For  Windows  IDE  就非常不错,

而至于系统性的开发,尤其是对于 Win32  汇编程序的开发,则选择  Visual  Studio  是个不错的选择。

2010 年 11 月 05 日

[转载]浅谈C# 中的lock 方法与Monitor 类的关系_以及同步与互斥

mikel阅读(824)

[转载]浅谈C# 中的lock 方法与Monitor 类的关系_以及同步与互斥 – xugang – 博客园.

这是一个旧瓶新装的话题。只是将我今日的所见所思予以实践和整理,以备往后所用。同时也提供给大家,希望能有所帮助。

A  从单例模式说起

代码如下:

class Program
{
 static void Main(string[] args)
 {
 Singleton demo1 = Singleton.Init();
 Singleton demo2 = Singleton.Init();
 }
}

public class Singleton
{
 private Singleton() { }

 private static Singleton instance = null;
 private static readonly object singleObj = new object();

 public static Singleton Init()
 {
 if (null == instance)
 {
 lock (singleObj) //singleObj 不能使用instance 代替
 {
 if (null == instance)
 {
 instance = new Singleton();
 }
 }
 }
 return instance;
 }
}

关于单例模式,大家可以参考:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html

B  关于lock 方法

在以上单列模式的代码中:

如果将: private static readonly object singleObj = new object();
修改为: private static readonly object singleObj = null;

将在lock( ) 方法处,抛出未处理的异常:System.ArgumentNullException: 值不能为空!

●  lock 关键字将语句块标记为临界区

lock( obj ) 方法中的obj 对象为:获取排他锁的指定对象

obj 对象为null 将导致 ArgumentNullException 异常。

lock 方法在MSIL 中会被编译成 Monitor.Enter( ) 和 Monitor.Exit( ) 。例如:

public static void MyLock()
{
 lock (typeof(Program))
 {
 }
}

以上代码通过lock 语句使MyLock 同步,这个方法被编译成MSIL 后,代码如下图所示:

image

从上图被标注的区域可以看到:一条lock 语句被编译成了调用Monitor 的Enter 和Exit 的方法。
lock 的功能就相当于直接调用Monitor 的Entry 方法,并在结束后会自动调用Monitor 的Exit 方法解除锁定。

C  关于Monitor 类

Monitor 类属于System.Threading 命名空间;

Monitor 类提供同步对对象的访问的机制;

使用 Monitor 锁定对象(即引用类型)而不是值类型;

Monitor 类型对于多线程操作是安全的;

Monitor 类的示例一:

class Program2
{
 static void Main(string[] args)
 {
 MyMonitor1 mon_1 = new MyMonitor1();
 mon_1.Test();
 }
}

class MyMonitor1
{
 private object obj = new object();

 public void Test()
 {
 //开始锁定
 System.Threading.Monitor.Enter(obj);
 try
 {
 //lock 的区域
 }
 catch (Exception e)
 {
 // 异常处理代码
 }
 finally
 {
 //解除锁定
 System.Threading.Monitor.Exit(obj);
 }
 }
}

Monitor 类的示例二:

class Program3
{
 static void Main(string[] args)
 {
 //多个线程调用Test方法
 Thread t1 = new Thread(MyMonitor2.Test);
 Thread t2 = new Thread(MyMonitor2.Test);
 t1.Start();
 t2.Start();
 }
}
class MyMonitor2
{
 private static object obj = new object();

 public static void Test()
 {
 //使用TryEntry方法设置一个锁定超时
 if (Monitor.TryEnter(obj, 2000))
 {
 try
 {
 Console.WriteLine("等待4秒开始");
 Thread.Sleep(4000);
 Console.WriteLine("等待4秒结束");
 }
 finally
 {
 //解除锁定
 Monitor.Exit(obj);
 }
 }
 else 
 {
 Console.WriteLine("已超时2秒!");
 }

 }
}

D  关于同步与互斥

关于同步的问题,可以使用Monitor 类来解决。

在使用Monitor 类的时候,建议将Monitor.Enter( ) 方法替换成Monitor.TryEnter( ) 方法。

使用Monitor.Enter( ) 方法时,代码如下:

Monitor.Entry(lockObj);
try
{
 // lockObj的同步区
}
catch(Exception e)
{
 // 异常处理代码
}
finally
{
 Monitor.Exit(lockObj); // 解除锁定
}

注意:如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。

使用Monitor.TryEnter( ) 方法时,代码如下:

if(Monitor.TryEntry(lockObj, 1000))
{
 try
 {
 }
 finally
 {
 Monitor.Exit(lockObj);
 }
}
else
{
 // 超时后的处理代码
}

注意:使用TryEntry方法设置一个锁定超时,单位是毫秒。

上面的代码设置了锁定超时时间为1秒。

如果在1秒钟之内,lockObj 还未被解锁,TryEntry 方法就会返回 false;

如果在1秒钟之内,lockObj 被解锁,TryEntry 方法就会返回 true。

这样,可以使用TryEntry 方法来避免死锁。

同步与互斥 示例一:

class Program4
{
 static void Main(string[] args)
 {
 Thread A = new Thread(TestClass1.GetA);
 A.Name = "Thread_A ";
 Thread B = new Thread(TestClass1.GetB);
 B.Name = "Thread_B ";
 A.Start();
 B.Start();
 }
}

class TestClass1
{
 private static object resource_A = new object();
 private static object resource_B = new object();

 public static void GetA()
 {
 MyWrite("in GetA()");
 if (Monitor.TryEnter(resource_A, 2000))
 {
 MyWrite("get resource_A");
 GetB();
 Thread.Sleep(2000);
 Monitor.Exit(resource_A);
 MyWrite("exit resource_A");
 }
 else
 {
 MyWrite("no has resource_A");
 }
 }

 public static void GetB()
 {
 MyWrite("in GetB()");
 if (Monitor.TryEnter(resource_B, 1000))
 {
 MyWrite("get resource_B");
 GetA();
 Thread.Sleep(1000);
 Monitor.Exit(resource_B);
 MyWrite("exit resource_B");
 }
 else
 {
 MyWrite("no has resource_B");
 }
 }

 //自定义打印方法
 private static void MyWrite(string str)
 {
 Console.WriteLine(Thread.CurrentThread.Name + str);
 }
}

结果如下:

TryEnter1

同步与互斥 示例二:

class Program5
{
 static void Main(string[] args)
 {
 Thread A = new Thread(TestClass2.GetA);
 A.Name = "Thread_A ";
 Thread B = new Thread(TestClass2.GetB);
 B.Name = "Thread_B ";
 A.Start();
 B.Start();
 }
}

class TestClass2
{
 //排他锁的对象 A
 private static object resource_A = new object();
 //排他锁的对象 B
 private static object resource_B = new object();

 public static void GetA()
 {
 MyWrite("in GetA()");
 if (Monitor.TryEnter(resource_A, 1000))
 {
 MyWrite("get resource_A");
 Thread.Sleep(1000);
 //GetB();
 if (Monitor.TryEnter(resource_B, 2000))
 {
 Monitor.Exit(resource_B);
 }
 Monitor.Exit(resource_A);
 MyWrite("exit resource_A");
 }
 else
 {
 MyWrite("no has resource_A");
 }
 }

 public static void GetB()
 {
 MyWrite("in GetB()");
 if (Monitor.TryEnter(resource_B, 1000))
 {
 MyWrite("get resource_B");
 Thread.Sleep(1000);
 //GetA();
 if (Monitor.TryEnter(resource_A, 2000))
 {
 Monitor.Exit(resource_A);
 }
 Monitor.Exit(resource_B);
 MyWrite("exit resource_B");
 }
 else
 {
 MyWrite("no has resource_B");
 }
 }

 //自定义打印方法
 private static void MyWrite(string str)
 {
 Console.WriteLine(Thread.CurrentThread.Name + str);
 }
}

结果如下:

TryEnter2

参考文章:

浅谈c#中使用lock的是与非 作者:Jeff Wong

同步技术之Monitor 作者:银河使者

示例下载

[转载]LogParser的IIS网站分析技巧

mikel阅读(1188)

[转载]LogParser的IIS网站分析技巧 – 虹桥路3号 – 博客园.

LogParser的IIS网站分析技巧

LogParser介绍

LogParser是微软的一个免费的日志分析工具,它支持许多格式的文件类型。主要有如下几类:

· IIS 文件格式

Ø IISW3C: IIS产生的W3C扩展格式

Ø IIS: IIS专有格式.

Ø BIN: IIS的BIN格式.

Ø IISODBC: IIS可以把日志存储在数据库中。LogParser可以分析存储在数据库中的IIS日志.

Ø HTTPERR: Http.sys日志格式.

Ø URLSCAN: URLScan 日志格式.

· 通用文本格式

Ø CSV: 逗号分隔符文件.

Ø TSV: 以空格或者以制表符分隔的文件.

Ø XML: XML格式.

Ø W3C: W3C格式.

Ø NCSA: NCSA格式.

Ø TEXTLINE: 普通文件文件. LogParser可以按行返回内容

Ø TEXTWORD: LogParser可以把按字返回内容.

· 系统信息

EVT: 事件日志文件.

FS: 文件目录.

REG: 注册表格式.

ADS: AD信息.

另外还有一些其它格式,如NetMon, ETW等,在此不详述了。

LogParser原理

LogParser架构如下图所示:

clip_image001

注:图片引自http://e-mojo.net/wp-content/uploads/2009/11/logparser_architecture.gif

LogParser的核心为类SQL引擎,主要用于LogParser的SQL解析。使用LogParser我们可以把日志文件转换为很多格式,然后,我们可以用自己顺手的工具对其进行分析。

需要注意的是,如果我们要输出图形格式,必须安装Office Web组件。

IIS高级日志分析

本文主要介绍一些高级IIS日志分析功能,基本的分析功能请参考这些BLOG:

http://hi.baidu.com/tpxc/blog/item/b6e4561060f2ecf9c2ce7931.html

http://www.cnblogs.com/yonglun/archive/2007/02/20/652929.html

每天用户访问数

logparser “SELECT To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time))) AS [Date1], c-ip AS CIP INTO IISHC_DistinctClientIPPerDay.csv FROM *.log GROUP BY [Date1], CIP” -i:IISW3C -o:CSV -recurse:-1

我们按日期进行汇总,主要是利用Group by 实现。由于IIS日志中时间为UTC格式,因此,我们需要使用To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))把其转换为本地时间。

recurse:-1参数使LogParser对子目录下所有文件进行统计。

本例中产生一个CSV文件,我们可以使用Excel进行处理,得出每天用户数曲线(当然,我们也可以直接用LogParser产生图形)。如下是一个例子:

clip_image003

每小时用户访问数

logparser “SELECT TO_LOCALTIME(QUANTIZE(TO_TIMESTAMP(date, time),3600)) AS Hours, COUNT(*) AS Hits INTO IISHC_RequestsPerHour.csv FROM *.log where To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))=TIMESTAMP(’10/08/2010′,’MM/dd/yyyy’ ) GROUP BY Hours ORDER BY Hours” -i:IISW3C -o:CSV -recurse:-1

主要用法与上例类似。不过我们需要指定日期。指定日期在where To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))=TIMESTAMP(’10/08/2010′,’MM/dd/yyyy’ )中实现。

clip_image005

拆分文件

缺省情况下,IIS每天产生一个日志文件。对于一些特别繁忙的网站来说,IIS日志文件可能会非常大。我曾经有一个客户,每个日志文件有2个G之多。这么大的文件用LogParser进行分析时会非常慢,同时也很容易报错。

解决办法是把日志文件进行拆分成许多小文件分别进行分析。如下命令可以把一个IIS日志按小时分成24个文件:

logparser “SELECT REPLACE_CHR(REPLACE_CHR(TO_STRING(TO_LOCALTIME(QUANTIZE(TO_TIMESTAMP(date, time), 3600)), ‘yyyy-MM-dd hh:mm:ss’), ‘:’, ‘_’), ‘ ‘, ‘_’), date, time, c-ip, cs-uri-stem, cs-uri-query, sc-status, sc-substatus, sc-win32-status, sc-bytes, cs-bytes, time-taken FROM ex080114.log TO ex080114_*.log” -i:IISW3C -o:W3C

这里边的技巧请大家自己去理解J 怎么样?

附录

1. LogParser下载地址

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&displaylang=en

2. Office 2003 Web Component

http://www.microsoft.com/downloads/en/details.aspx?FamilyId=7287252C-402E-4F72-97A5-E0FD290D4B76&displaylang=en

3. Security Update for Microsoft Office Web Components

http://www.microsoft.com/downloads/en/details.aspx?familyid=95c94c9a-6aca-42fb-9679-3234f06c72f7&displaylang=en

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

mikel阅读(1047)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2) – 刘铭.net-OPS.cc – 博客园.

webHandler执行类的方法,

但在多数情况下,我们会将WebHandler封装进一个单独的动态链接库,我们需要将引用WebHandler DLL的程序集或程序集中的任意一个类的Type做为参数传递给WebHandler,

这样就可以在WebHandler中利用反射调用引用WebHandler类库的程序集中的代码!

实现代码如下:

/* *
 * name     : ExecuteHandler.cs 
 * author   : newmin
 * date     : 09/29 2010
 * note     : 用来处理请求,请求的URI参数如:Exc.ashx?cmd=IP,GetIP,127.0.0.1
 * 
 * 要执行操作的类必需要程序集名称命名空间下:
 * 如要执行AtNet.Security下的User类,则User类的命名空间为:HuiShi.Security.User
 * 调用方式**.ashx?cmd=User,GetScore,newmin
 * 
 * */
namespace AtNet.Web
{
    using System;
    using System.Web;
    using System.Reflection;
    using System.Collections.Generic;

    public abstract class ExecuteHandler : IHttpHandler
    {
        //绑定类型用于获取程序集,只能在子类的静态构造函数中赋值
        protected static Type _type;
        #region IHttpHandler 成员
        public bool IsReusable{ get; set; }
        
        public void ProcessRequest(HttpContext context)
        {
            string cmd=context.Request["cmd"].Replace("+"," ");         //将空格做为+号替换

            string[] args = cmd.Split(',');
            if (args.Length > 2)
            {
                //获取执行当前代码的程序集并创建实例
               Assembly ass = Assembly.GetAssembly(_type);
                object obj = ass.CreateInstance(_type.Namespace+"."+args[0], true);

                //获取实例类型
                Type type=obj.GetType();

                //未添加WebExecuteAttribute特性的类将不被执行
                object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
                WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
                if (attr == null) { context.Response.Write("此模块不允许被执行!"); return; }

                //获取方法并执行
                MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
                object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(','))
                        :method.Invoke(obj, null);

                //如国返回String类型或值类型则输出到页面
                if (method.ReturnType == typeof(string) ||obj is ValueType)
                    context.Response.Write(returnObj.ToString());
            }
        }

        #endregion
    }
}

我们需在继承ExecuteHandler的类的静态构造函数中对_type赋值:

namespace AtNet.Web.Tools
{
    using System;
    using System.Reflection;

    public class WebHandler:AtNet.Web.ExecuteHandler
    {
        static WebHandler()
        {
           _type = typeof(WebHandler);
       }
    }
}

这样我们就能在将ExecuteHandler分离出来,被别的项目所引用

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

mikel阅读(1032)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1) – 刘铭.net-OPS.cc – 博客园.

一般处理程序(.ashx)比Web窗体文件(.aspx)性能更好,再不涉及到html的场景中经常用到!

通过VS创建的ashx文件包括代码后置文件,而实际上在ashx文件中定义只需要声明Web Handler并添加class

如: <%@ WebHandler Class=”Web.Handler” %>

我们可以在项目里面创建一个实现IHttpHandler接口的类,然后将ashx文件class设为该类的名称,这样维护起来是不是更方便?

大多数的同学可能就直接在IHttpHandler的ProccessRequest(HttpContext context)方法中添加自己的代码了,但如果网站包含50个ashx文件的话又会怎么样呢?下面我来阐述一个思路

我们是否可以将要请求的代码包含在一个个的类里,然后在ProccessRequest方法里利用反射技术执行代码就好了呢?

反射,程序员的快乐!

下面我们一步一步开始实现我们的想法:

首先我们需要为被执行代码添加授权,表明他能通过WebHandler执行,要不然就能通过WebHandler执行类库里的任何类!

1 代码:WebExecuteAttribute.cs
2 namespace HuiShi.Web
3 {
4 using System;
5 [AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
6 public class WebExecuteAttribute : Attribute{}
7 }
8
9 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

下面该是反射技术大展神手的时候了!先说明一下我们请求的URI格式如下:

http://localhost:11080/exc.ashx?cmd=IPQuery,GetNameByAddress,127.0.0.1

参数以”,”格开,IPQuery为类,GetNameByAddress为IPQuery的方法,GetNameByAddress后的为方法的参数

实际上执行的代码为:

01 namespace HuiShi.Web
02 {
03 using System;
04 using System.Web;
05
06 [WebExecute]
07 public class IPQuery
08 {
09 public string GetNameByAddress(string address)
10 {
11 return “newmin’s website www.atnet.cc“;
12 }
13 }
14 }

在代码中通过”,”来将参数传给方法,并判断方法的返回值是否可以输出到页面,可以的话就输出到页面!

01 代码:ExecuteHandler.cs
02
03 namespace HuiShi.Web
04 {
05 using System;
06 using System.Web;
07 using System.Reflection;
08 using System.Collections.Generic;
09
10 public class ExecuteHandler : IHttpHandler
11 {
12
13 #region IHttpHandler 成员
14 public bool IsReusable{ get; set; }
15 public void ProcessRequest(HttpContext context)
16 {
17 string cmd=context.Request["cmd"].Replace(“+”,” “); //将空格做为+号替换
18
19 string[] args = cmd.Split(‘,’);
20 if (args.Length > 2)
21 {
22 //获取执行当前代码的程序集并创建实例
23 Assembly ass = Assembly.GetAssembly(this.GetType());
24 object obj = ass.CreateInstance(this.GetType().Namespace+”.”+args[0], true);
25
26 //获取实例类型
27 Type type=obj.GetType();
28
29 //未添加WebExecuteAttribute特性的类将不被执行
30 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
31 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
32 if (attr == null) { context.Response.Write(“此模块不允许被执行!”); return; }
33
34 //获取方法并执行
35 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
36 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(‘,’))
37 :method.Invoke(obj, null);
38
39 //如国返回String类型或值类型则输出到页面
40 if (method.ReturnType == typeof(string) ||obj is ValueType)
41 context.Response.Write(returnObj.ToString());
42 }
43 }
44
45 #endregion
46 }
47 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

然后我们创建1个WebHandler将其Class设为”HuiShi.Web.ExecuteHandler”,再在 ExecuteHandler命名空间下创建几个类,并用[WebExecute]特性修饰,这样我们只需要加代码而不用加文件就可以完成操作了!是不是 省了很多功夫,将使用WebHandler请求的类放到1个文件中集中管理,不是方便了代码组织管理吗?

想想上面的实现,没什么错误,但如果我们要将WebHandler封装成一个动态链接库,引用到其他项目的话呢?

具体实现请浏览:更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

[转载]asp.net中的HttpHandler解决方案:OPS.ExecuteHandler组件

mikel阅读(839)

[转载]asp.net中的HttpHandler解决方案 – OPS.ExecuteHandler组件 – SkyBOOB – 博客园.

请看介绍这个解决方案的两篇文章

更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

此次在原有基础上进行大规模的改进和升级:

添加 IWebExecute 接口。用于对执行类和类的方法时候进行更多控制!

内置:PostAttributeGetAttribute 均实现了IWebExecute接口!

使用方法如下:

一:引用OPS.Lib.dll到项目中

二:向ExecuteHandler注册

01 namespace OPS.HandlerDemo
02 {
03 using OPS.Web; //引用命名空间
04
05 public class WebHandler:ExecuteHandler
06 {
07 static WebHandler()
08 {
09 _type=typeof(Login);
10 }
11 }
12 }

三:注册Handler载体 — 一般程序处理程序(.ashx后缀的文件)

添加ops.ashx文件,代码如下:

1 <%@ WebHandler Class="OPS.HandlerDemo.WebHandler" %>

我们使用ops.ashx来执行类和调用类的方法

ops.ashx参数说明:

ops.ashx?task=类名,方法名,参数(多个参数用”,”隔开)

例:ops.ashx?task=login,enter,ops,ops

(执行login类的enter方法,两个ops为enter方法的两个参数)

四:创建可被ExecuteHandler执行的类

如果需要被ExecuteHandler执行,则需要为类型添加 WebExecuteable 特性

01 namespace OPS.HandlerDemo.Login
02 {
03 [WebExecuteable] //必须添加此特性类型的方法才能被调用
04 public class Login
05 {
06 public string Enter(string username, string password)
07 {
08 return "成功";
09 }
10 }
11 }

运行ops.ashx?task=login,enter,ops,ops,你将会看见成功字样!

五:使用内置的Post和Get特性

1.为方法添加Post特性将可以阻止用户发送GET请求,如:

01 namespace OPS.HandlerDemo.Login
02 {
03 [WebExecuteable] //必须添加此特性类型的方法才能被调用
04 public class Login
05 {
06 [Post]
07 public string Enter(string username, string password)
08 {
09 return "成功";
10 }
11 }
12 }

在浏览器中直接输入地址将出现结果如图:

2.Get特性,跟Post同理

3.阻止短时间内的多次反复请求

只需要为Get或Post特性的AllowRefreshMillliSecond属性赋值就可以简单实现!如:

1 //1秒种之内只允许请求一次,否则提示服务不可用
2 [Get(AllowRefreshMillliSecond=1000)]
3 public string Enter(string username, string password)
4 {
5 return "成功";
6 }

六:为ExecuteHandler创建自定义特性

我们将通过实例创建一个NotLoginAttribute让已经登陆的用户不能再次登陆

01 using OPS.Web;
02
03 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=false,Inherited=false)]
04 public class NotLoginAttribute:Attribute,IWebExecute
05 {
06 #region IWebExecute 成员
07 //实现IWebExecute的方法
08 public void PreExecuting()
09 {
10 HttpContext.Current.Response.Write("已经登陆");
11 HttpContext.Current.Response.End();
12 }
13 #endregion
14 }

并在Login类的Enter方法上应用此特性

01 namespace OPS.HandlerDemo.Login
02 {
03 using OPS.Web;
04 [WebExecuteable] //必须添加此特性类型的方法才能被调用
05 public class Login
06 {
07 [Get]
08 [NotLogin]
09 public string Enter(string username, string password)
10 {
11 return "成功";
12 }
13 }
14 }

再次打开浏览器请求ops.ashx?task=login,enter,ops,ops

结果如下:

该组件在创建Ajax应用时候能简化很多工作,使用该组件可以称的上是在写类型,而不是写页面

点击这里下载ExecuteHandler的代码文件:

本地下载地址:http://files.cnblogs.com/newmin/ops.lib.rar

官方主页下载:http://www.ops.cc/lib/

[转载]InfoQ: WCF的未来是RESTful

mikel阅读(1043)

[转载]InfoQ: WCF的未来是RESTful.

Windows通信基础(WCF)的产品经理,Glenn Block在主题为“WCF,Evolving for the Web”的在线研讨会上表示,微软面向服务应用的构建框架将进行根本性的重构,新的架构将以HTTP为中心。

在这次在线会议的开始,Block总结了业界的当前趋势:

  • 向基于云的计算转变
  • SOAP逐渐淡出
  • 浏览器运行于各类设备之上日渐盛行
  • REST采纳的增长
  • 类似OAuth、WebSocket这样标准的出现

他表示,WCF的当前架构在很大程度上是基于SOAP的,如下图示:

image

WCF的一个关键特性是,在相同编程模型下支持多种传输协议(HTTP、TCP、命名管道)。遗憾的是,一旦触及HTTP,它的大量好处(伸缩性、 内容协商)就消失了,原因在于WCF只是把它当作一种传输手段。因此,Block期望将支持HTTP的WCF视为一种具备简单灵活编程模型的一流应用协 议。如下图示:

image

HTTP是在.NET 3.5中引进的,这让创建通过HTTP访问的服务成为可能,但是“没有办法访问所有HTTP必须提供的东西,它是一种非常扁平的模型,面向RPC,但 Web不是这样的。在Block看来,Web是一种非常丰富的资源集”。与其将当前的WCF改造成可以在HTTP之上正常工作,Block认为WCF应该 “以HTTP的思想,使用RESTful方式”重新构架。

WCF将包含助手API,完成预处理HTTP请求或响应、解析和操纵所有参数、将HTTP信息封装到对象中以供未来处理之用。只要愿意,用户就可以 利用它将自己从直接处理HTTP内部细节的痛苦中解脱出来。这个特性还将提供一种插件功能,主要针对像JSON, Atom, OData等这样的数据格式的媒体类型格式化器。WCF将内置部分格式的支持,但是用户能够加入自己的格式化器。

新的WCF已经正在构建当中,Block演示了使用它的样例代码,但他表示这个特性集和WCF将来的样子尚未最终定案。他们不久将在CodePlex上发布框架的初始版本,让社区能够进行测试和反馈,让WCF的未来逐渐成型。更多的细节将在PDC 2010大会期间得到公开。

更新

我们向Glenn Block问起了其他协议,尤其是SOAP,的未来状况。他的答复是,WCF将完全支持现有的技术栈,当前的发展旨在将WCF演变成完全支持HTTP,而又不宣布放弃WCF目前已经取得的成果。

现在,WCF社区站点搭建完成,所有对WCF演变感兴趣的人们可以通过它了解WCF的近况。

在PDC 2010大会上,Glenn Block在WCF未来和它与微软在SOA技术中的当前投资之间的关系里给出了更多细节。

查看英文原文: The Future of WCF Is RESTful [Updated]