人生是一场不能存盘的RPG,我只能尽量多搞几个Screenshot

June 29, 2006

使用AVG()

Filed under: SQL&DB Accessing

有两张表:
Student: stdudentid (int), name(string)
Scroe: stdudentid (int), score
Score表中会有多个老师给学生打的分数,

现在我想查出所有的学生,以及他们的平均分数,该如何写sql语句?
我瞎搞了一个
Select st.Name, AVG(sc.Score) from student as st join Score as sc on st. stdudentid = st. stdudentid

高手答曰:

Select st.studentid, st.name, AVG (sc.Score) from student as st inner join Score as sc on st. stdudentid = sc. stdudentid Group by st. stdudentid, st.name
我怎么没想到呢?

考虑有的学生没有分数,改进为:

Select st.studentid, st.name, AVG (IsNull(sc.Score,0)) from student as st LEFT JOIN Score as sc on st. stdudentid = sc. stdudentid Group by st. stdudentid, st.name

SQL 2005的安装程序

Filed under: 代码学习

今天把sql 2005的安装程序(一个hta, 很漂亮)扒开看了看,学到了

如何做mouse hover时图片和文在的淡入淡出(滤镜)

如何执行一个exe()

function onClickLinkApp(sApp)
{
var oShell = new ActiveXObject(”WScript.Shell”);
oShell.Run(sApp);
}

June 28, 2006

APM(Asynchronous Programming Modle)的3种模式

Filed under: .NET

出自CLR via C# ch23

//—-Wait until done

定义了FileOptions.Asynchronous,才能调用FileStream.BeignRead(),否则请调用FileStream.Read
如果定义了FileOptions.Asynchronous,又调用Read,FileStream会启动一个工作线程来操作文件,
并Sleep调用线程,知道工作线程完成.

FileStream fs = new FileStream(@”c:\boot.ini”, FileMode.Open, FileAccess)

Byte[] data = new Byte[100];

IAsyncResult ar = fs.BrginRead(data, 0, data.Length, null, null);

//Suspend this thread until the asynchronous operation completes
Int32 bytes = fs.EndRead(ar);

fs.Close();

//—-Polling

FileStream fs = new FileStream(@”c:\boot.ini”, FileMode.Open, FileAccess)

Byte[] data = new Byte[100];

IAsyncResult ar = fs.BrginRead(data, 0, data.Length, null, null);

while(!ar.IsComplete)
{
Thread.Sleep(10);
}

Int32 bytes = fs.EndRead(ar);

fs.Close();

//—-Callback

FileStream fs = new FileStream(@”c:\boot.ini”, FileMode.Open, FileAccess)

Byte[] data = new Byte[100];

fs.BrginRead(data, 0, data.Length, ReadIsDone, fs);

private static void ReadIsDone(IAsyncResult ar)
{
FileStream fs = (FileStream)ar.AyncState;

Int32 bytes = fs.EndRead(ar);

fs.Close();
}

也可以使用匿名方法写成:

FileStream fs = new FileStream(@”c:\boot.ini”, FileMode.Open, FileAccess)

Byte[] data = new Byte[100];

IAsyncResult ar = fs.BrginRead(data, 0, data.Length,
delegate(IAsyncResult ar)
{
Int32 bytes = fs.EndRead(ar);

fs.Close();
}
, null);

这样写的好处是匿名方法可以访问所有的局部变量(data, fs),所以不用把fs传递给它.

June 26, 2006

QueueUserWorkItem() 和UnsafeQueueUserWorkItem()

Filed under: .NET

Code Access Security(CAS) check.
CLR 会检查执行线程的call stack 中的所有assembly是否有权限访问受限制的资源.
否,则抛出SecurityException.

QueueUserWorkItem会把调用线程的权限赋给线程池中的线程,但是遍历调用线程的callstack
检查权限是一个耗时的操作,所以有了UnsafeQueueUserWorkItem().

调用UnsafeQueueUserWorkItem()的函数需要SecurityPermission,并把ControlPolicy和
ControlEvidenc打开.

CSS 入门

Filed under: ASP.NET

参考http://www.w3schools.com/css/css_syntax.asp
—————————————————————————————
语法: selector {property: value}
—————————————————————————————
1.Grouping
h1,h2,h3,h4,h5,h6
{
color: green
}

2.The class Selector
注意:Do NOT start a class name with a number! It will not work in Mozilla/Firefox.
* 对相同元素定义为不同风格
p.right {text-align: right}
p.center {text-align: center}
使用
<p class=”right”>
This paragraph will be right-aligned.
</p>
<p class=”center”>
This paragraph will be center-aligned.
</p>
注意:Only one class attribute can be specified per HTML element!

.center {text-align: center}
使用:
<h1 class=”center”>
This heading will be center-aligned
</h1>
<p class=”center”>
This paragraph will also be center-aligned.
</p>

3.The id Selector
注意:Do NOT start an ID name with a number! It will not work in Mozilla/Firefox.

match the element that has an id attribute with a value of “green”:
#green {color: green}

match the p element that has an id with a value of “para1″:
p#para1
{
text-align: center;
color: red
}

4.子选择器(descendant selectors)
div.item{….}
div.item div.itemEx{XXXXXX}

div.nav
{
text-transform: uppercase;
font-size: 18px;
}
div.nav a:visited
{
color: #000000;
}

<div class=”nav”>
<a href=”Default2.aspx”>aaaaa</a>
</div>

//——指定图片
span.title
{
background : transparent
url(imgs/xxx.gif) top left no-repeat;
}

//——引用

<head>
<link rel=”stylesheet” type=”text/css” href =”css/window.css”>
</head>

June 22, 2006

GridView的使用

Filed under: ASP.NET

GridView Examples for ASP.NET 2.0(by Scott Mitchell 4GuysFromRolla.com)
http://msdn.microsoft.com/library/en-us/dnaspp/html/GridViewEx.asp

[ 1 ]————–使用DatatSource control访问数据
1. 什么是数据(Data) : xml, database, 提供某些interface的class,如dataset.

2. 什么是data source controls:
封装了数据来源的差异,使用declarative syntax来配置,

3. GridView等数据显示控件如何使用data source control.
GridView.DataSourceID = DataSources.ID

3.1. 使用SqlDataSource
优点:简单, 缺点:增加了页面的复杂度,在页面上绑定数据访问逻辑.
配置DataSource时会设置SELECT,INSERT, UPDATE, 和 DELETE Statement,
<asp:SqlDataSource ID=”productsDataSource” Runat=”server”
“SelectCommand=”SELECT [ProductID], [ProductName], ” & _
“[QuantityPerUnit], [UnitPrice], [UnitsInStock] ” & _
“FROM [Products]”
ConnectionString=
“<%$ ConnectionStrings:NWConnectionString %>”
DataSourceMode=”DataReader”>
</asp:SqlDataSource>

3.2 使用ObjectDataSource
提供一个Data Access Layer (DAL).
注意,DAL和数据实体可以不在同一个class中,即可以有Product 和 ProductDAL两个class

在配置ObjectDataSource时指定执行Select, Update, delete, Insert操作的方法名.

3.3 使用 XmlDataSource

[ 2 ]—————Formatting the GridView
Format 相关的property:
BackColor, Font, ForeColor
HeaderStyle, RowStyle, AlternatingRowStyle, FooterStyle

使用Smart Tag上的Auto Formatting, 此功能只提供整体的配色方案

使用Smart Tag上的Edit Columns, 对单独的column进行format.
使用Bound Field的DataFormatString 来格式化输出,比如
日期column的DataFormatString: DataFormatString=”{0:yyyy.MM.dd}”
注意,出于安全上的考虑,还要设置HtmlEncode=”false”

使用Skin
一个project的Theme的目录结构
/app_themes/<ThemeName>/ .css .skin .Image

Theme : 多个Skin的集合.

Skin : 包含了某些control的外观的文件.
Skin的格式:
<!– Default Skin –>
<asp:GridView runat=”server” Font-Name=”Arial” />
<asp:GridView runat=”server” SkinID=”Professional” Font-Name=”Verdana”
Font-Size=”10pt” Cellpadding=”4″
HeaderStyle-BackColor=”#444444″
HeaderStyle-ForeColor=”White”
AlternatingRowStyle-BackColor=”#dddddd” />
<asp:GridView runat=”server” SkinID=”Fun” Font-Name=”Comic Sans MS”
Font-Size=”13pt” BackColor=”Khaki”
AlternatingRowStyle-BackColor=”Tan”
HeaderStyle-BackColor=”SaddleBrown”
HeaderStyle-ForeColor=”White”
HeaderStyle-Font-Bold=”True”/>

使用Skin
<%@ Page Language=”C#” StyleSheetTheme=”<Theme Name>” %>

<asp:GridView ID=”GridView1″ Runat=”server” SkinID=”<Skin Name>”>

根据数据动态Formatting the GridView,比如根据数据而使用不同的颜色.
void productsGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// determine the value of the UnitsInStock field
int unitsInStock = Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, “UnitsInStock”));
if (unitsInStock == 0)
{
// color the background of the row yellow
e.Row.BackColor = Color.Yellow;
}
}
}
RowDataBound event 在每个row被生成时触发,由于包含HeaderRow,所以使用e.Row.RowType来判断是否
需要fromatting.关键在于如何得到row的某个field:
DataBinder.Eval(e.Row.DataItem, “UnitsInStock”)

[ 3 ]—————Master/Detail
典型用法: ComboBox(DropDownList) + GridView
1. 把DropDownList的DataValueField设置为一个Field的Name 如”ProductID”, 意味着当DropDownList的一个Item被选中时,
DropDownList的SelectedValue等于字段”ProductID”的值,
2. 设置GridView对应的SqlDataSource的<SelectParameters>
指定使用DropDownList的SelectedValue属性来作为查询的条件.
<asp:SqlDataSource SelectCommand=”SELECT * FROM [OrderDetails] WHERE ([ProductID] = @ProductID)” ConnectionString=”…”>
<SelectParameters>
<asp:ControlParameter Name=”ProductID” Type=”Int32″ ControlID=”productSelector” PropertyName=”SelectedValue”>
</asp:ControlParameter>
</SelectParameters>
</asp:SqlDataSource>

使用DAL显示 Master/Detail 数据, 关键在于配置ObjectDataSource,指定其SelectMethod

<asp:ObjectDataSource ID=”orderDetailsForProduct”
Runat=”server” TypeName=”OrderDetailDAL”
SelectMethod=”GetOrderDetailsByProductID”>
<SelectParameters>
<asp:ControlParameter Name=”productID” Type=”Int32″
ControlID=”productSelector”
PropertyName=”SelectedValue”></asp:ControlParameter>
</SelectParameters>
</asp:ObjectDataSource>

[ 4 ]—————Paging and Soring
SqlDataSource 中的Paging and Soring只需要设置GridView的 AllowSorting=”True” 和AllowPaging=”True”
注意:
SqlDataSource 可以返回DataReader或DataSet,次行为可通过设置DataSourceMode属性来指定,
Default值为DataSet,如果要生成一个可”分页”的GridView, 必须使用DataSet.可”排序”的GridView
可以使用DataSet和DataReader,但使用DataReader时必须从一个接受sort expression的Stored procedure
中返回数据.
使用SqlDataSource的缺点是GridView 只能使用 default paging model, 即SqlDataSource会返回所有的数据.

