[教程]ASP.net组件开发教程

mikel阅读(818)

本系列文章示例源码下载.各位如遇问题,请多查msdn,多利用网络.本人可能没时间一一回复,谢谢你们的支持,希望看到此文的人都能学好控件开发
http://www.cnblogs.com/Clingingboy/archive/2008/01/31/1059617.html
此系列我将尽我所能写下去吧,跟大家分享自己的经验。也希望大家对我多提意见,让我们共同进步
本文将持续更新.

推荐图书

道不远人:深入解析ASP.NET 2.0控件开发 作者博客(博客园自己人写的)http://thinhunan.cnblogs.com/ 书出错或有问题就找他-__-
1.Building ASP.NET Server Controls

2.Developing Microsoft ASP.NET Server Controls and Components Microsoft

3.Wrox Professional ASP.NET2.0 ServerControl and Component Development

4.ASP.NET服务器控件开发技术与实例

5.深入剖析ASP.NET组件设计

第一部分 asp.net控件开发基础
1.asp.net控件开发基础(1) ———-接触自定义控件

2.asp.net控件开发基础(2) ———-明白使用Render方法呈现自定义控件
3.asp.net控件开发基础(3) ———-自定义控件事件处理
4.asp.net控件开发基础(4) ———-明白使用RenderContent方法呈现自定义控件
5.asp.net控件开发基础(5) ———-简单介绍自定义控件简单属性和复杂属性
6.asp.net控件开发基础(6) ———-简单介绍自定义控件样式属性

7.asp.net控件开发基础(7) ———-初步认识复合控件
8.asp.net控件开发基础(8) ———-在复合控件中中的事件处理(事件冒泡)
9.asp.net控件开发基础(9) ———-再谈属性,学习自定义类型转换器
10.asp.net控件开发基础(10) ——–再谈属性,实现自定义控件集合属性
11.asp.net控件开发基础(11) ——–自定义视图状态管理
12.asp.net控件开发基础(12) ——–为子控件添加样式
13.asp.net控件开发基础(13) ——–服务器控件客户端功能
14.asp.net控件开发基础(14) ——–服务器控件生成器
15.asp.net控件开发基础(15) ——–总结和补充
第二部分 asp.net控件开发进阶
16.asp.net控件开发基础(16) ——–服务器模板控件
17.asp.net控件开发基础(17) ——–初识数据绑定控件
18.asp.net控件开发基础(18) ——–让DadaSource接受过多的数据源

19.asp.net控件开发基础(19) ——–数据列表绑定控件
20 .asp.net控件开发基础(20) ——–asp.net2.0数据绑定控件新做法
21 .asp.net控件开发基础(21) ——–让旧数据绑定控件支持数据源控件
22 .asp.net控件开发基础(22) ——–定义数据源控件(1)
asp.net控件设计时支持

1.asp.net控件设计时支持(1)—-基础认识
2.asp.net控件设计时支持(2)—-自动格式设置
3.asp.net控件设计时支持(3)—-操作列表与模板编辑
4.asp.net控件设计时支持(4)—-设计器区域编辑

[教程]使用微软ASP.NET MVC Framework的一些感受 + 收集园子朋友发现的bug反

mikel阅读(640)

ASP.NET MVC快一星期了,之前是苦苦的等待,之后是苦苦的摸索和总结,现在这个MVC在我脑子里已经有了个大体的评价,写出来与大家分享。
    关于MVC本身的优点,就不再详述,地球人说了好多了。
    所以我光说说微软的ASP.NET MVC Framework(目前还非正式发布版本,为CTP版)的一些个人感受。
    这里先确定一个个人的感情基调:我对.NET3.5绝对拥护,对MVC绝对期待。正因为如此,对里面的不足我会不遗余力地和大家分析探讨。
    首先,ASP.NET 引入MVC这个模块不本身不能算是3.5的什么“独门绝技”,也不用因为使用了MVC而对.NET3.5大加赞赏(没有贬义),因为MVC(以下说的MVC都是ASP.NET MVC Framework CTP版) 的引入只能说明ASP.NET向更合理、更顺应企业级的开发模式潮流又进了一步,其模式是早就存在的(我不太愿意说谁抄谁的话,也不关心,对我们来说好用 就行)。甚至从这个角度上来说MS已经慢了半拍。之所以说是进步,至少MVC的出现解决了我认为ASP.NET在客户体验和模式上的3大不足:
   
    一、网页生命周期过长(那是相当的长)。
    二、与第一点相关的,“巨无霸”VIEWSTATE以及PostBack功能大大增加了用户流量,使得客户体验大大降低(这里不讨论Ajax的弥补作用,光说最基本的WebForm模式,不然有很多可以引起技术争论的地方)
    三、服务器控件自动生成的客户端ID,使得开发人员对客户端页面控制(如使用js)太吃力。不得不一天到晚和.ClientID打交道,效率也太低。
    
    所以有人说MVC具有里程碑式的意义,这点我赞同。
    下面来说说这一周不到的时间内我发现了MVC哪些值得改进和需要注意的地方。
   
    一、
