[代码]生成验证码的控件

mikel阅读(784)

看过网上很多关于ASP.NET生成 验证码的东西。大部分都牺牲了一个aspx页面来生成验证码图片。 而且还不利于二次使用。 于是想一直琢磨着想写一个不用牺牲一个aspx页面来完成验证码的控件,在使用的时候只需要引用一个dll并且在工具箱中直接拖到页面上就可。 经过几天努力还真琢磨出来了一个个人认为比较好的方法,于是拿出来共享一下,希望和大家交流交流意见。
现在开始

using System;
using System.Collections.Generic;
using System.Text;

using System.Web;
using System.Drawing;
using System.IO;
using System.Web.SessionState;

namespace jdTools.Web
{
    
public class VerifyImageHttpHandle : IHttpHandler, IRequiresSessionState
    
{
        
private string GetRandomNumberString(int codeCount)
        
{
            
int j1;
            
string strChoice = "2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z";
            
string[] strResult = strChoice.Split(new Char[] ',' });
            
string strReturn = "";
            Random rnd 
= new Random(unchecked((int)DateTime.Now.Ticks));
            
for (int i = 0; i < codeCount; i++)
            
{
                Random rnd1 
= new Random(rnd.Next() * unchecked((int)DateTime.Now.Ticks));
                j1 
= rnd1.Next(strResult.Length);
                rnd 
= new Random(rnd.Next() * unchecked((int)DateTime.Now.Ticks));
                strReturn 
= strReturn + strResult[j1].ToString();
            }

            
return strReturn;  
        }

        
private Color GetColor()
        
{
            
return Color.Black;
        }

        
private Bitmap CreateImage(string str_ValidateCode)
        
{
            Random newRandom 
= new Random((int)DateTime.Now.Ticks);
            
int int_ImageWidth = str_ValidateCode.Length * 14;
            
int int_ImageHeight = 20;
            
//  图高20px
            Bitmap theBitmap = new Bitmap(int_ImageWidth, int_ImageHeight);
            Graphics theGraphics 
= Graphics.FromImage(theBitmap);
            
//  白色背景
            theGraphics.Clear(Color.White);
            
//  灰色边框
            theGraphics.DrawRectangle(new Pen(Color.LightGray, 1), 00, int_ImageWidth  1, int_ImageHeight);

            
int num = theBitmap.Width * theBitmap.Height * 30 / 100;
            
for (int iCount = 0; iCount < num; iCount++)
            
{
                
// 在随机的位置使用随机的颜色设置图片的像素
                int x = newRandom.Next(theBitmap.Width);
                
int y = newRandom.Next(theBitmap.Height);
                
int r = newRandom.Next(255);
                
int g = newRandom.Next(255);
                
int b = newRandom.Next(255);
                Color c 
= Color.FromArgb(r, g, b);
                theBitmap.SetPixel(x, y, c);
            }
//for


            
//  10pt的字体
            Font theFont = new Font("Arial"12, FontStyle.Bold);

            
for (int int_index = 0; int_index < str_ValidateCode.Length; int_index++)
            
{
                
string str_char = str_ValidateCode.Substring(int_index, 1);
                Brush newBrush 
= new SolidBrush(GetColor());
                Point thePos 
= new Point(int_index * 13 + 1 + newRandom.Next(3), 1 + newRandom.Next(3));
                theGraphics.DrawString(str_char, theFont, newBrush, thePos);
            }

            
            theGraphics.Dispose();
            
return theBitmap;
            
        }


        
#region IHttpHandler 成员

        
public bool IsReusable
        
{
            
get return true; }
        }

        
public void ProcessRequest(HttpContext context)
        
{
            HttpResponse Response 
= context.Response;
            
//  将生成的图片发回客户端
            MemoryStream ms = new MemoryStream();
            
string NumStr=GetRandomNumberString(5);
            context.Session.Add(
"Verify", NumStr);

            Bitmap theBitmap 
= CreateImage(NumStr);
            theBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            Response.ClearContent(); 
//需要输出图象信息 要修改HTTP头 
            Response.ContentType = "image/jpeg";
            Response.BinaryWrite(ms.ToArray());
            theBitmap.Dispose();
            ms.Close();
            ms.Dispose();
            Response.End();
        }

        
#endregion

    }

}

GetRandomNumberString方法用于生成指定个数的随机数字符串。
IHttpHandle接口的ProcessRequest方法可以启用 HTTP Web 请求的处理。
VerifyImageHttpHandle 继承了IHttpHandle接口用于自定义程序处理的Web请求。然后在web.config的<system.web>节中配置

      <httpHandlers>
        