ObjectDataSource 中的Paging and Soring
要支持 分页 ,DAL class的要多提供一个接受两个int参数的SELECT method ,
GetProducts(maximumRows, startRowIndex)
第一个参数表示返回的记录数, 第二个参数表示起始的row index.

要支持排序,DAL class的要多提供下列函数
GetProducts(SortExpression) //返回排序后的所有记录
GetProducts(maximumRows, startRowIndex, SortExpression) //排序 + 分页

然后需要设置ObjectDataSource的下列属性:
<asp:ObjectDataSource ID=”productsDataSource” Runat=”server” TypeName=”ProductDAL”
EnablePaging=”True”
SortParameterName=”SortExpression”
SelectMethod=”GetProducts”
SelectCountMethod=”TotalNumberOfProducts”>
</asp:ObjectDataSource>

ObjectDataSource的MaximumRowsParameterName 属性和StartRowIndexParameterName属性一般不用指定,
MaximumRowsParameterName缺省对应maximunRows, StartRowIndexParameterName缺省对应startRowIndex.

显示分页信息:
<i>You are viewing page<%=productsGridView.PageIndex + 1%>of<%=productsGridView.PageCount%></i>

[ 5 ]—————Displaying Images
文中推荐的做法是在数据库中存放一个PicureURL字段(形如”~/DisplayingImages/Images/Blue hills.jpg”)
真正的图片存放在file system中.
在进行data binding时,删除PicureURL字段, 添加一个ImageField, 并指定ImageField的DataImageUrlField
属性为”PicureURL”(datasource中包含picture url的字段名).

文中还用到了一个小技巧, 给GridView指定一个动态生成的data source:
DataTable GetData()
{

}

<asp:GridView Runat=”server” DataSource=’<%# GetData() %>’ …>

</asp:GridView>

[ 6 ]————–Working with TemplateFields
GridView 可以使用不同的Column类型:
BoundFiled, 显示DataSource的Fieled的内容
ImageField, 通过DataSource的image url 字段来显示图片
CommandField 显示command buttons.
TemplateField, 可以显示HTML markup, web contorl, data-binding syntax

1.使用Function来自定义输出.
<%# FunctionName(parameter1, parameter2, …, parameterN) %>
Sample:

<%# ComputeSeniorityLevel(DateTime.Now - (DateTime)Eval(”HireDate”)) %>
string ComputeSeniorityLevel(TimeSpan ts)
{
int numberOfDaysOnTheJob = ts.Days;
if (numberOfDaysOnTheJob >= 0 && numberOfDaysOnTheJob <= 1000)
return “Newbie”;
else if (numberOfDaysOnTheJob > 1000 && numberOfDaysOnTheJob <= 4000)
return “Associate”;
else if (numberOfDaysOnTheJob >= 4000 && numberOfDaysOnTheJob <= 8000)
return “One of the Regulars”;
else
return “An Ol’ Fogey”;
}
2.嵌入一个Web Control
<Columns>

<asp:TemplateField HeaderText=”Territories”>
<ItemTemplate>
<asp:BulletedList ID=”bltTerritories” Runat=”server”
DataTextField=”TerritoryDescription”
DataValueField=”TerritoryDescription”>
</asp:BulletedList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
注意: 把DataTextField和DataValueField设置为DataSet的Field name
处理Gridview的RowDataBound event
<asp:GridView ID=”employeesGridView” OnRowDataBound=”employeesGridView_RowDataBound” />

void employeesGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
// For each DataRow in the GridView,
// programmatically access the BulletedList, filter
// the DataView based on the GridView row’s
// EmployeeID value and bind the filtered DataView
// to the BulletedList
if (e.Row.RowType == DataControlRowType.DataRow)
{
BulletedList bl = (BulletedList)e.Row.FindControl(”bltTerritories”);
territoryData.RowFilter = “EmployeeID = ” + ((DataRowView) e.Row.DataItem)[”EmployeeID”].ToString();
bl.DataSource = territoryData;
bl.DataBind();
}
}

[ 7.1 ]————–Master/Slave
一个Orders表和一个Order Details表
1. 用一个SqlDataSource取回Orders表中所有的数据.
2. 添加一个主GridView,绑定到SqlDataSource,并选中这个GridView的”Enable Selection”选项,
设置主GridView 的DataKeyNames属性,使得GridView的SelectValue属性会等于DataKeyNames属性
对应的字段的值.
3. 添加一个子SqlDataSource.设置其Select 方法的where参数的”Parameter Source”为Control,
ControlID为主GridView的ID.
4. 注意当主GridView分页时,子GridView不能正确显示数据,添加如下代码Fix
void orderGridView_PageIndexChanged(object sender, EventArgs e)
{
orderGridView.SelectedIndex = -1;
}

[ 7.2 ]—————- Summary to Detail
主GridView只显示部分数据, DetailsView显示所有的数据.
设置主GridView的DataKeyNames 属性为 CustomerID
设置DetailsView的SqlDataSource的FilterException属性为CustomerID=’{0}’

[ 8 ]——————–Summary Data in the Footer
处理RowDataBound事件
void detailsGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// add the UnitPrice and QuantityTotal to the running total variables
priceTotal += Convert.ToDecimal(DataBinder.Eval(e.Row.DataItem, _
“UnitPrice”));
quantityTotal += Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, _
“Quantity”));
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[0].Text = “Totals:”;
// for the Footer, display the running totals
e.Row.Cells[1].Text = priceTotal.ToString(”c”);
e.Row.Cells[2].Text = quantityTotal.ToString(”d”);

e.Row.Cells[1].HorizontalAlign = _
e.Row.Cells[2].HorizontalAlign = HorizontalAlign.Right;
e.Row.Font.Bold = true;
}
}

[ 9 ]———————Delete
在配置SqlDataSource时选中”Generate Insert, Update, and Delete Statements”check box.
如果使用了”Use optimistic concurrency”选项,当数据库中的数据和GridView中的当前数据
不一致时,对数据库的delete和update会失败.这个选项对应了SqlDataSource的ConflictDetection
属性的取值: CompareAllValues or OverwriteChanges.
设置GridView的 DataKeyNames 属性

GridView 提供了 RowDeleting Event:
e.Values, which provides data on the values of the row being deleted
e.Cancel.

Deleting from an ObjectDataSource
设置ObjectDataSource的ConflictDetection 属性.
如果使用了OverwriteChanges,需要提供方法
public static void DeleteMethod(int original_OrderID, int original_ProductID)
{

}

如果使用了CompareAllValues,需要提供方法:
public static void DeleteMethod(int original_OrderID, int original_ProductID, int original_Quantity, decimal original_UnitPrice)
{

}

Client Scitpt确认
注意:GridView’s CommandField does not include an OnClientClick property,故无法使用script.
<Columns>
<asp:TemplateField><ItemTemplate>
<asp:LinkButton ID=”LinkButton1″ Runat=”server” OnClientClick=”return confirm(’Are you sure you want to delete this record?’);”
CommandName=”Delete”>Delete Order Line Item</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>

[ 10 ]———————–Edit
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/GridViewEx10.asp
和Delete 类似

Customizing the Editing Interface!

GridView的SmartTag “Edit Columns”->Selected Fields->”Convert this field into a TemplateField”
使用GridView的SmartTag “Edit Templates”

1 . Validation
drag and drop the appropriate validation controls from the Toolbox into the EditItemTemplate

2. 在Combo中选择输入
Add a DropDownList to the EditItemTemplate and bind it to this SqlDataSource

June 16, 2006

DataField的DataFormatString

Filed under: ASP.NET

使用语法如下:
DataFormatString=”{0:格式字符串}”
如:
<asp:BoundField DataField=”StartTime” HeaderText=”活动开始时间” SortExpression=”StartTime” DataFormatString=”{0:yy-MM-dd}” HtmlEncode=”false”/>
DataFormatString=”Total: {0:C}” 12345.6789 显示为 Total: $12345.68

ASP.NET2.0出于安全性的考虑,除了设置DataFormatString,还需要设置HtmlEncode =”false” 才会格式化显示

不断调用System.Timers.Timer的Stop()和Start方法,会导致程序占用的内存和线程数骤增.

Filed under: .NET, My Questions

不断调用System.Timers.Timer的Stop()和Start方法,会导致程序占用的内存和线程数骤增.

System.Timers.Timer _tmr;