不是MVC本身不足,而是 Scott Guthrie 在他的教程(包括示例源码)中有点误导地球人,他普遍使用了这样的格式(下面说的这种方式需要用到MVCToolkit.dll,这里有下载http://asp.net/downloads/3.5-extensions/MVCToolkit.zip,目前vs2008和MVC CTP没有提供):
    
    大家注意Html.ActionLink()里面的"Action="后面,他使用的是字符串常量"Edit" 和"New",这是Controller层中的一个方法,用于控制网页行为。第一次看到这个,我简直有点气愤——.net3.5在面向对象上面花了那么大 功夫,到他手里怎么还要这样引用?这也叫面向对象?况且这比起原始的Codebehinde更不利于程序员和美工的协调。让我感觉大楼快封顶的时候,决定 用草棚做顶。两个字——失望。
    
    二、不过我信心马上又来了,我看到了ActionLink提供了另外一种使用范型的方法ActionLink<T>,并且找到了一篇ASP.NET MVC Preview: Using The MVC UI Helpers 的文章(强烈建议大家作为基础看看),看到了ActionLink<T>的使用已经另外一些ScottGu没有提到的方法。
    比如Button<T>是这样使用的:

<%=Html.Button<HomeController>(x=>x.Index(),“cmdNav2″,“Home”) %>

    用Lambda表达式x=>x.Index()取代了生硬的"Index"。
    于是我开始coding……几秒钟后,让我失望的事又发生了……
    当我输到x=>x.的时候,后面的再也出不来了,看来又是一个bug!
    起初我以为这只个是MVC调用功能上的bug,是不是这个功能他们还没有做好?
    后来TT.NET发现其实Button<T>不是不能调用,只是不能显示,如果先把后面的内容输好,再完成Lambda是可以.出来的!松了一口气,但这还是MVC或者是VS2008显示上的一个bug。
    补充一下:TT.NET刚才跟我说,不是所有的ctl<T>都不能使用Lambda来自动完成,比如Html.Form<>就是可以的,那应该可以更加肯定是MVC或者说是MVCToolkit的bug了。——2007.12.18 14:2
    三、在调试的时候发现,即使你在输入

<%=Html.Button<HomeController>(x=>x.Index(),“cmdNav2″,“Home”) %>

    的时候,忘了输入最后一个),编译也不会报错(这个问题可能属于vs本身检测机制的问题),而是到打开网页的时候,运行时错误,虽然不是大问题,细心的程 序员都会自己看一遍,但是由于是在.aspx中编写,貌似就享受不到linq在.cs中编译时就检查出错误的那种“舒适”。当然话说回来,MVC是不提倡 在View层使用这些Controller层的命令的,但终归是个遗憾。
    四、我们有时候需为了简化网页流程和减少代码页,往往把插入新纪录和编辑区域合为一体,即同样一 组TextBox输入框,在一个变量或者控件的控制下,可以转换“Insert”或者"Update"的功能。这是一种不错的思路,也免去了这一组 “TextBox”该不该复用的思想斗争以及复用之后一系列繁琐的操作(即使有些MVC观点似乎更提倡分开表示)。当你修改的时候,由ViewData传 入一个Entity,Entity里面是某条记录的所有值,这时候赋给TextBox显示是没有问题的,问题就出在这个页面需要我们执行"Insert" 的时候,我们往往会传入一个空的Entity(如:SzwEntity szwEntity= new SzwEntity();),这时候麻烦来了,如果你使用O/RM设计并且里面有string字段的话会发现一运行就报错,我找了半天总算找到了原因: 在.dbml(O/RM文件)下面的.designer.cs中,定义publish string str;的时候,并没有按照我SQL数据库中Default 'xxx'赋予初始值,当我们SzwEntity szwEntity= new SzwEntity();的时候,里面所有的string字段都为null,这当然不能为Html.TextBox()等作为value显示,此时int反而没事,因为int初始默认值已经是0了。
    因此目前最好的解决办法就是在.designer.cs中给他们赋一个初始值,比如:

        private System.DateTime _EndTime=DateTime.Now;
        
        
private string _UserName=string.Empty;

    他们原本是这样的:

        private System.DateTime _EndTime;
        
        
private string _UserName;

    这应该是算VS2008和MVC配合上出了点小问题。如果分来开看,或许倒不算什么bug,反而有他们各自的用意和规范在里面。

    五、我觉得最头疼的一个问题,应为在MVC技术层面上似乎还不那么好解决:打开MVC的Global.asax,我们可以看大哦这样一句话:

            // Note: Change Url= to Url="[controller].mvc/[action]/[id]" to enable 
            
