RSS

博客搬家到了博客园

手写了一个小程序,将原来博客中的所有图片都下载到本地,然后博客园的朋友帮我将所有图片(>400)批量上载之后,我的博客也顺利的搬家到了博客园。

所以从现在开始,大家可以通过kaneboy.cnblogs.com这个域名来访问我的博客。在博客堂的内容将停止更新。我仍然鼓励大家通过RSS阅读器订阅RSS以获得更好的阅读体验。

Happy SharePointing!

 

Posted by on 2012/04/08 in 未分类

Leave a comment

Linq to SharePoint与权限提升

SharePoint 2010支持Linq to SharePoint,让程序员可以使用Linq语法直接访问SharePoint 2010网站中的数据。但是在默认情况下,Linq to SharePoint不支持权限提升,也就是说,如果在代码中尝试通过SPSecurity.RunWithElevatedPrivileges()方法来提升执行权限,你可能会发现,代码并不会如你所愿的以系统帐户的身份,访问SharePoint网站的数据。

下面是一段典型的权限提升的代码,在匿名委托方法中,首先构造了新的SPSite和SPWeb对象,然后使用Linq to SharePoint查询了一个列表中所有列表项的标题。虽然看起来Linq to SharePoint好像会被提升它执行的权限,但实际情况并非如此。在下面的代码中,中间的Linq to SharePoint代码并不会受到外面调用SPSecurity.RunWithElevatedPrivileges()方法的影响。

private IEnumerable<String> GetAllHardwareNames()
{
    var currentWebUrl = SPContext.Current.Web.Url;
    List<String> result = null;

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        using (var site = new SPSite(currentWebUrl))
        {
            using (var web = site.OpenWeb())
            {

                using (var ctx = new ContosoDataContext(currentWebUrl))
                {
                    var names = from h in ctx.硬件资产跟踪
                                select h.标题;
                    result = names.ToList();
                }
            }
        }
    });

    return result;
}

如果希望Linq to SharePoint代码能够提升它的执行权限,在使用Linq to SharePoint之前,需要做一个比较trick的事情,那就是将当前HttpContext对象设置为null。下面的代码中,使用粗体标识了这些特殊的代码。

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (var site = new SPSite(currentWebUrl))
    {
        using (var web = site.OpenWeb())
        {
            var httpContext = HttpContext.Current;
            HttpContext.Current = null;

            using (var ctx = new ContosoDataContext(currentWebUrl))
            {
                var names = from h in ctx.硬件资产跟踪
                            select h.标题;
                result = names.ToList();
            }

            HttpContext.Current = httpContext;
        }
    }
});

只所以要使用这个技巧,是因为在Linq to SharePoint的实现中,使用了一个名为Microsoft.SharePoint.Linq.Provider.SPServerDataConnection的类,来真正连接到SharePoint网站。在这个类的构造函数中,有类似这样的代码:

if (SPContext.Current != null)
{
    this.defaultSite = SPContext.Current.Site;
    this.defaultWeb = (SPContext.Current.Web.Url == url) ? SPContext.Current.Web : this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}
else
{
    this.defaultSite = new SPSite(url);
    this.defaultWeb = this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}

为了提高性能,它会优先重用SPContext对象中所缓存的SPWeb和SPSite对象。这个行为虽然可以提高代码的运行效率,但是却会导致权限提升的失效,因为提升了权限的代码必须使用一个新构造的SPSite和SPWeb对象。

 

Posted by on 2012/01/25 in 未分类

2 Comments

使用Visual Studio 2010与Visual Studio 11“合作”开发SharePoint 2011程序

Visual Studio 11 Developer Preview版本在几个月之前就发布了出来,通过这个预览版,SharePoint开发人员可以了解Visual Studio 11中内置的有关SharePoint开发的新功能。Visual Studio 11内置支持的SharePoint版本仍然是SharePoint 2011。

这篇网页上,你可以了解使用Visual Studio 11开发SharePoint 2011应用程序的新功能。最有特色的,是Visual Studio 11中内置了Content Type设计器和List Template设计器,有了这些设计器的帮助,开发人员终于可以方便快捷的在自己的项目中添加内容类型和列表模板了,不再需要折腾让人头疼的CAML。

