昨天我在实现《通过扩展改善ASP.NET MVC的验证机制[使用篇]》的时候为了Attribute 的一个小问题后耗费了大半天的精力,虽然最终找到了问题的症结并解决了问题,但是我依然不知道微软如此设计的目的何在。闲话少说,我们先来演示一下我具体遇到的问题如何发生的。
目录:
一、问题重现
二、通过Attribute的Equals方法和GetHashCode方法进行对等判断
三、Attribute对象和Attribute类型的HashCode
四、倘若为FooAttribute添加一个属性/字段
五、Attribute的GetHashCode方式是如何实现的?
一、问题重现
如下面的代码片断所示,我们定义了两个Attribute。其中抽象的BaseAttribute中定义了一个Name属性,而FooAttribute直接继承自BaseAttribute,并不曾定义任何属性和字段。在类型Bar上,我们应用了三个FooAttribute特性,其Name属性分别为A、B和C。
1: [Foo(Name = "A")]
2: [Foo(Name = "B")]
3: [Foo(Name = "C")]
4: public class Bar
5: {
6:
7: }
8:
9: [AttributeUsage( AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
10: public abstract class BaseAttribute : Attribute
11: {
12: public string Name { get; set; }
13: }
14: public class FooAttribute : BaseAttribute
15: {
17: }
在我的程序中具有类似于如下一段代码:我们调用Bar类型对象的GetCustomAttributes方法得到所有的Attribute特性并筛选出类型为FooAttribute特性列表,毫无疑问,这个列表包含Name属性分别为A、B和C的三个FooAttribute对象。然后我们从该列表中将Name属性为C的FooAttribute对象移掉,最终打印列表出余下的FooAttribute的Name属性。
1: var attributes = typeof(Bar).GetCustomAttributes(true).OfType<FooAttribute>().ToList<FooAttribute>();
2: var attribute = attributes.First(item => item.Name == "C");
3: attributes.Remove(attribute);
4: Array.ForEach(attributes.ToArray(), a => Console.WriteLine(a.Name));
按照绝大部分人思维,最终打印出来的肯定是A和B,但是真正执行的结果却是B和C。下面所示的确实就是最终的执行结果:
二、通过Attribute的Equals方法和GetHashCode方法进行对等判断
然后我们通过如下的方式判定两个FooAttribute对象的对等性。如下面的代码片断所示,我们直接调用构造函数创建了两个FooAttribute对象,它们的Name属性分别设置为“ABC”和“123”。最后两句代码分别通过调用Equals和HashCode判断两个FooAttribute是否相等。
1: FooAttribute attribute1 = new FooAttribute{ Name = "ABC" };
2: FooAttribute attribute2 = new FooAttribute{ Name = "123"};
3: Console.WriteLine("attribute1.Equals(attribute2) = {0}",attribute1.Equals(attribute2));
4: Console.WriteLine("attribute1.GetHashCode() == attribute2.GetHashCode() = {0}", attribute1.GetHashCode() == attribute2.GetHashCode());
通过如下的输出结果我们可以看出这两个分明具有不同Name属性值FooAttribute居然被认定为是“相等的”:
1: attribute1.Equals(attribute2) = True
2: attribute1.GetHashCode() == attribute2.GetHashCode() = True
三、Attribute对象和Attribute类型的HashCode
实际上两个FooAttribute对象的HashCode和FooAttribute类型是相等的。为此我们添加了额外两行代码判断typeof(FooAttribute)和FooAttribute对象的HashCode之间的对等性。
1: FooAttribute attribute1 = new FooAttribute{ Name = "ABC" };
2: FooAttribute attribute2 = new FooAttribute{ Name = "123"};
3: Console.WriteLine("attribute1.Equals(attribute2) = {0}",attribute1.Equals(attribute2));
4: Console.WriteLine("attribute1.GetHashCode() == attribute2.GetHashCode() = {0}", attribute1.GetHashCode() == attribute2.GetHashCode());
5: Console.WriteLine("attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = {0}",
6: attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode());
typeof(FooAttribute)和FooAttribute对象之间对等性可以通过如下的输出结果看出来:
1: attribute1.Equals(attribute2) = True
2: attribute1.GetHashCode() == attribute2.GetHashCode() = True
3: attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = True
四、倘若为FooAttribute添加一个属性
但是不要以为Attribute的GetHashCode方法总是返回类型本身的HashCode,如果我们在FooAttribute定义一个属性/字段,最终的对等性判断又会不同。为此我们在FooAttribute定义了一个Type属性。
1: public class FooAttribute : BaseAttribute
2: {
3: public Type Type {get;set;}
4: }
然后我们在创建FooAttribute时指定其Type属性:
1: FooAttribute attribute1 = new FooAttribute{ Name = "ABC", Type=typeof(string)};
2: FooAttribute attribute2 = new FooAttribute{ Name = "ABC" , Type=typeof(int)};
3: Console.WriteLine("attribute1.Equals(attribute2) = {0}",attribute1.Equals(attribute2));
4: Console.WriteLine("attribute1.GetHashCode() == attribute2.GetHashCode() = {0}", attribute1.GetHashCode() == attribute2.GetHashCode());
5: Console.WriteLine("attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = {0}",
6: attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode());
现在具有不同Type属性值得两个FooAttribute就不相等了,这可以通过如下所示的输出结果看出来:
1: attribute1.Equals(attribute2) = False
2: attribute1.GetHashCode() == attribute2.GetHashCode() = False
3: attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = False
五、Attribute的GetHashCode方式是如何实现的?
Attribute的HashCode是由定义在自身类型的字段值派生,不包括从基类继承下来的属性值。如果自身类型不曾定义任何字段,则直接使用类型的HashCode,这可以通过Attribute的GetHashCode方法的实现看出来,而Equals的逻辑与此类似。
1: [SecuritySafeCritical]
2: public override int GetHashCode()
3: {
4: Type type = base.GetType();
5: FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
6: object obj2 = null;
7: for (int i = 0; i < fields.Length; i++)
8: {
9: object obj3 = ((RtFieldInfo) fields[i]).InternalGetValue(this, false, false);
10: if ((obj3 != null) && !obj3.GetType().IsArray)
11: {
12: obj2 = obj3;
13: }
14: if (obj2 != null)
15: {
16: break;
17: }
18: }
19: if (obj2 != null)
20: {
21: return obj2.GetHashCode();
22: }
23: return type.GetHashCode();
24: }
[02] 编程技巧
摘要:
昨天我为了Attribute 的一个小问题后耗费了大半天的精力,虽然最终找到了问题的症结并解决了问题,但是我依然不知道微软如此设计的目的何在。闲话少说,我们先来演示一下我具体遇到的问题如何发生的。
阅读全文
posted @
2012-01-12 17:03 Artech 阅读(815) |
评论 (9) 编辑
摘要:
System.Transactions.TransactionScope为了提供一种非常方便的实现分布式事务的方式,但是在某些情况下为了阻止本地事务向分布式事务提升,我们只能通过DbTransaction进行事务控制。在进行数据库操作的时候,我们经常会遇到这样的事务场景:当某个方法单独执行的时候,它应该在一个单一的DbTransaction中执行;当多个方法一起执行的时候,它们应用共同在DbTransaction中执行。在本篇文章中我们通过对DbTransaction进行封装,提供一种类似于TransactionScope的编程方式来解决这个问题。
阅读全文
posted @
2012-01-05 17:51 Artech 阅读(936) |
评论 (22) 编辑
摘要:
在《集成EntLib实现ASP.NET MVC的异常处理》我们实现采用EntLib的Exception Handling Application Block(EHAB)进行异常的处理,并导向指定的出错页面。在这篇文章中我们做一些改变,直接将处理过的异常消息显示在本页的ValidationSummary中。
阅读全文
posted @
2011-12-14 16:54 Artech 阅读(1685) |
评论 (11) 编辑
摘要:
在项目开发中,我们会使用到很多的描述性文字,比如验证消息、错误消息和确认消息等,让这些文本消息具有可维护性具有重要的意义。在我们的项目开发中使用的是专门的一个维护消息的组件。在这篇文章中将会通过扩展现有的ValidationAttribute特性让ASP.NET MVC应用可以使用我们的消息组件来获取验证消息。
阅读全文
posted @
2011-12-14 10:45 Artech 阅读(1860) |
评论 (13) 编辑
摘要:
谈到IoC和ASP.NET的集成,很多人会先后想到Ninject,不过我们个人还是倾向于Unity。这篇文章简单地介绍如果创建基于Unity的ControllerFactory。
阅读全文
posted @
2011-12-13 16:35 Artech 阅读(2047) |
评论 (12) 编辑
摘要:
本篇通过自定义ASP.NET MVC的异常筛选器实现了与EntLib的EHAB(Exception Handling Application Block)的集成,使我们可以通过配置的方式来定义异常处理策略,并最终通过错误页面显示被处理过的异常信息。[源代码从这里下载]
阅读全文
posted @
2011-12-13 13:28 Artech 阅读(1790) |
评论 (14) 编辑
摘要:
如果采用自我寄宿的方式,我们需要为每个寄宿的服务创建ServiceHost对象。但是一个应用往往具有很多服务需要被发布,基于单个服务的ServiceHost的创建将会变成一个很繁琐的事情。如果我们能够采用某种机制来读取所有配置的服务,并自动为它们创建相应的ServiceHost对象,这无疑是一种理想的方式。
阅读全文
posted @
2011-12-07 12:03 Artech 阅读(2207) |
评论 (12) 编辑
摘要:
IIS 7.0因引入WAS提供了对非HTTP协议的支持。这个对于WCF的服务寄宿来说意义重大,它意味着我们通过IIS/WAS寄宿的服务终结点不仅仅可以采用BasicHttpBinding、WSHttpBinding/WS2007HttpBinding等基于HTTP协议的绑定,也可以采用NetTcpBinding、NetNamedPipeBinding和NetMsmqBinding。
阅读全文
posted @
2011-12-04 22:56 Artech 阅读(1792) |
评论 (12) 编辑
摘要:
今天介绍WCF 4.0的另外两个新特性:标准终结点和无(.SVC)文件服务激活。前者实现了针对典型通信场景对终结点的定制,后者让你在进行IIS/WAS的服务寄宿中无须定义.svc文件。
阅读全文
posted @
2011-09-20 09:04 Artech 阅读(3147) |
评论 (34) 编辑
摘要:
对于传统的WCF配置系统,无论是绑定的配置还是行为(服务行为和终结点行为)都必须具有一个名称。而正是通过整个配置名称,它们才能被应用到目标对象(终结点或者服务)上。而在实际的项目开发中,绝大部分服务或者终结点都具有相同的绑定和行为,如果能够定义一种默认的绑定和行为,这无疑会简化我们的配置。WCF4.0为此提供了一个新的特性以支持默认绑定和行为的配置。
阅读全文
posted @
2011-09-19 08:20 Artech 阅读(2276) |
评论 (11) 编辑
摘要:
对于需要进行大规模数据传输的WCF应用来说,对于请求消息和回复消息进行传输前的压缩,不但可以降低网络流量,也可以提高网络传输的性能。由于WCF的扩展性,我们可以采用不同的方式实现对消息的压缩,本文提供一种比较简单的实现方式。
阅读全文
posted @
2011-08-07 08:50 Artech 阅读(4420) |
评论 (71) 编辑
摘要:
多年之前,我写了一篇通过WCF扩展实现上下文信息从客户端自动传递到服务端的文章,其实现机制很简单:将上下文信息存放到SOAP Header进行传递。那么对于非SOAP消息的RESTful服务就不使用了。为了解决这个问题,我们可以将存放上下文信息的地方从SOAP Header替换成HTTP Header。这篇为你消息讲述具体的实现[源代码从这里下载]。
阅读全文
posted @
2011-06-28 20:14 Artech 阅读(1846) |
评论 (13) 编辑
摘要:
大家都知道,我们具有三种定义可序列化类型的方式:在类型上应用SerializableAttribute特性;应用DataContractAttribute/DataMemberAttribute特性和实现ISerializable接口。当你通过继承一个现有的类来定义你需要被序列化的类,如果这个父类实现了ISerializable接口,如果定义不当,就会出现反序列化的问题。而且这个我们可能经常都不注意。
阅读全文
posted @
2011-04-14 21:56 Artech 阅读(5218) |
评论 (28) 编辑
摘要:
条件编译,顾名思义,就是根据在编译时指定的条件决定最后需要编译的代码。条件编译是我们可以针对某些特性的环境编写相应的代码,比如有写的代码只需要在Debug模式下才需要执行,有些代码仅仅是为了在SIT或者UAT环境下有效地进行Troubleshooting,而在Production环境下则不应该执行。通过条件编译机制,我们可以针对某中特定的“条件编译符(Conditional Compilation Symbol)”编写相应的代码。在进行最终编译的时候,通过指定的条件编译符,编译器判断这些特殊的代码是否应该被编译。
阅读全文
posted @
2011-04-06 16:21 Artech 阅读(3724) |
评论 (13) 编辑
摘要:
《上篇》主要介绍如何通过DataBinder实现批量的数据绑定,以及如何解决常见的数据绑定问题,比如数据的格式化。接下来,我们主要来谈谈DataBinder的设计,看看它是如何做到将作为数据源实体的属性值绑定到界面对应的控件上的。
阅读全文
posted @
2011-03-27 21:19 Artech 阅读(6017) |
评论 (28) 编辑
摘要:
昨天写了《三种属性操作性能比较》,有个网友写信问我一个问题:从性能上看,Expression Tree和IL Emit孰优孰劣?虽然我在回信中作了简单的回答,但不知道这个网友是否懂我的意思。反正今天呆在家里也没事儿,干脆再就这个话题再写一篇文章。
阅读全文
posted @
2011-03-27 15:30 Artech 阅读(3273) |
评论 (17) 编辑
摘要:
在《上篇》中,我比较了三种属性操作的性能:直接操作,单纯通过PropertyInfo反射和IL Emit。本篇继续讨论这个话题,我们再引入另外两种额外的属性操作方式:Expression Tree和通过Delegate的静态方法CreateDelegate创建相应的委托进行属性的赋值和取值
阅读全文
posted @
2011-03-26 02:09 Artech 阅读(6046) |
评论 (27) 编辑
摘要:
在《一句代码实现批量数据绑定》中,我通过界面控件ID与作为数据源的实体属性名之间的映射实现了批量数据绑定。由于里面频繁涉及对属性的反射——通过反射从实体对象中获取某个属性值;通过反射为控件的某个属性赋值,所以这不是一种高效的操作方式。为了提升性能,我通过IL Emit的方式创建了一个PropertyAccessor组件,以实现高效的属性操作。如果你看了我在文中给出的三种属性操作性能的测试结果,相信会对PropertyAccessor的作用有深刻的印象。
阅读全文
posted @
2011-03-24 21:23 Artech 阅读(3174) |
评论 (33) 编辑
摘要:
对于一个以数据处理为主的应用中的UI层,我们往往需要编写相当多的代码去实现数据绑定。如果界面上的控件和作为数据源的实体类型之间存储某种约定的映射关系,我们就可以实现批量的数据绑定。为了验证这种想法,我写了一个小小的组件
阅读全文
posted @
2011-03-23 22:53 Artech 阅读(5225) |
评论 (66) 编辑
摘要:
本篇文章讨论可空值类型(Nullable)的转换,却确地说是如何将一种类型的值对象转换成相应的可空值。这来源于今天我们的一个成员遇到的一个小问题,我经过一些整理写了这篇文章。虽然没有什么技术含量可言,也希望对某些读者带来帮助。
阅读全文
posted @
2011-03-17 20:20 Artech 阅读(6179) |
评论 (31) 编辑
摘要:
对于数据库设计来说,多对多(或者一对多)是一种常见的数据关系,比如联系人和地址之间的关系。我们通常采用建立关系表的方式来表示这种关系,比如我们创建一张表来存储联系人和地址之间的关系。如果我们最终需要通过存储过程的方式来维护他们之间的关系,该如何做呢?本篇文章给你一个具体的例子来演示如果采用存储过程来建立和删除实体之间的关系。
阅读全文
posted @
2011-03-16 16:41 Artech 阅读(2853) |
评论 (17) 编辑
摘要:
继续讨论EF中使用存储过程的问题,这回着重讨论的是为存储过程的参数进行赋值的问题。说得更加具体一点,是如何为实体映射的Delete存储过程参数进行赋值的问题。关于文中涉及的这个问题,我个人觉得是EF一个有待改进的地方,不知道各位看官是否同意?
阅读全文
posted @
2011-03-13 16:02 Artech 阅读(2884) |
评论 (6) 编辑
摘要:
本篇文章通过实例的方式,讨论两个在EF使用存储过程的主题:如何通过实体和存储过程的映射实现逻辑删除;对于具有自增长类型主键的数据表,在进行添加操作的时候如何将正确的值反映在实体对象上。
阅读全文
posted @
2011-03-13 00:13 Artech 阅读(2394) |
评论 (3) 编辑
摘要:
今天写程序频繁用到两中字符串操作:删除某个字符串指定的前缀和后缀。由于没有现成的方法可用,写了两个扩展方法:TrimPrefix和TrimSuffix。
阅读全文
posted @
2011-03-07 20:52 Artech 阅读(1758) |
评论 (11) 编辑
摘要:
在《实现存储过程的自动映射》中,我通过基于T4的代码生成实现了CUD存储过程的自动映射。由于映射的都是基于数据表结构的标准的存储过程,所以它们适合概念模型和存储模型结构相同的场景。如果两种模型存在差异,在进行数据更新操作的时候就会出错。本篇文章主要介绍当概念模型中具有继承关系的两个实体映射到数据库关联的两个表,如何使用存储过程。
阅读全文
posted @
2011-03-06 22:32 Artech 阅读(2903) |
评论 (8) 编辑
摘要:
最近一段时间的工作任务是如何将EF引入到我们的开发框架,进行相应的封装、扩展,使之成为一个符合在特定场景下进行企业级快速开发的ORM。在此过程中遇到了一些挑战,也有一些心得。为了向大家分享这些心得,接下来我会写一系列相关的文章。第一个主题是关于在EF中使用存储过程的问题
阅读全文
posted @
2011-03-05 10:04 Artech 阅读(4123) |
评论 (27) 编辑
摘要:
昨天在进行Code Review的时候,发现一个关于通过ConfigurationManager的GetSection方法进行配置节读取的问题。虽然这是一个很小的问题,还是它已经存在在项目里面很久了,直到今天才被发现,所以觉得具有一定分享的价值。
阅读全文
posted @
2011-01-15 15:27 Artech 阅读(3591) |
评论 (32) 编辑
摘要:
BackgroundWorker允许您在单独的专用线程上运行操作。操作是异步执行的,用户可能在操作执行过程中关闭窗体,而窗体的关闭会伴随着Dispose方法的执行。如果我们注册了RunWorkerCompleted事件,并且在该事件处理程序中需要操作这个被Dispose的窗体,就会出现一些无法预知的异常。
阅读全文
posted @
2010-11-25 13:34 Artech 阅读(3706) |
评论 (35) 编辑
摘要:
前一阵子写了不少关于代码生成相关的文章,介绍了一些如何通过VS自动生成代码的解决方案,比如CodeDOM、T4以及ASP.NET的BuildProvider等。现在将它们作一个汇总,给广大读者作一个参考。
阅读全文
posted @
2010-11-17 21:55 Artech 阅读(11228) |
评论 (114) 编辑
摘要:
在这之前,我写了一系列关于代码生成和T4相关的文章,而我现在也试图将T4引入我们自己的开发框架。在实践中遇到了一些问题,也解决了不少问题。如果你也在进行T4相关的开发,相信你也一定会遇到这些问题。为此,特意将这些问题和解决方案与朋友们分享,希望在遇到这些问题的时候少走弯路。本篇文章介绍的是两个重要的话题:程序集锁定和调试。
阅读全文
posted @
2010-11-16 22:58 Artech 阅读(3422) |
评论 (16) 编辑
摘要:
在众多.NET应用下的代码生成方案中,比如CodeDOM,BuildProvider, 我觉得T4是最好的一种。如果你编写T4模板,你不得不面对一个问题——如何引用一个程序集?VS 2010采用了与VS2008不同的程序集引用的解析机制。本篇文章为你介绍在VS2010下5种不同的程序集引用的方式。
阅读全文
posted @
2010-11-09 23:25 Artech 阅读(4577) |
评论 (60) 编辑
摘要:
之前写了一些关于代码生成的文章,提供了两种不同方式的代码生成解决方案,即CodeDOM+Custom Tool和T4。对于ASP.NET应用,你还有第三种选择——自定义BuildProvider。对于ASP.NET应用的开发者来说,你可能不知道什么是BuildProvider,但是你几乎无时无刻不在使用它所带来的代码生成机制。
阅读全文
posted @
2010-11-06 22:29 Artech 阅读(3555) |
评论 (49) 编辑
摘要:
C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的。相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制。但是即使你知道这个机制,你也很容易在不经意间掉入它制造的陷阱。
阅读全文
posted @
2010-10-28 20:32 Artech 阅读(4813) |
评论 (103) 编辑
摘要:
在《上篇》中我们通过T4模板为我们指定的数据表成功生成了我们需要的用于添加、修改和删除操作的存储过程。但是这是一种基于单个文件的解决方案,即我们必须为每一个生成的存储过程建立一个模板。如果我们提供一种基于多文件的代码生成方式,将会为编程人员带来极大的便利,本篇文章将为你解决这个问题。
阅读全文
posted @
2010-10-25 19:34 Artech 阅读(5854) |
评论 (69) 编辑
摘要:
在《基于T4的代码生成方式》中,我对T4模板的组成结构、语法,以及T4引擎的工作原理进行了大体的介绍,并且编写了一个T4模板实现了如何将一个XML转变成C#代码。为了让由此需求的读者对T4有更深的了解,我们通过T4来做一些更加实际的事情——为某个数据表自动生成进行插入、修改和删除的存储过程。
阅读全文
posted @
2010-10-25 07:37 Artech 阅读(6604) |
评论 (79) 编辑
摘要:
在之前写一篇文章《从数据到代码》(上篇、下篇)中,我通过基于CodeDOM+Custom Tool的代码生成方式实现了将一个XML表示的消息列表转换成了相应的C#代码,从而达到了强类型编程的目的。实际上,我们最常用的代码生成当时不是CodeDOM,而是T4,这是一个更为强大,并且适用范围更广的代码生成技术。今天,我将相同的例子通过T4的方式再实现一次
阅读全文
posted @
2010-10-23 22:25 Artech 阅读(7168) |
评论 (72) 编辑
摘要:
我们知道Modifier为Internal的类型成员仅限于当前程序集能够访问,但是在某些情况下,我们希望将它们暴露给另一个程序集。比较典型的应用场景包括如下两种:将一个组件或者模块定义成两个或者两个以上程序集,一个程序集需要访问另一个程序集的Internal成员;对一个组件或者模块进行单元测试时候,单元测试用例需要调用定义在被测试组件或者模块的Internal成员。
阅读全文
posted @
2010-10-06 17:05 Artech 阅读(2170) |
评论 (11) 编辑
摘要:
在《上篇》中,我们实现了将保存有消息条目的XML向CodeDOM的转换.在下篇中,我们将实现整个代码生成系统的第二个步骤——通过VS扩展实现数据(保存消息条目的XML)向代码文件的自动转换。即通过VS自动生成的代码结构是对数据结构的反映,继而使我们能够强类型的方式操作数据,不但极大地提高开发效率,也降低了出错的可能。
阅读全文
posted @
2010-09-18 02:05 Artech 阅读(3834) |
评论 (19) 编辑
摘要:
这确实是一个让人觉得“无语”的BUG,甚至让我觉得微软在故意和我们开玩笑。这个问题在我刚刚接触WCF的时候就遇到过,换言之,这个问题一直存在于.NET 3.0、3.5和现在的4.0。这是一个关于在你对WCF进行扩展的时候会经常碰到的问题,读者朋友们可以根据下面的步骤来再现这一个问题。
阅读全文
posted @
2010-09-16 20:34 Artech 阅读(5280) |
评论 (58) 编辑
摘要:
我不知道大家对CodeDom的代码生成机制是否熟悉,但是有一点可以确定:如果你使用过VS,你就应该体验过它带给我们在编程上的便利。随便列举三种典型的代码生成的场景:强类型DataSet、Resource和添加Web Reference。总的来说,通过和VS集成的动态代码生成工具使我们可以“强类型”的方式进行编程,进而提供我们的效率并减低错误的几率。除了VS提供的这些典型的代码生成场景中,我们可以根据需要开发一些自定义代码生成器,并且通过VS的扩展实现后台代码的实时生成,从而实现强类型编程的目的。
阅读全文
posted @
2010-09-16 00:05 Artech 阅读(4834) |
评论 (60) 编辑
摘要:
由于我们的项目底层使用到一个通过LogicalCallContext实现的上下文数据管理框架,导致所有的Unit Test不能正常运行。具体的现象在《只在UnitTest和WebHost中的出现的关于LogicalCallContext的严重问题》有过详细的介绍。解决的方案就是对相关的程序集进行强签名,并加到GAC中。程序集签名很好实现——仅仅需要借助VS给项目指定一个签名用的Key File就可以了,但是,VS做得不够好。
阅读全文
posted @
2010-09-10 23:32 Artech 阅读(2357) |
评论 (27) 编辑
摘要:
关于如何解决分布式系统中的跨时区问题,上一篇详细介绍了解决方案的实现原理。尽管《原理篇》中介绍了那么多,解决方案的本质就是:在进行服务调用过程中将客户端的时区信息作为上下文传入服务端,并以此作为时间转换的依据。在这一篇中我们根据这个原理通过一个简单的例子来证明其可行性。。
阅读全文
posted @
2010-09-10 00:23 Artech 阅读(1922) |
评论 (14) 编辑
摘要:
《谈谈你最熟悉的System.DateTime[上篇][下篇]》从跨时区的角度对DateTime这个我们熟知的类型进行了深入探讨,它们都是为这篇文章作的准备工作。在接下来的两篇文章中,我们将完整的介绍如果在一个分布式系统中处理时区的问题。
阅读全文
posted @
2010-09-08 23:50 Artech 阅读(2628) |
评论 (18) 编辑
摘要:
在《谈谈你最熟悉的DateTime》一文中,我们从跨时区的角度剖析了我们熟悉的时间类型。如果你采用传统的ADO.NET编程,并用DataSet作为数据实体,可能你会熟悉DataSetDateTime这个类型。这个类型也是为实现跨时区场景设计的,为了对前文的补充,这篇文章就来谈谈基于DataSet的时间处理问题。
阅读全文
posted @
2010-09-05 11:24 Artech 阅读(3568) |
评论 (29) 编辑
摘要:
最近一直在负责公司内部框架的升级工作,今天对一个小问题进行了重新思考——时间的处理。具体来说,是分布式应用中如何有效地进行时间的处理以提供对跨时区的支持。不过,对该问题解决方案的介绍我会放在后续的文章中,在这里我们先来介绍一些基础性的内容——谈谈我们熟悉的DateTime类型
阅读全文
posted @
2010-09-04 10:16 Artech 阅读(6650) |
评论 (64) 编辑
摘要:
在前一篇文章中我曾经说过,现在正在做一个小小的框架以实现采用统一的API实现对上下文(Context)信息的统一管理。这个框架同时支持Web和GUI应用,并支持跨线程传递和跨域传递,和对上下文项目的读写控制。在对后两个特性的支持上,出现一个小小的关于序列化的问题。解决方案只需要改动短短的一行代码,结果却让我折腾了老半天...
阅读全文
posted @
2010-08-31 20:16 Artech 阅读(3513) |
评论 (21) 编辑
摘要:
有一次和人谈起关于事务的话题,谈到怎样的资源才能事务型资源。除了我们经常使用的数据库、消息队列、事务型文件系统(TxF)以及事务性注册表(TxR)等,还有那些资源直接可以纳入事务进行状态的管理呢?我说如果我们按照.NET事务模型的规范对相应的资源进行合理的封装,原则上我们可以让任何可编程的资源成为事务型资源。本篇文章中,我将通过简单的编程将一个普通的变量变成支持事务,让变量的值也可以回滚,以确保事务前后的数据一致性。
阅读全文
posted @
2010-08-16 22:09 Artech 阅读(5459) |
评论 (61) 编辑
摘要:
最近园子里发表了一些讨论“事件(Event)”的文章,我也来凑个热闹,谈谈我对事件的一些粗浅的认识。本文不谈设计模式(主要是观察者模式),只从运行时的角度来分析事件这个对象到底是个什么东西?它有那么神秘吗?为了更好的分析事件,本文将会编写一些例子来模拟事件的订阅机制。本文对事件的分析可以概括为下面三句话:1.事件本质上是一个MulticastDelegate对象; 2.MulticastDelegate对象是多个Delegate对象的链表;3.Delegate = Object + MethodInfo,委托的执行最终通过反射来完成。
阅读全文
posted @
2010-07-10 13:56 Artech 阅读(7068) |
评论 (28) 编辑
摘要:
“异常处理对于最终的开发人员是透明的”,就我个人的项目经验来讲,这是一种理想的状态。由于异常策略是一般是通过配置动态配置的,不需要反映在代码上面。如果能够通过框架的方式提供异常处理的实现,使开发人员无需编写任何异常处理的代码,只需要关注业务流程的实现就可以了,这不仅能够提高开发的效率,也能够提高系统的可维护性。
阅读全文
posted @
2010-03-26 21:33 Artech 阅读(10865) |
评论 (86) 编辑
摘要:
在应用开发中,我们经常需要设置一些上下文(Context)信息,这些上下文信息一般基于当前的会话(Session),比如当前登录用户的个人信息;或者基于当前方法调用栈,比如在同一个调用中涉及的多个层次之间数据。在这篇文章中,我创建了一个称为ApplicationContext的组件,对上下文信息进行统一的管理。
阅读全文
posted @
2010-02-25 21:00 Artech 阅读(4593) |
评论 (48) 编辑
摘要:
在一个基于SOA架构的分布式系统体系中,服务(Service)成为了基本的功能提供单元,无论与业务流程无关的基础功能,还是具体的业务逻辑,均实现在相应的服务之中。服务对外提供统一的接口,服务之间采用标准的通信方式进行交互,各个单一的服务精又有效的组合、编排成为一个有机的整体。在这样一个分布式系统中某个活动(Activity)的实现往往需要跨越单个服务的边界,如何协调多个服务之间的关系使之为活动功能的实现服务,涉及到SOA一个重要的课题:服务协作(Service Coordination)。而具体来讲,一个分布式的活动可能会执行几秒钟,比如银行转帐;也可能执行几分钟、几个小时、几天甚至更长,比如移民局处理移民的申请。事务,无疑是属于短暂运行服务协作(Short-Running Service Coordination)的范畴。
阅读全文
posted @
2010-01-31 13:22 Artech 阅读(7422) |
评论 (14) 编辑
摘要:
在前面一篇给出的Transaction的定义中,信息的读者应该看到了一个叫做DepedentClone的方法。该方法对用于创建基于现有Transaction对象的“依赖事务(DependentTransaction)”。不像可提交事务是一个独立的事务对象,依赖事务依附于现有的某个事务(可能是可提交事务,也可能是依赖事务)。依赖事务可以帮助我们很容易地编写一些事务型操作,当环境事务不存的时候,可以确保操作在一个独立的事务中执行;当环境事务存在的时候,则自动加入其中。
阅读全文
posted @
2010-01-31 09:19 Artech 阅读(3838) |
评论 (11) 编辑
摘要:
在.NET 1.x中,我们基本是通过ADO.NET实现对不同数据库访问的事务。.NET 2.0为了带来了全新的事务编程模式,由于所有事务组件或者类型均定义在System.Transactions程序集中的System.Transactions命名空间下,我们直接称基于此的事务为System.Transactions事务。System.Transactions事务编程模型使我们可以显式(通过System.Transactions.Transaction)或者隐式(基于System.Transactions.TransactionScope)的方式进行事务编程。
阅读全文
posted @
2010-01-30 16:49 Artech 阅读(5028) |
评论 (19) 编辑
摘要:
在《
上篇》中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭。对于《WCF技术剖析(卷1)》的读者,应该会知道在第7章中我通过类似于AOP的方式解决了相似的问题,现在我们来讨论这个解决方案。
阅读全文
posted @
2010-01-08 20:49 Artech 阅读(4201) |
评论 (26) 编辑
摘要:
在进行基于会话信道的WCF服务调用中,由于受到并发信道数量的限制,我们需要及时的关闭信道;当遇到某些异常,我们需要强行中止(Abort)信道。在真正的企业级开发中,正如我们一般不会让开发人员手工控制数据库连接的开启和关闭一样,我们一般也不会让开发人员手工去创建、开启、中止和关闭信道,这些工作是框架应该完成的操作。这篇文章,我们就来介绍如果通过一些编程技巧,让开发者能够无视“信道”的存在,像调用一个普通对象一样进行服务调用。
阅读全文
posted @
2010-01-04 19:46 Artech 阅读(4857) |
评论 (41) 编辑
摘要:
在
上篇中我们谈到:将一个生命周期较短的对象(对象A)注册到一个生命周期较长(对象B)的某个事件(Event)上,两者便无形之间建立一个引用关系(B引用A)。这种引用关系导致GC在进行垃圾回收的时候不会将A是为垃圾对象,最终使其常驻内存(或者说将A捆绑到B上,具有了和B一样的生命周期)。这种让无用的对象不能被GC垃圾回收的现象,在托管环境下就是一种典型的内存泄漏问题。我们今天将会着重解释其背后的原因。
阅读全文
posted @
2009-12-06 22:57 Artech 阅读(3943) |
评论 (32) 编辑
摘要:
在
前面一篇文章中,我通过对三种Infragistics 控件(UltraToolBarManager、UltraGird和UltraListView)进行扩展,以实现对ToolTip样式的定义,今天我来介绍如何采用相同的方式实现另外一个更为常用的功能:在UltraGrid的Header中动态添加CheckBox,从而实现对所有数据行进行全选的功能。
阅读全文
posted @
2009-12-05 01:19 Artech 阅读(2515) |
评论 (12) 编辑
摘要:
最近这两天一直在忙着为一个项目检查内存泄漏(Memory Leak)的问题,对相关的知识进行了一下简单的学习和探索,其间也有了一些粗浅的经验积累,今天特意写一篇相关的文章与大家分享。那些对内存泄漏稍微有点了解的人,对于本篇文章的标题,相信不会觉得是在危言耸听。就我查阅的资料,已经这两天的发现也证实了这一点:觉得部分的内存泄漏问题与事件(Event)有关。本篇文章将会介绍其原理,以及如何发现和解决由事件导致的内存泄漏问题。
阅读全文
posted @
2009-12-03 21:02 Artech 阅读(5415) |
评论 (43) 编辑
摘要:
Infragistics是全球领先的UI工具和用户体验的专家,Infragistics开发了一系列的炫目的Windows、Web、WPF和Silverlight控件,相信很多人在使用它们。我们现在的项目就在使用Infragistics的Windows Form控件集。虽然这些控件功能强大,也不可能满足你所有的需求,尤其是那些比较苛刻的最终用户的需求。比如,我们最近就接收到这样的需求:让所以菜单项、工具栏按钮、网格单元的ToolTip以气球式的样式显示。最终,我通过对现有控件的扩展实现这个要求。
阅读全文
posted @
2009-12-02 22:41 Artech 阅读(3248) |
评论 (29) 编辑
摘要:
最近,用户提出了一个要求:需要通过按键方式来控制容器控件竖直滚动条。具体来讲就是说,如果一个容器内容过多,用户可以通过按键PageUp和PageDown来控制上下的滚动。刚开始,我试图采用注册事件的方式来实现,但是效果不理想,一来是没有一个单一的地方来对所有相关空间进行事件注册操作,二来如果容器被子控件完全遮挡,容器空间的事件将不会正常出发。有个同事提示采用自定义MessageFilter的方式,我觉得可行,于是进行了一番尝试。
阅读全文
posted @
2009-11-06 23:47 Artech 阅读(2105) |
评论 (9) 编辑
摘要:
HP QC(Quantity Center)是一款不错的测试管理工具,最近把公司的操作系统从Windows XP升级到Windows 7之后,发现登录到QC Server的Addin页面,很多客户端组件不能正常下载,从而导致整个QC不能使用。通过Google找到了解决方案,特发出来与大家共享,希望那些在Windows 7上使用HP QC的朋友遇到该问题的时候,能过及时得到解决。
阅读全文
posted @
2009-11-06 11:15 Artech 阅读(4817) |
评论 (19) 编辑
摘要:
VS2010 Beta 1发布还一阵了,相信很多人已经开始尝鲜了。不知道大家有没有遇到过这样的问题:当打开VS2010的时候,出现这样一个初始化界面。但是几秒钟之后,初始化界面消失,但是VS2010的UI界面并没有出现。但是通过Task Manager查看进程列表,Devenv.exe进行却在运行。我先后遇到了两次,第一次是在Windows 7上安装VS 2010 Team Suit,我还以为是Windows 7的问题。昨天在Windows Server 2008上安装有遇到这样的问题,我以为是安装过程出现问题,于是卸掉重装,问题依然存在。在网上也没有找到任何相关信息,整整折腾了一天。后来通过通过命令行,对VS进行重新设置后解决了这个问题。
阅读全文
posted @
2009-05-30 13:38 Artech 阅读(3521) |
评论 (26) 编辑
摘要:
今天看到看到一篇MSDN文章《Parallelizing Operations With Dependencies》,作者是微软Parallel Computing Platform团队的一个开发经理。文中提供出一种用于并行执行一组具有依赖关系的操作的解决方案,这不由得想起我在一年之前写的一个具有相同的功能的组件。于是翻箱倒柜找了出来,进行了一些加工,与大家分享一下。
阅读全文
posted @
2009-05-22 23:30 Artech 阅读(2390) |
评论 (22) 编辑
摘要:
开门见山,下面的例子中通过调用ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)的方式实现异步调用: List actions = new List(); //...... foreach (var action in actions) { ThreadPool.QueueUserWorkItem(state => action(), null); } Console.Read(); 但是出现错误的输出结果......
阅读全文
posted @
2009-05-22 09:31 Artech 阅读(6283) |
评论 (30) 编辑
摘要:
下面通过一个简单的Console Application演示Type Innitializer的执行顺序。希望大家各抒己见,对于实验的结果给出一个圆满的解释,同时希望读者从中理解到更多关于编译、关于CLR一些被我们忽略的细节。
阅读全文
posted @
2008-11-01 15:57 Artech 阅读(4204) |
评论 (21) 编辑
摘要:
对于稍微有点经验的.NET开发人员来说,倘若被问及如何保持线程同步,我想很多人都能说好好几种。在众多的线程同步的可选方式中,加锁无疑是最为常用的。如果仅仅是基于方法级别的线程同步,使用System.Runtime.CompilerServices.MethodImplAttribute无疑是最为简洁的一种方式。MethodImplAttribute可以用于instance method,也可以用于static method。当在某个方法上标注了MethodImplAttribute,并指定MethodImplOptions.Synchronized参数,可以确保在不同线程中运行的该方式以同步的方式运行。我们几天来讨论MethodImplAttribute(MethodImplOptions.Synchronized)和lock的关系。
阅读全文
posted @
2008-10-17 09:16 Artech 阅读(5593) |
评论 (27) 编辑
摘要:
对于所有的开发人员来说,Exception Handling是我们每天都要面对的事情。对于基于Source Code的Exception Handling,我想大家已经司空见惯了,但是对于Database级别的Exception Handling,就没有那么常见了。在这篇文章中,我将会介绍我对于基于Database编程中Exception Handling的一些粗浅的认识:在编写Stored Procedure时,如何抛出一个可预知的Exception,ADO.NET如何处理从Database抛出的Exception,如何保存基于Database Exception的Error Message,如何在Database和.NET Application之间进行消息的传递[注:这里的Database主要指SQL Server]。
阅读全文
posted @
2008-08-28 13:44 Artech 阅读(3351) |
评论 (7) 编辑
摘要:
在最近的一个Smart Client项目中,为了演示异步操作的实现,写了一个基于BackgorundWorker的例子。由于这个理基本上实现了BackgorundWorker的大部分功能:异步操作的启动、操作结束后的回调、异步操作的撤销和进度报告等等。尽管没有太多的技术含量,姑且放上来与大家分享。
阅读全文
posted @
2008-07-30 09:44 Artech 阅读(5915) |
评论 (14) 编辑
摘要:
在
谈谈基于SQL Server 的Exception Handling - PART II中,我给出了一个完整的例子说明了:如何在将message定义在sys.messages中保证message的一致性和可维护性;如何在Stored procedure中使用RAISERROR将一个可预知的Error抛出;如何在Stored procedure中使用TRY/CATCH进行异常的捕捉;在Application如果处理从SQL Server抛出的Exception。实际上,SQL Server database Engine抛出、被我们的.NET最终捕获的SqlException,我们通过SqlException的属性可
阅读全文
posted @
2007-12-17 12:53 Artech 阅读(3350) |
评论 (10) 编辑
摘要:
在
上面一节中,我通过RAISERROR重写了创建User的Stored procedure,实际上上面的Stored procedure是有问题的。我之所以没有立即指出,是因为这是一个很容易犯的错误,尤其是习惯了.NET Exception Handling的人更容易犯这样的错误。我们知道在.NET Application中,如果出现一个未处理的Exception,程序将立即终止,后续的程序将不会执行,但是对于上面的SQL则不一样,虽然我们通过RAISERROR将Error抛出,但是SQL的指定并不会被终止,INSERT语句仍然会被执行的。我想很多人会说在RAISERROR后加一个Return就可以了嘛。不错这是一个
阅读全文
posted @
2007-12-17 12:41 Artech 阅读(3382) |
评论 (6) 编辑
摘要:
对于所有的开发人员来说,Exception Handling是我们每天都要面对的事情。对于基于Source Code的Exception Handling,我想大家已经司空见惯了,但是对于Database级别的Exception Handling,就没有那么常见了。在这篇文章中,我将会介绍我对于基于Database编程中Exception Handling的一些粗浅的认识:在编写Stored Procedure时,如何抛出一个可预知的Exception,ADO.NET如何处理从Database抛出的Exception,如何保存基于Database Exception的Error Message,如何在Database和.NET Application之间进行消息的传递[注:这里的Database主要指SQL Server]。
阅读全文
posted @
2007-12-17 08:38 Artech 阅读(4061) |
评论 (8) 编辑
摘要:
较之C# 2.0, C# 3.x引入了一些列新的特性,为我们编程带来很大的便利,通过有效地利用这些新特性,我们可以编写出更加简洁、优雅的程序。不过这些新特性仅仅是编译器给我们耍的小花招:在编译的时候加入一些必要的Code,使这些在C# 2.0角度看略显残缺的Code变得“完整”,实际上最终生成的Assembly和在C# 2.0时代并没有本质的不同。为此,有些人对这些新特性不以为然,觉得仅仅是一些表面文章,是鸡肋。但是我的观点是:既然这些特性能给我们的编程带来便利,干嘛不用呢?
阅读全文
posted @
2007-10-07 12:38 Artech 阅读(12197) |
评论 (29) 编辑
摘要:
深入理解C# 3.x的新特性系列自开篇以后,已经有两个月了。在前面的章节中,我们先后深入讨论了C# 3.x新引入的一些列新特性:Anomynous Type、Extension Method、Lambda Expression、Automatically Implemented Property,今天我们来讨论本系列的涉及的另外两个简单的Feature: Object Initializer 和 Collection Initializer。
阅读全文
posted @
2007-09-30 17:17 Artech 阅读(4470) |
评论 (13) 编辑
posted @
2007-09-15 21:07 Artech 阅读(5216) |
评论 (31) 编辑
摘要:
在
第一部分中,我们讨论了
APPLY和
CTE这两个T-SQL Enhancement。APPLY实现了Table和TVF的Join,CTE通过创建“临时的View”的方式使问题化繁为简。现在我们接着来讨论另外两个重要的T-SQL Enhancement Items:
PIVOT和
Ranking。
阅读全文
posted @
2007-08-24 23:16 Artech 阅读(3959) |
评论 (17) 编辑
摘要:
较之前一版本,SQL Server 2005可以说是作出了根本性的革新。对于一般的编程人员来说,最具吸引力的一大特性就是实现了对CLR的寄宿,使我们可以使用任意一种.NET Programming Language来编写Stored Procedure、Function、Trigger、Custom Type等等。但是并不意味着我们使用多年的T-SQL即将被淘汰,而事实上T-SQL仍然是我们最为常见的基于Database的编程语言。 为了使编程人员更容易地使用T-SQL来实现一些较为复杂的功能,SQL Server 2005在T-SQL进行了一系列的改进,这篇文章将概括性地介绍这些T-SQL Enhancement。
阅读全文
posted @
2007-08-23 21:46 Artech 阅读(4257) |
评论 (20) 编辑
posted @
2007-07-19 13:47 Artech 阅读(5539) |
评论 (41) 编辑
摘要:
在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda expression, Object initializer, Anonymous type, Implicitly typed array, Query expression, Expression tree. 个人觉得在这一系列新特性的,最具创新意义的还是Extension method,它从根本上解决了这样的问题:在保持现有Type原封不动的情况下对其进行扩展,你可以在对Type的定义不做任何变动的情况下,为之添加所需的方法成员。在继
深入理解C# 3.0的新特性(1阅读全文
posted @
2007-07-18 01:30 Artech 阅读(6787) |
评论 (44) 编辑
摘要:
在C#3.0中,引入了一个新的Feature:Anonymous Method,允许我们已Inline的方式来定义Delegate,为Developer在Coding的时候带来了很大的便利。在C#3.0中,我们又有了另一个相似的Feature:Anonymous Type。Anonymous Type允许我们已Inline的方式的创建一个基于未知类型、具有所需数据结构的对象。
阅读全文
posted @
2007-07-15 21:50 Artech 阅读(8909) |
评论 (35) 编辑
摘要:
在项目开发中,发送邮件时一种非常常见的功能。一般的情况下,大型的公司都有自己的邮件系统,我们可以直接通过公司的Pop/SMTP Server进行邮件的发送和接收。不过,对于一些小公司不具有这样的条件,他们一般通过一些公共的邮件服务通过商提供的邮件服务。比如Sina、163就是很好的,常用的邮件服务。不过相比之下,我还是习惯使用Google Gmail。 接下来,我将介绍两方面来介绍今天的内容,如果通过Managed code通过Gmail进行邮件的发送,以及如何在Outlook中配置Gmail。今天介绍的东西和技术不是很沾边。只是觉得具有一定的实用性,同时介绍一下我在使用过程遇到的一些问题,希望给大家在使用过程中提供一些参考。
阅读全文
posted @
2007-05-16 01:48 Artech 阅读(5854) |
评论 (21) 编辑
摘要:
我想对于ASP.NET的Validator控件已经熟悉的不能再熟悉了。我们 已经习惯了用Validator控件来验证我们在表单的输入,并通过ValidationSummary来输出我们为Validator控件设置的Error message。不知道大家有没想过进一步改进一下我们的Validation来改善我们的User Experience。比如,在ValidationSummary输出一个Link连接到对应的控件,而不是显示单纯的Error message。
阅读全文
posted @
2007-05-12 01:52 Artech 阅读(5978) |
评论 (25) 编辑
摘要:
一直想写一系列如何提高Performance和Scalability的文章,把我的相关经验和所知道的相关的技巧同大家分享。前一阵在园子里有一篇讨论for each 和 for两种循环那个具有更好的performance的blog,议论得沸沸扬扬。我觉得这是一个很好的切入点,我就已此作为引子,开始我的这个系列的文章。这篇文章的重点不是在于比较这两种循环孰优孰劣,我将讨论的重点是如何更好地定义Collection,如何在判断在什么时候该用Array,什么时候用Collection。
阅读全文
posted @
2007-05-02 19:25 Artech 阅读(18640) |
评论 (47) 编辑
摘要:
在开发一个企业级 应用的时候,尤其在一个涉及到敏感数据的应用,比如财务系统、物流系统,我们往往有这样的需求:对于数据库中每一笔数据的添加、修改和删除,都需要有一个明确的日志,以便我们可以追踪每一笔记录的来龙去脉——数据的更新是被谁、在什么时候执行的?该操作还涉及到哪些具体的Table?原来的数据是什么?新的数据又是什么? 本Blog的目的就是基于上面提出的要求设计一个Audit Logging的解决方案。
阅读全文
posted @
2007-04-23 23:34 Artech 阅读(4540) |
评论 (14) 编辑
摘要:
在开发一个企业级 应用的时候,尤其在一个涉及到敏感数据的应用,比如财务系统、物流系统,我们往往有这样的需求:对于数据库中每一笔数据的添加、修改和删除,都需要有一个明确的日志,以便我们可以追踪每一笔记录的来龙去脉——数据的更新是被谁、在什么时候执行的?该操作还涉及到哪些具体的Table?原来的数据是什么?新的数据又是什么? 本Blog的目的就是基于上面提出的要求设计一个Audit Logging的解决方案。
阅读全文
posted @
2007-04-23 12:19 Artech 阅读(5260) |
评论 (27) 编辑
摘要:
经常在网上看到对ORM的讨论沸沸扬扬,我也来凑个热闹,谈谈我写的一个ORM。最近在做一项工作,把我们经常用到的一些业务逻辑抽象出来,写成一个个的Application Block,使之可以运用到不同的Application中,比如Data Access,Messaging,Auditing,Data binding等等。现在先做一个Data access application block。由于时间仓促,没有进行什么优化和较多的测试,大家不必深究我所提供的Code ,我只希望为大家的ORM提供另一种想法。
阅读全文
posted @
2007-04-03 18:55 Artech 阅读(7588) |
评论 (4) 编辑
摘要:
昨天在写一个SQLXML的Sample的时候,在SQL Server 2005添加新的User的时候出了一系列的问题,觉得这是一个很Common的问题,今天我把它重现,并把相关的Screen Shot截下来,希望大家在遇到相同的问题的时候能对大家有所帮助。
阅读全文
posted @
2007-03-26 21:51 Artech 阅读(3326) |
评论 (9) 编辑
摘要:
随着Internet的飞速发展,W3C成员意识到必须找到一种办法将数据和Web的表现方式分离出来,于是XML诞生了。当今的XML已经成为IT领域各个数据(特别是文档)的首选格式。由于它具有标记不同字段的能力,因此使搜索变得更简单。从微软发布SQL Server 2000的时候,就读XML数据的存储和检索提供内置的支持。而且微软早已意识到必须对其不断地改进,以便和不断发展的W3C的XML标准保持一致。在微软发布SQL Server 2000的几个月之后,它便在Web站点上发布了完全可以支持XML特性的软件包提供免费的下载。这些软件包被称作SQLXML(XML for SQL Server),当时的版本是3.0。5年之后,SQL Server 升级到了SQL Server 2005,提供了一系列的新的功能和特性,比如对新的XML数据类型的支持;提供了新的Data Access Provider——N
阅读全文
posted @
2007-03-26 02:59 Artech 阅读(6881) |
评论 (37) 编辑
摘要:
Remoting是NET平台下比较成熟高效的分布式技术,我们习惯采用传统的远程调用的方式使用Remoting。在客户端所在的Application Domain,我们通过Proxy(Transparent Proxy)远程地跨Application Domain调用一个方法。当来自Client端的调用请求通过Proxy到达Server端所在的Application Domain后,Remoting Infrastructure在Server 端激活(Activate)相应的远程对象(一个继承子System.MarshalByRefObject类对象)——这里仅仅以服务端激活对象(Server Activated Object——SAO),然后再Server端执行相应的操作后把Result传递给Proxy,并最终到达Client。这是一种典型的Request/Response的调用方式。 我之
阅读全文
posted @
2007-03-01 19:19 Artech 阅读(10913) |
评论 (45) 编辑