//       automatic support on IIS6 

    就是说,如果你用的是IIS6(WindowsXP/2003)的话,你就势必要使用[controller].mvc/[action]/[id]的格 式,而不能“享用”[controller]/[action]/[id]了。最大的问题倒不是在美观和这种格式可读性的初衷上面,而是在以下两个方面:
    1、如果到时候系统升级到IIS7(Windows2008/Vista),所有外部的链接是不是还能访问带".mvc"的路径,这面临着一个兼容性的考验。
    2、了解Search engine robots 工作原理的朋友肯定都知道,我们当初煞费苦心把.aspx/asp/php/jsp“伪装”成.html是为了什么。对,就是为了让Search engine robots能有对这些.html产生“好感”,便于收录和打分,而现在的.mvc算什么?Search engine robots是不是可能会把.mvc后面的当做网页参数,把.mvc当成文件扩展名?如果我的假设成立,天,那.mvc的遭遇岂不是很悲惨?不知道 Search engine robots是否会看到.mvc之后,久久崇拜一番然后一声叹息扬长而去。

    以上是我用了MVC之后,发觉的比较重要和“隐藏的够深”的一些问题,不涉及整体框架的不足(比如用{$}替换机制等等)。还有一些显示上的问题可能和 VS2008本身有关,待我确认是MVC的问题之后,我会都发上来,如果大家还发现了别的什么问题,希望一同交流,我会一并整理进来,方便大家参考!
    前途是光明的,道路是曲曲折折的 LIKE THIS~~~~~~~~haha  only a joke

http://szw.cnblogs.com/
研究、探讨ASP.NET
转载请注明出处和作者,谢谢!

[图书]Creating Mashups with Adobe Flex and AIR

mikel阅读(821)

下载:Creating Mashups with Adobe Flex and AIR
简介
Web applications no longer need be powered by any one individual's data, and they don't need to be confined to the desktop. Developers can draw on a wealth of publicly available content, from providers such as Flickr, Amazon, Google, Twitter, and Last.fm, and combine it for use in their own applications. Adobe Integrated Runtime (AIR) makes it simple to bring previously web-only applications to the desktop, allowing them to run alongside traditional applications on an end user's computer.
In this book, you'll learn how to create mashup applications from the vast array of web services, feeds, and APIs using Adobe Flash and Flex together with HTML and JavaScript (Ajax). You'll be introduced to the various sources of information and the tools necessary to gather and reuse that information, and then you'll learn how to combine that content in a variety of ways.
You'll learn how to have desktop applications interact with online services such as Flickr, you'll learn how to use Amazon S3 for enterprise-level data storage, and you'll embrace technologies such as OpenID. In addition, you'll create abstract visualizations based on music sourced from Last.fm and consume Twitter content via RSS. You will also see how to use the Flash-native data format SWX along with PHP to create a Yahoo! weather widget.
You'll discover just why you may want to build a widget or a desktop application rather leaving things web-based; then you'll create an application using Flex Builder and AIR and learn how best to distribute it. With so many tools and so much data available, the possibilities for mashup creation are endless. Creating Mashups with Adobe Flex and AIR provides all you need to get you up and running quickly, while also giving you a solid understanding of the technologies involved so you can take things further—to a place limited only by your imagination.
In this book you'll learn
* how to use Flex 3 in conjunction with ActionScript 3.0 to build powerful applications;
* how you can use Adobe AIR to take your application from the Web and onto the
desktop;
* the differences between developing for the Web and for the desktop;
* how you can use the APIs of popular web services such as Flickr, Amazon, Google, Twitter, and Last.fm as data sources for your application; and
* how to optimize your applications for fast and efficient performance.
目录 Summary of Contents
* Chapter 1 Introduction to Mashups
* Chapter 2 Technologies to Mash With!
* Chapter 3 An Introduction to Flex
* Chapter 4 Flex Components
* Chapter 5 Flexing Your Muscles
* Chapter 6 Performance Management in Flex Applications
* Chapter 7 Debugging Flex 3: The Tried-and-True, Plus the New
* Chapter 8 Getting the Most out of APIs
* Chapter 9 Mashing Up Functionality
* Chapter 10 SWX: A Native Flash Data Format
* Chapter 11 Taking It to the Desktop
* Chapter 12 Developing for the Desktop with AIR
* Chapter 13 Adding More Desktop Elements to the Web
* Chapter 14 Building a Desktop Experience
* Chapter 15 Completing the Experience
download: http://uploadstock.com//index.php?page=main&id=4c605910&name=Creating.Mashups.with.Adobe.Flex.and.AIR.rar
Password : knowfree.net

[教程]ASP.Net MVC的Html.ActionLink解析2

mikel阅读(818)

在《ASP.NET MVC框架配置与分析》这篇文章中,已经介绍了MVC框架的配置,并且简单讲述了它的运行机制。本文将重点描述,MVC框架中默认的地址重写。
1、注册地址重写