在刚刚装上Visual Studio 11,并体验了它内置的Content Type设计器与List Template设计器之后,笔者立马对其“一见钟情”,第一个想法就是马上开始使用Visual Studio 11开发接下来的SharePoint 11程序。但随即发现这个想法暂时似乎行不通,首先,Visual Studio 11仅仅在Developer Preview阶段,稳定性恐怕很成问题,另外,笔者在Visual Studio 2011中使用了不少协助开发SharePoint应用程序的各种插件,这些插件恐怕还没法在Visual Studio 11中使用。最后也是最重要的一个理由,大部分项目都是需要和团队中的其他人协作开发的,在其他人都在使用Visual Studio 2010的情况下,笔者恐怕没法一个人独自使用Visual Studio 11。

所幸Visual Studio 11内置了一个非常cool的特性,那就是它能向下兼容Visual Studio 2010的解决方案和项目文件,也就是说,如果使用Visual Studio 2010所创建的项目,当使用Visual Studio 11打开、编辑并保存后,仍然可以继续使用Visual Studio 2010打开,再对项目进行后续的编辑。这个特性需要Visual Studio 2010 SP1的支持。

首先,在Visual Studio 2010中新建一个SharePoint 2010项目。

image

使用Visual Studio 11打开这个项目,然后向项目中添加一个Content Type。

image

然后,就可以使用Content Type设计器来直接设计这个内容类型了。

image

对于每个Field,都可以直接通过Property窗口对它进行定制。

image

将项目保存,然后重新使用Visual Studio 2010打开这个项目,会发现没有任何问题。对于在Visual Studio 11中添加的SharePoint Project Item,同样可以双击打开再进行修改,当然,没法使用设计器了,只能直接修改其CAML。

image

有了Visual Studio 11的这个向后兼容新特性,SharePoint开发人员确实可以充分利用Visual Studio 2010和11这两个版本,同时使用两者来开发一个SharePoint 2010应用程序。

 

Posted by on 2011/12/13 in 未分类

Leave a comment

Some tips about crawling large external data with bcs connector

为了让SharePoint的搜索组件能够检索外部内容源(外部的数据库、业务系统、二进制文件等等等等),通常需要创建一个自定义的Indexing Connector。Indexing Connector是一种基于SharePoint 2010中的Business Connectivity ServicesSearch Connector Framework的组件,它替代了以前的Protocol Handler,成为了SharePoint 2010(和FAST Search for SharePoint 2010)所支持的主要的外部数据爬网扩展方式。(SharePoint 2010仍然支持自定义的Protocol Handler。)

在通过BCS的方式创建一个Connector之后,可能面临的问题之一,就是需要使用它去爬非常大的数据量。比如,几百万甚至上千万的数据项。如果Connector需要面对这样的挑战,那么就需要小心的设计Connector。

首先,Connector需要能够良好的支持增量爬网。你肯定不希望在增量爬网的速度和完全爬网一样。

Connector可以以两种方式来支持增量爬网:基于最后修改时间(Timestamp-based),和基于修改日志(Changelog-based)。基于最后修改时间也就是你需要指定一个日期时间字段,Crawler会将此字段作为数据项的最后修改时间,当增量爬网时,Crawler会通过比对这个数据,来知道自己是否需要对一个数据项重新进行处理。基于修改日志则是专门通过额外的方法,直接将某个时间之后新增、被修改、被删除的数据项,返回给搜索引擎,这样搜索引擎就直接知道了从上次爬网到现在,有哪些数据项需要重新处理。

如果外部内容源的数据量非常庞大,即使是第一次的完全爬网,也可能导致Crawler不能正常工作,或者导致外部内容源在短时间内承受过大的压力。

首先,慎重考虑是否直接使用一个Finder方法,来一次性的从外部内容源返回所有所需要的数据(类似于select * from db_table操作)。在小数据量的情况下,这样做很方便,但是如果数据量太大,这么做很可能是不合适的。

比较谨慎的做法,是仅仅使用IdEnumerator方法和SpecificFinder方法获取数据。IdEnumerator方法(类似于select id from db_table)可以返回数据项的ID,然后使用这些ID,重复调用SpecificFinder方法(类似于select * from db_table where id=@id),来一个一个的获取数据项。这时,你需要告诉Connector,这个IdEnumerator方法才是整个Entity的RootFinder。在大部分情况下,你甚至不需要去定义一个Finder方法,因为Crawler根本就不应该一次从外部内容源获取过多的数据。