<add verb="*" path="VerifyImg.jd" type="jdTools.Web.VerifyImageHttpHandle"/>
      
</httpHandlers>

此时在浏览器中访问VerifyImg.jd时就会得到一个验证码图片,生成验证码的内容就完成了。
现在我们要自定义一个WEB自定义控件。其代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;


namespace jdTools.Web.UI
{
    [ToolboxData(
"<{0}:VerifyImage runat=server></{0}:VerifyImage>")]
    
public class VerifyImage : WebControl
    
{
        
public string Value
        
{
            
get return HttpContext.Current.Session["Verify"].ToString(); }
        }

        
public virtual ImageAlign ImageAlign
        
{
            
get
            
{
                
object obj2 = this.ViewState["ImageAlign"];
                
if (obj2 != null)
                
{
                    
return (ImageAlign)obj2;
                }

                
return ImageAlign.NotSet;
            }

            
set
            
{
                
if ((value < ImageAlign.NotSet) || (value > ImageAlign.TextTop))
                
{
                    
throw new ArgumentOutOfRangeException("value");
                }

                
this.ViewState["ImageAlign"= value;
            }


        }


        
public VerifyImage()
            : 
base(HtmlTextWriterTag.Img)
        
{ }
        
protected override void AddAttributesToRender(HtmlTextWriter writer)
        
{
            
base.AddAttributesToRender(writer);
            writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor, 
"pointer");
            writer.AddAttribute(
"onclick""this.src='VerifyImg.jd?id='+Math.random()"true);
            writer.AddAttribute(HtmlTextWriterAttribute.Src, 
"VerifyImg.jd");
            
string str2;
            
switch (this.ImageAlign)
            
{
                
case ImageAlign.Left:
                    str2 
= "left";
                    
break;

                
case ImageAlign.Right:
                    str2 
= "right";
                    
break;

                
case ImageAlign.Baseline:
                    str2 
= "baseline";
                    
break;

                
case ImageAlign.Top:
                    str2 
= "top";
                    
break;

                
case ImageAlign.Middle:
                    str2 
= "middle";
                    
break;

                
case ImageAlign.Bottom:
                    str2 
= "bottom";
                    
break;

                
case ImageAlign.AbsBottom:
                    str2 
= "absbottom";
                    
break;

                
case ImageAlign.AbsMiddle:
                    str2 
= "absmiddle";
                    
break;

                
case ImageAlign.NotSet:
                    str2
="";
                    
break;
                
default:
                    str2 
= "texttop";
                    
break;
            }

            
if (str2 != "")
                writer.AddAttribute(HtmlTextWriterAttribute.Align, str2);
        }

    }

}

VerifyImage 类定义了两个属性。其中Value属性用于取得session中存放的验证码的值。
这里就很简单了,没有必要详说。
在使用的时候aspx页面如下:

                    <ul>
                        
<li>用户名:<asp:TextBox ID="txtUserName" runat="server"></asp:TextBox></li>
                        
<li>密 码:<asp:TextBox ID="txtPassWord" runat="server"></asp:TextBox></li>
                        
<li>检证码:<asp:TextBox ID="txtVerify" runat="server" Width="50px"></asp:TextBox><jd:VerifyImage ID="verify" runat="server" Height="23px" ImageAlign="AbsMiddle"/></li>
                    
</ul>

aspx.cs中:

            if (txtVerify.Text != verify.Value)
            
{
                
//.验证码错误
            }

            
else
            
{
                
//验证码正确
            }

[资源].net网站

mikel阅读(695)

博客园博客堂CSDN 当然是不用说了,大家都知道的。
51ASPX.com
国内非常优秀的ASP.NET源码发布下载站,相信很多人都到过这里下载过源码。
孟子E章
很多非常实用的技术实例,当你遇到什么问题不妨先到这里看看,没准儿会有意想不到的收获。
CodeUsing.com
一个不错的.NET资源分享站,也算一个Web2.0的网站,注册用户可以发布资源。
msproject.cn
简单整洁的.NET开源技术社区,以前是一个开源技术论坛,改版后又增加了一些功能:视屏、公司点评等。
.NET正则表达式库(regex-lib.net)
博客园 Anders Liu 刚发布的正则表达式分享网站

