[C#]一个较完整的关键字过滤解决方案(上)

mikel阅读(900)

  如果您希望看到关键字过滤算法的话那么可能就要失望了。博客园中已经有不少关于此类算法的文章(例如这里这里),虽然可能无法直接满足特定需求,但是已经足够作为参考使用。而本文的目的,是给出一个较为完整的关键字过滤功能,也就是将用户输入中的敏感字符进行替换——这两者有什么区别?那么就请继续看下去吧。:)

有趣的需求

   关键字过滤功能自然无比重要,但是如果要在代码中对每个输入进行检查和替换则会是一件非常费神费事的事情。尤其是如果网站已经有了一定规模,用户输入功 能已经遍及各处,而急需对所有输入进行关键字过滤时,上述做法更可谓“远水解不了近渴”。这时候,如果有一个通用的办法,呼得一下为整站的输入加上了一道 屏障,那该是一件多么惬意的事情。这就是本文希望解决的问题。是不是很简单?我一开始也这么认为,不过事实上并非那么一帆风顺,而且在某些特定条件下似乎 更是没有太好的解决方法……

  您慢坐,且听我慢慢道来……

实现似乎很简单

  数据结构中的单向链 表可谓无比经典。有人说:单向链表的题目好难啊,没法逆序查找,很多东西都不容易做。有人却说:单向链表既然只能向一个方向遍历,那么变化就会很有限,所 以题目不会过于复杂。老赵觉得后者的说法不无道理。例如在现在的问题上,我们如果要在一个ASP.NET应用程序中做一个统一的“整站方案 ”,HttpModule似乎是唯一的选择。

  思路如下:我们在Request Pipeline中最早的阶段(BeginRequest)将请求的QueryString和Form集合中的值做过滤,则接下来的ASP.NET处理过 程中一切都为“规范”的文字了。说干就干,不就是替换两个NameValueCollection对象中的值吗?这再简单不过了:

public class FilterForbiddenWordModule : IHttpModule
{
void IHttpModule.Dispose() { }
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
private static void OnBeginRequest(object sender, EventArgs e)
{
var request = (sender as HttpApplication).Request;
ProcessCollection(request.QueryString);
ProcessCollection(request.Form);
}
private static void ProcessCollection(NameValueCollection collection)
{
var copy = new NameValueCollection();
foreach (string key in collection.AllKeys)
{
Array.ForEach(
collection.GetValues(key),
v => copy.Add(key, ForbiddenWord.Filter(v)));
}
collection.Clear();
collection.Add(copy);
}
}

  在BeginRequest阶段,我们将调用ProcessCollection将QueryString和Form两个 NameValueCollection中的值使用ForbiddenWord.Filter方法进行处理。ForbiddenWord是一个静态类,其 中的Filter方法会将原始字符串中的敏感字符使用“**”进行替换。替换方法不在本文的讨论范围内,因此我们就以如下方式进行简单替换:

public static class ForbiddenWord
{
public static string Filter(string original)
{
return original.Replace("FORBIDDEN_WORD", "**");
}
}

  看似没有问题,OK,随便打开一张页面看看……

Collection is read-only.

Description: An unhandled exception occurred during the execution of the current web request... Exception Details: System.NotSupportedException: Collection is read-only.

  呀,只读……这是怎么回事?不就是一个NameValueCollection吗?在不得不请出.NET Reflector之后,老赵果然发现其中有猫腻……

public class HttpRequest
{
...
public NameValueCollection Form
{
get
{
if (this._form == null)
{
this._form = new HttpValueCollection();
if (this._wr != null)
{
this.FillInFormCollection();
}
this._form.MakeReadOnly();
}
if (this._flags[2])
{
this._flags.Clear(2);
ValidateNameValueCollection(this._form, "Request.Form");
}
return this._form;
}
}
...
}

  虽然HttpRequest.Form属性为NameValueCollection类型,但是其中的_form变量事实上是一个 HttpValueCollection对象。而HttpValueCollection自然是NameValueCollection的子类,而造成其 “只读”的最大原因便是:

[Serializable]
internal class HttpValueCollection : NameValueCollection
{
...
internal void MakeReadOnly()
{
base.IsReadOnly = true;
}
...
}

  IsReadOnly是定义在NameValueCollection基类NameObjectCollectionBase上的 protected属性,这意味着如果我们只有编写一个如同NameValueCollection或HttpValueCollection般的子类才 能直接访问它,而现在……反射吧,兄弟们。

public class FilterForbiddenWordModule : IHttpModule
{
private static PropertyInfo s_isReadOnlyPropertyInfo;
static FilterForbiddenWordModule()
{
Type type = typeof(NameObjectCollectionBase);
s_isReadOnlyPropertyInfo = type.GetProperty(
"IsReadOnly",
BindingFlags.Instance | BindingFlags.NonPublic);
}
...
private static void ProcessCollection(NameValueCollection collection)
{
var copy = new NameValueCollection();
foreach (string key in collection.AllKeys)
{
Array.ForEach(
collection.GetValues(key),
v => copy.Add(key, ForbiddenWord.Filter(v)));
}
// set readonly to false.
s_isReadOnlyPropertyInfo.SetValue(collection, false, null);
collection.Clear();
collection.Add(copy);
// set readonly to true.
s_isReadOnlyPropertyInfo.SetValue(collection, true, null);
}
}

  现在再打开个页面看看,似乎没事。那么就来体验一下这个HttpModule的功效吧。我们先准备一个空的aspx页面,加上以下代码:

<form id="form1" runat="server">
<asp:TextBox runat="server" TextMode="MultiLine" />
<asp:Button runat="server" Text="Click" />
</form>

  打开页面,在文本框内填写一些敏感字符并点击按钮:

  嗨,效果似乎还不错!