private void button1_Click(object sender, System.EventArgs e)
{
_tmr = new System.Timers.Timer();
_tmr.Interval = 10000000;
_tmr.Start();

while(true)
{
_tmr.Stop();
//Thread.Sleep(300); 如果使用了sleep,情况会大幅缓和,但线程数会增加.
_tmr.Start();
}

为什么?

June 14, 2006

Custom HTTP Handler

Filed under: ASP.NET

ASP.NET会按照被请求的文件的后缀把请求交给特定的Handler.
内置的Handler:
Page Handler Handles Web pages (.aspx)
User Control Handler Handles Web user control pages (.ascx)
Web Service Handler Handles Web service pages (.asmx)
Trace Handler Handles trace functionality(trace.axd)

同步的Hanlder实现
public interface IHttpHandler
{
//是用同一个Handler处理所有的request(高效),还是每个request都需要一个新的handler
bool IsReusable { get; }

// Enables processing of HTTP Web requests by a custom HttpHandler that implements
// the System.Web.IHttpHandler interface.
void ProcessRequest(HttpContext context);
}

异步的Handler实现
public interface IHttpAsyncHandler : IHttpHandler
{
IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
void EndProcessRequest(IAsyncResult result);
}

注册
<configuration>
<system.web>
<httpHandlers>
<add verb=”*” path=”*.myfile” type=”MyHandler”/>
</httpHandlers>
</system.web>
</configuration>

ASP.NET 提供了一个缺省的custom handler .ashx, 此handler会被自动注册给IIS,因为是
缺省的handler, 所以可以让.ashx来处理多种后缀的文件.
比如
<%@ WebHandler Language=”C#” Class=”ImageFetch” %>

using …;
public class ImageFetch : IHttpHandler
{

public bool IsReusable
{
get
{
return true;
}
}
}

参照
Use Custom HTTP Handlers in Your ASP.NET Applications
http://www.developer.com/net/asp/article.php/3565541

StarterKits Club Web Site
http://asp.net/downloads/starterkits/default.aspx?tabid=62

加密Web.config

Filed under: ASP.NET

比如要加密connnection string
<configuration>
<connectionStrings>
<add name=”mySqlServer” connectionString=”Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;” />
</connectionStrings>
</configuration>

//==使用aspnet_regiis
aspnet_regiis -pe “connectionStrings” -app “/MyApplication”
加密 MyApplication 应用程序的 Web.config 文件的 <connectionStrings> 节
aspnet_regiis -pe “connectionStrings” -app “/MyApplication”
解密

aspnet_regiis -pef “connectionStrings” “C:\PetShop4.0\Web”
加密指定的物理路径下的web.config
aspnet_regiis -pdf “connectionStrings” “C:\PetShop4.0\Web”
解密

aspnet_regiis -pa “NetFrameworkConfigurationKey” “NT AUTHORITY\NETWORK SERVICE”
授予 NETWORK SERVICE 帐户对计算机级别的 “NetFrameworkConfigurationKey” RSA 密钥容器的访问权限。

-pkm 对Machine.config 加密
-prov 指定要使用的加密提供程序,如 RsaProtectedConfigurationProvider.

//==如果无法控制物理的服务器,可以通过代码来加密web.congif
public void EncryptConfig(bool bEncrypt)
{
string path = “/tricks”;

Configuration config = WebConfigurationManager.OpWebConfiguration(path);
ConfigurationSection appSettings = config.GetSection(”connectionString”);

if(bEncrypt)
{
appSettings.SetionInformation.ProtectSection(”DataProtectionConfigurationProvider”);
}
else
{
appSettings.SetionInformation.UnprotectSection();
}
config.Save();
}

参考
受保护配置概述
http://msdn2.microsoft.com/zh-cn/library/hh8x3tas.aspx

使用受保护的配置加密配置信息
http://msdn2.microsoft.com/zh-cn/library/dtkwfdky.aspx

注册表中VS安装文件的位置

Filed under: Visual Studio

有这样的case:
VS.net安装盘放在公司的一个共享目录里,在安装VS.net时选择了部分安装,
在用到未安装的组件时,VS.Net会安装这些组件,但VS.net安装路径被移动了,
此时,请修改注册表:
HLM\Software\Classes\Installer\Products\{GUID}\SourceList

{GUID}需要自己找.
9040F50EA9E01A84CA403EE5033306A4 为 vs.net 2003
845140B1CB334714B879DA9C7B494888 为 vs.net 2005 Team edition

June 13, 2006

篡改.Net Strongly Name Assembly

Filed under: .NET

1.什么是Strong Name
一个strong name由4部分构成
filename(不含扩展名).version.Culture.PublicKeyToken

2.使用 System.Reflection.AssemblyName 可以得到 strong name的相关信息如:
CulturInfo, FullName, KeyPaire, Name, Version

3.SN.exe 的使用
生成key pair
sn -k my.keys

得到public key
sn -p my.keys my.publickey

查看public key内容
sn -tp my.publickey

4. Sign
[1]Assembly的FileDef manifest table包含了组成这个Assembly的所有文件,sign 一个assembly的
第一步就是把组成这个Assembly的所有文件的hash值和文件名放入FileDef manifest table.

[2]将整个PE文件的内容hash运算,结构使用private key 签名,再将结果(RSA数字签名)植入 CLR 文件头

[3]将public key植入AssemblyDef manifest table中.
不同的公司不可能拥有相同的public key,从而可以使用
filename(不含扩展名).version.Culture.PublicKeyToken来保证一个assembly的唯一性.

5. CLR 验证:
将文件的内容hash运算,把CLR 文件头中的RSA数字签名用public key反签名,二者比较可知文件是否
清白.如果被篡改过,CLR就会扔出个System.IO.FileLoadException.

6. Delay Sign.
[1]在PE文件中为 RSA数字签名留下空间
[assembly:AssemblyKeyFile(…keys)]
[assembly:AssemblyDelaySign(true)]

[2]关闭CLR验证
sn -Vr my.dll

[3]sign
sn -R my.dll my.keys

[4]打开认证
sn -Vu my.dll

7. 如何篡改SN Assembly
1.找一个Strong Name assembly, some.exe并篡改,执行some.exe会出错.
注意,此时使用sn -Vr some.exe 也不会由效果,否则 strong name将行同虚设.

2.生成一个自己的key pair文件 sn -k mykey.snk

3.编程,用mykey.snk中的public key 来替换 some.exe中的public key
SNReplace Some.exe mykey.snk

public class SNReplace
{
public static void Main(string[] args)
{
if (args.Length < 2)
{
Console.WriteLine(”Usage: SNReplace <assembly> <keyfile>”);
return;
}
SNReplace snr = new SNReplace();
snr.AssemblyFile = args[0];
snr.KeyFile = args[1];
snr.Replace();
}

public string KeyFile;
public string AssemblyFile;

byte[] currentKey;
byte[] newKey;

byte[] assembly;

private int keyStart;

public void Replace()
{
readKeys();
readAssembly();
findKeyStart();
replaceKey();
save();
resign();
}

private void readKeys()
{
//==得到assembly中的 pubic key
this.currentKey = AssemblyName.GetAssemblyName(this.AssemblyFile).GetPublicKey();

//==得到key pair 文件中的 pubic key
FileStream keyStream = File.OpenRead(this.KeyFile);
this.newKey = new StrongNameKeyPair(keyStream).PublicKey;
keyStream.Close();
}

private void readAssembly()
{
using (FileStream fs = File.OpenRead(this.AssemblyFile))
{
this.assembly = new byte[fs.Length];
fs.Read(this.assembly, 0, (int)fs.Length);
}
}

private void findKeyStart()
{
// Yes, it’s a slow algorithm.
byte startByte = currentKey[0];
for(int i = 0; i < this.assembly.Length; i++)
{
if (assembly[i] == startByte)
{
// Possible match
if (isKeyFound(i))
{
this.keyStart = i;
return;
}
}
}
// Not found…
Console.WriteLine(”Something’s wrong. Public key not found.”);
Environment.Exit(1);
}

private bool isKeyFound(int startIndex)
{
for(int i = 0; i < currentKey.Length; i++)
{
if (currentKey[i] != assembly[i + startIndex])
{
return false;
}
}
return true;
}

private void replaceKey()
{
for(int i = 0; i < newKey.Length; i++)
{
assembly[keyStart + i] = newKey[i];
}
}

private void save()
{
using (FileStream fs = File.Create(this.AssemblyFile))
{
fs.Write(assembly, 0, assembly.Length);
}
}
}

4. sn -R Some.exe mykey.snk

这招对于不被别人引用的assembly 非常有效,但对于被别的assembly引用的assembly,由于被引用的assembly
的hash 值被保存在引用者的FileDef中,篡改了一个assembly后还要篡改这些FileDef.比较恐怖.

做坏事之前先想清楚,是不是真的想做.

获取Public Key 信息

Filed under: Code snippets

//==得到assembly中的 pubic key
byte[] currentKey = AssemblyName.GetAssemblyName(”myAssembly.dll”).GetPublicKey();

//==得到key pair 文件中的 pubic key
FileStream keyStream = File.OpenRead(”mykey.snk”);
byte[] newKey = new System.Reflection.StrongNameKeyPair(keyStream).PublicKey;

//==使用 sn.exe

得到public key
sn -p my.keys my.publickey

查看public key内容
sn -tp my.publickey

_NET应用程序的自动更新

Filed under: .NET

出自
.NET Client Applications: .NET Application Updater Component
http://windowsforms.net/articles/appupdater.aspx
http://windowsforms.net/downloads/GDN/dotnetupdater.zip

Using The Updater Application Block
http://www.theserverside.net/tt/articles/showarticle.tss?id=UpdateAppBlock

TaskVision 解决方案概述:设计与实现
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/SCdnwinformswnftaskvision.mspx?mfr=true

.net的rich client自动升级方案
http://yyanghhong.cnblogs.com/archive/2004/11/08/61409.aspx

如何得知是否需要更新:
1.比较文件的时间戳,缺陷在于
如果管理员正在更新服务器上的程序,同时有个客户正在下载更新之前的版本,那么这个客户的计算
机上就会既存在更新之前的一些文件,也存在更新之后新版本的一些文件。

2.在服务器上放一个xml文件,来描述应用程序中所有assembly的版本,client会和本地的程序比较并决定
是否下载

3.server 端保存用户信息, client调用一个web service来决定是否需要更新.

如何下载:
下载使用HTTP-DAV来完成。DAV 是一种扩展的HTTP,提供遍历目录和文件的功能。
下载过程中可能会出现以下问题:更新文件所属的服务器可能会崩溃,客户端机器也可能崩溃,或者因为某种原因
用户关闭了应用程序,这些都会导致下载的终止。使用系统服务,即便应用程序自身没有在运行,更新下载也会继续。
Windows XP有一种称之为BITS的内建的下载服务,是Windows XP用来对Windows自身进行下载更新的。
参阅http://msdn.microsoft.com/library/en-us/dnwxp/html/WinXP_BITS.asp
在.NET应用程序更新组件中没有使用这种服务,因此可用在不支持系统服务的系统(Windows 9x,Mono)中使用。

.NET Application Updater component把download 和 update 过程分为几个独立,可重复执行的的过程,每个过程的
执行结果都记录在client 程序所在的路径下的一个文件中,如果某个步骤失败,.NET Application Updater component
会重试,实在不行就报错退出.

如何执行Update
该过程的难点在于有可能会更新正在运行的程序.
最简单的方案是使用一个独立的进程来执行更新,Update进程会shutdown Application进程,然后执行update,最后重启
Application.但是这个解决方案有如下的问题:
1. Update 进程由App进程产生, Update进程kill app进程,当APP运行在Job模式下, Update进程也会被终止.
2. 执行更新的模块也需要更新.

最终的方案使用了一个小的"诡计",避开直接更新应用程序本身,而是新建一个目录然后下载新版本的引用程序,下载完成
后使用新版本的可执行文件启动应用程序,并且删除老版本程序,由于要有选择地启动某个版本的程序,需要一个引子程序
AppStart,用它来作为应用程序的入口.整个应用程序的目录结构如下:
Program File
    My App
        AppStart.exe
        AppStart.config
        V1 Folder
            MyApp.exe
        V2 Folder
           MyApp.exe
AppStart.exe会根据AppStart.config来决定启动那个版本的exe
<Config>
    <AppFolderName>V1 Folder</AppFolderName>
    <AppExeName>MyApp.exe</AppExeName>
    <AppLaunchMode>appdomain</AppLaunchMode>
</Config>
更新程序可以通过修改<AppFolderName>来决定执行那个版本的app.
<AppLaunchMode>会使AppStart.exe和MyApp.exe运行在同一进程的不同的AppDomain中,
Appstart启动MyApp后就sleep,等待MyApp结束.通常情况下MyApp结束后,AppStart也会shutdown,
但如果MyApp结束时返回一个特有的返回值,AppStart会重新MyApp.

.Net Updater Component
只有一个文件,AppUpdater.dll.
主要属性:
AutoFileLoad: 用户实现按需下载,当CLR找不到一个dll时,会raise AppDomain.AssemblyResolve 事件,
.Net Updater Component会hook这个event,进行下载,更新.
ChangeDetectionMode: 采用何种方式检查更新,一般使用ServerManifestCheck.
ShowDefatultUI: 是否使用.Net Updater Component自带的UI提示用户,也可以hook .Net Updater Component的
有关事件如OnUpdateComplete来弹出自定义的UI.
AppUpdater obj必须生成在app的主UI线程中,否则不能显示UI,也不能给UI线程发Event显示UI.
UpdateUrl: 在何处查找Updata信息,如果使用了ServerManifestCheck Mode,UpdateUrl可指定为:
http://yourWebserver/SampleApp_ServerSetup/UpdateVersion.xml.
UpdateVersion.xml的内容为:
<VersionConfig>
     <AvailableVersion>1.0.0.0</AvailableVersion>
     <ApplicationUrl>http://localhost/SampleApp_ServerSetup/1.0.0.0/</ApplicationUrl>
</VersionConfig>
用来描述需要下载文件所在的目录

Downloader.DownloadRetryAttempts : 下载重试次数 
Downloader.SecondsBeteweenDownloadRety : 
Downloader.UpdateRetryAttempts : 
Downloader.ValidateAssemblies : 是否进行了Strong Name检查后才进行下载.

Poller.AutoStart : 是否在程序启动后自动检测
Poller.DownloadOnDetection : 是否在检测到更新后自动下载
Poller.InitialPollInterval : 程序启动后多长时间开始检测.
Poller.PollInterval

使用AppUpdater.dll

1.Create 一个带Form的Project,把 .Net Updater Component揪到From上,并配置

2.Client端
Build出一个AssemblyVersion为1.0.0.0的SampleApp.exe
c:\ClientSetup\Appstart.config
                   \AppStart.exe
                  \1.0.0.0\
                             \SampleApp.exe

Appstart.config的内容为
<Config>
    <AppFolderName>1.0.0.0</AppFolderName>
    <AppExeName>SampleApp.exe</AppExeName>
</Config>

3.Server端
Build出一个AssemblyVersion为2.0.0.0的SampleApp.exe
Create VD ServerSetup

ServerSetup\UpdateVersion.xml
                \2.0.0.0\

UpdateVersion.xml的内容为:
<VersionConfig>
    <AvailableVersion>3.0.0.0</AvailableVersion>
    <ApplicationUrl>http://localhost/ServerSetup/2.0.0.0/</ApplicationUrl>
</VersionConfig>

配置IIS,由于.net updater component使用了HTTP-DAV协议,所以在vd ServerSetup上要打开
"Directory Browsing"选项.

4.把玩
在Client端运行SampleApp.exe, 可看到提示是否需要更新…

5.深入讨论按需下载.
把AutoFileLoad设为true可实现按需下载,下载需要时间,此时applicatin 会完全失去相应

6.安全
1.拦截数据包,并篡改
解药:使用HTTPS,做法很简单只要使用HTTPS URL代替 HTTP URL
但价格昂贵,HTTPS会加密被下载的所有文件.

2.服务器上的文件被篡改.
解药:使用strong name..net updater component会比较已安装的组件的public key和要下载的组件
的public key,只有被相同private key标记的assembly才会由相同的public key, 所以如果一致,
就认为要下载的文件是合法的.
但在现实中,Application的各个组件常常是由不同的private key标记的,比如有这样的application,
由一个exe和一个第3方控件组成.此时,构造一个名为AppUpdateKeys.dll的assembly,
public class KeyList
{
public static byte[][] Keys;
public static string[] ExceptionList;

static KeyList()
{
//Add the list of public keys your app uses here
Keys = new byte[][]
{
new byte[] { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 95, 81, 246, 90, 218, 186, 162, 97, 166, 49, 31, 81, 219, 192, 9, 180, 14, 174, 24, 158, 138, 225, 14, 38, 226, 192, 31, 171, 74, 47, 210, 255, 104, 31, 90, 175, 172, 246, 149, 141, 132, 248, 25, 166, 64, 102, 240, 89, 239, 22, 97, 54, 233, 217, 7, 155, 23, 87, 172, 111, 39, 104, 48, 97, 200, 50, 155, 32, 37, 42, 212, 167, 201, 220, 50, 119, 84, 201, 191, 19, 164, 227, 94, 9, 44, 79, 115, 18, 25, 236, 73, 169, 16, 14, 84, 241, 175, 110, 112, 223, 214, 81, 111, 220, 222, 16, 224, 208, 204, 65, 108, 207, 171, 88, 52, 149, 212, 147, 62, 9, 112, 118, 105, 25, 24, 161, 235, 213 }
};

//Add the list of files that don’t need to be signed, but are allowed to be downloaded even if not signed.
//PDB files would be a good example of this type of file.
ExceptionList = new string[] {"simpleform.dll", "simpleform.pdb"};
}
}
AppUpdateKeys.dll包含了应用程序用到的所有assembly的public key,然后用应用程序的private key
来标记AppUpdateKeys.dll,下载时updater会首先对比AppUpdateKeys.dll的public key和应用程序的publickey,
如果通过验证,就下载AppUpdateKeys.dll,并提取AppUpdateKeys.dll中所有的public key,包含这些 public key
的Assembly就被认为是合法的.同时AppUpdateKeys.dll和可以定义一个ExceptionList, list中的文件可以不进行
验证.

实际应用 Terrarium:
Terrarium hook .NET Application Updater component 的 OnCheckForUpdate event,并在event handler中调用web
service来检查更新.OnCheckForUpdate是由poller 线程引发的,所以调用web service不会lock UI 线程.

Terrarium hook .NET Application Updater component 的 OnUpdateComplete event 使用自定义的UI, OnUpdateComplete
由UI 线程引发,所以可以直接在OnUpdateComplete的event handler中使用UI.

附录:
.Net 平台上的其他自动升级方案

Updater Application Block version 2.0
http://www.microsoft.com/downloads/details.aspx?FamilyID=c6c09314-e222-4af2-9395-1e0bd7060786&DisplayLang=en

Using the Updater Application Block
http://www.theserverside.net/tt/articles/showarticle.tss?id=UpdateAppBlock

DotNet No-Touch Deployment (NTD)
http://www.dotnet-online.de/web/notouch/

Clickonce
http://www.windowsforms.net/WhidbeyFeatures/default.aspx?PageID=2&ItemID=19&Cat=Runtime&tabindex=5

June 10, 2006

设置AssemblyVersion

Filed under: 开发工具

1. DIY一个EXE.
http://code.mattgriffith.net/UpdateVersion/
http://code.mattgriffith.net/UpdateVersion/UpdateVersion-src-1.2.zip

用在Nant中修改AssemblyVersion
<project name=”ExecTest” default=”test”>
<target name=”test” description=”tests using exec to run UpdateVersion.exe”>
<echo message=”** Running UpdateVersion.exe.”/>
<exec program=”UpdateVersion.exe” commandline=”-b MonthDay -s 2002-01-21 -i Input.txt -o Output.txt” verbose=”true” failonerror=”true” />
<echo message=”** End of Tests”/>
</target>
</project>
Input.txt是一个包含AssemblyVersion的文本文件

也可以用在VS中;
Tools -> External Tools… -> Add :

Title: Update Version Number
Command: UpdateVersion.exe
Arguments: -b MonthDay -s 2002-11-23 -i “AssemblyInfo.cs” -o “AssemblyInfo.cs”
Initial directory: $(ProjectDir)
Use Output window: Checked

2.NAntContrib 中的 <version> task

<Version BuildType=”increment”
RevisionType=”increment”
Path=”$(BuildNumberFile)”
WriteVersionInfo=”true”
VersionInfoPath=”$(VersionInfoFile)”>
<Output TaskParameter=”BuildNumber” PropertyName=”BuildNumber”/>
</Version>

3. 在NAnt中使用脚本
<script language=”C#”>
<imports>
<import name=”System.Globalization” />
<import name=”System.Threading” />
</imports>
<code><![CDATA[
[Function(”test-func”)]
public static void ScriptMain(Project project)
{
Version version = new Version(project.Properties[”build.version”]);
int major = version.Major;
int minor = version.Minor;
int build = version.Build;
int revision = version.Revision;
if (build == -1)
{
DateTime start = Convert.ToDateTime(project.Properties[”startdate”]);
Calendar calendar = Thread.CurrentThread.CurrentCulture.Calendar;

int months = ((calendar.GetYear(DateTime.Today)
- calendar.GetYear(start)) * 12)
+ calendar.GetMonth(DateTime.Today)
- calendar.GetMonth(start);
int day = DateTime.Now.Day;
build = (months * 100) + day;
}
if (revision == -1)
{
TimeSpan difference = DateTime.Now.Subtract(DateTime.Today);
revision = (int)(difference.TotalSeconds / 10);
}
version = new Version(major, minor, build, revision);
project.Properties[”build.version”] = version.ToString();
}
]]></code>
</script>

<echo message=’${test::test-func()}’/>

4. 使用macor, 使用ProjectItem来查找AssemblyInfo,然后进行替换.
Auto Increment Build Numbers for C# Projects in VS.NET 2003
http://www.biasecurities.com/blogs/jim/archive/2003/10/08/166.aspx

Managing AssemblyVersion
http://weblogs.asp.net/sjoseph/archive/2004/02/19/76277.aspx

参考
Using Open Source .NET Tools for Sophisticated Builds

Versioning with NAnt
http://geekswithblogs.net/flanakin/archive/2004/08/16/9763.aspx

http://nant.sourceforge.net/release/latest/help/tasks/script.html

在NAnt中使用C#,VB脚本

Filed under: NAnt

http://nant.sourceforge.net/release/latest/help/tasks/script.html

核心就是使用<script>

<script language=”C#” prefix=”test” >
<code>
<![CDATA[
[Function(”test-func”)]
public static string Testfunc( )

{
return “some result !”;
}
]]>
</code>
</script>
<echo message=’${test::test-func()}’/>

最酷的是用c#定义一个 custom task 并调用.

.NET Assembly的Versions

Filed under: .NET

参考 CLR via C# Assemlby Version Resource Information

.NET Assebly的Versions

Version 的格式
Major Number.Minor Number.Build Number.Reversion Number
Major Number和Minor Number是面向用户的版本.
Build Number 每次build递增一次.
Reversion Number 对build进行修订, 比如修改了一个daily build中一个严重的bug.

Jeffrey Richter 在书中写道:未来的CLR会自动加载最新版本的Assembly,并在新版本出错时
自动加载老版本, CLR希望Assembly在修改了一些bug后保持相同的Major Number和Minor Number,
用Build Number和Reversion Number来描述bug的修改.

既然Build Number 每次build递增一次,有没有什么工具来自动完成这个工作呢?答案是:自理.

每个Assebmly包含三个Version
AssemblyFileVersion :存储在win32资源中, CLR不关心这个版本号,
AssemblyInformationnalVersion :存储在win32资源中, CLR不关心这个版本号,此版本号用来表示包含
Assembly的产品的版本
AssemblyVersion: 存储在AssemblyDef manifest metadata table中,CLR会使用这个版本号

工具的支持:
CSC.exe和AL.exe在每次build时可以自动增加AssemblyVersion, 但要慎用.改变一个Assembly的
AssemblyVersion会导致引用这个Assembly的其它Assembly无法工作.

在VS会为每一个.net Porject生成 AssemblyInfo.cs 可在其中设置相关的信息.
[assembly: AssemblyVersion(”1.0.0.0″)]
[assembly: AssemblyFileVersion(”1.0.1.0″)]
如果使用[assembly: AssemblyVersion(”1.0.*”)], 在每次程序修改后build或rebuild后, assembly的
AssemblyVersion的Build Number和 ReversionNumber和会自动增加.ReversionNumber每次都变,
Build Number随日期的变化而变化.

有没有什么工具可以显式地设置一个solution中所有的project的AssemblyVersion?

通过程序获得版本信息:
//== Get File Version
System.Diagnostics.FileVersionInfo.GetVersionInfo

//==Get Assembly Version
AssemblyName assName = Assembly.GetExecutingAssembly().GetName();
string version = assName.Version.ToString();

对于一个win32的exe或dll,在Explore中查看它的属性(Properties->Version)可以看到
File Version
Product Version

一个.net Assembly在Explore中查看它的属性(Properties->Version)可以看到
Assebly Version (对应 AssemblyVersion)
File Version (对应 AssemblyFileVersion)
Product Version (对应 AssemblyInformationnalVersion, 如果不指定,则和AssemblyFileVersion对应)

听Alen讲MS Build

Filed under: Visual Studio

1. MS Build的位置
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727

2. 相关namespace
Microsoft.Build.Framework
Microsoft.Build.Engine
Microsoft.Build.Utilities

3. MS build的 4个要素:
Target : task的组合
<Target Name=”Build”>
<Task1 Property1=”XX” Property2=”XXX”>
<Output TaskParameter=”NewVersion” PropertyName=”ET4NewVersion” />
</Task1>

<Testn> </Testn>

</Target>

Task : 可复用的执行单元, 由脚本和dll协同工作

<UsingTask TaskName=”VssGet” AssemblyFile=”$(DLL)” />

<Target Name=”Build”>
<VssVersion VssIni=”$(VssIni)” Property2 =”XXXX”>
<Output TaskParameter=”NewVersion” PropertyName=”ET4NewVersion” />
</VssVersion>
</Target>

public class VssGet : Microsoft.Build.Utilities.Task
{
//
// Properties….
//
[Required] //从脚本中读取
public string ProjectPath
{
get
{
return _projectPath;
}
set
{
_projectPath = value;
}
}

[Output]
public string Date
{
get
{
return DateTime.Today.ToShortDateString();
}
}
public override bool Execute()
{
}
}
Property: key-value 对,用来对build进行配置
<PropertyGroup>
<BuildDir>Build</BuildDir>
<DLL>..\GrapeCity.DailyBuild.dll</DLL>
</PropertyGroup>

使用property
<UsingTask TaskName=”XCopy” AssemblyFile=”$(DLL)” />
<XCopy Projects=”@(PublishOutputPath)” Destination=”$(TargetFolder)\LastBuild\Publish”/>

Item : Task的参数

4. 在命令行传入参数
MSBuild.exe MyProj.proj /property:Configuration=Debug

5. 执行外部命令
<PropertyGroup>
<EncryptPath>”D:\Work\DailyBuild\”</EncryptPath>
</PropertyGroup>

<Target Name=”Encrypt”>
<Exec IgnoreExitCode=”True”
Command=”$(EncryptPath)\Encrypt.bat”/>
</Target>

_NET程序中的重画

Filed under: .NET

参考
MSDN : Synchronous and Asynchronous Drawing

Control.Invalidate()

查看 Reflector的结果
//–.net 1.1
public void Invalidate(bool invalidateChildren)
{
if (this.window.Handle != IntPtr.Zero)
{
if (invalidateChildren)
{
SafeNativeMethods.RedrawWindow(new HandleRef(this.window, this.window.Handle), null, NativeMethods.NullHandleRef, 0x85);
}
else
{
SafeNativeMethods.InvalidateRect(new HandleRef(this.window, this.window.Handle), null, (this.controlStyle & ControlStyles.Opaque) != ControlStyles.Opaque);
}
this.NotifyInvalidate(this.ClientRectangle);
}
}

//–.net 2.0
public void Invalidate(bool invalidateChildren)
{
if (this.IsHandleCreated)
{
if (invalidateChildren)
{
SafeNativeMethods.RedrawWindow(new HandleRef(this.window, this.Handle), null, NativeMethods.NullHandleRef, 0x85);
}
else
{
using (Control.MultithreadSafeCallScope scope1 = new Control.MultithreadSafeCallScope())
{
SafeNativeMethods.InvalidateRect(new HandleRef(this.window, this.Handle), null, (this.controlStyle & ControlStyles.Opaque) != ControlStyles.Opaque);
}
}
this.NotifyInvalidate(this.ClientRectangle);
}
}

SafeNativeMethods.RedrawWindow(new HandleRef(this, this.Handle), null, new HandleRef(region, ptr1), 0x85);
如果invalidateChildren 为true, MS偷了个懒,直接调用了Win32 API RedrawWindow(),
重画了整个window,而不是调用每个子Control的Invalidate

#define RDW_INVALIDATE 0x0001 [*]
#define RDW_INTERNALPAINT 0x0002
#define RDW_ERASE 0x0004 [*]

#define RDW_VALIDATE 0x0008
#define RDW_NOINTERNALPAINT 0x0010
#define RDW_NOERASE 0x0020

#define RDW_NOCHILDREN 0x0040
#define RDW_ALLCHILDREN 0x0080 [*]

#define RDW_UPDATENOW 0x0100
#define RDW_ERASENOW 0x0200

#define RDW_FRAME 0x0400
#define RDW_NOFRAME 0x0800

如果使用了RDW_UPDATENOW, RedrawWindow API会直接调用win proc来处理WM_PAINT消息,而不是向消息队列中
插入WM_PAINT消息,RedrawWindow()才返回.这一点和UpdateWindow()相似.

SafeNativeMethods.InvalidateRgn(new HandleRef(this, this.Handle), new HandleRef(region, ptr1), !this.GetStyle(ControlStyles.Opaque));
这相当于一个异步调用,函数并不会在画法结束后返回,而是产生一个window 的invalidata range.
当窗口的消息队列为空时,windows会在消息队列中添加一个WM_PAINT Message,画法将在WM_PAINT
被处理时执行.如果消息队列中已经包含一个WM_PAINT Message,则windows会计算出一个新的invalidata range,
第3个参数为true,则整个background 在BeginPaint()被调用时被擦掉,对应透明的control(Control.Opaque 为false)
第3个参数为false,则整个background保持不变,对应不透明的control

MultithreadSafeCallScope是一个private class,从名字上看是为了提供线程安全.

Control.Update()
实际直接调用 Win32 API UpdateWindow(new HandleRef(this.window, this.window.Handle));
如果window的invalid range非空,UpdateWindow会直接调用win proc来处理WM_PAINT消息,而不
是向消息队列中插入WM_PAINT消息,处理结束后UpdateWindow()才返回.

Control.Refresh()
Invalidate control 的client area,并立即重画control及其子control
public virtual void Refresh()
{
this.Invalidate(true);
this.Update();
}
由于调用了Update(),Refresh()会在WM_PAINT消息处理函数执行完毕后才返回.

Control.OnPaint
Raises the Paint event,同时提供画法的实现.

June 9, 2006

石头记

Filed under: 歌词

石头记

曲:刘以达词:陈少琪

看遍了冷冷清风吹飘雪渐厚
鞋踏破路湿透
再看遍远远青山吹飞絮弱柳
曾独醉病消瘦

听遍那渺渺世间轻飘送乐韵
人独舞乱衣鬓
一心把思绪抛却似虚如真
深院内旧梦复浮沉
一心把生关死结与酒同饮
焉知那笑黡藏泪印

丝丝点点计算
偏偏相差太远
兜兜转转
化作段段尘缘
纷纷扰扰作嫁
春宵恋恋变挂
真真假假
悉悲欢恩怨原是诈

花色香皆看化

Take My Breath Away and 激情

Filed under: 歌词

Take My Breath Away

Watching every motion in my foolish lover’s gaze
On this endless ocean finally lovers know no shame
Turning and returning to some secret place inside
Watching in slow motion as you turn around and say

Take my breath away
Take my breath away

Watching I keep waiting still anticipating love
Never hesitating to become the fated ones
Turning and returning to some secret place to hide
Watching in slow motion as you turn to me and say

Take my breath away

Through the hourglass I saw you, in time you slipped away
When the mirror crashed I called you, and turned to hear you say
If only for today I am unafraid

Take my breath away
Take my breath away

Watching every motion in this foolish lover’s game
Haunted by the notion somewhere there’s a love in flames
Turning and returning to some secret place inside
Watching in slow motion as you turn to me and say

Take my breath away
My love, take my breath away

激情

歌手:林忆莲
曲:G Moroder/T Whitlock 词:林振强

思海中的波涛滔滔不息飞跃起
心窝中的激情终于不可关闭起
当初喜欢孤独要爱却害怕交出爱
你那野性眼神偏偏将恋火惹起
Take my breath away
Take my breath away

火一般的激情滔滔不息因你起
当中一双恋人甘心给恋火灼死
漆黑之中等待你再次与我一起
火一般的嘴唇浪漫地令我不羁
My love Take my breath away

肌肤都紧张地拉紧 只因你就荡来
不可转弯的一颗心 不管有没未来
仍留在禁地 赌赌我运气
Take my breath away
Take my breath away

火一般的激情滔滔不息因你起
今天只得单程即使终于给灼死
漆黑之中等待你再亲身交低你
火一般的嘴唇浪漫地令我不羁
My love Take my breath away
My love Take my breath away

_NET 中的 Timers

Filed under: .NET

.NET 中的Timer3胞胎

Win32平台上有两种线程:UI线程和工作线程,UI线程大多数时间是空闲的,它实际上是一个形如
while (GetMessage (&msg))
{
ProcessMessage (&msg) ;
}
的循环,如果这个UI线程的消息队列中有消息, UI线程就会取出这个message并处理.
工作线程没有message loop,主要用来在后台处理事务.

System.Windows.Forms.Timer Control
windows timer, 其历史可以追溯到vb 1.0, 主要是为了方便windows froms程序的编写.
有一个Interval属性
为使用UI线程进行事务处理的单线程环境设计,依赖于os的timer message,精度较差,
操作可以在UI线程中进行,也可以在别的线程中进行.

注意windows不会向消息队列中放入多个WM_TIMER消息,而是将多个WM_TIMER消息合并成
一个消息(和WM_PAINT类似),如果设定WM_TIMER消息的间隔为1秒,而消息处理函数的执行
时间超过1秒,在消息3处理函数的执行期间程序不会收到WM_TIMER消息.

System.Timers.Timer component
有一个Interval属性
针对server的多线程环境进行了了优化,采用了和System.Windows.Forms.Timer不同的架构.
值得注意的是System.Timers.Timer的SynchronizingObject属性.如果这个属性为null,处理
Elapsed event由线程池中的线程触发,即Elapsed event的处理函数将运行在系统线程池的
线程中,如果 SynchronizingObject属性被设置为一个Windows Forms component, 那么
Elapsed event的处理函数将运行在生成component的那个线程中,通常情况下,这个线程就
是UI线程.
如果处理Elapsed event的方法的执行时间大于Interval属性的值,又会有一个线程池中的线
程激发Elapsed event,Elapsed event的处理函数将会被重入
.

using System;
using System.Timers;

public class Timer1
{
public static void Main()
{
// Normally, the timer is declared at the class level, so
// that it doesn’t go out of scope when the method ends.
// In this example, the timer is needed only while Main
// is executing. However, KeepAlive must be used at the
// end of Main, to prevent the JIT compiler from allowing
// aggressive garbage collection to occur before Main
// ends.
System.Timers.Timer aTimer = new System.Timers.Timer();

// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;

Console.WriteLine(”Press the Enter key to exit the program.”);
Console.ReadLine();

// Keep the timer alive until the end of Main!
GC.KeepAlive(aTimer);
}

// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine(”Hello World!”);
}
}
注意!由于Elapsed event由线程池中的线程出发,存在着这样的可能:event 的处理函数
正在执行,而另一个线程池中的线程调用的Timer.Stop(),这将导致在Timer.Stop()调用后
Elapsed event仍可被触发.使用Interlocked.CompareExchange()可以避免这种情况.