image

如果数据量超大,甚至IdEnumerator方法的执行可能也是有问题的。想象一下,一次性从外部数据源返回所有几千万个数据项的ID。这个时候就需要更进一步,让IdEnumerator方法每次只返回特定数量(比如1000)的数据项ID。

我们可以为IdEnumerator方法定义一个类型为LastId的筛选器和对应的输入参数(即方向为In的Parameter),这样Crawler会尝试重复调用IdEnumerator方法,每次都将上一次调用后所得到的最后一个ID,作为参数传入。在IdEnumerator方法的实现代码中,就可以根据这个传入的参数,仅从外部内容源检索此ID之后的数据项ID。

image

image

Crawler会尝试以下面这种方式,来重复调用IdEnumerator方法,直到它返回0个结果项为止。(每次调用返回多少数据项,只取决于我们在IdEnumerator方法的实现代码里面返回了多少项。)

image

搜索引擎的Crawler有可能会多次调用SpecificFinder方法来获取同一个数据项(具体原因未知…),所以在Connector里面,可以考虑使用一些cache的技巧,来减少向外部内容源请求数据的次数。如果内容源的数据量很大,将所有数据都一股脑保存到内存里面并不是一个好主意。可以考虑使用HttpRuntime.Cache,虽然看起来它仅能用于Web程序,但实际上只需要在程序中引用System.Web这个程序集,在你的Connector里面使用它是没有问题的(注:微软MSDN文档中注明了它在非ASP.NET程序中可能无法正常工作,但似乎并不存在无法正常工作的情况,但我并不担保…)。这个Cache的实现已经内置了诸如自动清除、优先级设置、缓存时间设置等等功能,比自己写一个要方便很多。另外EntLib里面也有一个可以用于任意类型程序的Cache实现。

除了上面所说的这些之外,Eric Wang还贡献过一个idea。那就是,(按照他的观点,)一次性获取大量数据是没有问题的,如果真的碰到超大规模的数据,可以在搜索管理中创建多个内容源,每个内容源针对外部数据的一部分进行爬网。比如,如果外部数据有200万项,可以考虑创建4个内容源,每个内容源根据某种划分规则,获取并爬网其中的50万项数据。

 

Posted by on 2011/10/19 in 未分类

Leave a comment

为SharePoint搜索创建自定义优化参数

当我们使用SharePoint 2010所提供的搜索功能时,在搜索结果的左侧,有一个搜索结果优化区域。通过这个区域,用户可以进一步的精简搜索结果。比如,仅仅显示类型为Word文件的搜索结果,或者仅仅显示作者为“kaneboy”的搜索结果。

image

这个优化区域内置了最常见的几个精简项目,包括类型(搜索结果是何种类型)、来源(搜索结果来自于哪个网站)、作者、修改日期等。如果在文档管理系统中使用了SharePoint 2010新的托管元数据服务中的术语来定义了企业关键字,那么这些关键字也会自动出现在优化区域中。

除了内置的这些精简项目,管理员可以添加更多的额外精简项目。不过如果希望某个属性能作为一个精简项目,管理员需要首先将它定义为搜索服务中的托管属性。

比如,在文档系统中,我们定义了一个专门的字段,“技术等级”,来描述所有技术文档的难度。这个字段的内部名称是“TechLevel”。

image

首先,在SharePoint 2010搜索管理中对所有内容进行一次完全爬网。如果爬网引擎发现了爬网内容有一个额外的字段,它会将这个字段作为已爬网属性存储到搜索数据库中。

接下来,我们需要将这个已爬网属性定义为托管属性。从SharePoint 2010管理中心里面,通过“管理服务应用程序 – Search Service Application – 元数据属性”,就打开了元数据属性管理界面。点击“新建托管属性”。

为新托管属性取名为“TechLevel”,然后,我们需要将它与已经存在的那个已爬网属性关联起来。点击“添加映射”按钮,然后搜索“TechLevel”(因为这是那个字段的内部名称),找到这个已爬网属性。将它与新托管属性建立起映射。

image

最后这个新托管属性的定义如下。