MVC的地址重写必须在Global.asax.cs中初始化,从而保证所有的请求都能被Controller控制。简单的意思就是必须在运行期,应用程 序启动的时候被初始化。为什么要到运行期,而不发生在编译器,为什么不能用静态构造函数来完成呢?那是因为编译期连地址都没确定,怎么能够保证地址是正确 的呢?
在Global.asax.cs中默认有两个重写方法被注册

 1         protected void Application_Start(object sender, EventArgs e)
 2         {
 3             // Note: Change Url= to Url="[controller].mvc/[action]/[id]" to enable 
 4             //       automatic support on IIS6 
 5 
 6             RouteTable.Routes.Add(new Route
 7             {
 8                 Url = "[controller]/[action]/[id]",
 9                 Defaults = new { action = "Index", id = (string)null }   ,
10                 RouteHandler = typeof(MvcRouteHandler)
11             });
12 
13 
14             RouteTable.Routes.Add(new Route
15             {
16                 Url = "Default.aspx",
17                 Defaults = new { controller = "Home", action = "Index", id = (string)null },
18                 RouteHandler = typeof(MvcRouteHandler)
19             });
20 
21 
22         }

第一个注册方法是描述了一组规则,而第二组方法描述了根目录下的Default.aspx如何交由controller 来处理。
2、controller 处理地址

比如,我们现在的URL地址是www.yurow.cn,那么,当请求www.yurow.cn的时候,实际上是请求的Default.aspx,这个时候,程序找到规则Defaults = new { controller = "Home", action = "Index", id = (string)null },(这个是默认规则,所有的默认规则都可以通过Defaults = object的方式来调用,当然也有例外,下面会讲到。)。默认规则告诉程序,这个页面请求要交给一个类名为HomeController的控制器来处理(controller = "Home", 就是用控制器的类名减去Controller,这点和Attribute非常相似)。而action = "Index"告诉程序,请求的是控制器中的Index方法,最后的 id = (string)null 则是默认参数。在MVC中,默认参数只有一个,就是id。而这里id值是null。在默认HomeController类中也有两个方法

 1         [ControllerAction]
 2         public void Index()
 3         {
 4             RenderView("Index");
 5         }
 6 
 7         [ControllerAction]
 8         public void About()
 9         {
10                RenderView("About");
11         }


请求Default.aspx调用Index方法后,将输出定位到Index.aspx(RenderView("Index");)。这时候显示的就是Index.aspx。当然,这时候浏览器显示的地址是http://www.yurow.cn/,实际上还可以有另外一种表示方式http://www.yurow.cn/Home/Index
而“域名/controller/action/id” 才是MVC真正的地址现实方式。映射的地址则是“根路径 /Views/controller/action(.aspx)”。id参数不是交由aspx文件处理的,而是交由controller处理,这点我认 为就是和WebForm模型最大的不同。
再来看看注册的第一组规则: Url = "[controller]/[action]/[id]",定义了URL的路径就是上面所说的“域名/controller/action/id”,在这里就是http://www.yurow.cn/Home/About 。
3、controller 到View的数据传递

这两组定义中似乎都没有用到id参数,id到底体现在哪里呢?
尝试在HomeController和About.aspx.cs中接收id参数Request["id"],然后把地址变成http://www.yurow.cn/Home/About/1,结果Request["id"]是null并不是我们想象中的'1'。而事实上是这样接收这个id参数的:

        [ControllerAction]
        
public void About(string id)
        {
            
if (string.IsNullOrEmpty(id))
                id 
= "";
                RenderView(
"About", (object)id);
            
        }

在About.aspx.cs中要这样使用

1     public partial class About : ViewPage< string>
2     {
3 
4         protected void Page_Load(object sender, EventArgs e)
5         {
6             Response.Write(ViewData);
7         }
8     }

ViewPage< string>定义了About.aspx.cs接收Controller里传递过来的 (object)id,并且申明这是一个string类型。而ViewData就是这个值。当然也可以定义成任何类型,因为这里接收的类型是object。
4、重写后的地址构造
MVC提供了自动构造重写地址的方法——Html.ActionLink。
Html.ActionLink一共有3个重载。
1)先说简单的public string ActionLink(string linkText, string actionName);
参数一是链接显示的文字,而参数二是action的名称。比如Html.ActionLink("链接文字","About");
链接地址实际是< a href="/Home/About">链接文字< /a>。地址中的Home是怎么来的呢?就是Defaults里定义的。注意,如果你不去改写,那么赋值了一次,无论是controller 还是action或者id的值都是一直不变的。而这个Home在注册的时候就已经被赋值了。
2)public string ActionLink(string linkText, string actionName, string controllerName);
参数一和参数二和1)相同,参数三则是controller的名称。比如你可以赋值
Html.ActionLink("链接文字","MyPage","Test");
链接地址实际是< a href="/Test/MyPage">链接文字< /a>。明明没有Test控制器,也没有MyPage页面,怎么能够定义成功?这就是因为,虽然参数名是这样定义的,实际上这仅仅是一个字符串,代表要请求的目录(controllerName),和aspx文件(actionName)。
3)public string ActionLink(string linkText, object values);
这个是自定义式的赋值。可以这样写:
< %= Html.ActionLink("About Us", new { id="1",controller="Home", action="About" })%>
实际地址就是< a href="/Home/About/1">About Us"< /a>。

[教程]ASP.Net MVC的Html.ActionLink解析

mikel阅读(870)

Html.ActionLink 方法用于指向Controller的Action
ActionLink方法定义的代码