System.Threading.Timer class
在代码中使用,不依赖于os 的timer
使用 TimerCallback delegate 来指定需要执行的函数,这个函数将执行在线程池
的线程中,而不是生成System.Threading.Timer的线程中.
在timer生成后,可以使用System.Threading.Timer.Change()来重新定义timer的
等待时间和执行间隔时间.
注意,如果使用了System.Threading.Timer,就要保持对Timer的引用,否则,Timer将会被
GC回收,使用Timer.Dispose()可以释放Timer所占用的资源.
由于callback函数由线程池中的线程执行,如果timer的interval值小于callback函数的
执行时间,callback函数会被多个线程执行.如果线程池中的线程被用光,callback函数
会排队等待,不能如期执行.

//—-
using System;
using System.Threading;

class TimerExample
{
static void Main()
{
//信号量,false参数用来设置信号量的初始状态为non-signaled
AutoResetEvent autoEvent = new AutoResetEvent(false);
StatusChecker statusChecker = new StatusChecker(10);

// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate = new TimerCallback(statusChecker.CheckStatus);

// Create a timer that signals the delegate to invoke
// CheckStatus after one second, and every 1/4 second
// thereafter.
Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, 250);

// When autoEvent signals, change the period to every 1/2 second.
autoEvent.WaitOne(5000, false);
stateTimer.Change(0, 500);

// When autoEvent signals the second time, dispose of the timer.
autoEvent.WaitOne(5000, false);
stateTimer.Dispose();
}
}