image

定义好了托管属性之后,对内容源进行第二次完全爬网!这是完全必要、不可或缺的,否则,内容的这个托管属性中将不会包含任何有效的值。

完成第二次爬网之后,打开搜索结果页面,编辑此页面,找到页面上的“精简面板”Web部件,编辑它的属性。这个Web部件的作用就是显示页面上的优化区域。

image

展开这个Web部件属性中的“优化”区域,将“筛选器类别定义”中的内容全部复制出来。把“使用默认配置”选项清除,否则我们做的任何修改都不会生效。

image

随便找一个XML文本编辑器,按照下面的格式,创建一段XML文本。在下面的示例XML中,“MappedProperty”属性的值需要设置为托管属性的名称(TechLevel),“Title”属性决定了这个优化选项显示在页面左侧的抬头。

<Category Title=”技术等级”
Description=”文档的技术等级”
Type=”Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator”
MetadataThreshold=”1″
NumberOfFiltersToDisplay=”4″
MaxNumberOfFilters=”20″
SortBy=”Frequency”
SortDirection=”Descending”
SortByForMoreFilters=”Name”
SortDirectionForMoreFilters=”Ascending”
ShowMoreLink=”True”
MappedProperty=”TechLevel
MoreLinkText=”显示更多”
LessLinkText=”显示更少”/>

把上面的XML文本,插入到从Web部件属性面板“筛选器类别定义”中复制出来的XML文本里面,需要插入到“<FilterCategories>”这个节点里面。

image

然后将新的XML文本内容复制回Web部件属性面板“筛选器类别定义”文本框,确定即可。保存并刷新页面,就能看到大功告成了。

image

 

Posted by on 2011/09/23 in 未分类

1 Comment

如何“正确”为SharePoint字段命名

当大家需要扩展一个SharePoint列表/文档库的数据结构时,就会为列表/文档库创建新的字段(栏)。不管是直接为列表/文档库新建字段,还是在网站集里面创建网站栏,作为管理员,最好使用一些“最佳实践”来为字段命名。使用正确的字段名,在未来的配置、管理、开发过程中,都可以节省很多的时间和精力。

每个SharePoint字段实际上有两个名称,一个是“标题”(Title,有时候也把它叫做“显示名称”),一个是“内部名称”(Internal Name)。平时用户在列表视图界面上看到的,都是字段的标题。字段的内部名称可以看作是字段的唯一标识。如果你曾经使用SharePoint对象模型,通过代码从列表中获取数据,那么对“内部名称”这个概念一定很熟悉。基本上,SharePoint对“内部名称”的格式有非常严格的要求,它只能由英文字母、数字和下划线字组成,且不能包含空格。但是“标题”则没有这么多限制,通常我们会使用中文作为字段的“标题”,而且“标题”中很可能会包含空格。当一个字段被创建之后,它的“内部名称”就被固定下来了,但是“标题”则可以在之后被随时修改。

var list = site.Lists[“任务”];
var titleField = list.Fields.GetFieldByInternalName(“Title”); // 使用字段的内部名称来获取一个字段
var statusField = list.Fields.GetField(“状态”); // 使用字段的标题来获取一个字段,注意,GetField()会先尝试内部名称,然后再尝试使用标题进行查找

怎么知道一个字段的内部名称呢?最简单的方法就是对一个字段进行编辑,然后观察浏览器地址栏中的URL地址。比如,当我们编辑“状态”字段时,在地址栏就能看到一个“Field=Status”参数,这表示“状态”字段的内部名称是“Status”。

image

当我们在Visual Studio 2010中开发SharePoint应用程序时,也可以通过VS内置的SharePoint Explorer来查看一个字段的详细信息。在VS2010的“服务器资源管理器”中点击“添加SharePoint连接”,就能打开一个SharePoint网站。

image

通过展开列表节点,就能直接查看列表的所有字段,以及字段的各种属性。内部名称这个属性也能直接看到。

image

但是当管理员创建一个字段时,在页面UI上并不能分别输入新字段的标题和内部名称。在新建字段的界面上,只有一个“栏名”文本框。

image

SharePoint系统会使用管理员输入在“栏名”文本框内的内容作为新字段的标题,然后根据这个标题,调用System.Xml.XmlConvert.Encode()方法,来将标题自动转换成内部名称。这样,才能让转换后的内部名称符合SharePoint对内部名称命名的规范。

