[CodeDOM] 使用C# 2.0实现语言无关的代码生成器

mikel阅读(881)

一、什么是CodeDom? 现 在的程序规模越来越大,虽然在计算发展的几十年间,产生了许多快捷、高效的编程语言和开发工具,如C#、Visual Studio、java等。也产生了许多用以辅助软件设计、开发的思想和方法,如UML、OOP、Agile等。尽管利用这些技术和方法可以大大提高程序 编写的效率,但是仍可能有重复的编码工作。因此,现在出现了许多可以自动产生源代码或者目标文件的软件,即Code Wizards。
    一 般这些Code Wizards在生成源代码时都是通过设置模板文件,然后根据这些模板文件生成源代码。有很多Code Wizards只能生成固定的语言(如java、C#等)。虽然有一些Code Wizards可以生成多种语言,但也只是固定的几种。而且生成源代码部分都是显示地固定在程序中。这样非常不易扩展。如CodeSmith系统,这是一 个非常不错的Code Wizard。它使用一个扩展名为cst的文件来设置模板。这个模板文件的格式类似于ASP.NET。如果想生成C#源代码,必须要在其中显示地标明,并 且模板的固定部分要使用C#语言编写。如果这样的话,同样功能要生成不同语言的代码,如C#和VB.net。就要编写两个模板文件。这是非常不方便的。
    从 以上的描述来看, Code Wizard所面临的一个重要问题就是如何使用一个模版文件来生成不同语言的源代码。幸好Microsoft提供了一种解决方案,这就是CodeDOM技 术。CodeDOM的全称是代码文档对象模型(Code Document Object Model)。整个CodeDOM就是一张对象图(object graph)。它用这张图中的所有对象描述了面向对象语言中的几乎所有的语法现象,如类、接口、方法、属性等。
CodeDOM通过对象模型对语言进行了抽象,然后利用具体语言所提供的生成源代码的机制来生成源代码,并可调用相应的编译器将源码生成*.dll或*.exe。从而可以达到与语言无关的目的。图1描述了使用CodeDOM
生成和编译源代码的过程。


图1 CodeDom生成和编译源代码的过程

从上图可以看出,CodeWizard只使用CodeDOM对语言进行抽象,然后通过CodeDomProvider生成源代码。最后通过编译器生成中间语言。下面将详细讨论如何利用CodeDOM来实现CodeWizard。

二、实现CodeWizard
下 面要实现的这个CodeWizard非常简单。其功能主要是将一个数据表映射成一个类。这个类提供了Add和Save方法以及和数据表的每个字段相对应的 属性。使用这个类可以向数据表添加记录。为了便于描述,将这个数据表保存成xml文件格式。每条记录为一个item结点,每一个字段为这个结点的一个属 性。表名为这个xml文件的根结点名称。这个xml文件的格式如下所示:
<MyTable>                                 
<item id = "01" name = "Bill"/>
<item id = "02" name = "Mike" />
</MyTable>
这个CodeWizard通过一个模板文件来定义数据表的结构。模板文件的格式如下:
<MyTable>
<id type = "System.Int32"/>
<name type = "System.String"/>
</MyTable>
其 中type为字段的类型,它的值是在.net framework中的System中定义的简单类型,如System.Int32、System.String、System.Char等。下面就详细 讨论如何利用这个模板文件和CodeDOM技术来生成C#和VB.net的源代码。
   
CodeDOM的结构
CodeDOM由两部分组成:
1. 用 于描述抽象代码结构的一组类。其中CodeCompileUnit类是这些类的根。代表一个源码文件(如C#的*.cs和VB.net的*.vb)。在使 用CodeDOM时,必须先建立一个CodeCompileUnit类的对象,然后在这个对象中加入必要的namespace、class等面向对象元 素。
2.     用于生成和编译源代码的类。这个类必须从CodeDomProvider类继承。每种.net framework
所支持的语言都有自己的CodeDomProvider类。如在C#中的CodeDomProvider类叫CSharpCodeProvider,而在VB.net中叫VBCodeProvider

三、数据表类的定义
要用CodeDOM定义一个类需要三步:
1. 建立一个CodeCompileUnit对象。这个类相当于一个源码文件。
2. 建立一个CodeNamespace对象。理论上在.net framework上运行的程序语言,如C#、VB.net
等,可以没有namespace。但在CodeDOM中必须使用这个类,如果不想要namespace,可以将namespace的名字设为 null或空串。
2.     建立一个CodeTypeDeclaration对象。这个类可以建立Class和Interface两种Type。在
这个例子中只建立Class。如果想建立Interface,只需将IsInterface属性设为true即可。
主要的实现代码如下:

private CodeCompileUnit m_CodeCompileUnit; private CodeNamespace m_CodeNameSpace; private CodeTypeDeclaration m_Class; private void InitCodeDom() { m_CodeCompileUnit = new CodeCompileUnit(); m_CodeNameSpace = new CodeNamespace("xml.tables"); m_CodeCompileUnit.Namespaces.Add(m_CodeNameSpace); m_Class = new CodeTypeDeclaration(m_ClassName); m_CodeNameSpace.Types.Add(m_Class); }

    其中namespace的名子是“xml.tables”。在建立完namespace后,将其加入到m_CodeCompileUnit的 Namespaces集合中。m_ClassName是一个String变量,它的值就是数据表的表名。最后将所建立的类加入到namespace的 Types集合中。在产生完类后。需要在这个类中加入四部分内容,它们分别是:全局变量、属性、构造函数和方法(Add和Save方法)。下面就分别讨论 它们的实现过程。

 
全局变量的生成
这个数据表类中有四种全局变量:用于操作xml文件的类型为XmlDocument的变量、用于保存数据表文件名的变量、用于确定是否为加入状态的Boolean型变量、以及用于保存每个字段值的变量组。具体实现代码如下:

private void GenerateFields() { // 产生 "private XmlDocument m_xml = new XmlDocument();" CodeMemberField xml = new CodeMemberField("System.Xml.XmlDocument", "m_xml"); CodeObjectCreateExpression createxml = new CodeObjectCreateExpression("System.Xml.XmlDocument"); xml.InitExpression = createxml; m_Class.Members.Add(xml); // 产生 "private String m_XmlFile;" CodeMemberField xmlfile = new CodeMemberField("System.String", "m_XmlFile"); m_Class.Members.Add(xmlfile); // 根据模板文件产生保存字段值的变量 String fieldname = "", fieldtype = ""; foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes) { fieldname = "m_" + xn.Name; fieldtype = xn.Attributes["type"].Value; CodeMemberField field = new CodeMemberField(fieldtype, fieldname); m_Class.Members.Add(field); } // 产生 "private bool m_AddFlag;" CodeMemberField addflag = new CodeMemberField("System.Boolean", "m_AddFlag"); m_Class.Members.Add(addflag); }


    在以上代码中每段程序上方的注释是它们所生成的C#源代码。在输入这段代码之前,需要引入两个namespace。

using System.CodeDom;
using System.CodeDom.Compiler;

四、属性的生成

 
    在数据表类中每个属性代表数据表的一个字段,名子就是字段名。这些属性和保存字段的全局变量一一对应。下面是具体的实现代码:

private void GenerateProperties() { String fieldname = "", fieldtype = ""; foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes) { fieldname = xn.Name; fieldtype = xn.Attributes["type"].Value; CodeMemberProperty property = new CodeMemberProperty(); property.Attributes = MemberAttributes.Public | MemberAttributes.Final; property.Name = fieldname; property.Type = new CodeTypeReference(fieldtype); property.HasGet = true; property.HasSet = true; CodeVariableReferenceExpression field = new CodeVariableReferenceExpression("m_" + fieldname); // 产生 return m_property CodeMethodReturnStatement propertyReturn = new CodeMethodReturnStatement(field); property.GetStatements.Add(propertyReturn); // 产生 m_property = value; CodeAssignStatement propertyAssignment = new CodeAssignStatement(field, new CodePropertySetValueReferenceExpression()); property.SetStatements.Add(propertyAssignment); m_Class.Members.Add(property); } }


    这些生成的属性是可读写的。这就需要将HasGet和HasSet两个属性设为true,然后分别将get和set方法中的语句分别加到GetStatements和SetStatements中。

构造函数的生成
    构造函数的主要工作是打开数据表。如果数据表不存在,就创建这个数据表文件。在编写代码之前,需要先定义三个全局变量。因为这三个全局变量在程序中会多次 用到。它们的类型都是CodeVariableReferenceExpression。这个类型变量其实在生成源码中的作用就是对某一个变量的引用。具 体的实现代码如下:

private CodeVariableReferenceExpression m_XmlFileExpression; private CodeVariableReferenceExpression m_XmlExpression; private CodeVariableReferenceExpression m_AddFlagExpression; private void InitVariants() { m_XmlFileExpression = new CodeVariableReferenceExpression("m_XmlFile"); m_XmlExpression = new CodeVariableReferenceExpression("m_xml"); m_AddFlagExpression = new CodeVariableReferenceExpression("m_AddFlag"); }

下面是生成构造函数的源代码:


Add和Save方法生成
Add方法只有一条语句,功能是将m_AddFlag设为true,以使数据表类处于加入状态。Save方法比较复杂。它的功能是当m_AddFlag为true时在数据表文件的最后加入一条记录,并保存。具体实现代码如下:
private void GenerateMethods() { CodeTypeReference voidReference = new CodeTypeReference("System.void"); //产生Add方法 CodeMemberMethod add = new CodeMemberMethod(); add.ReturnType = voidReference; add.Name = "add"; add.Attributes = MemberAttributes.Public | MemberAttributes.Final; CodeAssignStatement assignAddTrue = new CodeAssignStatement(m_AddFlagExpression, new CodePrimitiveExpression(true)); add.Statements.Add(assignAddTrue); m_Class.Members.Add(add); //产生Save方法 CodeMemberMethod save = new CodeMemberMethod(); save.ReturnType = voidReference; save.Name = "save"; save.Attributes = MemberAttributes.Public | MemberAttributes.Final; System.Collections.Generic.List<CodeStatement> ifStatements = new System.Collections.Generic.List<CodeStatement>(); //产生 "XmlNode xn = m_xml.CreateNode(XmlNodeType.Element, "item", "");" CodeVariableDeclarationStatement xmlNode = new CodeVariableDeclarationStatement("System.Xml.XmlNode", "xn"); CodeMethodInvokeExpression createNode = new CodeMethodInvokeExpression(m_XmlExpression, "CreateNode", new CodeExpression[] {new CodeVariableReferenceExpression("System.Xml.XmlNodeType.Element"), new CodePrimitiveExpression("item"), new CodePrimitiveExpression("") }); xmlNode.InitExpression = createNode; ifStatements.Add(xmlNode); //产生 "XmlAttribute xa = null; " CodeVariableDeclarationStatement xmlAttr = new CodeVariableDeclarationStatement("System.Xml.XmlAttribute", "xa"); xmlAttr.InitExpression = new CodePrimitiveExpression(null); ifStatements.Add(xmlAttr); //产生字段属性 CodeStatementCollection statements = new CodeStatementCollection(); foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes) { CodeMethodInvokeExpression createAttribute = new CodeMethodInvokeExpression(m_XmlExpression, "CreateAttribute", new CodePrimitiveExpression(xn.Name)); CodeAssignStatement assignxa = new CodeAssignStatement(new CodeVariableReferenceExpression("xa"), createAttribute); CodeMethodInvokeExpression invokeToString = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("m_" + xn.Name), "ToString"); CodeAssignStatement assignValue = new CodeAssignStatement(new CodeVariableReferenceExpression("xa.Value"), invokeToString); CodeMethodInvokeExpression invokeAppend = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("xn.Attributes"), "Append", new CodeVariableReferenceExpression("xa")); statements.Add(invokeAppend); ifStatements.Add(assignxa); ifStatements.Add(assignValue); ifStatements.Add(statements[0]); } // 产生 "m_xml.DocumentElement.AppendChild(xn);" CodeMethodInvokeExpression invokeAppendChild = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("m_xml.DocumentElement"), "AppendChild", new CodeVariableReferenceExpression("xn")); statements.Clear(); statements.Add(invokeAppendChild); ifStatements.Add(statements[0]); // 产生 "m_xml.Save(m_XmlFile);" CodeMethodInvokeExpression invokeSave = new CodeMethodInvokeExpression(m_XmlExpression, "Save", m_XmlFileExpression); statements.Clear(); statements.Add(invokeSave); ifStatements.Add(statements[0]); // 产生 "m_AddFlag = false;" CodeAssignStatement assignAddFalse = new CodeAssignStatement(m_AddFlagExpression, new CodePrimitiveExpression(false)); ifStatements.Add(assignAddFalse); // 产生if语句: "if (m_AddFlag)" CodeConditionStatement ifStatement = new CodeConditionStatement(m_AddFlagExpression, ifStatements.ToArray()); save.Statements.Add(ifStatement); m_Class.Members.Add(save); }

 

五、生成源代码
生成具体语言的源代码需要一个从CodeDomProvider继承的类。对于C#而言是CSharpCodeProvider类。实现代码如下:

using Microsoft.CSharp; public void SaveCSharp(String filename) { IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter(filename, false), " "); CodeDomProvider provide = new CSharpCodeProvider(); provide.GenerateCodeFromCompileUnit(m_CodeCompileUnit, tw, new CodeGeneratorOptions()); tw.Close(); }

    在使用CSharpCodeProvider类时需要用到m_CodeCompileUnit这个全局变量。这样可产生一个*.cs文件。以上代码中的 IndentedTextWriter类是建立一个文件的Writer,用于向这个文件中输出源代码。但和其它的Writer不同的是它的输出是缩进的 (以四个空格进行缩进)。如是想生成VB.net的代码,只需将CSharpCodeProvider改为VBCodeProvider即可。

 
编译源代码
到 现在为止,这个数据表类的源代码已经全部生成了。你可以将这个源文件直接加入到自己的工程中。或者直接将其编译成*.dll文件,然后在程序中调用。如果 想编译,可以直接调用指定语言的编译器(如C#中的csc.exe)。但这样不是太方便。在CodeDOM中提供了一种机制,可以在程序中通过 CodeDomProvider直接调用指定语言的编译器。下面是编译C#源程序的一个例子。
 

public void CompileCSharp(String sourcefile, String targetFile) { CompilerParameters cp = new CompilerParameters(new String[] { "System.Xml.dll" }, targetFile, false); CodeDomProvider provider = new CSharpCodeProvider(); cp.GenerateExecutable = false; // 调用编译器 CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourcefile); if (cr.Errors.Count > 0) { // 显示编译错误 foreach (CompilerError ce in cr.Errors) System.Windows.Forms.MessageBox.Show(ce.ToString()); } }

    对于以上代码有两点说明:

  1. 使用CodeDomProvider调用编译器时也需要传递相应的参数,如在本例中将System.Xml.dll
作为一个参数,表示目标文件需要调用这个dll中的资源。
  1. 在调用编译器后,如果出现错误,可使用cr.Errors获得错误信息。
结束语
我花了一个晚上的时间实现了这个简单的例子,并用C#2.0调试通过,只是为了抛砖引玉。自动生成源代码有很多的方法,但使用CodeDom生成源代码会有更大的灵活性,主要表现在以下三个方面:
1.     语言无关。即只要是.net framework所支持的语言,并且这种语言提供了CodeDomProvider。
就可以生成这种语言的源代码。
2.     如果所生成的语言是测试版或要将这种语言升级到下一个版本,也可以考虑使用CodeDOM。
因为当这种语言的语法有所变化时,CodeDomProvider也会随之升级。因此,使用CodeDOM的Code Wizards也会随着CodeDOM而升级,这样就不必修改Code Wizards的源代码了。
3.     如果所生成的一种语言是你所不熟悉的,如果不使用CodeDOM,必须要熟悉这种语言的语
法,才能生成它的源代码。而使用CodeDOM却可以避免这一点。因为CodeDOM是使用抽象的object graph来描述语言的。而语言的具体语法是由CodeDomProvider所决定的。
 
其实CodeDOM不仅可以用在Code Wizards上,也可以用在许多其它地方,如可以生成Web

Services的客户端代理(Client Proxies),或根据UML图生成类的构架代码。总之,使用CodeDom可以大大降低和语言的偶合度,并且很容易维护和升级系统。

[ORM]使用CodeDom提高ORM性能

mikel阅读(882)

使用CodeDom提高ORM性能

下载本文代码:http://www.cnblogs.com/Files/afritxia2008/WebTest.rar(请使用 Visual Studio 2008 打开)
  在进行讨论之前,我假设读者已经了解
.NET反射、自定义属性、CodeDom这些技术。并接触过ORM框架源码,如果对ORM并不了解,可以参考:
http://www.cnblogs.com/xdesigner/archive/2008/06/24/1228702.html。在这篇文章中,我们主要讨论通过CodeDom提高ORM读取数据的性能问题。

  ORMObject/Relation Mapping对象关系数据库映射)其中的一个功能是将数据源数据赋值给实体。实现方法是利用自定义属性和.NET反射机制。例如:

 1    public class LWordEntity
 2    {
 3        /// <summary>
 4        /// 获取或设置留言 ID
 5        /// </summary>

 6        [DataColumn(ColumnName = "LWordUID")]
 7        public int LWordUID
 8        {
 9            // 
10        }

11
12        /// <summary>
13        /// 获取或设置发送用户
14        /// </summary>

15        [DataColumn(ColumnName = "PostUser")]
16        public string PostUser
17        {
18            // 
19        }

20
21        /// <summary>
22        /// 获取或设置发送时间
23        /// </summary>

24        [DataColumn(ColumnName = "PostTime")]
25        public DateTime PostTime
26        {
27            // 
28        }

29
30        /// <summary>
31        /// 获取或设置文本内容
32        /// </summary>

33        [DataColumn(ColumnName = "TextContent")]
34        public string TextContent
35        {
36            // 
37        }

38    }


  DataColumn是自定义的属性类,代码并不复杂所以在这里也就省略了。接下来需要通过反射读取自定义属性,并赋值。代码如下:

 1    public void PutEntityProperties(object objEntity, DbDataReader dr)
 2    {
 3        // 获取实体类型
 4        Type objType = objEntity.GetType();
 5
 6        // 获取属性信息
 7        PropertyInfo[] propInfoList = objType.GetProperties();
 8
 9        if (propInfoList == null || propInfoList.Length <= 0)
10            return;
11
12        foreach (PropertyInfo propInfo in propInfoList)
13        {
14            object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
15
16            // 未标记 DataColumn 属性
17            if (colAttrList == null || colAttrList.Length <= 0)
18                continue;
19
20            // 获取数据列属性
21            DataColumnAttribute colAttr = colAttrList[0as DataColumnAttribute;
22
23            int ordinal = 1;
24
25            try
26            {
27                // 获取数据列序号
28                ordinal = dr.GetOrdinal(colAttr.ColumnName);
29            }

30            catch (Exception ex)
31            {
32                throw new MappingException(
33                    String.Format("{0} 未找到该数据列( Cannot Found this Column {0} )", colAttr.ColumnName), ex);
34            }

35
36            // 获取数据列值
37            object objValue = dr.GetValue(ordinal);
38
39            if (objValue is DBNull)
40            {
41                // 将 null 值设置到属性
42                propInfo.SetValue(objEntity, nullnull);
43            }

44            else
45            {
46                // 将值设置到属性
47                propInfo.SetValue(objEntity, objValue, null);
48            }

49        }

50    }

51


  以上代码实现 了读取数据源数据并向实体赋值的功能。但这样做速度非常慢,因为每读取一条数据库记录,每读取一个数据字段并向实体赋值的时候,都必须进行一次反射操作。 数据量越大,且数据字段或实体属性越多,那么速度就越慢!在以上代码中,对实体的反射操作,其目的就是赋值。可以被等价的语句所替代:
    
entity.Prop = dr[“Porp”];
用简单的赋值语句肯定要比反射的速度快很多,而大数据量和多数据库字段对其影响也不是很大。不过需要注意的是因为每一个实体的具体属性不相同,所以赋值过程也是不相同的。例如:
News实体赋值代码:

 1        void PutEntityProperties(NewsEntity entity, DbDataReader dr)
 2        {
 3            // 新闻 ID
 4            entity.ID = (int)dr["ID"];
 5            // 标题
 6            entity.Title = (string)dr["Title"];
 7            // 摘要
 8            entity.Summary = (string)dr["Summary"];
 9            // 发送用户
10            entity.PostUser = (string)dr["PostUser"];
11            // 发送时间
12            entity.PostTime = (DateTime)dr["PostTime"];
13            // 文本内容
14            entity.TextContent = (string)dr["TextContent"];
15        }

User实体赋值代码:

 1        void PutEntityProperties(UserEntity entity, DbDataReader dr)
 2        {
 3            // 用户 ID
 4            entity.ID = (int)dr["ID"];
 5            // 用户名称
 6            entity.UserName = (string)dr["UserName"];
 7            // 密码
 8            entity.UserPass = (string)dr["UserPass"];
 9            // 电子邮件
10            entity.EMail = (string)dr["EMail"];
11            // 注册时间
12            entity.RegisterTime = (DateTime)dr["RegisterTime"];
13        }

14

  NewsUser所具备的属性不同,所以赋值过程,也不相同!但毫无疑问,使用直接赋值的方法是速度最快的!试想一下,假如在做反射的时候不是直接赋值,而是根据自定义属性,动态的生成赋值代码,编译以后临时保存起来。那么以后再进行赋值操作的时候,直接调用这个编译好的赋值代码,不就可以大大提升程序性能了么?有没有一个办法可以自动建立类似上面这样的代码呢?我们可以考虑使用反射和CodeDom技术。

  首先为了解决不同实体的不同的赋值过程,我们需要建立一个接口:IEntityPropertyPutter。在该接口中的PutEntityProperties函数负责真正的赋值逻辑。在赋值的过程中会调用IEntityPropertyPutter的具体实现类的实例。具体类图如下:
 

  EntityPropertyPutterFactory工厂类负责创建IEntityPropertyPutter接口具体实现类的实例。首先该工厂类会从缓存中获取IEntityPropertyPutter接口实例,如果该实例为空(还没有被创建),那么该工厂类会调用EntityPropertyPutterMaker构建者类创建实例(Entity实体类本身也可以直接实现IEntityPropertyPutter接口,来加快程序的运行速度)。在构建者内部会动态创建新的程序集(Assembly),在该程序集中只存在一个QuicklyPutter类。在QuicklyPutter类中描述了具体的赋值逻辑,这些逻辑编码则是根据反射和CodeDom完成的。最后交由CodeDom动态编译……根据不同的实体,所创建的程序集也不相同。所编译成功的程序集是临时存放在内存里,所以QuicklyPutter类用白色表示。具体代码如下:

 1using System;
 2using System.Collections.Generic;
 3using System.Data.Common;
 4using System.Reflection;
 5
 6using Net.AfritXia.Data.Mapping;
 7
 8namespace Net.AfritXia.Data
 9{
10    partial class SQLHelper
11    {
12        public void PutEntityProperties<T>(T entity, DbDataReader dr) where T : class
13        {
14            // 获取设置器
15            IEntityPropertyPutter<T> putter = EntityPropertyPutterFactory.Create<T>(entity, this.IncludeDebugInformation);
16
17            if (putter == null)
18                throw new NullReferenceException(@"设置器为空( Null Putter )");
19
20            try
21            {
22                // 设置实体属性
23                putter.PutEntityProperties(entity, dr);
24            }

25            catch (Exception ex)
26            {
27                string errorMessage = null;
28                
29                // 定义异常信息格式
30                errorMessage = @"从数据库字段{0} 读取值并赋给属性{1} 时出错(实体类型: {2})";
31                // 格式化信息
32                errorMessage = String.Format(errorMessage, putter.CurrentDBColName, putter.CurrentPropName, putter.EntityTypeName);
33
34                // 抛出异常
35                throw new Exception(errorMessage, ex);
36            }

37        }

38    }

39}

40

 

设置器工厂类EntityPropertyPutterFactory:

 

 1using System;
 2using System.Collections;
 3using System.Reflection;
 4
 5namespace Net.AfritXia.Data
 6{
 7    /// <summary>
 8    /// 实体属性设置器工厂类
 9    /// </summary>

10    internal sealed class EntityPropertyPutterFactory
11    {
12        // 设置器字典
13        private static readonly Hashtable g_putterHash = Hashtable.Synchronized(new Hashtable());
14
15        /// <summary>
16        /// 创建实体属性设置器
17        /// </summary>
18        /// <typeparam name="T">实体类型模版</typeparam>
19        /// <param name="fromEntity">实体</param>
20        /// <param name="includeDebugInfo">是否包含调试信息</param>
21        /// <returns></returns>

22        public static IEntityPropertyPutter<T> Create<T>(T fromEntity, bool includeDebugInfo) where T : class
23        {
24            if (fromEntity == null)
25                return null;
26
27            // 如果实体本身已经实现了 IEntityPropertyPutter<T> 接口, 
28            // 则直接返回
29            if (fromEntity is IEntityPropertyPutter<T>)
30                return (IEntityPropertyPutter<T>)fromEntity;
31
32            IEntityPropertyPutter<T> putter = null;
33
34            // 获取字典关键字
35            string hashKey = fromEntity.GetType().FullName;
36
37            if (g_putterHash.ContainsKey(hashKey))
38            {
39                // 从字典中获取设置器
40                putter = g_putterHash[hashKey] as IEntityPropertyPutter<T>;
41            }

42            else
43            {
44                EntityPropertyPutterMaker maker = null;
45
46                // 创建构建器
47                maker = new EntityPropertyPutterMaker();
48                // 是否包含调试信息
49                maker.IncludeDebugInformation = includeDebugInfo;
50
51                // 新建应用程序集
52                putter = maker.Make<T>();
53                // 保存应用设置器到字典
54                g_putterHash.Add(hashKey, putter);
55            }

56
57            return putter;
58        }

59    }

60}

构建器EntityPropertyPutterMaker:

  1#undef _Debug  // 用于调试
  2
  3using System;
  4using System.CodeDom;
  5using System.Collections.Specialized;
  6using System.CodeDom.Compiler;
  7using System.Data.Common;
  8#if _Debug
  9using System.IO;
 10#endif
 11using System.Reflection;
 12
 13using Microsoft.CSharp;
 14
 15using Net.AfritXia.Data.Mapping;
 16
 17namespace Net.AfritXia.Data
 18{
 19    /// <summary>
 20    /// 构建实体属性设置器
 21    /// </summary>

 22    internal sealed class EntityPropertyPutterMaker
 23    {
 24        // 默认名称空间
 25        private const string DefaultNamespace = "Net.AfritXia.Data._AutoCode";
 26        // QuicklyPutter 类名称
 27        private const string QuicklyPutterClassName = "QuicklyPutter";
 28
 29        // 包含调试信息
 30        private bool m_includeDebugInfo = false;
 31
 32        类构造器
 40
 41        /// <summary>
 42        /// 设置或获取是否包含调试信息
 43        /// </summary>

 44        public bool IncludeDebugInformation
 45        {
 46            set
 47            {
 48                this.m_includeDebugInfo = value;
 49            }

 50
 51            get
 52            {
 53                return this.m_includeDebugInfo;
 54            }

 55        }

 56
 57        /// <summary>
 58        /// 构建实体属性设置器
 59        /// </summary>
 60        /// <typeparam name="T">实体类型模版</typeparam>
 61        /// <returns></returns>

 62        public IEntityPropertyPutter<T> Make<T>() where T : class
 63        {
 64            // 创建一个可编译的单元
 65            CodeCompileUnit compileUnit = this.MakeCompileUnit();
 66            // 创建名称空间
 67            CodeNamespace namespace_code = this.MakeNamespace();
 68            // 定义类
 69            CodeTypeDeclaration class_code = this.MakeClass<T>();
 70            // 创建 PutEntityProperties 方法
 71            CodeMemberMethod method_code = this.MakeMethod<T>();
 72
 73            // 添加方法到类
 74            class_code.Members.Add(method_code);
 75            // 添加类到名称空间
 76            namespace_code.Types.Add(class_code);
 77            // 添加名称空间到编译单元
 78            compileUnit.Namespaces.Add(namespace_code);
 79
 80            // 创建 C# 编译器
 81            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
 82            // 创建编译参数
 83            CompilerParameters options = new CompilerParameters();
 84
 85            // 添加对 System.dll 的引用
 86            options.ReferencedAssemblies.Add("System.dll");
 87            // 添加对 System.Data.dll 的引用
 88            options.ReferencedAssemblies.Add("System.Data.dll");
 89            // 添加对该项目的引用
 90            options.ReferencedAssemblies.Add(this.GetType().Assembly.Location);
 91            // 添加对实体项目的引用
 92            options.ReferencedAssemblies.Add(typeof(T).Assembly.Location);
 93            // 只在内存中编译
 94            options.GenerateInMemory = true;
 95
 96#if _Debug
 97            string srcFilePath = null;
 98
 99            srcFilePath = @"C:\{0}_{1}.cs";
100            srcFilePath = String.Format(srcFilePath, typeof(T).Name, QuicklyPutterClassName);
101
102            // 源文件输出流
103            StreamWriter srcOutput = new StreamWriter(srcFilePath, false);
104            // 写出源文件
105            provider.GenerateCodeFromCompileUnit(compileUnit, srcOutput, new CodeGeneratorOptions());
106
107            srcOutput.Flush();
108            srcOutput.Close();
109#endif
110
111            // 编译并获取编译结果
112            CompilerResults compileResult = provider.CompileAssemblyFromDom(options, compileUnit);
113
114            // 编译失败则抛出异常
115            if (compileResult.NativeCompilerReturnValue != 0)
116                throw new Exception("编译失败 ( Compile Failed )");
117
118            // 创建设置器
119            object putter = compileResult.CompiledAssembly.CreateInstance(DefaultNamespace + "." + QuicklyPutterClassName);
120
121            return (IEntityPropertyPutter<T>)putter;
122        }

123
124        /// <summary>
125        /// 构建可编译单元
126        /// </summary>
127        /// <returns></returns>

128        private CodeCompileUnit MakeCompileUnit()
129        {
130            // 创建一个可编译的单元
131            return new CodeCompileUnit();
132        }

133
134        /// <summary>
135        /// 构建名称空间
136        /// </summary>
137        /// <returns></returns>

138        private CodeNamespace MakeNamespace()
139        {
140            // 创建名称空间
141            return new CodeNamespace(DefaultNamespace);
142        }

143
144        /// <summary>
145        /// 构建 QuicklyPutter 类
146        /// </summary>
147        /// <returns></returns>

148        private CodeTypeDeclaration MakeClass<T>() where T : class
149        {
150            // 定义 QuicklyPutter 类
151            CodeTypeDeclaration class_code = new CodeTypeDeclaration(QuicklyPutterClassName);
152
153            // 令该类实现 IEntityPropertyPutter<T> 接口
154            class_code.BaseTypes.Add(typeof(IEntityPropertyPutter<T>));
155
156            // 添加 EntityTypeName 属性
157            class_code = this.MakeEntityTypeNameProperty<T>(class_code);
158            // 添加 CurrentPropName 属性
159            class_code = this.MakeCurrentPropNameProperty(class_code);
160            // 添加 CurrentDBColName 属性
161            class_code = this.MakeCurrentDBColNameProperty(class_code);
162
163            return class_code;
164        }

165
166        /// <summary>
167        /// 构建 EntityTypeName 属性
168        /// </summary>
169        /// <typeparam name="T">实体类型模版</typeparam>
170        /// <param name="targetClass">目标代码</param>
171        /// <returns></returns>

172        private CodeTypeDeclaration MakeEntityTypeNameProperty<T>(CodeTypeDeclaration targetClass) where T : class
173        {
174            if (targetClass == null)
175                throw new ArgumentNullException("targetClass");
176
177            /* 
178             * 以下代码将生成
179             * 
180             * public string EntityTypeName
181             * {
182             *     get
183             *     {
184             *         return 实体类型名称字符串
185             *     }
186             * }
187             * 
188             * 
189             */

190
191            // EntityTypeName 属性
192            CodeMemberProperty entityTypeNameProp_code = null;
193            
194            // 创建属性
195            entityTypeNameProp_code = new CodeMemberProperty();
196            // 定义为公共属性
197            entityTypeNameProp_code.Attributes = MemberAttributes.Public;
198            // 返回字符串类型
199            entityTypeNameProp_code.Type = new CodeTypeReference(typeof(string));
200            // 属性名称
201            entityTypeNameProp_code.Name = "EntityTypeName";
202            // 返回语句
203            entityTypeNameProp_code.GetStatements.Add(
204                new CodeMethodReturnStatement(new CodePrimitiveExpression(typeof(T).Name)));
205
206            // 添加属性到类
207            targetClass.Members.Add(entityTypeNameProp_code);
208
209            return targetClass;
210        }

211
212        /// <summary>
213        /// 构建 CurrentPropName 属性
214        /// </summary>
215        /// <param name="targetClass">目标类代码</param>
216        /// <returns></returns>

217        private CodeTypeDeclaration MakeCurrentPropNameProperty(CodeTypeDeclaration targetClass)
218        {
219            if (targetClass == null)
220                throw new ArgumentNullException("targetClass");
221
222            /* 
223             * 以下代码将生成
224             * 
225             * private string m_currPropName;
226             * 
227             * public string CurrentPropName 
228             * {
229             *     get
230             *     {
231             *         return this.m_currPropName;
232             *     }
233             * }
234             * 
235             */

236
237            // 变量名称
238            const string VaribleName = "m_currPropName";
239
240            // m_currPropName
241            CodeMemberField m_currPropName_code = null;
242
243            // 创建字段
244            m_currPropName_code = new CodeMemberField();
245            // 定义为私有成员
246            m_currPropName_code.Attributes = MemberAttributes.Private;
247            // 创建变量
248            m_currPropName_code = new CodeMemberField(typeof(string), VaribleName);
249
250            // 添加成员到类
251            targetClass.Members.Add(m_currPropName_code);
252
253            // CurrentPropName
254            CodeMemberProperty currPropName_code = null;
255            
256            // 创建属性
257            currPropName_code = new CodeMemberProperty();
258            // 定义为公共属性
259            currPropName_code.Attributes = MemberAttributes.Public;
260            // 返回字符串类型
261            currPropName_code.Type = new CodeTypeReference(typeof(string));
262            // 属性名称
263            currPropName_code.Name = "CurrentPropName";
264            // get 返回语句
265            currPropName_code.GetStatements.Add(
266                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), VaribleName)));
267
268            // 添加属性到类
269            targetClass.Members.Add(currPropName_code);
270
271            return targetClass;
272        }

273
274        /// <summary>
275        /// 构建 CurrentDBColName 属性
276        /// </summary>
277        /// <param name="targetClass">父级类</param>
278        /// <returns></returns>

279        private CodeTypeDeclaration MakeCurrentDBColNameProperty(CodeTypeDeclaration targetClass)
280        {
281            if (targetClass == null)
282                throw new ArgumentNullException("targetClass");
283
284            /* 
285             * 以下代码将生成
286             * 
287             * private string m_currDBColName;
288             * 
289             * public string CurrentDBColName 
290             * {
291             *     get
292             *     {
293             *         return this.m_currDBColName;
294             *     }
295             * }
296             * 
297             */

298
299            // 变量名称
300            const string VaribleName = "m_currDBColName";
301            // m_currDBColName
302            CodeMemberField m_currDBColName_code = null;
303
304            // 创建字段
305            m_currDBColName_code = new CodeMemberField();
306            // 定义为私有成员
307            m_currDBColName_code.Attributes = MemberAttributes.Private;
308            // 创建变量
309            m_currDBColName_code = new CodeMemberField(typeof(string), VaribleName);
310
311            // 添加成员到类
312            targetClass.Members.Add(m_currDBColName_code);
313
314            // CurrentDBColName
315            CodeMemberProperty currDBCol_code = null;
316
317            // 创建属性
318            currDBCol_code = new CodeMemberProperty();
319            // 定义为公共属性
320            currDBCol_code.Attributes = MemberAttributes.Public;
321            // 返回字符串类型
322            currDBCol_code.Type = new CodeTypeReference(typeof(string));
323            // 属性名称
324            currDBCol_code.Name = "CurrentDBColName";
325            // get 返回语句
326            currDBCol_code.GetStatements.Add(
327                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_currDBColName")));
328
329            // 添加属性到类
330            targetClass.Members.Add(currDBCol_code);
331
332            return targetClass;
333        }

334
335        /// <summary>
336        /// 构建 PutEntityProperties 方法
337        /// </summary>
338        /// <typeparam name="T"></typeparam>
339        /// <param name="fromEntity"></param>
340        /// <returns></returns>

341        private CodeMemberMethod MakeMethod<T>() where T : class
342        {
343            // PutObjectProperties 方法
344            CodeMemberMethod method_code = null;
345            
346            // 创建方法
347            method_code = new CodeMemberMethod();
348            // 定义为公共方法
349            method_code.Attributes = MemberAttributes.Public;
350            // 返回类型
351            method_code.ReturnType = new CodeTypeReference(typeof(void));
352            // 方法名称
353            method_code.Name = "PutEntityProperties";
354            // 添加参数 entity
355            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(T), "entity"));
356            // 添加参数 dr
357            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(DbDataReader), "dr"));
358
359            // 获取实体类型
360            Type objType = typeof(T);
361
362            // 获取 DataTable 属性标记
363            object[] tabAttrList = objType.GetCustomAttributes(typeof(DataTableAttribute), false);
364
365            if (tabAttrList == null || tabAttrList.Length <= 0)
366            {
367                throw new MappingException(
368                    String.Format(@"类 {0} 未标记 DataTable 属性 ( Unlabeled [DataTable] Attribute On Class {0} )", objType.Name));
369            }

370
371            // 获取属性信息
372            PropertyInfo[] propInfoList = objType.GetProperties();
373
374            if (propInfoList == null || propInfoList.Length <= 0)
375                return null;
376
377            foreach (PropertyInfo propInfo in propInfoList)
378            {
379                object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
380
381                // 未标记 DataColumn 属性
382                if (colAttrList == null || colAttrList.Length <= 0)
383                    continue;
384
385                // 获取数据列属性
386                DataColumnAttribute colAttr = colAttrList[0as DataColumnAttribute;
387
388                // 创建方法内容
389                method_code = this.MakeMethodContent(method_code, propInfo, colAttr, this.IncludeDebugInformation);
390            }

391
392            return method_code;
393        }

394
395        /// <summary>
396        /// 构建 PutEntityProperties 方法内容
397        /// </summary>
398        /// <param name="targetMethod"></param>
399        /// <param name="prop"></param>
400        /// <param name="attr"></param>
401        /// <param name="includeDebugInfo"></param>
402        /// <returns></returns>

403        private CodeMemberMethod MakeMethodContent(CodeMemberMethod targetMethod, PropertyInfo prop, DataColumnAttribute attr, bool includeDebugInfo)
404        {
405            if (targetMethod == null)
406                throw new ArgumentNullException("targetMethod");
407
408            if (attr == null)
409                throw new ArgumentNullException("attr");
410
411            // 实体变量名称 entity
412            string varEntityName = targetMethod.Parameters[0].Name;
413            // 数据源变量名称 dr
414            string varDrName = targetMethod.Parameters[1].Name;
415
416            // entity 属性名称
417            string varEntityPropName = String.Format(@"{0}.{1}", varEntityName, prop.Name);
418            // dr 属性名称
419            string varDrPropName = String.Format(@"{0}[""{1}""]", varDrName, attr.Name);
420
421            // 创建变量
422            CodeVariableReferenceExpression entityProp_code = new CodeVariableReferenceExpression(varEntityPropName);
423            // 创建值
424            CodeVariableReferenceExpression dr_code = new CodeVariableReferenceExpression(varDrPropName);
425
426            // 包含调试信息
427            if (includeDebugInfo)
428            {
429                // this.m_currPropName = entity.Prop
430                targetMethod.Statements.Add(new CodeAssignStatement(
431                    new CodeVariableReferenceExpression("this.m_currPropName"),
432                    new CodePrimitiveExpression(prop.Name)));
433
434                // this.m_currDBColName = attributeName
435                targetMethod.Statements.Add(new CodeAssignStatement(
436                    new CodeVariableReferenceExpression("this.m_currDBColName"),
437                    new CodePrimitiveExpression(attr.Name)));
438            }

439
440            if (attr.IsNullable)
441            {
442                /* 
443                 * 以下代码生成的是条件判断代码
444                 * 
445                 * if (dr[""] != DBNull.Value) {
446                 *     entity.Prop = dr[""];
447                 * }
448                 * 
449                 */

450
451                CodeConditionStatement if_code = new CodeConditionStatement();
452
453                // if (dr[""] != DBNull.Value)
454                if_code.Condition = new CodeBinaryOperatorExpression(
455                    new CodeVariableReferenceExpression(varDrPropName),
456                    CodeBinaryOperatorType.IdentityInequality,
457                    new CodeVariableReferenceExpression("System.DBNull.Value"));
458
459                // entity.Prop = dr[""];
460                if_code.TrueStatements.Add(new CodeAssignStatement(
461                    entityProp_code,
462                    new CodeCastExpression(prop.PropertyType, dr_code)));
463
464                targetMethod.Statements.Add(if_code);
465            }

466            else
467            {
468                // entity.Prop = dr[""];
469                targetMethod.Statements.Add(new CodeAssignStatement(
470                    entityProp_code,
471                    new CodeCastExpression(prop.PropertyType, dr_code)));
472            }

473
474            return targetMethod;
475        }

476    }

477}

代码时序图如下:

 

具体代码可以参考:
Net.AfritXia.Data/IEntityPropertyPutter.cs
Net.AfritXia.Data/EntityPropertyPutterFactory.cs
Net.AfritXia.Data/EntityPropertyPutterMaker.cs
TestProj/UnitTest_Putter.cs(可以运行该测试文件)

[教程]HTTP请求流程(二)----Telnet模拟HTTP请求

mikel阅读(593)

上一部分"流程简介", 我们大致了解了下HTTP请求的流程,这一篇我向大家介绍下如何利用Telnet来模拟Http请求—访问百度。
      我们直接开始吧!
      1、打开"运行"->cmd进入命令环境;
      2、输入"telnet www.baidu.com 80",回车后 ,屏幕为全黑,此时我们利用快捷键"Ctrl+](右中括号)"来打开本地回显功能,这样我们就可以看见我们所打的东西了,如图:(注本阶段执行过程和以 下的过程均要求操作时间尽可能短,因为时间一长,便会被认为断开连接。)

      3、单击回车,进行编辑状态。
      4、输入:"GET / HTTP/1.1"后回车,在第二段接着输入:"HOST:"然后按回车,这样一个简单的HTTP请求就完成了,接着我人只要再按下回车,便向服务器递交 这个请求了。如图:(我们来看一下这个是什么意思:GET表示请求方式,/表示请求的根目录下的文件,HTTP/1.1表示HTTP协议版本,HOST就 是一个消息头,据某些朋友说1.1的版本一定要加一个"HOST:"可是我实验后发现"HOST :"不加仍旧可以正常发送请求,但是GET HTTP这个必须大写,否则就该请求无法发送)

      5、接收服务器返回,这步其实不需要我们来做,因为当我们发送请求后,只需几秒钟,我们便会收到来自服务器反应.

 
      6、这样,请求就算完成了。下面我们在百度中搜一下"1",浏览器中的地址应该是:http://www.baidu.com/s?wd=1.看看请求是怎么样的

      怎么样,大家会了吗?以上只是用GET方式进行请求,当然还可以用POST方式进行请求,只是POST我这不方便做实验,所以就不写了。大概的格式给大家参考下:
      POST /localhost/login.aspx HTTP/1.1
      HOST:
      Content-Type:application/x-www-form-urlencoded
      Content-Length:10
      
      uid=xxxxxx
参考:
1.张孝祥老师的HTTP协议详解
2.关于HTTP的请求头可以参考:http://hi.baidu.com/ʫչ/blog/item/13c2e3ddb3a133ee77c638cd.html

[控件].Net让你的实体字段和页面上的控件映射,自动绑定 -- ObjectBinding1.0

mikel阅读(755)

背景:使用ASP.NET开发,在编辑或新增一条记录时,你要把你的数据一个个赋值到页面上的控件去如:
Job job=…..;//获取一个Job实体
this.textbox1.Text=job.Name;
this.textbox2.Text=job.Position;
this.DropDownList1.SelectedValue=job.Grade;
….
….
由于基于bs的限制,控件不能想cs那样有(DataBindings)高级属性,于是在这种情况下,我自己封装了一个类似于中间件的控件ObjectBinding,把实体字段和页面上的控件映射,实现自动绑定。
下面就演示一下,如何在ASP.NET上使用:
1 首先把这控件拖拽到页面上:

2 设置ObjectBindingSourceTypeItemsMappings属性
SourceType即你的实体类型,类似与ObjectDataSource空间的TypeName,会自动加载所有的类型

ItemsMappings即建立控件与字段的映射,都只需要下拉选择一下就行

3 OK,基本的设置就这么多,现在我们在后台写些代码:

public partial class _Default : System.Web.UI.Page
{
    
protected void Page_Load(object sender, EventArgs e)
    
{
        
if (!Page.IsPostBack)
        
{
            ObjectBinding1.DataSource 
= (new ClassLibrary.Job()).getInstance();
            ObjectBinding1.DataBind();
        }

 
    }


    
protected void Button1_Click1(object sender, EventArgs e) {
        ObjectBinding1.ControlBind();
        ClassLibrary.Job Job 
= ObjectBinding1.DataSource as ClassLibrary.Job;

        Response.Write(
"Job.ID:" + Job.ID + "————–Job.Name:" + Job.Name);
    }

}


好了到此就能很好地显示出来了,看看效果

到此,就简单地介绍这么多,至于源码自己下载了去看吧,希望大家提些宝贵意见:)
源码下载

