首先推荐下Community Server,这个大家再熟悉不过了,给出最新版的下载地址。
Community Server 源码最新版下载http://get.communityserver.com/download/moredownloads.aspx
你可以找到:
Community Server Developers
Community Server 2008.5,Software Developer Kit(SDK) 因为开发版才有源码。
一、Add,Edit只要一个页面就可以了
web site通常都避免不了CRUD,页面类型通常有List,Detail,Add,Edit,Del这5种。
怎样做会比较合理且方便呢?
Add与Edit这两种类型页面通常可以通用。通过Edit.aspx?action=add (Add)与Edit.aspx?action=edit&id=xxx(Edit)来区分二者有点没有必要。可以直接使用Edit.aspx(Add)与Edit.aspx?id=xxx(Edit)
在CommunityServer.Web下有个SiteUrls.config文件,其中包含了CommunityServer的站点结构。
<?xml version="1.0" encoding="utf-8" ?>
<SiteUrls>
<location name="controlpanel" path="/controlpanel/" exclude = "true" applicationType="admin">
<!-- ControlPanel paths -->
<url name="controlpanel" path="default.aspx" />
<url name="controlpanel_loading" path="loading.aspx?msg={0}" />
<!-- Forums
Control Panel Pages -->
<url name="forums_ControlPanel_Home" path="forums/" />
<url name="forums_ControlPanel_NewForum" path="forums/SectionEdit.aspx"
/>
<url name="forums_ControlPanel_NewGroup" path="forums/GroupEdit.aspx"
/>
<url name="forums_ControlPanel_EditForum" path="forums/SectionEdit.aspx?SectionID={0}" />
<url name="forums_ControlPanel_EditGroup" path="forums/GroupEdit.aspx?GroupID={0}" />
<url name="forums_ControlPanel_ForumList" path="forums/Forums.aspx"
/>
<url name="forums_ControlPanel_Created_ForumList" path="forums/Forums.aspx?SectionID={0}" />
<url name="forums_ControlPanel_ForumListByGroup" path="forums/Forums.aspx?GroupID={0}" />
<url name="forums_ControlPanel_GroupList" path="forums/ForumGroups.aspx"
/>
<url name="forums_ControlPanel_SortOrder" path="forums/SortOrder.aspx"
/>
<url name="forums_ControlPanel_DefaultPermissionList" path="forums/DefaultPermissionList.aspx" />
<url name="forums_ControlPanel_PostOptions" path="forums/options/PostOptions.aspx" />
</location>
</SiteUrls>
仔细查看这个xml,你会发现结构真的很清晰。
forums_ControlPanel_NewForum 对应
forums/SectionEdit.aspx (Add)
forums_ControlPanel_EditForum 对应
forums/SectionEdit.aspx?SectionID={0}(Edit)
二、
Url参数的处理
期望Url
http://localhost/cs/controlpanel/forums/SectionEdit.aspx?SectionID=1 (正常)(Edit)
http://localhost/cs/controlpanel/forums/SectionEdit.aspx (正常)(Add)
非期望Url
http://localhost/cs/controlpanel/forums/SectionEdit.aspx?SectionID=xxx (正常)(Add)
http://localhost/cs/controlpanel/forums/SectionEdit.aspx?xxx=xxx (正常)(Add)
等等,你会发现Community Server对Url参数的处理很稳定。
有很大一部份朋友会使用如下方式:
private int id;
protected void Page_Load(object
sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request.QueryString["id"])) //
edit
{
id
= int.Parse(Request.QueryString["id"]);
}
else // add
{
}
}
这样会有很多麻烦事,比如传入的id非int类型,会抛异常,而且这种需求太常见了,到处放try-catch也不是很好。
让我们来看看community server的作法
private int sectionID;
private bool isNew
{
get{return sectionID
<= 0;}
}
private void Page_Load(object
sender, EventArgs e)
{
context
= CSContext.Current;
if( !context.User.IsForumAdministrator )
throw new CSException(CSExceptionType.AdministrationAccessDenied);
sectionID
= context.GetIntFromQueryString("SectionID",
-1);
if (isNew)
{
}
else
{
}
}
把类型转换的异常在GetIntFromQueryString里就处理掉,所以如果传入的参数是SectionID=xxx,也不会抛异常。只会返回-1,也就是传入的默认值。
我想这种方式是很值得借鉴使用的,而且整个代码都非常的漂亮美观。
至于context.GetIntFromQueryString这个类要怎么编写就看个人了。像Discuz!NT是封装成一个帮助类。CommunityServer有些不是区别的区别。
大体都差不多。
刚刚听了一个很不错的建意。就是获取Request.QueryString。比如上面获取sectionID都是在Page_Load方法中取得,但是这个职责并不属于Page_Load。而且要是改动的话,比如对Request.QueryString的值做判断的话,改动的地方可能会比较多。而且也不直观方便。推荐的作法是放到属性Section中,直接在属性中获取与判断值。如下:
public int SectionID
{
get{return context.GetIntFromQueryString("SectionID", -1);}
}
三、数据层CRUD的编写
CUD Community Server通常都是采用如下这种方式
public override int
CreateUpdateDeleteGroup(Group group, DataProviderAction action) {
}
DataProviderAction为枚举:Create、Update、Delete、NoSet
Community Server在架构上支持多数据库,通过上面的override就可以看出来,不过是面向抽象类,不是面向接口。
把一些多数据库都支持的方法放在抽象类中,省了些重复的代码。
不过Community Server只是实现了Sql Server数据库,其它数据库并没有实现。
Community Server在这里主要是把操作嫁接到数据库中,将action做为参数传入到存储过程中。
所以如果实现Access数据库的话,这个方法可能就会长一点。
不过我是很喜欢这种规到一起的方式,然后在逻辑层分开。
还有就是枚举在开发中是非常好用的,不要浪费到了噢。
不过最好要有统一的命名比如在名称后加Type或Enum来区分感觉会好点。
四、杂七杂八
分层不是越多越好,这个毛病是很多刚接触分层的朋友经常犯的。
CommunityServer的设计有很多可以学习的地方。
不过CommunityServer.Components项目下的命名空间有点恐怖。
比如Common文件夹的命名空间成了namespace
CommunityServer.Common
比如Components文件夹的命名空间成了namespace
CommunityServer.Components
小菜之前也干过一种更疯狂的作法如下:
AA.Library项目
命名空间 namespace AA.Library
Configuration文件夹 命名空间 namespace AA.Library
Enumeration文件夹 命名空间 namespace AA.Library
Helpers文件夹 命名空间 namespace AA.Library
等等文件夹
命名空间只使用AA.Library,这样用起来很方便,只要引用一个命名空间就可以了。
不过这种作法是强烈反对的。
比如AA.Library下的类一定会很多。你AA.Library智能提示会出现多少个类?单纯从你找类的角度就麻烦。
微软的MVC下的命名空间是怎么划分的?
Controler/View/Model
所以如下会比较好
AA.Library项目
命名空间 namespace AA.Library
Configuration文件夹 命名空间 namespace AA.Library.Configuration
Enumeration文件夹 命名空间 namespace AA.Library.Enumeration
Helpers文件夹 命名空间 namespace AA.Library.Helpers
等等文件夹
说到这里就顺便说下在Linq中的一些注意地方
1最好使用FistOrDefault而不要使用SingleOrDefault免的出错。
2在使用GetAll().FirstOrDefault或者GetAll().Where等等先要判断GetAll()是否为空。