比如,如果管理员使用页面UI创建一个标题为“Live ID”的字段,这个字段的内部名称会被自动命名为“Live_x0020_ID”。如果管理员创建一个标题为“技术等级”的字段,它的内部名称将是“_x6280__x672f__x7b49__x7ea7_”。

但是这种自动转换后的内部名称的格式非常不好看,也不易记忆。实际上,管理员应该始终使用一个符合内部名称规范的名称,来创建字段,这样这个新字段的内部名称和标题都相同。然后,管理员再回过头去修改这个字段,将其标题修改为更符合用户习惯的名字。由于内部名称一旦确定就不再更改,所以字段的内部名称将始终保持为初始值。

比如,我们要创建一个“技术等级”字段。最好的方法,是使用“TechLevel”为名,来新建一个字段。

image

这时,这个字段的标题,和内部名称,都将是“TechLevel”。

image

然后,在界面上将这个字段名称修改为“技术等级”。这样,用户将看到这个字段的名字叫做“技术等级”,但由于字段的内部名称会始终保持原始值,所以这个字段的内部名称仍然为“TechLevel”。

image

如果我们要在代码里面创建新字段,也应该使用类似的方法。

image

为字段命名一个好记、易识别的内部名称,无论是在我们的自定义代码中,还是在SharePoint Search里面,都要或得更好的便利性。

 

Posted by on 2011/09/23 in 未分类

Leave a comment

在SharePoint 2010程序中使用Session

很多开发人员喜欢在ASP.NET程序中使用Session,用它来记录当前登录用户的一些信息。但是在SharePoint 2010系统中,默认是禁用Session功能的。如果在一个应用程序中使用了Session,你很可能会发现代码会抛出一个“引用的对象没有实例化”异常。如果通过Visual Studio调试一下代码,就能发现HttpContext.Session属性返回的是null。

image

要在一个SharePoint 2010程序中使用Session,开发人员会面临一些潜在的问题。SharePoint 2010系统很可能被部署为一个服务器场的模式,它可能包含有多台Web前端服务器,用户的Http请求会被NLB机制分发到多台Web前端服务器的任意一台上。这就要求开发人员应该尽可能的编写出“无状态”的代码,也就是说,代码不能依赖于某一台具体的服务器,因为开发人员没有办法确定自己的代码会始终运行在一个服务器上。有可能一个用户浏览一个页面时,它的请求被分配到Web服务器A,然后当用户刷新一下页面,这次请求则被分配到了Web服务器B。

在这样的服务器场模型中,代码在服务器的内存里面保存的任何数据,都会随着下次用户刷新后,处理用户请求的服务器转移,而变得没有意义。这也是编写大规模分布应用代码的一个很典型的挑战。

当编写有可能运行在服务器场中的分布式应用时,通常都会引入一个专门的分布式数据存储或分布式缓存方案。比如说,有名的Memcached就是专门干这事儿的。

好吧,稍微扯远了一点。无论如何,SharePoint 2010由于某种原因,默认禁止在代码中使用Session。禁止的理由很可能是为了预防开发人员写出过于依赖Session的“有状态”代码,因为ASP.NET的Session默认是保存在服务器的内存中。一旦这些代码被部署到分布式服务器场环境中,它们就很可能由于依赖仅仅存储在某一台服务器内存中的Session数据而出错。

“你就别忽悠了,不要以为我们不知道ASP.NET的Session除了默认的InProc模式,还支持StateServer和SQLServer模式!”嗯,是的,ASP.NET的Session其实是可以配置成StateServer和SQLServer模式。StateServer模式是使用一台特定服务器上的一个Session State服务,来为服务器场中的所有服务器提供状态保存服务,SQLServer模式则是将所有状态信息保存到SQL Server数据库中。这两个模式都是能够很好的支持分布式服务器场模型的。

所以,对于喜欢在代码中使用Session的同学而言,我们可以大胆的通过修改Web应用程序的web.config文件,手工启用Session。不过,稍等,SharePoint 2010其实已经内置了一个PowerShell指令,让我们轻松的在服务器场里面启用Session。这个指令就是Enable-SPSessionStateService。

image

如上图所示,打开SharePoint 2010 Management Shell,输入如上指令,就可以在SharePoint配置数据库所在的SQL Server服务器上,自动创建一个名为“SharePoint_Session_State”的数据库,然后在所有Web应用程序的web.config中自动添加相应的条目。

image

这个自动添加的条目,指明了Session将使用SQLServer模式以及存放Session的数据库连接字符串。打开SQL Server Management Studio,就能找到这个由Enable-SPSessionStateService自动创建的数据库,它仅包含2个Table。

image

Enable-SPSessionStateService还提供了几个其他的参数。-DefaultProvision参数表示将直接使用SharePoint系统现有的配置数据库(默认就是SharePoint_Config)作为存放Session数据的数据库,而不再使用专门的数据库(我非常不推荐这个做法)。-DatabaseServer和-DatabaseCredentials则可以指定使用自定义的数据库服务器(而不是默认的放置配置数据库的那个服务器)和数据库连接帐户。

如果需要做一个反向操作,即在服务器场禁止Session的使用,可以使用Disable-SPSessionStateService指令。

 

Posted by on 2011/08/07 in 未分类

Leave a comment

Tags:

关于SharePoint 2010 SP1

如果你想要为你的SharePoint 2010服务器场安装SP1,相信本文可以提供一些重要的指导。

首先,在真正动手之前,建议你阅读下面这几篇blog:

 

下面是所有与SharePoint系统相关的产品(与组件)的SP1补丁包的下载地址,以及其所对应的KB文章。


程序包名称 如何获取该程序包 知识库文章
Microsoft SharePoint Server 2010 Service Pack 1

下载

立即下载 64 位程序包。

2460045  SharePoint Server 2010 SP1 说明
Microsoft SharePoint 和 Project Server 2010 Service Pack 1

下载

立即下载 64 位程序包。

2460047  Project Server 2010 SP1 说明
Microsoft Office Web Apps Service Pack 1

下载

立即下载 64 位程序包。

2460073  Office Web Apps SP1 说明
Microsoft Search Server 2010 Service Pack 1

下载

立即下载 64 位程序包。

2460070  Search Server 2010 SP1 说明
Microsoft FAST Search Server 2010 for SharePoint Service Pack 1

下载

立即下载 64 位程序包。

2460039  FAST Search Server 2010 for SharePoint SP1 说明
Microsoft Groove Server 2010 Service Pack 1

下载

立即下载 64 位程序包。

2460067  Groove Server 2010 SP1 说明
Microsoft 2010 Server Language Pack Service Pack 1

下载

立即下载 64 位程序包。

2460056  Office Servers 2010 Language Pack SP1 说明
Microsoft SharePoint Foundation 2010 Service Pack 1

下载

立即下载 64 位程序包。

2460058  SharePoint Foundation 2010 SP1 说明
Microsoft SharePoint Foundation 2010 Language Pack Service Pack 1

下载

立即下载 64 位程序包。

2460059  SharePoint Foundation 2010 Language Pack SP1 说明
Microsoft SharePoint 2010 Indexing Connector for Documentum Service Pack 1

下载

立即下载 64 位程序包。

2460054  SharePoint 2010 Indexing Connector for Documentum SP1 说明

 

对于一个比较标准的SharePoint Server 2010系统(即不包含Project Server、FAST Search for SharePoint,但包含Office Web Apps),基本的补丁包安装顺序如下:

  1. 安装SharePoint Foundation 2010 SP1
  2. 如果服务器场中额外安装了某种语言的语言包,安装对应语言的SharePoint Foundation 2010 Language Pack SP1
  3. 安装SharePoint Server 2010 SP1
  4. 如果服务器场中额外安装了某种语言的语言包,安装对应语言的SharePoint Server 2010 Language Pack SP1
  5. 安装Office Web Apps SP1
  6. 运行SharePoint 2010产品配置向导

 

之前曾经有些文档可能指出SharePoint Server SP1已经包含了SharePoint Foundation SP1,但为了统一补丁安装方式,TechNet仍然要求使用先安装SharePoint Foundation补丁,然后安装SharePoint Server补丁的方式,来完成整个补丁的安装过程。