//页面显示linkText指向Global.asax.cs中默认的Controller对象的actionName方法
public string ActionLink(string linkText, string actionName) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
return GenerateLink(linkText, null /* routeName */, actionName, null /* controllerName */, new RouteValueDictionary());
}
//页面显示linkText指向默认Global.asax.cs中默认的Controller对象的actionName方法并且带的参数值values
public string ActionLink(string linkText, string actionName, object values) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
return GenerateLink(linkText, null /* routeName */, actionName, null /* controllerName */, new RouteValueDictionary(values));
}
//页面显示linkText指向定义的RouteValueDictionary中的Controller对象的actionName方法
public string ActionLink(string linkText, string actionName, RouteValueDictionary valuesDictionary) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
if (valuesDictionary == null) {
throw new ArgumentNullException("valuesDictionary");
}
return GenerateLink(linkText, null /* routeName */, actionName, null /* controllerName */, new RouteValueDictionary(valuesDictionary));
}
//页面显示linkText指向ControllerName对应的Controller的actionName方法
public string ActionLink(string linkText, string actionName, string controllerName) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
if (String.IsNullOrEmpty(controllerName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
}
return GenerateLink(linkText, null /* routeName */, actionName, controllerName, new RouteValueDictionary());
}
//
public string ActionLink(string linkText, string actionName, string controllerName, object values) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
if (String.IsNullOrEmpty(controllerName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
}
return GenerateLink(linkText, null /* routeName */, actionName, controllerName, new RouteValueDictionary(values));
}
public string ActionLink(string linkText, string actionName, string controllerName, RouteValueDictionary valuesDictionary) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
if (String.IsNullOrEmpty(controllerName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
}
if (valuesDictionary == null) {
throw new ArgumentNullException("valuesDictionary");
}
return GenerateLink(linkText, null /* routeName */, actionName, controllerName, new RouteValueDictionary(valuesDictionary));
}

使用实例代码

<li>
<%= Html.ActionLink("Home","Index")%>
</li>
<li>
<%= Html.ActionLink("About","About")%>
</li>
<li>
<%=Html.ActionLink("Products","Detail","Products" )%>
</li>
<li>
<%=Html.ActionLink("Products","Detail","Products" ,2)%>
</li>

[教程]ASP.Net MVC定义URL Routing

mikel阅读(752)

文/QLeelulu  出处/博客园+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
定义URL Routing +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
在一个route中,通过在大括号中放一个占位符来定义( { and } )。当解析URL的时候,符号"/"和"."被作为一个定义符来解析,而定义符之间的值则匹配到占位符中。route定义中不在大括号中的信息则作为常量值。+2½_U‚JåU˜www.pin5i.comùsP©6è—
下面是一些示例URL: +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—

+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
通 常,我们在Global.asax文件中的Application_Start事件中添加routes,这确保routes在程序启动的时候就可用,而且 也允许在你进行单元测试的时候直接调用该方法。如果你想在单元测试的时候直接调用它,注册该routes的方法必需是静态的同时有一个 RouteCollection参数。+2½_U‚JåU˜www.pin5i.comùsP©6è—
下面的示例是Global.asax中的代码,演示了添加一个包含两个URL参数action 和 categoryName的Route对象:+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—

引用:
protected void Application_Start(object sender, EventArgs e)+2½_U‚JåU˜www.pin5i.comùsP©6è—
{+2½_U‚JåU˜www.pin5i.comùsP©6è—
    RegisterRoutes(RouteTable.Routes);+2½_U‚JåU˜www.pin5i.comùsP©6è—
}+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
public static void RegisterRoutes(RouteCollection routes)+2½_U‚JåU˜www.pin5i.comùsP©6è—
{+2½_U‚JåU˜www.pin5i.comùsP©6è—
    routes.Add(new Route+2½_U‚JåU˜www.pin5i.comùsP©6è—
    (+2½_U‚JåU˜www.pin5i.comùsP©6è—
        "Category/{action}/{categoryName}"+2½_U‚JåU˜www.pin5i.comùsP©6è—
        , new CategoryRouteHandler()+2½_U‚JåU˜www.pin5i.comùsP©6è—
    ));+2½_U‚JåU˜www.pin5i.comùsP©6è—
}

+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
设置Route参数的默认值 +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
当你定义个一route的时候,你可以分配一个默认值给route的参数。默认值是当URL中没有包含参数的值的时候使用的。你可以在Route类中通过dictionary来设置Default属性来设置route的默认值: +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—

引用:
void Application_Start(object sender, EventArgs e) +2½_U‚JåU˜www.pin5i.comùsP©6è—
{+2½_U‚JåU˜www.pin5i.comùsP©6è—
    RegisterRoutes(RouteTable.Routes);+2½_U‚JåU˜www.pin5i.comùsP©6è—
} +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
public static void RegisterRoutes(RouteCollection routes)+2½_U‚JåU˜www.pin5i.comùsP©6è—
{+2½_U‚JåU˜www.pin5i.comùsP©6è—
  routes.Add(new Route+2½_U‚JåU˜www.pin5i.comùsP©6è—
  (+2½_U‚JåU˜www.pin5i.comùsP©6è—
    "Category/{action}/{categoryName}"+2½_U‚JåU˜www.pin5i.comùsP©6è—
          new CategoryRouteHandler()+2½_U‚JåU˜www.pin5i.comùsP©6è—
  )+2½_U‚JåU˜www.pin5i.comùsP©6è—
    {+2½_U‚JåU˜www.pin5i.comùsP©6è—
      Defaults = new RouteValueDictionary +2½_U‚JåU˜www.pin5i.comùsP©6è—
          {{"categoryName", "food"}, {"action", "show"}}+2½_U‚JåU˜www.pin5i.comùsP©6è—
    }+2½_U‚JåU˜www.pin5i.comùsP©6è—
  );+2½_U‚JåU˜www.pin5i.comùsP©6è—
}

+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
当URL Routing处理URL Request的时候,上面route定义产生的结果如下表所示:  +2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—
+2½_U‚JåU˜www.pin5i.comùsP©6è—

+2½_U‚JåU˜www.pin5i.comùsP©6è—拼吾爱程序人生

[教程]使用.Net的CodeDOM技术实现语言无关的Code Wizard

mikel阅读(797)

本文曾发表于It168:http://tech.it168.com/m/2007-09-11/200709111500188.shtml

摘要:CodeDOM是.net framework的一项重要的源代码生成技术。本文详细讨论了CodeDOM的原理以及如何利用CodeDOM技术实现一个与语言无关的Code Wizard。并给出了一个用C#语言实现的例子。

关键字:Code Wizards、CodeDOM、.net framework数据表、模板文件

一、什么是CodeDom?

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

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

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

二、实现CodeWizard

下面要实现的这个 CodeWizard非常简单。其功能主要是将一个数据表映射成一个类。这个类提供了Add和Save方法以及和数据表的每个字段相对应的属性。使用这个 类可以向数据表添加记录。为了便于描述,将这个数据表保存成xml文件格式。每条记录为一个item结点,每一个字段为这个结点的一个属性。表名为这个 xml文件的根结点名称。这个xml文件的格式如下所示:

<MyTable>    
    
<item id = "01 " name = "Bill "/>
    
<item id = "02" name = "Mike" />
</MyTable>

这个CodeWizard通过一个模板文件来定义数据表的结构。模板文件的格式如下:

<MyTable>
    
<id type = "System.Int32"/>
    
<name type = "System.String"/>
</MyTable>

其中type为字段的类 型,它的值是在.net framework中的System中定义的简单类型,如System.Int32、System.String、System.Char等。下面就详细 讨论如何利用这个模板文件和CodeDOM技术来生成C#和VB.net的源代码。

三、CodeDOM的结构

CodeDOM由两部分组成:

1. 用于描述抽象代码结构的一组类。其中CodeCompileUnit类是这些类的根。代表一个源码文件(如C#的*.cs和VB.net的*.vb)。在使用CodeDOM时,必须先建立一个CodeCompileUnit类的对象,然后在这个对象中加入必要的namespace、class等面向对象元素。

用于生成和编译源代码的类。这个类必须从CodeDomProvider类继承。每种.net framework

所支持的语言都有自己的CodeDomProvider类。如在C#中的CodeDomProvider类叫CSharpCodeProvider,而在VB.net中叫VBCodeProvider

四、数据表类的定义

要用CodeDOM定义一个类需要三步:

1. 建立一个CodeCompileUnit对象。这个类相当于一个源码文件。

2. 建立一个CodeNamespace对象。理论上在.net framework上运行的程序语言,如C#、VB.net

等,可以没有namespace。但在CodeDOM中必须使用这个类,如果不想要namespace,可以将namespace的名字设为 null或空串。

建立一个CodeTypeDeclaration对象。这个类可以建立Class和Interface两种Type。在

这个例子中只建立Class。如果想建立Interface,只需将IsInterface属性设为true即可。

主要的实现代码如下:

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

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

五、全局变量的生成

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

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

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

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

五、属性的生成

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

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

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

六、构造函数的生成

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

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

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

private void GenerateConstructor()
{
    
// 定义构造函数
    CodeConstructor constructor = new CodeConstructor();
    constructor.Parameters.Add(
new CodeParameterDeclarationExpression("System.String""xmlFile"));
    constructor.Attributes 
= MemberAttributes.Public;
    
// 产生 "m_XmlFile = xmlFile;" 
    CodeAssignStatement assignXmlFile = new CodeAssignStatement(m_XmlFileExpression,
    new
 CodeVariableReferenceExpression("xmlFile"));
    
// 产生 "m_xml.LoadXml("…");"
    CodeMethodInvokeExpression invokeLoadXml = new CodeMethodInvokeExpression(m_XmlExpression, "LoadXml",
   new CodePrimitiveExpression("<?xml version=\"1.0\" encoding=\"gb2312\" ?><" + m_Xml.DocumentElement.Name
   +
 "></" + m_Xml.DocumentElement.Name + ">"));
    
// 产生 "m_xml.Save(m_XmlFile);"
    CodeMethodInvokeExpression invokeSave = new CodeMethodInvokeExpression(m_XmlExpression, "Save",
    m_XmlFileExpression);
    CodeStatementCollection statements 
= new CodeStatementCollection();
    statements.Add(invokeLoadXml);
    statements.Add(invokeSave);
    
// 产生if语句:  "if (System.IO.File.Exists(m_XmlFile))  else  "
    CodeConditionStatement ifStatement = new CodeConditionStatement(new CodeMethodInvokeExpression(
   new
 CodeVariableReferenceExpression("System.IO.File"), "Exists", m_XmlFileExpression), new CodeStatement[] { } ,
   new CodeStatement[] { statements[0], statements[1] });
    
// 产生 "m_xml.Load(m_XmlFile);"
    CodeMethodInvokeExpression invokeLoad = new CodeMethodInvokeExpression(m_XmlExpression, "Load",
     m_XmlFileExpression);
    
// 产生 "m_AddFlag = false;"
    CodeAssignStatement assignAddFalse = new CodeAssignStatement(m_AddFlagExpression,
    new CodePrimitiveExpression(false));
    constructor.Statements.Add(assignXmlFile);
    constructor.Statements.Add(ifStatement);
    constructor.Statements.Add(invokeLoad);
    constructor.Statements.Add(assignAddFalse);
     m_Class.Members.Add(constructor);
}


七、Add和Save方法生成

Add方法只有一条语句,功能是将m_AddFlag设为true,以使数据表类处于加入状态。Save方法比较复杂。它的功能是当m_AddFlag为true时在数据表文件的最后加入一条记录,并保存。具体实现代码如下:

private void GenerateMethods()
{
CodeTypeReference voidReference 
= new CodeTypeReference("System.void");
    
//产生Add方法
    CodeMemberMethod add = new CodeMemberMethod();
    add.ReturnType 
= voidReference;
    add.Name 
= "add";
    add.Attributes 
= MemberAttributes.Public | MemberAttributes.Final;
    CodeAssignStatement assignAddTrue 
= new CodeAssignStatement(m_AddFlagExpression,
   
new CodePrimitiveExpression(true));
    add.Statements.Add(assignAddTrue);
    m_Class.Members.Add(add);
    
//产生Save方法
    CodeMemberMethod save = new CodeMemberMethod();
   save.ReturnType 
= voidReference;
   save.Name 
= "save";
   save.Attributes 
= MemberAttributes.Public | MemberAttributes.Final;
   System.Collections.Generic.List
<CodeStatement> ifStatements =
  
new System.Collections.Generic.List<CodeStatement>();
   
//产生 "XmlNode xn = m_xml.CreateNode(XmlNodeType.Element, "item", "");"
  CodeVariableDeclarationStatement xmlNode = new CodeVariableDeclarationStatement("System.Xml.XmlNode""xn");
   CodeMethodInvokeExpression createNode 
= new CodeMethodInvokeExpression(m_XmlExpression, "CreateNode"
  new CodeExpression[] {new CodeVariableReferenceExpression("System.Xml.XmlNodeType.Element"),
 
new CodePrimitiveExpression("item"),
  new
 CodePrimitiveExpression("") });
   xmlNode.InitExpression 
= createNode;
   ifStatements.Add(xmlNode);
   
//产生 "XmlAttribute xa = null; "
   CodeVariableDeclarationStatement xmlAttr = new CodeVariableDeclarationStatement("System.Xml.XmlAttribute""xa");
   xmlAttr.InitExpression 
= new CodePrimitiveExpression(null);
   ifStatements.Add(xmlAttr);
//产生字段属性
   CodeStatementCollection statements = new CodeStatementCollection();
   
foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes)
   {
   CodeMethodInvokeExpression createAttribute 
= new CodeMethodInvokeExpression(m_XmlExpression,
           
"CreateAttribute"new CodePrimitiveExpression(xn.Name));
       CodeAssignStatement assignxa 
= new CodeAssignStatement(
        new
 CodeVariableReferenceExpression("xa"), createAttribute);
       CodeMethodInvokeExpression invokeToString 
= new CodeMethodInvokeExpression(
        new
 CodeVariableReferenceExpression("m_" + xn.Name), "ToString");
       CodeAssignStatement assignValue 
= new CodeAssignStatement(
     
new CodeVariableReferenceExpression("xa.Value"), invokeToString);
       CodeMethodInvokeExpression invokeAppend 
= new CodeMethodInvokeExpression(
      new
 CodeVariableReferenceExpression("xn.Attributes"),
       "Append"new CodeVariableReferenceExpression("xa"));                
       statements.Add(invokeAppend);
       ifStatements.Add(assignxa);
       ifStatements.Add(assignValue);
       ifStatements.Add(statements[
0]);
   }
   
// 产生 "m_xml.DocumentElement.AppendChild(xn);"
   CodeMethodInvokeExpression invokeAppendChild = new CodeMethodInvokeExpression(new
  CodeVariableReferenceExpression(
"m_xml.DocumentElement"), "AppendChild",
   new
 CodeVariableReferenceExpression("xn"));
   statements.Clear();
   statements.Add(invokeAppendChild);
    ifStatements.Add(statements[
0]);
    
// 产生 "m_xml.Save(m_XmlFile);"
    CodeMethodInvokeExpression invokeSave = new CodeMethodInvokeExpression(m_XmlExpression,
  
"Save", m_XmlFileExpression);
    statements.Clear();
    statements.Add(invokeSave);
    ifStatements.Add(statements[
0]);
    
// 产生 "m_AddFlag = false;" 
    CodeAssignStatement assignAddFalse = new CodeAssignStatement(m_AddFlagExpression,
   
new CodePrimitiveExpression(false));
    ifStatements.Add(assignAddFalse);
// 产生if语句: "if (m_AddFlag)"
    CodeConditionStatement ifStatement = new CodeConditionStatement(m_AddFlagExpression,
    ifStatements.ToArray());
    save.Statements.Add(ifStatement);
    m_Class.Members.Add(save);
}