[Linq]在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Pa

mikel阅读(659)

构建业务外观层(Business Facade Layer
所有业务逻辑将在这一层实现。一般而言,这一层负责处理数据和在表现层与数据访问层之间传递数据。这一层从物理上提供上层接口隔离表现层代码和 数据访问层代码,ASP.NET页面不能直接与数据访问层交互。相反,页面应该调用业务外观层的方法。图3.1 展示了业务外观层的详细视图。

图3.1:业务外观层-详细视图
 
在我们的示例程序中,业务外观层仅仅包含一个组件-BFLCustomer。示例代码如下:
代码片段1.2:业务外观层
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataAccess;
using System.Data.Linq;
using DataLinq;
 
namespace BusinessFacade
{
    public class BFLCustomer
    {
        private DALCustomer objDataAccess = new DALCustomer();
 
        public Table<Customer> SelectRecordAll()
        {
            return objDataAccess.SelectRecordAll();
        }
 
        public Customer SelectRecordByID(string customerID)
        {
            return objDataAccess.SelectRecordByID(customerID);
        }
 
        public List<Customer> SelectRecordByIDListable(string customerID)
        {
            return objDataAccess.SelectRecordByIDListable(customerID);
        }
 
        public string InsertRecord(Customer localTable)
        {
            return objDataAccess.InsertRecord(localTable);
        }
 
        public void UpdateRecord(Customer localTable)
        {
            objDataAccess.UpdateRecord(localTable);
        }
 
        public void DeleteRecord(string customerID)
        {
            objDataAccess.DeleteRecord(customerID);
        }
 
        public Table<Order> SelectAllOrder()
        {
            return objDataAccess.SelectAllOrder();
        }
 
        public Table<Order_Detail> SelectAllOrderDetail()
        {
            return objDataAccess.SelectAllOrderDetail();
        }
    }
}
 
BFLCustomer 组件包括下面类图所示的公共方法列表,这些方法用来与数据访问层交换。
注:业务外观层没有创建DataContext类的实例,因此它不能够实现任何数据访问逻辑。
BFLCustomer 组件的类图如下:

图3.2:业务外观层 – 类图
EntLib.com 开源小组注:本文翻译《Building Multi-Tier Web Application in .NET 3.5 Framework Using LINQ to SQL》。后面内容待续。欢迎交流LINQ相关技术。

上几篇文章:
在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 1)
在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 2)
在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 3)