如果你的SharePoint 2010系统中有多台服务器,那么在服务器上安装SP1的顺序如下:

  1. 在运行管理中心网站的应用服务器上安装所有SP1补丁包
  2. 在其他应用服务器上安装所有SP1补丁包
  3. 在所有Web前端服务器上安装所有SP1补丁包
  4. 在运行管理中心网站的应用服务器上运行SharePoint 2010产品配置向导
  5. 在其他应用服务器上运行SharePoint 2010产品配置向导
  6. 在所有Web前端服务器上运行SharePoint 2010产品配置向导

 

有些文章可能告诉你,建议在安装了SP1之后,马上安装June 2011 CU(2011年6月份积累更新包)。不要这样做!这是因为:

  • Service Pack与CU的测试等级、支持等级都是不一样的。对待CU,我们应该秉承更谨慎的态度。比如,June 2011 CU的一个已知问题就是,它有可能破坏SharePoint Server 2010系统中的Profile Service。
  • 实际上,今天微软已经“召回”了June 2011 CU补丁包。

 

在我的SharePoint 2010系统中,在我安装完SP1,运行SharePoint 2010产品配置向导后,配置向导提示说它没有能够成功完成所有配置项。在升级Log文件中,我找到了如下错误信息:

无法在当前的 Active Directory 域中创建服务连接点。验证 SharePoint 容器是否存在于当前域中并验证您是否具有向其写入的权限。
Microsoft.SharePoint.SPException: 目录中不存在对象 LDAP://CN=Microsoft SharePoint Products,CN=System,DC=contoso,DC=com。

根据我的推测,产生这个错误的原因是在我的SharePoint 2010系统所在的Active Directory中,根本就没有一个名为“Microsoft SharePoint Products”的Container。我们可以在安装SP1之前,按照这篇文章的指导,手工在Active Directory中将这个Container创建出来。

但是这个错误,似乎并不会导致SharePoint 2010系统出现问题,因为在AD中通过创建服务连接点,跟踪企业内部所有部署的SharePoint系统,这个功能并不是必需的。在我的环境中,虽然产品配置向导提供了这个问题,但我的SharePoint 2010服务器场仍然成功的升级到了SP1版本,所有功能和内容也工作正常。

完成了SP1安装后,从SharePoint 2010管理中心中通过“查看产品和修补程序的安装状态”,应该能看到SharePoint Server 2010、Language Pack和Office Web Apps的各个组件的版本号变成14.0.6029.1000。

image

 

Posted by on 2011/07/11 in 未分类

Leave a comment

创建与SharePoint 2010风格一致的下拉菜单 (续) 整合Feature Custom Action框架

上一篇“创建与SharePoint 2010风格一致的下拉菜单”文章中,演示了如何添加一个额外的菜单到页面顶端,并使其的样式风格与SharePoint 2010内置的菜单保持一致。如果只需要创建一个子菜单项目固定的菜单,那么这篇文章里面的包含的内容已经足够了。但是如果在设计这个菜单的时候,我们并不确定需要向菜单中加入什么菜单项呢?

在SharePoint企业应用开发的过程中,有时候我们会希望能够创建一个可扩展的菜单。最开始的时候,开发人员在SharePoint网站页面的某个位置添加一个菜单,之后,就允许其他开发人员使用一种标准的扩展方式,先这个菜单中添加其他子菜单项。

实际上,SharePoint已经内置了一种这样的机制。如果你对Custom Action有了解,就应该知道,SharePoint开发人员可以通过在Feature中定义Custom Action,就可以向SharePoint内置的UI界面上添加额外的菜单项、按钮、Ribbon操作控件等等UI元素。是否可以让开发人员通过统一的Custom Action机制,向自定义的菜单中添加菜单项呢?答案是可以。

在创建自定义菜单的时候,除了添加MenuItemTemplate(表示菜单项)和SubMenuTemplate(表示二级菜单)之外,还可以添加FeatureMenuTemplate。FeatureMenuTemplate类似于定义了一个菜单占位符,并定义了这个菜单占位符的Location和Group ID。之后开发人员可以通过Custom Action,使用自定义的Location和Group ID,向这个菜单占位符中添加菜单项。

在下面的代码中,就添加了一个FeatureMenuTemplate,它的Location是“HP.ExtendedMenu”,Group ID是“TopToolsMenu”。