问题来了

  太简单了,是不?

  可惜问题才刚开始:如果业务中有些字段不应该被替换怎么办?例如“密码”。如果我们只做到现在这点,那么密码“let-us-say- shit”和“let-us-say-fuck”则会被认为相同——服务器端逻辑接收到的都是“let-us-say-**”。也就是说,我们必须提供一 个机制,让上面的HttpModule可以“忽略”掉某些内容。

  如果是其他一些解决方案,我们可以在客户端进行一些特殊标记。例如在客户端增加一个“-noffw-password”字段来表示忽略对 “password”字段的过滤。不过根据著名的“Don't trust the client”原则,这种做法应该是第一个被否决掉的。试想,如果某些哥们发现了这一点(别说“不可能”),那么想要绕开这种过滤方式实在是一件非常容易 的事情。不过我们应该可以把这种“约定”直接运用在字段名上。例如原本我们如果取名为“password”的字段,现在直接使用“-noffw- password”,而HttpModule发现了这种前缀就会放它一马。由于字段的命名完全是由服务器端决定,因此采取这种方式之后客户端的恶人们就无 法绕开我们的过滤了。

  还有一种情况就是我们要对某些特定的字段采取一些特殊的过滤方式。例如,之前相当长的一段时间内我认为在服务器端反序列化一段JSON字符串是 非常不合理的,不过由于AJAX几乎成了事实标准,亦或是现在的Web应用程序经常需要传递一些结构复杂的对象,JSON格式已经越来越多地被服务器端所 接受。假如一个字段是表示一个JSON字符串,那么首先我们只应该对它的“值”进行过滤,而忽略其中的“键”。对于这种字段,我们依旧可以使用如上的命名 约定来进行忽略。例如,我们可以使用-json-data的方法来告诉服务器端这个字段应该被当作JSON格式进行处理。

  如何?

  其实问题远没有解决——尽情期待《一个较完整的关键字过滤解决方案(下)》。

[SQL]SQL Server 2005新特性之使用with关键字解决递归父子关系

mikel阅读(908)

1. 引言

现实项目中经常遇到需要处理递归父子关系的问题,如果把层次关系分开,放在多个表里通过主外键关系联接,最明显的问题就是扩展起来不方便,对于这种情况,一般我们会创建一个使用自连接的表来存放数据。例如存放会员地区数据表结构可能是这样:

列名

描述

location_id

地区编号

location_name

地区名称

parentlocation_id

上级地区编号

或者某个部分的职员表结构可能如下所示:

列名

描述

employee_id

职员编号

employee_name

职员名称

manager_id

职员的直接上级管理者,和employee_id进行自联接

通过类似表结构,我们就可以通过一个表理论上管理无限级数的父/子关系,但是当我们需要将这些数据读取出来,不论是填充到一个树中,或是使用级联显示出来,需要花费一定的精力。传统的做法,是做一个递归调用,首先连接数据库将顶层数据(也就是parent_xxxnull的记录)读取出来,再对每一条数据进行递归访问填充集合,这种做法需要连接数据库多次,显然不是较好的解决方法,那么我们能不能通过一次数据库访问,将数据全部读取出来,并且为了按照父子关系形成集合,使返回的数据满足某种格式。

2. 分析

理想情况下,如果父/子关系数据时严格按照关系结构添加到数据库中,亦即首先添加某条父记录,接着添加该父记录的子记录,如果子记录还包含子记录的话继续添加,最终数据表中父/子关系按规则排列数据,我们就可以使用某种算法填充集合,但是正如我们所说,这是理想情况,实际情况下数据经常会发生改变,导致数据没有规律可言,如下图所示,这样的话读取数据填充集合就不太容易的。

所以我们要做的就是通过查询使数据库返回的数据满足这种格式,那么我们的思路是首先查找顶层(0层)记录,再查询第1层记录,接下来是第2层、第3层直到第n层。因为层数是不确定的,所以仍然需要使用递归访问。

SQL Server 2005中提供了新的with关键字,用于指定临时命名的结果集,这些结果集称为公用表表达式(CTE)。该表达式源自简单查询,并且在SelectInsertUpdateDelete 语句的执行范围内定义。该子句也可用在 Create VIEW 语句中,作为该语句的 Select 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表表达式。

其语法为:

[ WITH <common_table_expression> [ ,…n ] ]

<common_table_expression>::=

        expression_name [ ( column_name [ ,…n ] ) ]

    AS

        ( CTE_query_definition )

使用with关键子的一个简单示例,以下代码将tb_loc表中数据源样输出:

WITH locs(id,name,parent)

AS

(

    Select * FROM tb_loc

)

Select * FROM locs

为了创建良好层次记录结构集,使用with关键字首先读取顶层记录,并且针对每一条顶层记录读取其子记录,直到读取到最底层级记录,最后将所有的记录组合起来,这里用到了UNION ALL关键字,用于将多个查询结果组合到一个结果集中。

接下来就可以使用该关键字创建存储过程返回结果集,并附加每条记录所位于的“层”数,如下图所示:

最后需要在前台界面将其显示出来,由于记录已经按层次返回,需要做的就是按层次首其输出,首先将第0层数据输出,接下来将遍历第0层 数据,将第一层数据添加到合适的父对象中,重复此过程直到填充结果。那么这里的难题就在于如何查找父对象,我们当然可以遍历集合,但是这么做的话如果数据 量很大将导致效率低下。既然可以得到当前对象所位于的层的信息,就也是这树倒置的树是一层一层向下填充的,我们可以定义一个临时集合变量,存储当前层上一 层的所有父对象,在插入当前层对象时遍历集合变量以插入到合适的位置,同时我们还必须保证在逐层读取数据时临时集合变量中持有的始终时当前层上一层所有的 对象,程序流程图如下所示:

根据以上分析,我们就可以编写实现代码了(为了方便,将本文中用到的数据表和创建记录等SQL语句一并给出)。

3. 实现

3.1 打开SQL Server 2005 Management Studio,选择某个数据库输入以下语句创建表结构:

Create TABLE [tb_loc](

    [id] [int],

    [name] [varchar](16),

    [parent] [int]

)

 

GO

3.2 创建测试数据:

Insert tb_loc(id,name,parent) VALUES( 1,'河北省',NULL)

Insert tb_loc(id,name,parent) VALUES( 2,'石家庄',1)

Insert tb_loc(id,name,parent) VALUES( 3,'保定',1)