class StatusChecker
{
int invokeCount, maxCount;

public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}

// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine(”{0} Checking status {1,2}.”,
DateTime.Now.ToString(”h:mm:ss.fff”),
(++invokeCount).ToString());

if(invokeCount == maxCount)
{
// Reset the counter and signal Main.
invokeCount = 0;
autoEvent.Set();
}
}
}

ThreadPool
线程池中的线程为后台线程,其IsBackgroud为true, 当application的所有前台线程执行
完毕后,就算是线程池中的线程仍在执行,application也会结束.

June 7, 2006

VS2005 AddIn Line Counter

Filed under: Visual Studio

Line Counter - Writing a Visual Studio 2005 Add-In

http://www.codeproject.com/useritems/LineCounterAddin.asp

除了提供了一个很不错的插件,这篇文章还教学了

1.AddIn的原理和写法

2.AddIn的安装

其中对资源的处理使用了Build event,是个不错的解决方案

AddIn的安装需要注意.AddIn 文件的部署,文章曰:

This is important for when VS tries to register the add-in. If it is missing, then the add-in will not register. This particular file is somewhat unique in that it is a shortcut. The actual location of this file should be in your {MyDocuments}\Visual Studio 2005\Addins\ folder. It should contain the following xml (NOTE: The [ProjectOutputPath] should match the output path of the project on your own system, so you will probably have to edit it).