image

以后,其他开发人员就可以使用标准的SharePoint Feature框架中的Custom Action元素,来向这个位置添加想要的菜单项。如下面截图所示,我们定义了两个Custom Action,第一个是“About this Site”,第二个是“GetIT Support”。

image

将包含上面这两个Custom Action元素的Feature部署到SharePoint系统中,并在网站上激活后,就能看到它们会出现在我们想要它们出现的菜单中。

image

通过使用Feature Custom Action机制,我们就可以让自定义菜单具有更好的灵活性和扩展性。比如,在设计自定义母版页时,我们就可以将自定义菜单控件添加到母版页上,而开发人员可以在项目后续通过Custom Action机制向菜单中不断的添加所需的菜单项。

 

Posted by on 2011/06/26 in 未分类

Leave a comment

创建与SharePoint 2010风格一致的下拉菜单

在笔者公司中,SharePoint得到了大规模的使用。最近,在IT托管的SharePoint 2010系统中,页面最上方被统一加上了一个额外的区域,右上角放置了两个额外的下拉菜单。

image

这两个下拉菜单为用户提供了一些快捷链接,包括访问IT的Support网站、查看当前网站的信息,以及从系统中申请一个新的SharePoint网站等。

imageimage

从上面的截图可以看到,这两个定制的下拉菜单使用了SharePoint的内置风格,它们的样式与SharePoint 2010页面上的网站操作与欢迎菜单保持了一致。如果我们要在自己的应用中,创建这样一个与SharePoint 2010风格一致的下拉菜单,应该如何做呢?

要创建一个使用SharePoint内置风格的下拉菜单,可以创建一个自定义类,并让其继承自Microsoft.SharePoint.WebControls.ToolBarMenuButton类。通过调用父类所提供的各个属性与方法,我们的自定义类就可以为菜单添加自定义的菜单项。

在下面所示的代码中,从第18到28行,初始化了这个菜单的基本样式。基本上,我们会复用SharePoint 2010内置的CSS Class和图片。第19行通过将MenuTemplateControl.LargeIconMode属性指定为true,使得菜单以大图标模式进行展现。

第31行通过MenuControl.Text属性指定了这个下拉菜单所显示出来的文本内容。

image

接下来,我们开始向这个下拉菜单中添加子菜单项。添加子菜单项的方法有两种,第一种是直接调用父类所提供的AddMenuItem()方法。此方法的各个参数分别是:

  • id:指定一个唯一的ID号;
  • displayName:菜单项的标题文字;
  • imageUrl:菜单项的图标;
  • description:菜单项的描述文字;
  • navigateUrl:用户点击菜单项时,将用户导航到此路径;
  • onClickScript:用户点击菜单项时,执行指定的JavaScript脚本

image

第二种方法是先创建一个MenuItemTemplate对象,为它的各个属性赋值,然后将它添加到MenuTemplateControl.Controls集合里面。

image

要在下拉菜单中添加一个分割线,调用父类的AddMenuItemSeparator()方法。

image

如果想在下拉菜单中添加二级菜单,就需要先创建一个SubMenuTemplate对象,将它添加到MenuTemplateControl.Controls集合里面。然后一个一个的创建MenuItemTemplate对象,将它们添加到SubMenuTemplate对象的Controls集合中。

下面的代码创建了一个“Support”二级菜单,然后向这个二级菜单添加了一个“GetIT”子菜单项。

image

最后要做的,就是将我们创建的这个自定义控件,放到页面上去。根据我们想要放置的地方的不同,可以有不同的方式。比如,可以修改(或创建一个新的)母版页。

通过上面的示范代码最后创建出来的下拉菜单的呈现效果,如下图所示。在下图中,笔者将这个额外的菜单,放到了页面的用户欢迎菜单的左侧。

image

在下一篇文章中,我将讲述如何让我们创建的自定义菜单,能够和SharePoint Feature框架中的Custom Action整合在一起。也就是说,网站开发人员可以使用Custom Action,直接向我们所创建的自定义菜单中添加子菜单项,就如同向“网站操作”菜单中添加子菜单项那样。通过这样的整合,我们的自定义菜单将具有更好的灵活性和可扩展性。

 

Posted by on 2011/06/21 in 未分类

1 Comment