C#资源大全
不用说,是一些开源资源了,只是好像两年没有更新了。
http://java.poac.ac.cn/codeopen/jiaocheng/cs-open/index.html

[代码]JavaScript 图片切换展示效果

mikel阅读(897)

看到alibaba的一个图片切换效果,感觉不错,想拿来用用。但代码一大堆的,看着昏,还是自己来吧。
由于有了做JavaScript 图片滑动展示效果的经验,做这个就容易得多了。
先看看效果:
根据alibaba做的效果:

  • 1
  • 2
  • 3

alibaba的按钮有一个延迟的功能,应该加个定时器,但这个不是重点就省了吧。
扩展成能左右切换:

  • 1
  • 2
  • 3

其他扩展功能:



切换速度:
停顿时间:


程序说明:
首先需要一个容器,设置它的overflow为hidden,position为relative;
容器里面还要一个滑动对象,设置它的position为
absolute;
initialize()函数里初始化一些属性。
在切换之前先执行Start()函数,进行相关设置,
主要是设置Index属性(索引)和_target属性(目标值):


if(this.Index < 0){
    
this.Index = this._count  1;
else if  (this.Index >= this._count){ this.Index = 0; }
this._target = 1 * this._parameter * this.Index;

接着就执行Move()函数开始移动了,原理通过设置滑动对象的top(或left)来做出移动的效果,
而减速的效果就需要执行GetStep()函数来获取步长:

var iStep = (iTarget  iNow) / this.Step;

用目标值减当前值再除以一个参数,得到步长,
这样取得的步长在当前值越接近目标值时会越来越小,也做成了减速的效果,
然后在top(或left)的设置中加上这个步长,并设置定时器继续Move(),直到到达目标值:


this._slider.style[style] = (iNow + iStep) + "px";
this._timer = setTimeout(function(){ oThis.Move(); }, this.Time);

下面例子里的容器结构:


<div class="container" id="idTransformView">
  
<ul class="slider" id="idSlider">
    
<li><img src="http://shundebk.cn/temp/1.jpg"/></li>
    
<li><img src="http://shundebk.cn/temp/2.jpg"/></li>
    
<li><img src="http://shundebk.cn/temp/3.gif"/></li>
  
</ul>
  
<ul class="num" id="idNum">
    
<li>1</li>
    
<li>2</li>
    
<li>3</li>
  
</ul>
</div>

要美观的话需要css设置一下:


.container, .container *{margin:0; padding:0;}
.container
{width:408px; height:168px; overflow:hidden;}
.slider
{position:absolute;}
.slider li
{ list-style:none;display:inline;}
.slider img
{ width:408px; height:168px; display:block;}
.slider2
{width:2000px;}
.slider2 li
{float:left;}
.num
{ position:absolute; right:5px; bottom:5px;}
.num li
{
    float
: left;
    color
: #FF7300;
    text-align
: center;
    line-height
: 16px;
    width
: 16px;
    height
: 16px;
    font-family
: Arial;
    font-size
: 12px;
    cursor
: pointer;
    overflow
: hidden;
    margin
: 3px 1px;
    border
: 1px solid #FF7300;
    background-color
: #fff;
}
.num li.on
{
    color
: #fff;
    line-height
: 21px;
    width
: 21px;
    height
: 21px;
    font-size
: 16px;
    margin
: 0 1px;
    border
: 0;
    background-color
: #FF7300;
    font-weight
: bold;
}

样式的设置跟程序也有一定关系,例如宽和高,这里就不说明了。
接着就可以实例化了:


var tv = new TransformView ("idTransformView", "idSlider", 168, 3, {
    onStart : function(){ Each(objs, function(o, i) { o.className = tv.Index == i ? "on" : ""; })  }//按钮样式
});

这里主要有4个参数,分别是容器对象、滑动对象、切换参数和切换数量。
当程序是上下切换时,切换参数切换的高度,当左右切换时,是切换的宽度。
切换数量就是有多少个切换对象了,例如上面的例子就是3个。
最后的参数是一些设置:
属性: 默认值//说明
Up:   true,//是否向上(否则向左)
Step:  5,//滑动变化率
Time:  10,//滑动延时
Auto:  true,//是否自动转换
Pause:  2000,//停顿时间(Auto为true时有效)
onStart: function(){},//开始转换时执行
onFinish: function(){}//完成转换时执行

例子里设置了onStart属性,作用是在切换开始时,设置按钮的样式
例子里完整的测试代码:


function Each(list, fun){
    
for (var i = 0, len = list.length; i < len; i++) { fun(list[i], i); }
};
var objs = $("idNum").getElementsByTagName("li");
var tv = new TransformView("idTransformView""idSlider"1683,  {
    onStart : 
function(){ Each(objs, function(o, i) { o.className = tv.Index == i ? "on" : ""; }) }//按钮样式
});
tv.Start();
Each(objs, 
function (o, i){
    o.onmouseover 
= function(){
        o.className 
= "on";
        tv.Auto 
= false;
        tv.Index 
= i;
        tv.Start();
    }
    o.onmouseout 
= function(){
        o.className 
= "";
        tv.Auto 
= true;
        tv.Start();
    }
})

源码:


var $ = function (id) {
    
return "string" == typeof id ? document.getElementById(id) : id;
};
var Class = {
  create: 
function() {
    
return function() {
      
this.initialize.apply(this, arguments);
    }
  }
}
Object.extend 
= function(destination, source) {
    
for (var property in source) {
        destination[property] 
= source[property];
    }
    
return destination;
}
var TransformView = Class.create();
TransformView.prototype 
= {
  
//容器对象,滑动对象,切换参数,切换数量
  initialize: function(container, slider, parameter, count, options) {
    
if(parameter <= 0 || count <= 0return;
    
var oContainer = $(container), oSlider = $(slider), oThis = this;
    
this.Index = 0;//当前索引
    
    
this._timer = null;//定时器
    this._slider = oSlider;//滑动对象
    this._parameter = parameter;//切换参数
    this._count = count || 0;//切换数量
    this._target = 0;//目标参数
    
    
this.SetOptions(options);
    
    
this.Up = !!this.options.Up;
    
this.Step = Math.abs(this.options.Step);
    
this.Time = Math.abs(this.options.Time);
    
this.Auto = !!this.options.Auto;
    
this.Pause = Math.abs(this.options.Pause);
    
this.onStart = this.options.onStart;
    
this.onFinish = this.options.onFinish;
    
    oContainer.style.overflow 
= "hidden";
    oContainer.style.position 
= "relative";
    
    oSlider.style.position 
= "absolute";
    oSlider.style.top 
= oSlider.style.left = 0;
  },
  
//设置默认属性
  SetOptions: function(options) {
    
this.options = {//默认值
        Up:            true,//是否向上(否则向左)
        Step:        5,//滑动变化率
        Time:        10,//滑动延时
        Auto:        true,//是否自动转换
        Pause:        2000,//停顿时间(Auto为true时有效)
        onStart:    function(){},//开始转换时执行
        onFinish:    function(){}//完成转换时执行
    };
    Object.extend(
this.options, options || {});
  },
  
//开始切换设置
  Start: function() {
    
if(this.Index < 0){
        
this.Index = this._count  1;
    } 
else if (this.Index >= this._count){ this.Index = 0; }
    
    
this._target = 1 * this._parameter * this.Index;
    
this.onStart();
    
this.Move();
  },
  
//移动
  Move: function() {
    clearTimeout(
this._timer);
    
var oThis = this, style = this.Up ? "top" : "left", iNow = parseInt(this._slider.style[style]) || 0, iStep = this.GetStep(this._target, iNow);
    
    
if (iStep != 0) {
        
this._slider.style[style] = (iNow + iStep) + "px";
        
this._timer = setTimeout(function(){ oThis.Move(); }, this.Time);
    } 
else {
        
this._slider.style[style] = this._target + "px";
        
this.onFinish();
        
if (this.Auto) { this._timer = setTimeout(function(){ oThis.Index++; oThis.Start(); }, this.Pause); }
    }
  },
  
//获取步长
  GetStep: function(iTarget, iNow) {
    
var iStep = (iTarget  iNow) / this.Step;
    
if (iStep == 0return 0;
    
if (Math.abs(iStep) < 1return (iStep > 0 ? 1 : 1);
    
return iStep;
  },
  
//停止
  Stop: function(iTarget, iNow) {
    clearTimeout(
this._timer);
    
this._slider.style[this.Up ? "top" : "left"= this._target + "px";
  }
};

下载测试代码

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

mikel阅读(889)

一、什么是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阅读(889)

使用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阅读(597)

上一部分"流程简介", 我们大致了解了下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阅读(768)

背景:使用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阅读(670)

构建业务外观层(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阅读(913)

以下是指在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阅读(808)

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;}
可以得到另外一种效果哦!