If you need to add this file to the project, place it in the proper location under your My Documents folder first. When you add the file to the LineCounterAddin project, instead of clicking the Add button, use the down arrow next to it, and choose “Add As Link“.

有关.AddIn File可以参考

Packaging Add-ins and Toolbox Controls for use with Visual Studio Content Installer

http://blogs.msdn.com/chetanc/archive/2005/10/10/479000.aspx

VS2005 AddIn CoolCommands 3.0

Filed under: Visual Studio

CoolCommands 3.0 for Visual Studio 2005

http://weblogs.asp.net/gmilano/archive/2006/05/10/446010.aspx

装完后在Project的右键菜单上会多出很多功能,

Collapse All Project

Open Container Folder

VS Prompt Here

Resove Project Refrence

Refrence Manager

非常有用!

无Cookie 的 Session State

Filed under: ASP.NET

//–Session State是1997年 ASP引入的技术.
当用户首次连接到站点时,ASP会创建一个类似Hashtable的内存块来会保存Session State,同时
还会创建一个 ID 以便将其与当前用户唯一地联系起来。当下一次发出请求时,该用户将被要求提交该
Session ID,以便检索并正确地还原会话状态。Sessioin ID 是 ASP 和 ASP.NET 完全自主生成的字母
数字字符串. 浏览器会使用Cookie(最早由 Netscape 发明)在客户端保存Session ID,

//–在asp.net中使用无 cookie的session
修改web.config
<sessionState cookieless=”true” />

此时请求http://yourserver/folder/default.aspx,实际上发送的是
http://yourserver/folder/(session ID)/default.aspx

这种做法的缺点是如果在得到ID后浏览了别的网站,然后重新输入原来的URL,会得到一个新的ID
以前的session信息将丢失.

//—实现
无Cookie session的实现依赖于两个模块
1. SessionStateModule.这是一个Managed Http Module,需要ASP.NET 和CLR才能工作.
2. aspnet_filter.dll 这是一个win32 dll, 充当 ISAPI filter,由IIS调用.
二者都截获在请求处理过程中激发的 IIS 事件.

当新浏览器会话的第一个请求进入时,SessionStateModule 读取 web.config 文件中有关 Cookie
支持的设置。如果 节的 cookieless 属性设置为 true,则该模块生成一个Session ID,并把Session ID
填充到资源名称前,从而得到一个新的URL,并且使用 HTTP 302 命令将浏览器重定向到新的 URL。

当每个请求到达 IIS 入口时(远早于它被移交给 ASP.NET),aspnet_filter.dll 获得了一个查看
它的机会。如果该 URL 将会话 ID 嵌入到括号中,则会提取该会话 ID 并将其复制到一个名为
AspFilterSessionId 的请求标头中。然后,重写该 URL 以使其看起来像原来请求的资源,并且将其释放。
这一次,ASP.NET 会话状态模块从请求标头中检索会话 ID,并且通过会话-状态绑定继续工作。

只要该 URL 包含可用来获取会话 ID 的信息,无 Cookie 机制就可以很好地工作。

//—Thumbs Up
在 ASP.NET 中,Session state和forms authentication 证是仅有的两个在后台使用 Cookie 的系
统功能。ASP.NET 1.x 仍需要使用 Cookie 来实现表单身份验证。在 ASP.NET 2.0 中,表单身份验证可以
选择以无 Cookie 方式工作,在这种模式下,用户的身份信息也是通过URL来传递.

//—Thumbs Down
由于Session ID直接显示在浏览器的地址栏中!Cookieless的session是危险的,直接抓一个包含Session
ID的URL,就算换一个计算机使用,还是认为是同一个session.
每次同一个浏览器内部手动键入指向某个站点的URL,都将丢失Cookieless的Session state。

使用Cookieless Session还会引起与链接有关的问题。不能在 ASP.NET 页中具有绝对链接。如果这样做,
那么源自该链接的每个请求都将被视为新会话的一部分。无 Cookie 会话要求您总是使用相对 URL,就像在
ASP.NET 回发中一样。仅当可以将会话 ID 嵌入到 URL 中时,您才可以使用完全限定的 URL。但是,既然会
话 ID 是在运行时生成的,那么如何才能做到这一点呢?

下面的代码中断了该会话:

<a runat=”server” href=”/test/page.aspx”>Click</a>

要使用绝对 URL,可以使用 HttpResponse 类上的 ApplyAppPathModifier 方法:

<a runat=”server” href=<% =Response.ApplyAppPathModifier(”/test/page.aspx”)%> >Click</a>
ApplyAppPathModifier 方法采用一个表示 URL 的字符串作为参数,并且返回一个嵌入了会话信息的绝对 URL。
例如,当您需要从 HTTP 页重定向到 HTTPS 页时,该技巧尤其有用。

最后,请特别注意,还要请您注意的是,对于移动应用程序,如果设备无法处理专门格式化的 URL,Cookieless
Session 可能会出现问题。

参考
无 Cookie 的 ASP_NET (Dino Esposito)
http://www.microsoft.com/china/msdn/library/webservices/asp.net/asppcookieless.mspx
http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/cookieless.asp

ASP.NET Session State

Foiling Session Hijacking Attempts
http://msdn.microsoft.com/msdnmag/issues/04/08/WickedCode/default.aspx

Cookie and Form Authentication

Filed under: ASP.NET

ASP.NET 2.0中的Cookies Form Authentication

<authentication mode=”Forms”>
<forms name=”.ASPXCOOKIEDEMO” loginUrl=”login.aspx” defaultUrl=”default.aspx”
protection=”All” timeout=”30″ path=”/” requireSSL=”false”
slidingExpiration=”true” enableCrossAppRedirects=”false”
cookieless=”UseDeviceProfile” domain=”">
<!– protection=”[All|None|Encryption|Validation]” –>
<!– cookieless=”[UseUri | UseCookies | AutoDetect | UseDeviceProfile]” –>
</forms>
</authentication>

ASP.NET 2.0 Forms Authentication can store the forms authentication ticket in either a cookie,
or in a cookie-less representation on the URL.

UseDeviceProfile Default value, ASP.NET determines where to store the ticket based on
pre-computed browser profiles.

AutoDetect ASP.NET to dynamically determine if the browser supports cookies or not.

UseUri and UseCookies force cookieless and cookied tickets respectively.

ASP.NET QuickStart
http://www.asp.net/QuickStart/aspnet/doc/security/formsauth.aspx

ASP.NET Forms Authentication所生成Cookie的安全性
http://www.achot.com/Article/110/Article_33237_1.html

Role-based Security with Forms Authentication
http://www.codeproject.com/aspnet/formsroleauth.asp

Cookieless ASP.NET forms authentication
http://www.codeproject.com/aspnet/cookieless.asp

如何使用 Forms 身份验证创建 GenericPrincipal 对象
http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/BuildSucApp/BSSAsecmodsecmod18.mspx?mfr=true

June 6, 2006

Regex.Replace 中MatchEvaluator 的使用

Filed under: Regular Expression

using System.Text.RegularExpressions;

class RegExSample
{
static string CapText(Match m)
{
// Get the matched string.
string x = m.ToString();
// If the first char is lower case…
if (char.IsLower(x[0]))
{
// Capitalize it.
return char.ToUpper(x[0]) + x.Substring(1, x.Length-1);
}
return x;
}

static void Main()
{
string text = “four score and seven years ago”;
System.Console.WriteLine(”text=[” + text + “]”);
string result = Regex.Replace(text, @”\w+”, new MatchEvaluator(RegExSample.CapText));
System.Console.WriteLine(”result=[” + result + “]”);
}
}
在replace时传入一个delegate ,完全DIY.

VS 中使用SOS

出自

More on debugging with SOS.DLL - enter Visual Studio
http://mtaulty.com/blog/archive/2004/08/06/628.aspx

FIX: Unmanaged debugging not possible until you install Visual C++ .NET
http://support.microsoft.com/default.aspx?scid=kb;en-us;813134

//—-调试Managed application
1. 设置project的属性,把”Enable Unmanaged Debugging”设置为true
否则在load sos时vs会报错:

SOS not available while Managed only debugging.
To load SOS, enable unmanaged debugging in your project properties.

如果没有安装 vc++.net, 上面的设置并不会有效果,使用F5直接运行project, vs会报错
—————————
Microsoft Development Environment
—————————
Error while trying to run project: Unable to start debugging.

Unable to start program ‘D:\Work2006\CursorTest\bin\Debug\CursorTest.exe’.

Unmanaged debugging is not available.

尝试使用 ctrl+F5启动程序,并Attach 进程,SOS也不能加载,提示:

SOS not available while Managed only debugging.
To load SOS, enable unmanaged debugging in your project properties.

3. 在 Immediate window (Debug-> Windows -> Immediate)中输入 .load sos
在Immediate window中输入 immed 和 cmd 可在Immediate mode和Command mode之间切换

//—-调试 dump file
1. File 打开 dump file

2. Debug->Start 等待中断

3. 在Immediate window中输入 .load sos

常用命令
!EEVersion
!ProcInfo
!ClrStack
!Help <command>
!

正则表达式的替换

Filed under: Regular Expression

想做这样一件事:

把命令行参数中的敏感信息滤掉,比如将

Tool /U:”my Name” /P:”my password” 替换为 Tool /U:”<UserName>” /P:”<Password>”

Private Function HideUserInfo(ByVal para As String) As String
Dim result = para
If (para.IndexOf(”/P:”) > 0) Then
result = Me.ReplaceParameter(result, “/P:”, “<Password>”)
End If
If (para.IndexOf(”/U:”) > 0) Then
result = Me.ReplaceParameter(result, “/U:”, “<UserName>”)
End If
Return result
End Function