Insert tb_loc(id,name,parent) VALUES( 4,'山西省',NULL)

Insert tb_loc(id,name,parent) VALUES( 5,'太原',4)

Insert tb_loc(id,name,parent) VALUES( 6,'新华区',2)

Insert tb_loc(id,name,parent) VALUES( 7,'北焦村',6)

Insert tb_loc(id,name,parent) VALUES( 8,'大郭村',6)

Insert tb_loc(id,name,parent) VALUES( 9,'河南省',NULL)

Insert tb_loc(id,name,parent) VALUES( 10,'大郭村南',8)

Insert tb_loc(id,name,parent) VALUES( 11,'大郭村北',8)

Insert tb_loc(id,name,parent) VALUES( 12,'北焦村东',7)

Insert tb_loc(id,name,parent) VALUES( 13,'北焦村西',7)

Insert tb_loc(id,name,parent) VALUES( 14,'桥东区',3)

Insert tb_loc(id,name,parent) VALUES( 15,'桥西区',3)

 

GO

3.3 创建pr_GetLocations存储过程:

Create PROCEDURE pr_GetLocations

AS

BEGIN

    WITH locs(id,name,parent,loclevel)

    AS

    (

        Select id,name,parent,0 AS loclevel FROM tb_loc

        Where parent IS NULL

        UNION ALL

        Select l.id,l.name,l.parent,loclevel+1 FROM tb_loc l

            INNER JOIN locs p ON l.parent=p.id

    )

 

    Select * FROM locs

END

3.4 Visual Studio 2008里创建解决方案并新建一个网站

3.5 网站中添加APP_Code目录,并创建Location实体类,该类标识了所在地编号和名称,并且保存了父级所在地编号和它所包含的所有子所在地的集合:

public class Location

{

    public int Id

    {

        get;

        set;

    }

 

    public string Name

    {

        get;

        set;

    }

 

    public LocationCollection SubLocations

    {

        get;

        set;

    }

 

    public int ParentId

    {

        get;

        set;

    }

 

    public Location()

    {

        Id = 0;

        Name = string.Empty;

        SubLocations = new LocationCollection();

 

        ParentId=0;

    }

}

3.5 以上代码使用了LocationCollection集合类,使用泛型集合创建该类(同样位于APP_Code目录下):

using System.Collections.Generic;

 

public class LocationCollection:List<Location>

{

   

}

3.6 APP_Code目录下创建DAO类用于访问数据库,添加必要的命名空间引用:

using System;

using System.Data;

using System.Data.SqlClient;

 

public class DAO

{

}

3.7编写GetLocations方法,返回所在地集合对象(请根据实际情况修改数据库连接字符串):

public LocationCollection GetLocations()

{

    LocationCollection locs = new LocationCollection();

 

    using (SqlConnection conn = new

        SqlConnection("server=.;uid=sa;pwd=00000000;database=temp;"))

    {

        conn.Open();

 

        SqlCommand cmd = new SqlCommand();

        cmd.CommandText = "pr_GetLocations";

        cmd.CommandType = CommandType.StoredProcedure;

        cmd.Connection = conn;

 

        SqlDataReader reader = cmd.ExecuteReader();

                   

        int level = 0;

        int oldlevel = 1;

 

        LocationCollection container=new LocationCollection();

        LocationCollection current = new LocationCollection();

 

        while (reader.Read())

        {

            Location loc = GetLocationFromReader(reader, out level);

 

            if (level == 0)

            {

                locs.Add(loc);

                container.Add(loc);                

            }

            else

            {

                if (oldlevel != level)

                {

                    container.Clear();

 

                    foreach (Location l in current)

                        container.Add(l);

 

                    current.Clear();

                    oldlevel = level;

                }

 

                current.Add(loc);

 

                CreateLocation(container, loc);

            }              

        }

    }

 

    return locs;

}

在该方法按照以下步骤执行:

1. 使用命令对象对象执行pr_GetLocations存储过程返回结果集