[代码]Window的onunload和onbeforeunload事件

mikel阅读(904)

以下是指在js中实现,而非 这种方法!
因为这样是在unload掉body的时候触发,而无聊任何浏览器,都会在关闭的时候unload掉body的!
模型1:
function close(){
alert(“sdfsdfsdf”);
}
window.onbeforeunload=close;
模型2:
function close(){
if(document.body.clientWidth-event.clientX< 170&&event.clientY< 0||event.altKey) { alert("sdfsdfsdf"); } } window.onbeforeunload=close; 对于模型1: 1).刷新,多窗口和单窗口都适合. 2).单窗口ie关闭整个ie触发. 3).ie7多窗口中关闭单页触发 4)其他多窗口刷新触发.关闭单个和关闭整个都不触发 对于模型2: 1).ie单窗口 和ie7多窗口,都要关闭整个浏览器才触发 2).其他多窗口浏览器刷新.关闭单页,关闭整个都不触发

[代码]标题栏闪烁

mikel阅读(804)

title_tmp1=document.title
if
(title_tmp1.indexOf(">>")!=-1){
title_tmp2=title_tmp1.split(">>");
title_last=" —> "+title_tmp2[1];
title_last=title_last + " —> " + title_tmp2[2];
}else{
if (title_tmp1.indexOf("——")!=-1){
title_tmp2=title_tmp1.split("——");
title_last=" —> "+title_tmp2[1];
if (title_last==" —> "){title_last=" —> "};
if (title_last==" —> "){title_last=" —> "};
}
else {    title_last="by:globetour"}
}
title_new="黑与白"+title_last+""
step=0
function flash_title()
{
step++
if (step==7) {step=1}
if (step==1) {document.title=&#39;◆◇◇◇&#39;+title_new+&#39;◇◇◇◆&#39;}
if (step==2) {document.title=&#39;◇◆◇◇&#39;+title_new+&#39;◇◇◆◇&#39;}
if (step==3) {document.title=&#39;◇◇◆◇&#39;+title_new+&#39;◇◆◇◇&#39;}
if (step==4) {document.title=&#39;◇◇◇◆&#39;+title_new+&#39;◆◇◇◇&#39;}
if (step==5) {document.title=&#39;◇◇◆◇&#39;+title_new+&#39;◇◆◇◇&#39;}
if (step==6) {document.title=&#39;◇◆◇◇&#39;+title_new+&#39;◇◇◆◇&#39;}
setTimeout("flash_title()",180);
}
flash_title()
***把上面这段:
if (step==7) {step=1}
if (step==1) {document.title=&#39;◆◇◇◇&#39;+title_new+&#39;◇◇◇◆&#39;}
if (step==2) {document.title=&#39;◇◆◇◇&#39;+title_new+&#39;◇◇◆◇&#39;}
if (step==3) {document.title=&#39;◇◇◆◇&#39;+title_new+&#39;◇◆◇◇&#39;}
if (step==4) {document.title=&#39;◇◇◇◆&#39;+title_new+&#39;◆◇◇◇&#39;}
if (step==5) {document.title=&#39;◇◇◆◇&#39;+title_new+&#39;◇◆◇◇&#39;}
if (step==6) {document.title=&#39;◇◆◇◇&#39;+title_new+&#39;◇◇◆◇&#39;}
换成:
if (step==5) {step=1}
if (step==1) {document.title=&#39;☆° .★·&#39;+title_new+&#39;.★·☆° &#39;}
if (step==2) {document.title=&#39;·☆° .★&#39;+title_new+&#39;★·☆° .&#39;}
if (step==3) {document.title=&#39;★·☆° .&#39;+title_new+&#39;·☆° .★&#39;}
if (step==4) {document.title=&#39;.★·☆° &#39;+title_new+&#39;☆° .★·&#39;}
可以得到另外一种效果哦!

[指南]ASP.NET学习路线

mikel阅读(876)

如果你已经有较多的面向对象开发经验,跳过以下这两步:
  第一步 掌握一门.NET面向对象语言,C#或VB.NET 我强烈反对在没系统学过一门面向对象(OO)语言的前提下去学ASP.NETASP.NET是一个全面向对象的技术,不懂OO,那绝对学不下去!
   第二步 对.NET Framework类库有一定的了解 可以通过开发Windows Form应用程序来学习.NET Framework。ASP.NET是建构在.NET Framework之上的技术,你对.NET Framework了解得越深,学习ASP.NET就越快。 举个例子:下面简单列出几个对掌握ASP.NET非常重要的概念: 对象的内存模型,委托,事件,多线程,程序集和应用程序域,安全模型 .NET Framework当然还有许多其它的东西,但不理解与把握清楚上述这些东西,是很难真正把握ASP.NET的。 出于急迫的心情与现实的考虑,不少人没有扎实的面向对象基础就想直接学习ASP.NET,其结果只能是欲速则不达。 在具备了OO基础之后,以下是具体的学习ASP.NET技术步骤。
  第一步:学习HTML与CSS
  这并不需要去学一大堆的诸 如Dreamweaver,Firework之类的各种网页设计工具,关键是理解HTML网页嵌套的block结构与CSS的box模型。许多 ASP.NET控件最后都必须转化为HTML。而且,div+CSS是当前主流的网页布局模型。 学习这部分时,关键在于理解概念,而不需要将精力花在美化页面的许多技巧上,那是网站美工的工作,不是程序员的工作。
  第二步:学习JavaScript
  JavaScript不是Java,它主要运行于浏览器端。可以完成许多工作,功能也很强大:比如它将客户端网页中的HTML元素看成一棵树,可以编写代码访问并修改树节点,动态生成新的HTML代码,从而达到动态修改网页显示特性的目的。
  JavaScript在目前的网站开发中用得很多,非常重要。
  另外,它也是目前非常流行的AJAX技术的基础。
  第三步:学习计算机网络原理
  找一本大学<计算机网络>教材,重点看看它的有关互联网的部分,了解一些域名解析和HTTP协议等知识。这是进行互联网开发的理论基础。
  第四步:学习ASP.NET表示层技术,会设计Web页面
  需要结合先前打好的面向对象技术的基础,至少掌握以下内容:
  (1) 各种Web控件的使用方法,
  (2) 理解信息在网页中的传送方式,比如Cookie,ViewState,Session等的使用。
  (3) ASP.NET应用程序与网页的生命周期,以及相关对象(比如httpcontext,response,request)的用途。
  (4) ASP.NET实现事件驱动的内幕
  (5) 自定义用户控件
  再次强调一下,没有OO基础,很难掌握上述技术,就只能被这些东东牵着鼻子走了,会很被动。
  第五步 掌握数据库技术
  具体地说,要学习以下内容:
  (1) 学会使用SQL Server 2005:不要求精通它的各种工具与管理配置技术,但至少知道如何连接,如何建表,如何创建存储过程
  (2) 学习ADO.NET,掌握使用代码人工访问数据库(别用VS2005的向导)的方法
  (3) 学习数据绑定控件的使用
  第六步 理解多层架构
  这时,先前在OO学习阶段涉及到的程序集与应用程序域等就派上用场了,现在,网站架构大多采用多层架构:表示层、业务逻辑层、数据存取层以及数据库本身。
  可以先上网找一此多层架构的资料看,再找一个现成的比较复杂的开源ASP.NET项目分析一下其架构就差不多了。基本上都是一个套路,到处应用。
  有的朋友问:学习架构是不是必须学习设计模式。
   我的看法是:不必!当然,你如果学习过设计模式,那当然更好。但在实际开发中,如果只想着机械地套用某种模式,反而起不到好的结果。我的观点:在学习设 计模式时要多思多悟,其思想就会渐渐地融入你的大脑,在真实的设计实践中,忘掉所有的写在书上的模式,一切从实际出发,相信你的直觉,只要达到设计要求的 方案就是可行的方案,事实上,你这样做了之后,回过头来再看,会发现你的设计往往暗合设计模式的理论。
  第七步 学习XML与Web Service
  先了解XML的基础知识,找本讲XML的书看一下就差不多了,然后,再学习Web Service。Web Service其实可类比为远程方法调用(以XML格式表达的调用信息)。
  学 到了这里,如果你还有兴趣,不妨再去看看SOA,不过SOA的资料都是理论与概念,看起来比较郁闷,而且离实际开发可能比较远。所以,这是可选项。
  第八步 学习AJAX
  学习AJAX的主要目的是创建具有更丰富特性的Web表示层,而经过前面七步的学习,到此再学习AJAX已水到渠成,所有的基础都已具备,不会有太大的问题了。
  在基础未具备的前提下直接学AJAX,就象“浮沙之上筑高台”,所以,将AJAX的学习次序安排在这里。
  第九步 学习RIA技术
  RIA:Rich internet application,可看成是将C/S与B/S优点合二为一的尝试。就具体技术来说,主要指微软的Silverlight(WPF_E),毕竟前头一路行来都是微软路线。
  不过目前学习它主要是为了技术储备。估计此技术的普及需要2到3年的时间,因为预装Vista的机器今年才开始大卖。
本贴来自ZDNetChina中文社区 http://bbs.zdnet.com.cn ,本贴地址:http://bbs.zdnet.com.cn/viewthread.php?tid=108315

[四格]有趣的血型漫画

mikel阅读(1199)

据说中国人B型血最多,美国O型最多,日本A型最多。
关于血型的四格漫画 作者:Realcrazyman 翻译:Bunny 























开车的时候会…





[Flex]采用Flex开发的虚拟社区《都市人生》

mikel阅读(825)

http://gz.o.cn/index.jspa
《都市人生》是结合都市圈虚拟仿真地图的在线虚拟社区游戏,采用Flex开发。地址是http://gz.o.cn。进去加载完后点击左上角的“都市人生”按钮后就可以进入游戏了
《都市人生》和其他Flash虚拟社区在线游戏最大的不同点是《都市人生》是和现实的3D地图结合起来的,例如你可以在珠江新城购买一套房产,然后购买户型,再购买家具装修等等。
《都市人生》已经实现的功能有购买房产、购买户型、购买家具、购买服饰等等,然后可以DIY自己的虚拟形象。装修自己的房间。在场景内和其他玩家聊天、看视频等。还可以玩小游戏等。