Private Function ReplaceParameter(ByVal paras As String, ByVal para As String, ByVal dummy As String) As String
Dim regexStr As String = String.Format(”{0}\”"([^\”"]*)\”"”, para)
‘Dim match As Match = Regex.Match(paras, regexStr)
‘ Console.WriteLine(match.Groups(0))
‘ Console.WriteLine(match.Groups(1))
Dim result As String = Regex.Replace(paras, regexStr, String.Format(”{0}”"{1}”"”, para, dummy))
Return result
End Function

本来是想在ReplaceParameter中替换掉group(1)所对应的内容,但不知道怎么写,只好用了上面的代码.

此外还试了

Regex.Replace(paras, regexStr, String.Format(”$1 “+dummy))

这个写法可以用源字符串中的字符(group1)来生成替换字符串

还可以给group 命名:
Dim regexStr As String = String.Format(”{0}\”"(?<title>[^\”"]*)\”"”, para)

Regex.Replace(paras, regexStr, String.Format(”${title} “+dummy))

大小写要统一.

June 5, 2006

SQL 监视

Filed under: SQL&DB Accessing

//—工具:
0. Sql Profiler 和Index Tuning

1. 使用SQL server Management Studio(sql2005)的Management节点下的Active Monitor
或 Enterprise Manager(sql2000)的Management节点下的Current Active
可以查看 进程信息, lock信息

2. 上述节点下的 SQL Server logs

3. 系统存储过程,如 sp_who, sp_monitor,等.
可以在程序中使用这些sp来监视sql server

4. 内置函数

5. Query Analyzer中的 Show Server Trace选项

6. WMI SQL Server Administration Provider

//—用Sql Profiler来查看sql 语句的执行:
Events 选 TSQL
Column 选 TextData

Column Filter中Application Name 的Like设置为 “<app name>”

参考
SQL Server 2000 Performance Tuning Tools
http://www.sqlteam.com/item.asp?ItemID=761

Tips for Using SQL Server Query Analyzer
http://www.sql-server-performance.com/query_analyzer_tips.asp

webcast_How do I Video Series_Cache

Filed under: ASP.NET

How do I? Video Series : Caching (hilo_cache1_final.wmv ,hilo_cache2_final.wmv)
http://asp.net/default.aspx?tabindex=4&tabid=3000
http://asp.net/learn/howdoi/default.aspx?tabid=63

//–Output Caching
<%@ Page Language=”C#” %>
<%@ OutputCache Duration=”10″ VaryByParam=”none”%>
<script runat=”server”>
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
}
</script>

<html>
<head runat=”server”>
<title></title>
</head>
<body>

</body>
</html>

注意, 对于OutputCache directive, Duration 和 VaryByParam要同时使用,VaryByParam
对应于GET方法的query string 或 POST方法的parameter, VaryByParam可以被设置为 none,
*,query string 或 POST方法的参数名.

//–Database caching
—Step 1
> aspnet_regsql -S <SqlServerName> -U sa -d <DatabaseName> -ed -et -t <TableName>

以上命令会在Database(<DatabaseName>)中生成一个custom table
dbo.AspNet_SqlCacheTableForXXXXXX
并在Table(<TableName>)上生成Trigger Customers_AspNet_SqlCacheNotification_Trigger

—Step2 修改web.Config
<system.web>
<caching>
<sqlCacheDependency enable =”true” pollTime=”2000″>
<databases>
<add connectionStringName=”XXX” name=”XXX” pollTime=”120000″>
</database>
</sqlCacheDependency>
</caching>
</system.web>

—Step 3
使用SqlCacheDependency Object 来监视数据库
<%@ OutputCache Duration=”60″ VaryByParam=”none” SqlDependency=”"ConnectionString1:Table1;ConnectionString2:Table2″%>
如果使用了相同的select 语句, asp.net会直接从catch table中取结果.

如果使用了sql2005,可以由sql2005来通知应用程序而不是由应用程序监视数据库,如果数据没有变化
不会有sql 语句在sql server上执行

<%@ OutputCache Duration=”60″ VaryByParam=”none” SqlDependency=”CommandNotification”%>
同时需要在Global.asax中添加
void Application_Start(object sender, EventArgs e)
{
System.Data.SqlClient.SqlDependency.Start(ConfigurationManager.ConnectionStrings(”XXX”).ConnectionString);
}

CommandNotification 只能用于web page(.aspx),User Control只能使用table-based polling with
the @ OutputCache directive.

—-Testing
使用Sql server Profiler来监视TSQL event, 看TextData 列就可知道有什么sql语句被执行了.

//–Partial page caching
Page上可能使用多个User Control, 可以在某个user control内使用
<%@ OutputCache Duration=”10″ VaryByParam=”none”%>
从而实现部分caching

也可以在User Control中使用class attribute:
[PartialCaching(120)]
public partial class CachedControl : System.Web.UI.UserControl
{
// Class Code
}
注意,在create User control要选择”Place code in seperate file”

如果User Control所在的page也使用了<%@ OutputCache directive,User Control
的Duration 将优先使用.

[*]使用 Substitution Control

<script runat=”server”>
Private static string GetRealTime(HttpContext context)
{
return DateTime.Now.ToString()
}
</script>

<asp:Substitution ID=”" MethodName=”GetRealTime”>

//–Caching API
//–Code 1
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
stirng path =”names.xml”;
DataSet ds = new DataSet();
ds.ReadXml(path);

dataGrid.DataSource = ds;
dataGrid.DataBind();
}
}

//–Code 2
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
DataSet ds = (DataSet)(Cache(”names”));

if(ds==null)
{
stirng path =”names.xml”;
ds.ReadXml(path);

CacheDependency cd = new CacheDependency(path);
Cache.Insert(”names”, ds, cd);
Trace.Warn(”Names read from xml”);
}
else
{
Trace.Warn(”Names read from cache”);
}
dataGrid.DataSource = ds;
dataGrid.DataBind();
}
}

//–Testing
添加
<%@ Page Trace=”true” TraceMode=”SortByCategory”>
关调IE再打开,依然显示”Names read from cache”

Refresh Cache:
Cache.Remove(”names”);

参考
Caching Data with the SqlDataSource Control (MSDN)

June 3, 2006

NUnit+TestDriven

Filed under: 开发工具

http://www.testdriven.net/

TestDriven的主要功能:

1.Run Tests

可以在VS中直接运行unit test 代码,并将结果显示在Out put窗口中.

2.Test With->Debugger

debug Test 代码

MBUnit

Filed under: 开发工具

http://www.mertner.com/confluence/display/MbUnit/Home

MbUnit : Generative Unit Test Framework

http://www.codeproject.com/gen/design/gunit.asp

_Net Framework 中的design pattern

Filed under: .NET

出自
Discover the Design Patterns You’re Already Using in the .NET Framework
http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/

//–Observer Pattern
当一个对象(Subject)发生改变时,会通知另外一个对象(Observer).

最原始的做法是由 Subject 来调用Observer上的方法,这将导致 Subject 与某个特定的 Observer
紧耦合,当Observer的个数不定时,代码将无法控制.

GOF中的Observer Pattern

public abstract class CanonicalSubjectBase
{
private ArrayList _observers = new ArrayList();

public void Add(ICanonicalObserver o)
{
_observers.Add(o);
}

public void Remove(ICanonicalObserver o)
{
_observers.Remove(o);
}

public void Notify()
{
foreach(ICanonicalObserver o in _observers)
{
o.Notify();
}
}
}

public interface ICanonicalObserver
{
void Notify();
}
所有的Observer角色将实现ICanonicalObserver接口,Subject角色派生自CanonicalSubjectBase,

.Net中的Observer Pattern,利用的event 和 delegate

public delegate void Event1Hander();
public delegate void Event2Handler(int a);

public class Subject
{
public Subject(){}

public Event1Hander Event1;
public Event2Handler Event2;

public void RaiseEvent1()
{
Event1Handler ev = Event1;
if (ev != null)
ev();
}

public void RaiseEvent2()
{
Event2Handler ev = Event2;
if (ev != null)
ev(6);
}
}

public class Observer1
{
public Observer1(Subject s)
{
s.Event1 += new Event1Hander(HandleEvent1);
s.Event2 += new Event2Handler(HandleEvent2);
}

public void HandleEvent1()
{
Console.WriteLine(”Observer 1 - Event 1″);
}

public void HandleEvent2(int a)
{
Console.WriteLine(”Observer 1 - Event 2″);
}
}

//–Iterator Pattern
Iterator Pattern被应用在for ,和for each语句中,查看IL代码可以看到

int[] values = new int[] {1, 2, 3, 4, 5};

IEnumerator e = ((IEnumerable)values).GetEnumerator();

while(e.MoveNext())
{
Console.Write(e.Current.ToString() + ” “);
}

//–Decorator Pattern
.NET 对Stream及其派生类的实现是Decorator Pattern的一个范本,Stream的派生类
在派生的同时又包含基类,在保持接口不变的情况下实现了功能的扩展.

MemoryStream ms = new MemoryStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8});
PrintBytes(ms); //不变

BufferedStream buff = new BufferedStream(ms);
PrintBytes(buff);
buff.Close(); //不变

FileStream fs = new FileStream(”../../decorator.txt”, FileMode.Open);
PrintBytes(fs); //不变
fs.Close();

//–Adapter Pattern
.NET Framework的一个强大之处就是实现了向后兼容,.NET代码 和 COM对象之间可以
任意调用. 在.net 代码中调用COM对象只需使用VS.NET的”Add Refrence”来引入这个
COM对象,VS.NET会调用tlbimp.exe来生成一个包含Runtime Callable Wrapper (RCW)
class的interop assembly, .NET通过调用 RCW class中的方法来使用COM对象.
需要注意的是COM对象使用了和.NET不同的数据类型和错误处理机制,比如,.NET使用
System.String 而 COM对象使用 BSTR , COM组件中的方法返回一个 HRESULT 来标识执行
结果,而RCW 会产生exception,供其他的managed 代码处理.
在.net代码中调用一个包含string 参数的COM方法, 可直接传入System.String,RCW
会负责把System.String转化成 BSTR.

Adapter Pattern 中Adapter 封装了 Adaptee,这一点和Decorator Pattern有所类似,
但二者的区别在于Decorator 中object的接口保持不变,Adapter可以改变接口.

//–Factory Pattern
.NET Framework中有大量的class,在使用时不是通过调用构造器来产生实例的,
比如使用System.Convert.ToXXX() 静态方法可进行对象转换,产生新的实例.
System.Net.WebRequest.Create() 会根据传入的URI参数产生对应的Request实例,

//–Strategy Pattern
Array 和 ArrayList 都提供了Sort()方法,它们的Sort()方法都使用了QuickSrot算法
缺省情况下Sort()方法利用List中各个元素对IComparable的实现来比较,但也可以传入一个
实现了IComparer的参数,使用IComparer.Compare()方法来排序.比如:

public class Certificate
{

public static List<Certificate> GetAllCertificate(String sortExpression)
{
SQLDataAccess dataAccess = SQLDataAccess.GetSQLDataAccess();
List<Certificate> certificates = dataAccess.GetAllCertificate();
certificates.Sort(new CertificateComparer(sortExpression));
return certificates;
}

}

