在
下载VC#2005、VB2005、WebDev2005的时候,千万不要错过SqlServer 2005 Express这个东东!为什么?我只列举它两项最Cool的特性!
1、CLR集成。可以与VS2005开发环境完美的集成,现在,我们可以用我们自己喜欢的语言(C#/VB.NET)来写StoredProcedure和Function了!
2、XCopy部署数据库!是的,当要移动数据库时,我们只需要将数据库像文件那样拷贝到另一台电脑上,然后,修改数据库连接字符串中的“AttachDBFilename”参数的值为数据库文件所在的路径,其他一切就不需要再操心了。嗯,是不是部署就像Access文件那样简单?
明天(6/29),在TechEd Europe会议上,微软将正式发布VS2005 Beta1,本周内,MSDN的订阅用户就可以下载到VS2005 Beta1。
同时,微软还将定制多个Express Edition,包括Visual Web Developer 2005 Express Edition、VB 2005/VC# 2005/VJ# 2005/VC++ 2005 Express Edition、SqlServer 2005 Express Edition,以上各个Express Edition将公开向所有人提供下载。
一旦开始使用VS2005作为开发平台,我相信,你将再也不愿意再用回VS2003...
我最爱的VS2005的特性:1、开发Web项目终于可以摆脱IIS和虚拟目录了;2、C# Generic(已经有人打主意将STL移植到C#了,另外,想知道C# 3.0有什么东东更Cool的吗?look
here!);3、Modeling Tools(WhiteHorse)
我最不满意的:为什么Unit Testing不直接集成进VS2005,而要放在VS2005 Team System里面呢?何必浪费程序员的时间再去安装NUnit?已经有人发起了一场
灌水运动,来呼吁将Unit Testing放入所有版本的VS2005中。
这两天忙着做手头的一个项目,ASP.NET的,没太多技术难度。但做项目通常能让我在思考实现的过程中,冒出各种各样的想法...
为了在ASP.NET 1.1里面实现类似2.0里面的Membership(用于用户的身份验证Authentication)和Role Manager(用于用户的权限验证Authorization)模块,我认真将2.0的文档里面相关的部分看了一遍,然后在1.1里面几乎依葫芦画瓢的实现了出来。在实现的过程中,我渐渐感到Membership和RoleManager的实现方式很是眼熟,然后,我越来越觉得它们的概念非常像一样东东:SOA!
随便写个例子吧,想象一下我们通常如何设计User类和Role类:
class User {
RoleCollection Roles;
}
class Role {
UserCollection Users;
}各个类之间都有Association。于是,我们用User.Roles来获得一个用户的角色信息,用Role.Users来获得一个角色下有哪些用户。
或者:
class User {}
class Role {}
ICollection RoleService.GetRolesFromUser( String username );
ICollection RoleServie.GetUsersFromRole( String roleName );
void RoleService.AddUserToRole( String username, String roleName );各个类之间没有Association,我们通过一个(或几个)相关的ServiceFacade来获取相关的信息和进行相关的操作。
Membership和Role Manager就是用的类似于第二种的方式来实现的。好处?Membership和RoleManager之间完全各自独立,两者之间没有直接的联系,没有“依存”关系。比如,我们可以让Membership用AD集成的方式来进行用户认证,但是用户的角色、权限信息则放在SqlServer的表里面。
各个Domain Model的独立,还带来了更多的好处。1、在用ORM(或者手工)载入Entity的数据的时候,因为各个Entity之间被设计成没有Association,所以,我们可以暂时抛开令人烦恼的Lazy-Loading的问题。2、Entity完全可以通过WebService传递到远程,如果有各种Assocation,想象被传递到远程的User实体被直接调用User.Roles将是件多么令人烦恼的事。
但是,别忘了Membership和Role Manager从逻辑上来说,是完全可以分开的,而通常很多东西,天生就是结合非常紧密的。比如:Order和OrderDetail、OrderDetail和Product。
总之,程序员的一大工作就是:Do right thing in right place!
不少人和我说SPS站点中的权限只能分配到文档库,而文档库中的文件的权限则不能进行更细微的控制了。的确如此,SharePoint中权限管理的最小单位是列表,所以文档库中的内容的权限不能再进行细分了。
但是,很多时候,为了各种各样的理由,我们有时候要绕着弯来实现这本来没有的功能。
我在以前曾经在一个基于WSS的产品里面实现过这样的一个功能:在文档库里面,可以建立“高级文件夹”,不同于普通文件夹的是,高级文件夹可以再进行授权管理,这样,间接的实现了我想要的效果。

如下图:“产品代理价格”就是一个高级文件夹,而边上的其他文件夹则是普通文件夹,无法再进行权限授权管理。

实现这个效果的关键是:
1、高级文件夹其实是一个单独的列表。
2、定制自己的WebPart,来显示文件夹的内容,这样才能将那个“体现”为文件夹的列表作为一个文件夹显示出来。
因为最近在看Pico的一些资料,所以对IoC(或者叫Dependency Injection)相关的其他东东也关注了一下。
如果对IoC不熟悉,你可以在今年第三期的《程序员》上面,找到一篇Martin Fowler写的介绍文章。英文原文在这里。
在Java平台上,基于IoC的轻量级Container已经不少了,像大家熟悉的Spring、PicoContainer(NanoContainer)、Apache Avalon(此Avalon可不是Longhorn里面的那个Avalon)等等,但是.NET平台下除了一个Pico的移植和Spring作者开发Spring.Net的计划外,就少有所见了。
当然有人很不服气,这篇文章的作者认为,IoC根本不是什么新概念,在2000年.NET的测试版里面,就可以看到IoC的影子了。在System.ComponentModel下面,就隐藏着IComponent、IContainer、ISite、IServiceProvider、IServiceContainer等接口和相应的默认实现。
模仿Martin Fowler那篇文章中的代码,我用这些接口和默认实现写了一个IoC的“最小实现”,除了创建了一个新的MyServiceContainer类用来对ServiceContainer做了一下包装之外,其他全部是利用的.Net Framework本身提供的类和接口。
// 创建一个Container
IServiceContainer container = new MyServiceContainer();
// 在Container中注册新的组件
container.AddService(typeof(IMovieFinder), new DefaultMovieFinder());
container.AddService(typeof(IMovieLister), new DefaultMovieLister());
// 也可以从Container中删除组件
//container.RemoveService(typeof(IMovieFinder));
// 从Container中获取指定接口的组件后调用其功能
IMovieLister lister = (IMovieLister) container.GetService(typeof(IMovieLister));
if (lister != null)
{
lister.ListMovieByName("kaneboy");
}
注意上面代码中,在注册新的组件时,仍然用的HardCode创建新的实例,这里仅作为演示(通常实例类型是放在配置文件中或者完全按照配置文件来自动在Container中创建Component)。
再来看看DefaultMovieFinder的实现:
public class DefaultMovieFinder : System.ComponentModel.Component, IMovieFinder
{
public String[] FindByName(String name)
{
return new String[1] {"Matrix"};
}
}
DefaultMovieFinder是一个实现了IMovieFinder接口并从System.ComponentModel.Component继承下来的类。
public class DefaultMovieLister : System.ComponentModel.Component, IMovieLister
{
public void ListMovieByName(String name)
{
IMovieFinder finder = (IMovieFinder) this.Site.GetService(typeof(IMovieFinder));
if (finder != null)
{
foreach(String movie in finder.FindByName(name))
{
Console.WriteLine(movie);
}
}
}
}
上面是DefaultMovieLister的实现,它是一个实现了IMovieLister并从System.ComponentModel.Component继承下来的类。在ListMovieByName()方法中,它通过Component类自带的Site属性(一个实现了ISite接口的类)来获得了Container中所需的Component。
如果对完整源码感兴趣,可以在这里下载完整的源码项目文件。
现在手头正刚开始一个ASP.NET 1.1的项目,因为客户需求中有一项是某些用户的认证信息需要同客户现行的AD认证集成起来,首先想到的就是ASP.NET 2.0中一个非常方便的特性,Membership,因为使用了Provider Model Patterns,在系统中插入定制的用户认证机制是非常方便的。那干嘛不自己在ASP.NET 1.1里面实现出来呢?然后又想到既然将Membership实现出来,那不如将Roles、Personalization一同实现,充分(“抢先”)利用2.0带给我们的好处。
刚开始还有计划在Roles和Personalization这两块使用现成的Authorization and Profile Application Block,但是在仔细研究了一下它自带的QuickStart后,又感觉这个东东太过“笨重”而不灵活。非常奇怪,我个人觉得ASP.NET 2.0开发组的众多设计要比做Application Block的PAG组的要好得多...
最后推荐一个非常Cool的MS发布的站点,weRock247.NET,学习SmartClient开发不可错过的站点!
最近好像很流行在ViewState上面玩花样,有人做了一个
ViewState Decoder的东东,可以用软件直接解析出
ViewState中的内容。
其实ViewState这个东东要解析出来的确不难,Paul Wilson(也就是做那个模仿ObjectSpaces的ORMapper的)写过
一篇言简意赅的文章,里面就讲解了ViewState的结构,并提供了解析ViewState的例子。
这么看来ViewState其实还是很“脆弱”的,因为能够被很轻易的解析出来,所以很自然的会面临被恶意修改的问题。而且如果页面里面有一个DataGrid之类的控件,ViewState也会膨胀到令人不满意的地步。当然我们可以自己补足它的种种缺点。
MSDN上很早也有
一篇讲解ViewState的文章,并且在文章里面说明了如何加强ViewState的安全性,包括将散列计算值附加在ViewState里面以保证不被篡改,还有给ViewState进行一些加密。
ViewState默认是保存在客户端页面的一个Hidden Field里面的,自然会增加下载页面和提交页面(别忘了这个Hidden Field里面的内容被下载回来以后,还要被原样的Postback回去)的时间,但干吗不把ViewState直接保存在服务器端呢?比如保存在服务器上的文件里面,或者SqlServer数据库里面,这样就完全的避免了使返回页面体积增大的问题。Dino Esposito在他著名的Cutting Edge专栏里面就写过这么一篇文章,讲解了
如何透明的将ViewState保存在服务器端。
如果不想这么麻烦,还有其他方法,比如,
将ViewState在服务器端压缩后再写到Hidden Field里面,传回到服务器后再解压缩,这样一样可以很有效的打压ViewState的体积。
当然,最最简单有效的方法,就是适当的使用控件的EnableViewState属性。
开始了GotDotNet上的第二个SharePoint相关的项目,SharePoint Data Provider,目标是让程序员可以用标准的DataSet来操作SharePoint站点中的数据,并用类似SQL的语法方便的获取数据。
现在项目在Pre-Alpha阶段,只初步实现了将指定站点指定列表指定目录的数据导入到DataSet中,如下面的代码:
ListDataAdapter ada = new ListDataAdapter("http://sps", "共享文档库");
DataSet ds = ada.Fill();
this.dataGrid1.DataSource = ds;
DataSet ds2 = ada.Fill("子目录一/子目录二");
this.dataGrid2.DataSource = ds2;
效果如下:

这个项目的目标是可以用类似下面语法的代码来获取数据,并可以修改数据后更新回SharePoint:
ListDataAdapter ada = new ListDataAdapter("http://sps", "共享文档库");
ada.SelectCommandText = "Select Top 10 *.doc From 子目录一 Where (创建者='Kaneboy') and (文件大小 < 20000) Order By 上次修改时 Desc";
DataSet ds = ada.Fill();
ds.Tables["共享文档库"].Rows[0]["自定义属性"] = someData;
ada.Update(ds);如果感兴趣,现在就可以在
WorkSpaces.GotDotNet.Com/SharePointDataProvider下载源码。
1、Office IBF
在商业企业办公中用得最多的软件是什么?Word、Excel、Outlook...但是问题是为了在Word中写一篇给Boss的报告或者在Excel中编写财务收支表的时候,我们常常要切换到企业的内部系统中,或者用IE或者用专门的客户端软件来查找自己需要的信息,客户表、营业额、库存情况等等......
Office Information Bridge Framework就是基于这个理念,帮助我们创建可以集成在Office里面的,能够迅速的获取企业内部管理系统、合作伙伴的信息查询系统等等来源的信息,甚至通过Office来处理某个只能在内部管理系统中处理的事务。
SmartClient in Office,这样的应用相信也会渐渐的成为企业内部系统的一种不可忽略的方式。看看微软的这篇文章:Overview of Smart Client Applications in the Microsoft Office System。
为了帮助Office的企业用户能够发挥出OfficeSystem的更大潜能,微软还发布了一系列新的Office Solution Accelerators and Tools。
2、匈牙利命名法
匈牙利命名法,你还在用吗?一个叫Rory Blyth的伙计对匈牙利命名法猛烈开火,他认为所有人都应该把匈牙利命名法扔到太平洋里面去...但是我现在仍然习惯用iCount、sUsername的命名方法,感觉也挺好的嘛
...
3、Some Links
这里是TechEd2004上的关于Whidbey的一些Slide和CodeSample。
想看看Longhorn下面基于Avalon的程序能呈现什么样的3D效果吗?看看这里,一个很Cool的Longhorn程序。
想过在.NET里面能以WYSIWYG的方式用GDI+画图吗?这个VG.NET的东东很Cool吧。
这里是一辑VS Team System的MSDN TV节目。
还有人用VisualFoxpro吗?VF9的Beta开始提供下载了。
周末了,轻松一下,老外的乞丐原来和国内的一样,只要Money,不要Food。
4、SharePoint WalkThroughs
SharePoint WalkThrough系列重新启动,哈哈。计划是InfoPath + SharePoint。另外,我会抽空把SharePoint DataAdapter写完,这个东东可以用“SPSAdapter.Fill(ds, “共享文档库”)”的语法将SharePoint站点中的数据直接填充到DataSet里面,方便开发。
我以前一篇文章介绍过XC#,用XC#可以非常方便的在一个Method上插入前置和后置条件的检查。XC#的实现是通过在编译时根据插入的指定Attribute动态在原有代码上加入相应的代码。
Lostinet的ContextBoundModel(以下简称CBM)是一个AOP.NET的框架,在CBM的基础上,可以非常方便的实现类似XC#的前置和后置条件检查,而且具有更大的灵活性,因为我们可以自己定制各种检查的条件。
下面示范在一个Person类的SetAge()方法和GetAge()方法上应用前置和后置条件:
public class Person : AspectObject
{
...
public void SetAge([AgeArg] Int32 age)
{
_iAge = age;
}
[AgeResult]
public Int32 GetAge()
{
return _iAge;
}
上面SetAge()方法需要检查传入的参数age是否如何年龄所需的要求(比如大于16岁,小于150岁),而GetAge()方法则需要检查返回的值是否如何要求。加在参数和方法上的两个Attribute,AgeArg和AgeResult都是实现了Lostinet.ContextBoundModel.IMessageHandlerAttribute接口的Attribute,所以可以用于标示拦截。
下面演示了AgeResultAttribute的实现:
[AttributeUsage(AttributeTargets.Method)]
public class AgeResultAttribute : Attribute, IMessageHandler, IMessageHandlerAttribute
{
...
public IMethodReturnMessage ProcessMessage(IMethodCallMessage mcm, AspectObjectProxy proxy, MessageHandlerQueue queue)
{
IMethodReturnMessage result = queue.InvokeNext(mcm, proxy);
if (Convert.ToInt32(result.ReturnValue) < 0)
{
throw new ApplicationException("返回值不能是" + result.ReturnValue.ToString());
}
return result;
}
}
在ProcessMessage()方法中,代码首先调用了“真实”的方法代码,然后对返回值进行检测。
如果感兴趣,点击这里下载这个示范项目的源码。在这里下载ContextBoundModel的最新的版本。
[本文中所有对ContextBoundModel的资料的引用,都得到了Lostinet的允许]