八、生成源代码

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

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

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

九、编译源代码

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

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

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

  1. 使用CodeDomProvider调用编译器时也需要传递相应的参数,如在本例中将System.Xml.dll

作为一个参数,表示目标文件需要调用这个dll中的资源。

  1. 在调用编译器后,如果出现错误,可使用cr.Errors获得错误信息。

十、结束语

我花了一个晚上的时间实现了这个简单的例子,并用C#2.0调试通过,只是为了抛砖引玉。自动生成源代码有很多的方法,但使用CodeDom生成源代码会有更大的灵活性,主要表现在以下三个方面:

1.     语言无关。即只要是.net framework所支持的语言,并且这种语言提供了CodeDomProvider。

就可以生成这种语言的源代码。

2.     如果所生成的语言是测试版或要将这种语言升级到下一个版本,也可以考虑使用CodeDOM。

因为当这种语言的语法有所变化时,CodeDomProvider也会随之升级。因此,使用CodeDOM的Code Wizards也会随着CodeDOM而升级,这样就不必修改Code Wizards的源代码了。

3.     如果所生成的一种语言是你所不熟悉的,如果不使用CodeDOM,必须要熟悉这种语言的语

法,才能生成它的源代码。而使用CodeDOM却可以避免这一点。因为CodeDOM是使用抽象的object graph来描述语言的。而语言的具体语法是由CodeDomProvider所决定的。

其实CodeDOM不仅可以用在Code Wizards上,也可以用在许多其它地方,如可以生成Web

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

[资源]国外几款开源的CMS

mikel阅读(769)

1、Ludico
Ludico是C#编写的居于ASP.NET 2.0的Portal/CMS系统。它的模块化设计是你可以按照你希望的使用或开发网站功能。它里面有高级的用户管理,一个所见即所的(WYSIWYG)的编辑器等。
下载地址:http://sourceforge.net/projects/ludico/
2、umbraco 
Umbraco是一款在.net平台下C#开发的开源内容管理系统,该系统效率,灵活,用户界面都不错。
下载地址:http://umbraco.org/
3、mojoPortal
mojoPortal是一款C#开发的面相对象网站框架,它可以运行于Windows的ASP.NET 和GNU/Linux 或Mac OS X的Mono的平台上。
下载地址:http://www.mojoportal.com/
4、Kodai CMS
Kodai CMS是.net平台下的一款功能齐全的内容管理系统。
下载地址:http://www.gotdotnet.com/workspaces/workspace.aspx?id=070f30c3-6089-4a75-b84c-fac654a7ec08
5、nkCMS
NkCMS是使用ASP.NETSQL server 2000开发的内容管理系统。
下载地址:http://nkcms.sourceforge.net/
6、Go.Kryo
Go.Kryo是一个用ASP.net(C#).NET 实现的简单的内容管理系统,后台数据库使用Microsoft SQL Server 。
下载地址:http://sourceforge.net/projects/gokryo/
7、Amplefile
Amplefile是一款内容管理系统,是.net环境下的windows应用程序,使用了.Net remoting.
下载地址:http://sourceforge.net/projects/amplefile/
8、ndCMS
ndCMS是 ASP.net (C#)下的一个内容管理系统。它提供了用户管理,文件管理,一个WYSIWYG编辑器,模板管理,拼写检查和内置的http压缩。ndCMS的目标是提供一个简单而快速的方式部署.Net站点
下载地址:http://ndcms-net.sourceforge.net/
9、Cuyahoga
Cuyahoga是C#开发的灵活的CMS / Portal 解决方案。它可以运行于Microsoft .net 和Mono 平台,支持SQL Server, PostgreSQL或MySQL作为底层数据库。
下载地址:http://www.cuyahoga-project.org/
10、Rainbow
Rainbow项目是一款使用Microsoft's ASP.net和C#技术开发的有丰富功能的开源内容管理系统。
下载地址:http://www.rainbowportal.net/Rainbow/Default.aspx