public class CertificateComparer : IComparer<Certificate>
{
private bool _reverse;
private string _sortColumn;

public CertificateComparer(string sortExpression)
{
_reverse = sortExpression.ToLowerInvariant().EndsWith(” desc”);
if (_reverse)
{
_sortColumn = sortExpression.Substring(0, sortExpression.Length - 5);
}
else
{
_sortColumn = sortExpression;
}

}

public int Compare(Certificate a, Certificate b)
{
int retVal = 0;
switch (_sortColumn)
{
case “Type”:
retVal = (int)a.CertificateType - (int)b.CertificateType;
break;
case “Name”:
retVal = String.Compare(a.CertificateName, b.CertificateName, StringComparison.InvariantCultureIgnoreCase);
break;
case “Description”:
retVal = String.Compare(a.Description, b.Description, StringComparison.InvariantCultureIgnoreCase);
break;
}
return (retVal * (_reverse ? -1 : 1));
}
}

List<T>.FindXXX<T>(Predicate<T>) 系列方法可以使用传入的Predicate<T> delegate来查找元素,
Predicate<T> delegate的定义如下:
public delegate bool Predicate<T> (T obj)

using System;
using System.Collections.Generic;

public class Example
{
public static void Main()
{
List<string> dinosaurs = new List<string>();

dinosaurs.Add(”Compsognathus”);
dinosaurs.Add(”Amargasaurus”);

Console.WriteLine(”\nTrueForAll(EndsWithSaurus): {0}”, dinosaurs.TrueForAll(EndsWithSaurus));
Console.WriteLine(”\nFind(EndsWithSaurus): {0}”, dinosaurs.Find(EndsWithSaurus));
Console.WriteLine(”\nFindLast(EndsWithSaurus): {0}”,dinosaurs.FindLast(EndsWithSaurus));
}

// Search predicate returns true if a string ends in “saurus”.
private static bool EndsWithSaurus(String s)
{
if ((s.Length > 5) && (s.Substring(s.Length - 6).ToLower() == “saurus”))
{
return true;
}
else
{
return false;
}
}
}

//–Composite Pattern in ASP.NET
准确的说应该是.net 的control设计中到处体现了Composite Pattern, Parent control中包含了 sub control,
对from或page的重画调用可以通过这种层级关系一层层传递下去.

//–Template Method Pattern
重载父类方法:
Page.CreateChildControl()
Page.Render()
….

//–Patterns in the ASP.NET Pipeline
从一个web request到在浏览器上显示出结果会经过多个步骤:
Request -> IIS + aspnet_isapi.dll -> ASP.net Work process

-> HttpApplication -> HttpModules * n -> HeepHandler
其中, HttpApplication 通常是由 Global.asax 产生的, HttpModules是一些实现了IHttpModule
接口的class, 每个HttpModule都会修改request,然后把request传递给下一个HttpModule,ASP.NET
提供了一些标准的module:FormsAuthenticationModule, PassportAuthenticationModule,
WindowsAuthenticationModule, and SessionStateModule…最后,request被交给了HttpHandler,
一个HttpHandler是实现了IHttpHandler接口的class, 最典型的HttpHandler就是System.Web.UI.Page
在IHttpHandler.ProcessRequest 中,Page 会发出一系列的events:Init, Load, and Render,处理
ViewState.

//–Intercepting Filter Pattern
HttpApplication class 在处理 request时会发出一系列的event,BeginRequest, AuthenticateRequest,
AuthorizeRequest, and EndRequest,当HttpApplication加载某个HttpModule时,会调用 IHttpModule.Init()
HttpModule会利用这个机会来注册它所关心的event.

//–Other Web Presentation Patterns in ASP.NET
MVC 模式:View:ASPX 页面, Model-Control: codebehind file.

June 1, 2006

我的经典-方舟子(转载)

Filed under: 乱翻书

我的经典

               ·方舟子·

                 乃摒弃本业,而驰鹜古典。  

                        ──张居正

  从中学的时候起,我就常常被误会为读过许多书,其实我最多不过只能算翻
过许多书罢了。我的读书习惯是随便抽出一本书来翻翻,偶尔被某句话或某件事
吸引住,就把目光停住看一会。就连鲁迅所说凡是要冒充读书读得多者必读的
《四库全书提要》,我也只是翻翻而已。交谈、作文时想起了曾经在某本书上读
过的某句话、某件事,说出来,也就往往让听者、读者误以为我读过那本书,而
其实我对那本书的所有知识可能也就是那句话、那件事。虽说从小就被教育”好
记性不如烂笔头”,我却也几乎不做读书笔记,需要照抄原文的时候,再凭记忆
去翻查,也往往能查到,而翻查的过程也相当于又把那本书”看”了一遍了。

  以我这样的读书法,身边也就需要堆放一堆书供随时翻、查,等到床上地下
越堆越多的时候,既然没有女秘书来给我整理,也就只能亲自动手收拾,收拾时
又顺带把这些书翻翻。近日收拾时,翻出了杜小真译的加缪的《西西弗的神话》,
翻开扉页,看到写着”我的经典”四字,已忘了是什么时候写上去的了。于是又
翻到最后,见写着”1988.4.3阅毕。1989.2.17重阅毕”。能
让我从头读到尾、而且边读边划线的书很少,一年之内重读两遍的书更是屈指可
数。出国时,因为担心行李超重,本打算一本书也不带,后来还是忍不住塞了几
本小册子,其中就有这一本。当时大概是计划到了美国后再重读一遍的,然而竟
没有。初到美国时在一家旧书店看到这本书的英译本,把它买回来,也只是翻了
一下,并未再细读。我与这本书的缘分,也就结束于1989年2月17日。

  但在我的大学本科时代,与我最有缘分的书也就是这一本了。在我上大学之
前,早已把整个人生设计完毕,思想也已成熟,所以,那时候读书,已不是要找
引路的导师,而是在找知心的朋友。而使我对这个朋友一见如故的,却是它的开
头所引的古希腊诗人平达的两句诗:

    哦,我的灵魂并不追求永恒的生命,
    而是要穷尽可能的领域。

  而全书所论证、抒情的,也都不出这两句。我早知道人生道路的结局只有一
个──鲁迅说是”坟”,而其实有时候是连”坟”也未必有的,而通往这个结局
的道路却可以有无数条。要让宿命的人生变得有趣,就尽可能地多走几条路;要
让荒谬的人生变得有意义,就不妨细细地体味每一过程的悲欢痛快,结局如何也
就无关紧要了。唐璜穷尽女人,演员穷尽角色,征服者穷尽土地,创作者穷尽艺
术,而一无所有的我们,至少可以以心灵穷尽世界,永不停息。当我无师自通地
想明白了这一切,突然看到有人在哲学上对此做洋洋洒洒的论证,让我从此在旅
途上可以把胸膛挺得更高,那种亲切,如遇故人。而加缪完成这本书的时候,也
不过二十九岁。

  而我书中的爱人,则是我在高二那一年读的罗曼·罗兰的《约翰·克利斯多
夫》。初中的时候,阅读的范围限于中国的经典。上了高中,突然觉得应该放眼
世界了。大部头的世界名著,除了卡夫卡、博尔赫斯、加缪、萨特、马尔科斯这
些较现代的作家的作品是在大学时才开始涉猎;经典的部分,象雨果、列夫·托
尔斯泰、屠格涅夫、陀斯妥耶夫斯基、巴尔扎克的作品,却都是在高中时候读完
的,以后也未再读。尤其是高三那年,由于要准备高考,上课基本上只是复习,
没有多少新内容可学,闲得很,也就成了我读闲书最多的一年,而其实也是我看
电影最多的一年,独自去看电影的习惯也就是在那时候养成的。然而所有的这些
名著、名片,却没有哪一部象《约翰·克利斯朵夫》那样给我的心灵如此深沉的
激动。那是我在书的世界所发生的刻骨铭心的初恋,事实上也是唯一的一次爱情。
在那个假期我日日与她为伴,共享了所有的喜怒哀乐,除此之外,似乎在整个假
期里未再做别的什么事了。如果能翻翻那时候的日记,一定很有意思,可惜都留
在了国内。当时的纪录其实并不重要。一个十六岁的少年从此带着”以不断的创
造征服不断的磨难”的信念,无悔地越过成年的门坎,去追求不息地扩张、更新
的生命,这就够了。从那以后我没有、也不必再去读这部书。

  有时想想也觉得奇怪,于我最为有缘的两部外国作品,都是法国人写的,而
我偏偏不懂法文,也不知会因此未能偿到多少的原汁原味,想来总是一件很遗憾
的事。对英语作品,却从未能让我有那样深厚的感情,虽然反反复复读过不少达
尔文、罗素的著作,对他们,却只有对智者的敬畏。对于智者,无法为朋友、爱
人,而只能为老师了。但是,我书中的先生,在初一那年从家庭藏书中翻出了一
套年龄比我还大好几岁的《鲁迅选集》之日起,就已经注定了。从那时候起,我
的案头就总会有一、两册的鲁迅全集分册或作品集的单行本放着,不时地翻翻,
对我而言几乎就等于是休息。第一次上美国大学图书馆,借回来的也是几本鲁迅
作品集。与《西西弗的神话》、《约翰·克利斯朵夫》不过是一时因缘,而与
《鲁迅全集》的缘分则恐怕是要持续一生了。对这套中国百科全书式的巨著,在
初中、高中、大学时代和现在不同的时候读,总能有新的感受;在少年、青年、
中年和老年来读,滋味也不会相同,所以也就可以时时、不停地读下去。先生所
教给我的,并非人生观–我觉得人生观是应该靠自己去领悟的,无人可教──
而是更为实际的东西,教我为人,教我处世,教我作文,甚至也教我写诗。我对
现代诗歌的最初的感悟,就是在把《野草》反反复复读了无数遍、自然而然地记
住了其中的每一句话所以不必再读以后所得来的。

  是那个老问题了:如果你被流放到一个孤岛,只允许你带一本书,你将带哪
一本?其实,在孤岛上,有蓝天碧海为伴,即使无书可读,也不要紧的。这个问
题,不妨改成:如果你被判单独监禁,只允许你带一本书,你将带哪一本?在十
年前大学校园人人自危的日子里,我是认真地考虑过这个问题的。这一本书,必
须可以景仰,可以钩沉;可以索隐,可以发挥;可以默诵,可以吟咏。每一个字
都可以发现一个故事,每一篇作品都可以写作一篇文章。既有无限丰富的内容,
又有无比精深的内涵。既平易近人如知心的好友,百读常新如永远的爱人,又超
凡入圣如旷世的良师。我的回答不假思索。我将带着一册《杜工部集》欣然赴命,
让这道”四千年文化中最庄严、最瑰丽、最永久的光彩”(闻一多语)照亮漫漫
长夜。也许我很幸运地永远不必真正去面对这个选择,但总有一天,我终将退隐
到家乡的岛上,自我划地为牢,让一千四百首诗包围我。不在千家注杜中再加入
一家,那个在孩提时代从一副对联”两个黄鹂鸣翠柳,一行白鹭上青天”中所发
现的美丽新世界在我的眼中就不会圆满。当我看够了世界,当我厌倦了流浪,回
归也就是无可改变的结局。我从哪里来,还到哪里去。

  ”东行万里堪乘兴,须向山阴入小舟。”(杜甫《卜居》)

1999.3.21

NOPEN—.NET平台下的开源项目大全

Filed under: 技术资源

http://nopen.net/






















Get free blog up and running in minutes with Blogsome
Theme designed by Hadley Wickham