2. 如果数据阅读器读取了数据(reader.Read方法返回true)执行:

       2.1. 从数据阅读器当前记录中读取Location对象,并返回层数信息(out level

       2.2. 如果是第一层(level等于0)填充locs集合,并加入到container对象

       2.3. 如果不是第一层根据层标志(oldlevel)判断当前层是否是新的一层

2.4 如果当前层是新的一层清空container集合并将current集合中实体复制到container集合中,清空current集合并置层标志(oldlevel

2.5 将当前对象添加到current集合中

2.6 调用CreateLocation方法从container上层集合中匹配当前实体父级对象并加入父对象的子集合中

3. 重复第2步直到读取完全部数据

可以看到container集合始终保存了当前层的上层所有的实体对象,并且为了在更换层数后能够正确的更新container集合,使用current集合保存当前层的实体对象。

3.8 编写GetLocationFromReader方法,用于从数据阅读器中返回Location实体对象,并将层数信息使用out参数返回:

private Location GetLocationFromReader(SqlDataReader reader, out int level)

{

    Location loc = new Location();

    loc.Id = Convert.ToInt32(reader["id"]);

    loc.Name = Convert.ToString(reader["name"]);

 

    object o = reader["parent"];

    if (o != DBNull.Value)

        loc.ParentId = Convert.ToInt32(o);

 

    level = Convert.ToInt32(reader["loclevel"]);

 

    return loc;

}

3.9 编写CreateLocation方法,该方法遍历实体集合找到与当前实体对象的父级编号匹配的实体,并将当前实体加入到父级实体的子集合中:

private void CreateLocation(LocationCollection container, Location loc)

{

    foreach (Location location in container)

    {

        if (location.Id == loc.ParentId)

        {

            location.SubLocations.Add(loc);

            break;

        }

    }

}

3.10 Default.aspx页面上添加TreeView控件:

<asp:TreeView ID="trvLocation" runat="server" Font-Size="12px"

    ShowLines="True">

</asp:TreeView>

3.11 Default.aspx页面后置代码中编写BindData数据绑定方法:

private void BindData()

{

    DAO dao = new DAO();

 

    LocationCollection locs = dao.GetLocations();

 

    TreeNodeCollection nodes = CreateTreeNodes(locs);

 

    foreach (TreeNode node in nodes)

    {

        trvLocation.Nodes.Add(node);

    }

}

3.12 BindData方法调用了CreateTreeNode方法返回节点集合,该方法中递归调用自身以得到全部所在地节点:

private TreeNodeCollection CreateTreeNodes(LocationCollection locs)

{

    TreeNodeCollection nodeColl = new TreeNodeCollection();

 

    foreach (Location loc in locs)

    {

        TreeNode node = new TreeNode(loc.Name, loc.Id.ToString());

       

        if (loc.SubLocations.Count > 0)

        {

            TreeNodeCollection subColl = CreateTreeNodes(loc.SubLocations);

 

            foreach (TreeNode subNode in subColl)

                node.ChildNodes.Add(subNode);

        }

 

        nodeColl.Add(node);

    }

 

    return nodeColl;

}

3.13 最后在页面加载事件里执行数据绑定:

protected void Page_Load(object sender, EventArgs e)

{

    if (!IsPostBack)

    {

        this.BindData();

    }

}

3.14 在浏览器中预览结果:

 

4. 总结

原来在处理类似父子关系时总是找不到好的解决办法,现在通过SQL Server 2005里的新特性可以较为合理的解决该类问题,在这里主要用到了with关键字实现递归访问,并且在输出数据时同样使用了递归的方法。如果各位有更好的实现方式,请不不吝赐教。

本文示例代码下载:示例代码

[C#]自己动手写个ORM实现(4) 关于反射DataRow数据记录到实体性能的优化

mikel阅读(750)

总所周知,反射对于运行时确定对象类型十分方便,但是它最大的不足就是效率低下,比直接调用的效率慢了一百倍有余。

在3.5以前有codeDom或借助Emit直接编写IL来优化其效率,但是使用不便,借助3.5新增的Expression,让我们有了一种既简洁,在速度上又较反射有很大的提高。 示例如下


 1 public static T GetEntityByDataRowSlow<T>(this DataRow data) where T : new()
 2         {
 3             T t = new T();
 4             PropertyInfo[] properties = typeof(T).GetProperties();
 5 
 6             foreach (PropertyInfo p in properties)
 7             {
 8                 object value = data[p.Name] == DBNull.Value ? null : data[p.Name];
 9                 p.SetValue(t, value, null); 
10             }
11             return t;
12         }

 

如上,整段代码慢就慢在p.SetValue(t,value,null)这段上。 也有可能有人会说 typeof(T).GetProperties()获取所有属性应该缓存,但实际测试结果看下来影响并不大,效率相差无几。

接下来,主角登场了

 

 1 static Func<T, MethodInfo, objectobject> GetSetDelegate<T>(MethodInfo m,Type type)
 2         {
 3            
 4             var param_obj = Expression.Parameter(typeof(T), "obj");
 5             var param_val = Expression.Parameter(typeof(object), "val");
 6             var param_m = Expression.Parameter(typeof(MethodInfo), "m");
 7             var body_val = Expression.Convert(param_val, type);
 8             var body = Expression.Call(param_obj, m, body_val);
 9             Action<T, MethodInfo, object> set = Expression.Lambda<Action<T, MethodInfo, object>>(body, param_obj, param_m, param_val).Compile();
10             return (instance, method, v) =>
11             {
12                 set(instance, method, v);
13                 return null;
14             };
15         }

 

1 static void FastSetValue<T>(this PropertyInfo property,T t, object value)
2         {
3             MethodInfo m = property.GetSetMethod();
4             GetSetDelegate<T>(m,property.PropertyType)(t, m, value);
5         }

 

关于Expression和lambda的介绍可参看园里大牛赵哥的文章  方法的直接调用,反射调用与……Lambda表达式调用

经过改良的调用方法

 

 

public static T FastGetEntityByDataRow<T>(this DataRow data) where T : new()
        {
            T t 
= new T();
            PropertyInfo[] properties 
= GetProperties(typeof(T));
            
            
foreach (PropertyInfo p in properties)
            {                    
                
object value = data[p.Name] == DBNull.Value ? null : data[p.Name];
                p.FastSetValue
<T>(t, value);
            }
            
return t; 
        }

 

经过测试下来  如果直接是Entity.Property = "somevalue"设置属性的速度比值是1的话,反射的速度比值是100多,而经过改良的上述方法比值在2-3之间。

尽管这样,常见Web应用的主要瓶颈还是在结构的设计,数据库的读取,上面的方法对于整个程序框架的影响也只是积跬步,单用这个地方用了也几乎白用,不用白不用。谨记录一下。

[C#]在C#中实现Socket端口复用

mikel阅读(808)

一、什么是端口复用:

  因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分。这种多重绑定便称之为端口复用。

二、我们如何实现Socket端口复用:

  其实我们要实现端口复用很简单,我们只要使用SetSocketOption函数设置Socket选项就可以了。MSDN是这样解释的:
Socket 选项确定当前 Socket 的行为。对于具有 Boolean 数据类型的选项,指定非零值可启用该选项,指定零值可禁用该选项。对于具有整数数据类型的选项,指定适当的值。Socket 选项按照协议支持程度来分组。

我们来看看这个函数是怎么用的:

public void SetSocketOption (
    SocketOptionLevel optionLevel,
    SocketOptionName optionName,
    
int optionValue
)

 

参数
optionLevel
SocketOptionLevel 值之一。
optionName
SocketOptionName 值之一。
optionValue
该选项的值。

以上参数大家可以去看看MSDN。我这里就不多讲了。

在这里我们optionLevel 参数传SocketOptionLevel.Socket;optionName参数传 SocketOptionName.ReuseAddress;optionValue参传一个非零值,我传的是True,如果要禁用的话,就传 False。

如:

socket2.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

具体我们看看下面的代码:

我们首先建立第一个Socket:

        Socket socket1;
        IPEndPoint localEP 
= new IPEndPoint(IPAddress.Any, 20000);
        socket1 
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket1.Bind(localEP);

再建立第二个Socket:

        Socket socket2
        IPEndPoint localEP 
= new IPEndPoint(IPAddress.Any, 20000);
        socket2
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket2.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 
true);
       
//请注意这一句。ReuseAddress选项设置为True将允许将套接字绑定到已在使用中的地址。 
        socket2.Bind(localEP);

这样Socket1和Socket2便绑定在同一个端口上了。

例程源代码我上传到我的资源里面大家可以到http://files.cnblogs.com/wzd24/28135640620.rar去下载。

[C#]利用委托实现充血模式的实体类

mikel阅读(929)

最近一直在想实体类应不应该具有操作,还是如以往的一样是缺血模式的实体类呢,目前KiWing框架用的是缺血模式的实体类(缺血实体类指那些只有属性而没有方法的实体类),于是将现有的实体类进行了改写,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KiWing.CustomAttribute;
using KiWing.Helper.Attribute;
namespace KiWing.Test
{
    class Program
    {
        [Table("Table1","Identifier","table1Insert","table1update","table1delete","table1select")]
        public class Test
        {
            /// <summary>
            /// 委托保存方法列表
            /// </summary>
            private SaveMethod saveList;
           
            public int Identifier { get; set; }
            public string TestName { get; set; }
            /// <summary>
            /// 委托保存方法
            /// </summary>
            /// <param name="test"></param>
            /// <returns></returns>
            public delegate int SaveMethod(Test test);
            /// <summary>
            /// 注册保存委托方法
            /// </summary>
            /// <param name="method"></param>
            public void AddSaveMethod(SaveMethod method)
            {
                saveList += method;
            }
            /// <summary>
            /// 删除已经注册的委托方法
            /// </summary>
            /// <param name="method"></param>
            public void RemoveSaveMethod(SaveMethod method)
            {
                saveList -= method;
            }
         
            /// <summary>
            /// 保存方法
            /// </summary>
            /// <returns></returns>
            public int Save()
            {
                if (saveList != null)
                   return saveList(this);
                return 1;
            }
        }
        public class Area
        {
           
        }
        /// <summary>
        /// 业务处理类
        /// </summary>
        public class Business
        {
            public int Save<T>(T obj) where T : class
            {
                Console.Write("Business Save {0}!",typeof(T).Name);
                return 1;
            }
       
        }
        static void Main(string[] args)
        {
            //实例化实体类
            Test test = new Test();
            //属性赋值
            test.Identifier = 1;
            test.TestName="Test";
            //创建业务逻辑对象
            Business business=new Business();
            //注册委托方法
            test.AddSaveMethod(business.Save<Test>);
            //保存数据
            test.Save();
            Console.Read();
          
           
        }
    }
}

[图书]AIR Bible (download)

mikel阅读(947)

Download AIR Bible
下载 AIR 圣经
RIAbook Rank:★★★★

简介 Book Description:
Adobe Integrated Runtime, or AIR, enables developers to create desktop applications using HTML,JavaScript, and ActionScript. These applications are able to run on Windows, Mac OS X, and Linux systems, meaning that Web developers will be able to use familiar languages and tools to easily create desktop software.
A Web application can look the same to every user, on any computer, because the same code is being executed to create the interface. The browser application itself handles the differences between operating systems, which allows code to execute in the same way on a wide variety of machines. A desktop application, on the other hand, starts up quickly because it is run directly from the user’s computer, accesses data quickly because it can store data locally, does not require an Internet connection to run, and is not constrained by the browser window.
Consider the current market of e-mail applications. If you use a Web application for your e-mail,you will be able to access the interface from any computer, and possibly even some mobile devices.
These applications have become very popular as a result, but there are still drawbacks to using a Web application over a desktop application. For example, if you want to find an e-mail you received last week or last month, you often need to page through old messages to find the right place in a Web application. This is a necessity because the data is stored remotely, so the amount of data passed to the browser must be constrained. In a desktop application, messages can be stored locally, and you can easily scroll down to find an older message.
Clearly there are uses for both Web applications and desktop applications. With AIR, there is now a way to use the same interface in both environments. While there may need to be some differences between a Web implementation and a desktop implementation in order to take full advantage of those environments, there is a lot to be gained from not having to create an entirely new application for each environment. AIR, along with other recent developments that enable Web applications to run on the desktop, blurs the line between Web and desktop applications, and it will raise user expectations on both.
One of the most powerful features of Web development languages is that they are high-level scripting languages designed for developing presentation layers. HTML isn’t able to manage memory or access low-level operating system APIs; it was never intended to do such things. Instead, a browser interprets HTML, and the developers of that browser’s engine focus on those things. This allows developers of the higher-level language to focus their efforts on the user experience and the business logic of an application.
In the world of desktop applications, C, C++, Cocoa, Java, and .NET are considered high-level languages.
There is no question that scripting languages like ActionScript and JavaScript are less powerful than these traditional desktop languages. At the same time, Web-scripting languages are also much more focused on user experience and allow for much quicker development. AIR opens up the door to this world and allows the Web development community to prove that user experience is the key to a great application.
Put simply, this is the direction that application development is heading. Users and businesses should not have to wait for developers of lower-level programming languages to reinvent the wheel for every application when the same application could be developed far more quickly using a scripting language interpreted by a low-level framework. Add to that the fact that these same scripting languages can be interpreted by Web browsers and mobile devices, and it’s clear that this is going to create a real shift in the world of application development. AIR is the future of application development, and this is the book to get you on your feet.
目录 Summary of Contents
Part I: Introduction to AIR
Chapter 1: Clearing the AIR
Chapter 2: Setting Up Your Development Environment
Chapter 3: Building Your First AIR Application
Part II: Programming for AIR Essentials
Chapter 4: Crash Course in AIR Programming
Chapter 5: Development Essentials
Chapter 6: Debugging and Profiling
Part III: AIR API
Chapter 7: Communicating with the Local Machine
Chapter 8: Using the Filesystem
Chapter 9: Using the Clipboard
Chapter 10: Dragging and Dropping
Chapter 11: SQLite Databases
Chapter 12: Using Native Operating System Windows
Chapter 13: HTML Content
Part IV: Building an Application
Chapter 14: Preparing to Build a Large-Scale Application
Chapter 15: Building a Reusable Config Class
Chapter 16: Application Design Best Practices
Chapter 17: SDK Development
Chapter 18: Sample Application: LogReader
Chapter 19: Polishing a Finished Application
Part V: Testing and Deploying
Chapter 20: Deployment Workflow
Chapter 21: Leveraging Ant to Automate the Build Process
Chapter 22: Installation and Distribution
Index
关于作者 About the Author
Benjamin Gorton has been developing software for the desktop and the Web for over 10 years. For the
past seven years, he has been working in Flash and ActionScript, doing projects for such companies as
Disney, MTV, Neopets, and Sandisk. He currently resides in Los Angeles, where he works as a Senior
Software Developer for Schematic.
Ryan Taylor is an award-winning artist and programmer specializing in object-oriented architecture,
CGI mathematics/programming, as well as both static and motion design. Ryan, 25, has already landed
his name in the credits of the #1 and #5 all-time best selling video game titles, written for multiple
books, and established himself as an all-around leader in the digital arts community. Currently, Ryan
serves as a senior developer on the Multimedia Platforms Group at Schematic. He also works as an independent
contractor, offering his expertise to top companies and agencies all over the world.
Jeff Yamada lives with his wife AmyLynn and son Jackson in Salt Lake City, Utah, where he is currently
a Senior Interactive Developer at the award-winning RED Interactive Agency. Jeff specializes in the
architecture and development of immersive branded Flash experiences, rich Internet applications, and of
course, AIR applications. As both a designer and developer, Jeff has spent the last ten years freelancing,
consulting, and working for the University of Washington, Microsoft, Avenue A | Razorfish, Schematic,
and Nintendo. Jeff contributes to the open-source community and shares his thoughts and ideas with
the world at http://blog.jeffyamada.com.
http download
From rapidshare : AIR Bible

[Json]Json初探

mikel阅读(834)

JSON初探

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。

JSON建构于两种结构:

  • “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
  • 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。

JSON具有以下这些形式:

对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

{"UserID":11, "Name":"Truly", "Email":"zhuleipro◎hotmail.com"};

 
数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。 
[
{"UserID":11, "Name":{"FirstName":"Truly","LastName":"Zhu"}, "Email":"zhuleipro◎hotmail.com"},
{"UserID":12, "Name":{"FirstName":"Jeffrey","LastName":"Richter"}, "Email":"xxx◎xxx.com"},
{"UserID":13, "Name":{"FirstName":"Scott","LastName":"Gu"}, "Email":"xxx2◎xxx2.com"}
]

值(value)可以是双引号括起来的字符串(string)、数值(number)、truefalsenull、对象(object)或者数组(array)。这些结构可以嵌套。

{UserID:001,UserName:"Majie",IsAdmin:true,Rights:{IsAdd:true,IsDelete:false,IsEdit:true},fn:null}

 

字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。

字符串(string)与C或者Java的字符串非常相似。

数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。

 
  • 对象是属性、值对的集合。一个对象的开始于“{”,结束于“}”。每一个属性名和值间用“:”提示,属性间用“,”分隔。
  • 数组是有顺序的值的集合。一个数组开始于"[",结束于"]",值之间用","分隔。
  • 值可以是引号里的字符串、数字、true、false、null,也可以是对象或数组。这些结构都能嵌套。
  • 字符串和数字的定义和C或Java基本一致。
  • [Google]Google Web Toolkit(GWT) v1.5.3 - Google We

    mikel阅读(847)

    如今,编写网络应用程序是一个单调乏味且易于出错的过程。开发人员可能要花费 90% 的时间来处理浏览器行话。此外,构建、重复使用以及维护大量 JavaScript 代码库和 AJAX 组件可能困难且不可靠。Google Web 工具包 (GWT) 通过允许开发人员用 Java 编程语言快速构建和维护复杂但高性能的 JavaScript 前端应用程序来减轻该负担。

    Google Web 工具包工作原理
    有了 Google Web 工具包 (GWT),可以使用 Java 编程语言编写 AJAX 前端,然后 GWT 会交叉编译到优化的 JavaScript 中,而 JavaScript 可以自动在所有主要浏览器上运行。在开发过程中,您可以用 JavaScript 按习惯的相同“编辑 – 刷新 – 查看”循环快速反复,还有另一个好处就是能够调试和逐行单步调试 Java 代码。准备好进行部署后,GWT 会将 Java 源代码编译到优化且独立的 JavaScript 文件中。使用 Google Web 工具包可以轻松地为现有网页或整个应用程序构建一个 Widget。
    使用 Java 语言编写 AJAX 应用程序,然后编译为优化的 JavaScript
    与仅在文本级别运行的 JavaScript Minifier 不同,GWT 编译器会在整个 GWT 数据库中执行综合性静态分析和优化,通常生成的 JavaScript 加载和执行均比等效手写的 JavaScript 更快。例如,GWT 编译器可以安全地消除无用代码 — 极大的减少不使用的类别、方法、字段甚至方法参数 — 以确保您编译的脚本尽可能最小。另一个示例:GWT 编译器选择性地内联方法,消除方法调用的性能开销。
    交叉编译提供了开发所需的可维护的提取和模块性,而不会导致运行时性能损失。
    开发工作流程
    编辑 Java 代码,然后立即查看更改而无需重新编译
    在开发过程中,使用 GWT 的托管模式浏览器可以立即查看代码更改。无需汇编译为 JavaScript 或部署到服务器。只需进行更改,然后在托管模式浏览器中单击“刷新”。
    使用 Java 调试器单步调试当前 AJAX 代码
    在生产过程中,可以将代码编译为纯 JavaScript,但是在开发阶段,代码将在 Java 虚拟机作为字节码运行。这意味着,当代码执行处理鼠标事件等操作时,将获得功能完整的 Java 调试。Java 调试器可以执行的任何操作也应用于 GWT 代码,所以也可以执行断点和单步调试等自然操作。
    编译和部署优化的、跨浏览器的 JavaScript
    准备好进行部署后,GWT 会将 Java 代码编译成独立的纯 JavaScript 文件,任何网络服务器都支持该文件。此外,GWT 应用程序可自动支持 IE、Firefox、Mozilla、Safari 和 Opera,而无需在代码中进行浏览器检测或特殊封装。编写相同的代码后,GWT 会根据每个用户的特殊浏览器将其转换为最有效的 JavaScript。
    功能
    通过非常简单的 RPC 与服务器通信
    GWT 支持一组开放的传输协议,例如 JSON 和 XML,但 GWT RPC 使所有 Java 通信都特别轻松且有效。类似于传统 Java RMI,只需创建一个用于指定您要调用的远程方法的接口。从浏览器调用远程方法时,GWT RPC 将自动串行化参数,并调用服务器上的适当方法,然后反串行化客户端代码的返回值。GWT RPC 也将非常成熟,其可以处理多态类层次结构、对象图循环,甚至可以跨网抛出异常。
    根据用户个人资料优化 JavaScript 脚本下载
    延时绑定是 GWT 的一种功能,可以生成许多版本的编译代码,而在运行时自引导期间仅其中一个版本需要由特殊客户端载入。每个版本均以浏览器为基础生成,并带有应用程序定义 或使用的任何其他轴。例如,如果要使用 GWT 的国际化模块来国际化应用程序,GWT 编译器可能会根据每个浏览器环境生成各个版本的应用程序,例如“英文版 Firefox”、“法文版 Firefox”、“英文版 Internet Explorer”等,因此,部署的 JavaScript 代码非常紧凑并且下载比在 JavaScript 中编码然后声明更快。
    跨项目重复使用 UI 组件
    通过合成其他 Widget 来创建可重复使用的 Widget,然后轻松地在面板中自动对他们进行布局。GWT 展示应用程序可以提供 GWT 中各种 UI 功能的概述。要在其他项目中重复使用 Widget 吗?只需将其打包以便他人在 JAR 文件中使用。
    使用其他 JavaScript 库和本机 JavaScript 代码
    如果 GWT 的类库不能满足您的需要,则可以使用 JavaScript 本地接口 (JSNI) 在 Java 源代码中加入手写的 JavaScript。使用 GWT 1.5,现在就可以为 GWT JavaScriptObject (JSO) 类创建子类以将 Java“类覆盖”创建到任意 JavaScript 对象上。因此,可以获得将 JS 对象比拟为适当的 Java 类型(例如代码完成、重构、内联)而无需另外占用内存或速度的好处。此功能可以优化使用 JSON 结构。
    轻松支持浏览器的后退按钮和历史记录
    不,AJAX 应用程序无需破坏浏览器的后退按钮。使用 GWT,您可以通过轻松地为浏览器的后退按钮历史记录添加状态,来使您的站点更加有用。
    有效的本地化应用程序
    使用 GWT 功能强大的延时绑定技术来轻松创建有效的国际化应用程序和库。此外,从 1.5 版起,标准 GWT Widget 开始支持双向性。
    使用选择的开发工具提高生产力
    由于 GWT 使用 Java,您可以使用所有喜欢的 Java 开发工具(Eclipse、IntelliJ、JProfiler、JUnit)来进行 AJAX 开发。这使网络开发人员可以控制自动化 Java 重构和代码提示/完成的生产效率。此外,Java 语言的静态类型检查使开发人员可以在编写代码时而非运行时找出一类 JavaScript 错误(输入错误、类型不匹配),在减少错误的同时提高生产率。没有临时变量发现的更多用户。最后,则可以利用基于 Java 的 OO 设计模式和提取,由于编译器优化,模式和提取易于理解和维护而无需用户承担任何运行时性能损失。
    使用 JUnit 测试代码
    GWT 与 JUnit 直接集成,使您可以在调试器和浏览器中进行单元测试,并且您甚至可以对异步 RPC 进行单元测试。
    扩展或投稿 – Google Web 工具包是一种开源软件
    使用 Apache 2.0 许可,可获取所有 GWT 代码。如果您对投稿感兴趣,请访问使 GWT 变得更好。
    Google Web Toolkit (GWT) is an open source Java software development framework that makes writing AJAX applications like Google Maps and Gmail easy for developers who don't speak browser quirks as a second language. Writing dynamic web applications today is a tedious and error-prone process; you spend 90% of your time working around subtle incompatibilities between web browsers and platforms, and JavaScript's lack of modularity makes sharing, testing, and reusing AJAX components difficult and fragile.
    GWT lets you avoid many of these headaches while offering your users the same dynamic, standards-compliant experience. You write your front end in the Java programming language, and the GWT compiler converts your Java classes to browser-compliant JavaScript and HTML.
    Release Notes for 1.5.3
    Fixed Issues
    RPC requests no longer fail on the embedded Android web browser
    Leaf TreeItems now line up with their non-leaf siblings
    Removing the last child node from a TreeItem no longer creates extra margins on the left
    HTTPRequest no longer uses POST instead of GET on some IE installs because of incorrect XHR selection
    Compiler now uses a more reliable check to prevent methods with local variables from being inlined
    getAbsoluteTop()/Left() can no longer return non-integral values
    Time.valueOf() no longer fails to parse "08:00:00" or incorrectly accepts "0xC:0xB:0xA".
    更新:http://code.google.com/intl/zh-CN/webtoolkit/releases/release-notes-1….
    官网:http://code.google.com/webtoolkit
    官方下载:
    Windows:http://google-web-toolkit.googlecode.com/files/gwt-windows-1.5.3.zip
    Mac OS X:http://google-web-toolkit.googlecode.com/files/gwt-windows-1.5.3.zip
    Linux:http://google-web-toolkit.googlecode.com/files/gwt-linux-1.5.3.tar.bz2

    [MVC]调试、部署Oxite 开源系统

    mikel阅读(1178)

    调试、部署Oxite 开源系统
     
    Oxite 是微软近期发布了一个开源CMS或博客平台,关于Oxite 系统的基本介绍,请参考文章 – 微软发布Oxite开源CMS博客平台。
     
    这里,EntLib.com 开源论坛小组一步一步详细介绍如何编译、调试和部署 Oxite 系统。假设你的系统已经有SQL Server 2005 和 Visual Studio 2008。
     
    1. 首先下载并安装 ASP.NET MVC 开发包。
    ASP.NET MVC下载地址:
     
    如果你之前有安装 ASP.NET MVC 的前期版本,则你需要先下载早期的版本。ASP.NET MVC 的安装过程很简单,这里就不具体介绍了。
    关于ASP.NET MVC 的介绍,推荐你阅读如下文章:
    Microsoft ASP.NET MVC Preview 5 及LINQ TO SQL最新版开发示例演示(提供源码下载)
     
    2. 下载 Oxite 开源软件。
    展开压缩文件,通过 Visual Studio 2008 打开Oxite.sln 项目文件。先看看项目文件:
     
     
    接下来,设置 OxiteSite 项目为启动项目(Set as Startup Project)。编译整个Oxite 项目,整个项目编译通过。到现在,一切都很顺利。
     
    但是,当你运行OxiteSite 项目时,Visual Studio 2008 会提示你Deploy Failed-发布失败。仔细看看,这是Oxite.Database 项目产生的。
     
    最简单的解决办法是,右键单击Oxite.Database项目,选择 Unload Project 或者 Remove 菜单项,如下图所示。
     

     
    现在,你再次运行Oxite 项目,发现可以正常运行了,并且显示如下运行界面。
     
     
    Oxite.Database 项目到底有什么用呢?这里,Oxite.Database 项目用来创建Oxite 数据库,由于OxiteSite Web项目采用的是SQL Server Express进行 Oxite 数据库连接。数据库连接字符串Connection String 如下:
     
     <connectionStrings>
        <add name="ApplicationServices" connectionString="Data Source=.\SQLEXPRESS;AttachDBFileName=|DataDirectory|Oxite.Database.mdf;Integrated Security=true;User Instance=true;"/>
     </connectionStrings>
    默认,数据库文件存放在\OxiteSite\App_Data 目录下。所以,上面的Oxite.Database 项目可以直接Unload 或者 Remove。
     
    如果你想通过Oxite.Database 直接在SQL Server 2005 创建一个Oxite 的数据库,你也可以按照如下的步骤,轻松创建Oxite数据库。
    首先,需要修改Oxite.Database 项目的一些设置,如下图所示:
    (1) 设置Default collation 属性为 Chinese_PRC_CI_AS,采用中文字符集。
     
     
    (2) 正确设置Oxite.Database 项目的Target database name 属性为:Oxite。同时,设置Default location for target database files – 默认数据库文件存放位置属性为:c:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\。这一属性根据实际情况,可以设置为其他路径。
    具体设置信息如下图所示:
     
     
    现在,编译、部署Oxite.Database 项目就可以正确通过了。此时,你可以进一步修改OxiteSite 项目中的web.config 配置文件,修改其中的数据库连接字符串 Connection String。如下所示:
     <connectionStrings>
        <addname="ApplicationServices"connectionString="Server=localhost; Database=Oxite;Integrated Security=true;"/>
     </connectionStrings>
     
    现在,重新编译、运行OxiteSite 项目,数据库连接到 SQL Server 2005 中的Oxite 数据库了,而不是先前的SQL Server express 的Oxite.Database.mdf 数据库文件。
     
    本文由http://forum.entlib.com 开源论坛小组提供,欢迎交流、讨论、分享。
     
    相关文章:
    1. 微软发布Oxite开源CMS博客平台
     
    2. Oxite 配置入门文章
     
    3. Microsoft ASP.NET MVC Preview 5 及LINQ TO SQL最新版开发示例演示(提供源码下载)

    [SQL]SQL Server2005 Sp3

    mikel阅读(903)

    Feature Pack for SQL Server 2005 December 2008

    Download the December 2008 Feature Pack for Microsoft SQL Server 2005, a collection of standalone install packages that provide additional value for SQL Server 2005.

    12/15/2008

    Microsoft SQL Server Protocol Documentation

    The Microsoft SQL Server protocol documentation provides technical specifications for Microsoft proprietary protocols that are implemented and used in Microsoft SQL Server 2008.

    12/15/2008

     

    SQL Server 2005 Express Edition with Advanced Services SP3

    Microsoft SQL Server 2005 Express Edition with Advanced Services is a free, easy-to use version of SQL Server Express that includes more features and makes it easier than ever to start developing powerful data-driven applications for web or local desktop development.

    12/15/2008

     

    SQL Server Management Studio Express SP3

    Microsoft SQL Server Management Studio Express (SSMSE) is a free, easy-to-use graphical management tool for managing SQL Server 2005 Express Edition and SQL Server 2005 Express Edition with Advanced Services.

    12/15/2008

    SQL Server 2005 Express Edition Toolkit SP3

    Microsoft SQL Server 2005 Express Edition Toolkit provides additional tools and resources for SQL Server 2005 Express Edition and SQL Server 2005 Express Edition with Advanced Services.

    12/15/2008

     

    SQL Server 2005 Express Edition SP3

    Microsoft SQL Server 2005 Express Edition is a free, easy-to-use, lightweight version of SQL Server 2005. It is fast and easy to learn, allowing you to quickly develop and deploy dynamic data-driven applications.

    12/15/2008

    SQL Server Data Mining Add-ins for Office 2007

    Download SQL Server 2005 Data Mining Add-ins for Office 2007. This package includes two add-ins for Microsoft Office Excel 2007 (Table Analysis Tools and Data Mining Client) and one add-in for Microsoft Office Visio 2007 (Data Mining Templates).

    12/15/2008

    SQL Server Reporting Services Add-in for SharePoint Technologies

    The Microsoft SQL Server 2005 Reporting Services Add-in for Microsoft SharePoint Technologies is a Web download that provides features for running a report server within a larger deployment of Windows SharePoint Services 3.0 or Microsoft Office SharePoint Server 2007.