RSS

Monthly Archives: 十二月 2004

把数据源看成一个Service

Rockford Lhotka在ServerSide.Net上发表了一篇文章《The Fallacy of the Data Layer》(博客园的朋友已经将此文翻译成了中文)。

作者在这篇文章中表达了一种观点,即数据源与其说是整个Application中的一个Layer(Tier),不如把数据源当作Application之外的一个单独的Service。作者将Application这个词定义为:“an application is hereby defined as a set of code, objects, components, services, layers or tiers that exist within a trust boundary.”就是说,一个Application的内部是紧密联系的、互相信任的一组内容。Layer可以看作Application内部的一种层次。而数据源(通常是SqlServer之类的数据库)在真实世界中,并没有将它“完全包裹”在一个Application的里面,而是可以被其他Application(或者叫其他Service)访问的。

其实作者的观点并非什么“惊世骇俗”,在很多情况下,我们早已经把Data Access Layer和Data Source 分来了,Data Source作为一个单独的“服务”存在于系统之外的某个地方,而且可以作为“插配件”一样更换和替代。我的个人观点更倾向于把Data Access Layer叫做Persistent Layer,持久层。在Application内部,我们看到的只是反映客观世界的Entity,对数据库“一无所知”,在需要保存Entity时,由持久层负责将Entity持久化,至于它是如何将它持久的,对于Domain Logic来说,没有意义。

About VS2005:
最近VS2005的各种测试版本开始满天飞,包括Yukon的各种测试版本,越来越“混乱”了(可怜我手头的Indigo组件还点名需要PD6版本…),在11月份的VS2005 CTP之后,12月份的CTP也快要出来了。如果想等稳定的版本,期待明年2月份的Beta2 Release吧!:)

再附,To Office MVPs:
OTEC(Office技术专家俱乐部)成员名单即将确定,请有意参加的Office MVPs发送邮件给我,并在邮件中附上相关信息(详见回复)。

 

Posted by on 2004/12/21 in 未分类

7 Comments

Tags: ,

What’s wrong with this code ?

这个有意思的问题出自Eric Gu的Blog。代码如下:

public void TransmitResponse(ArrayList responses,
                             StreamWriter streamWriter)
{
   foreach (DataResponse response in responses)
   {
      NetworkResponse networkResponse = response.GetNetwork();
      networkResponse.Send(streamWriter);
   }
   GC.Collect();      // clean up temporary objects
}

这段代码问题何在?

原Blog Entry的众多回复非常有意思。首先,有人指出,代码没有关闭NetworkResponse对象和StreamWriter对象,应该在代码中加上“using”来保证正确调用这些对象的Dispose()方法。但是,随即有人指出,在这个方法中调用这些对象的Dispose(),是不正确的。

首先,作为参数的DataResponse集合和StreamWriter对象,根本不能假定它们“应该”在这个方法内部被关闭,也许在调用这个方法之后,其他地方仍然要使用它们。而在循环中通过GetNetwork()方法得到的临时NetworkResponse对象,很难看出GetNetwork()方法是否是创建一个新的NetworkResponse对象抑或只是返回一个已有的对象(还有人指出,如果是创建一个新的对象,那个方法名称应该是CreateNetwork(),而不是GetNetwork()),所以贸然调用它的Dispose()也是不可取的。

最后讨论的结果,这段代码的问题主要是:1、代码中未检测各个相关的对象是否为null,或者ArrayList中的对象是否类型正确;2、调用GC.Collect()毫无理由。

原Blog Entry的众多回复所统一的意见:只有一个方法亲自创建了一个新的对象实例,才有义务调用这个实例的Dispose()。

呵呵,我想到一个典型的“反例”,那就是ADO.NET中DataReader的使用,它的使用者在某些情况下,有义务调用它的Close()方法。当然,作为开发人员,可以利用各种模式来“修正”这个“反例”。比如,这篇文章所介绍的使用Delegate来将DataReader的Dispose责任回收到创建DataReader的地方。

 

Posted by on 2004/12/07 in 未分类

4 Comments

Tags:

SharePoint站点中用户信息与AD用户信息的“不一致”问题

先把问题描述一下:已把AD用户“User1”加到SharePoint站点中,然后进行如下类似操作:将“User1”从SharePoint站点中删除,将“User1”从AD中删除,在AD中增加一个新用户“User1”,在SharePoint站点中增加一个用户“User1”,这时,您会发现很有意思的问题:可能可以成功增加这个用户,但是这个用户始终无法登录到SharePoint站点中;或者根本增加不了这个用户到SharePoint站点中,提示您站点中已经存在这个用户了。

在上次CSDN站点的SharePoint技术聊天活动中,有参与的网友询问了类似的问题,由于当时我在聊天活动中无法给出非常详细的解释,所以只是给出了一个相关的链接。今天用这篇文章详细解释一下。

这个问题出现的原因,是出自SharePoint对于站点用户的存储机制所造成的。SharePoint站点用户信息保存在站点对应的内容数据库的UserInfo表中,如果站点管理员删除了站点中的某个用户,您可能会惊奇的发现,这个用户相应的记录并未从UserInfo表中删除,而只是将“tp_Deleted”这个列的数据进行了设置。(这种机制的原因所在是这条记录可能已经通过外键关联了其他表的其他记录,比如此用户编写的文档,所以将此记录直接删除是不可取的。)

在以后,如果站点管理员将一个同名的用户增加到这个站点中,由于UserInfo表中已经有这条用户记录的存在,所以SharePoint也只是将这条记录的“tp_Deleted”列的数据再进行设置。

这时候,问题就来了。在UserInfo表中,有一个“td_SystemID”列,这个列是用来记录这个用户的Security Identification Number(SID)的。我们在AD中删除一个用户,再新增一个同名用户,这先后两个用户的SID肯定是不同的。而SharePoint使用了这个“td_SystemID”列来识别用户,由于前后两个用户的SID肯定不同,所以SharePoint站点就“不认”在AD中重新增加的这个用户了。

解决方法就是把UserInfo表的“td_SystemID”列的数据和当前AD中的用户信息进行同步。在SqlServer中有一个SUSER_SID()函数,可以返回某用户的SID信息。在Dean的Blog上,他已经给出了一个完整的Sql语句,大家可以直接使用。

顺便题一下,在Deam的Blog上,他也描述了这个问题所造成的另外一个问题:如果我们备份站点的时候,将用户信息也一起备份了下来,在恢复到另外一个AD中时,如果站点用户有同名的现象,也同样会造成SharePoint“不认”这个AD用户。

 

Posted by on 2004/12/05 in 未分类

12 Comments

Tags:

Portal中的列表不能设置权限?

有网友询问我,为何在SPS2003的Portal中建立的列表,不能单独设置其访问权限,而WSS站点中的列表就可以?

其实肯定是可以设置的,只是基于Portal和Area的定位,才屏蔽了它们里面的列表的权限设置的入口链接。

顺便做了一个WebPart,在一个下拉框中显示当前站点(或者当前Portal、当前Area)所有的列表,选择以后就会进入这个列表的权限设置页面。提供了一个自定义属性来确定是否只有在当前用户是管理员时,才显示这个下拉框。

这个WebPart需要用户控件包装器的支持。源码请在这里下载。

 

Posted by on 2004/12/01 in 未分类

14 Comments

Tags: