一般来说,我们的代码如果需要运行在SharePoint Foundation上面,在SharePoint Foundation的环境中开发是最方便的;如果需要运行在SharePoint Server上面,在SharePoint Server的环境中开发是最方便的。如果我们的代码需要同时兼容SharePoint Server和Foundation的话,我们应该在SharePoint Server上进行开发,想要代码运行在SharePoint Foundation平台上,要额外考虑几个问题。
首先就是判断当前SharePoint是Server版本还是Foundation版本的。最精确的判断方法是检查注册表中的SharePoint产品ID,可以参考这篇文章
但是查注册表比较麻烦,简单的方法是可以直接从代码获得当前SharePoint的product id,然后在产品的ID列表中查找就好了,以下是代码:
bool IsSharePointServer(){
// B2C0B444-3914-4ACB-A0B8-7CF50A8F7AA0 : SharePoint Server 2010 Standard Trial
// 3FDFBCC8-B3E4-4482-91FA-122C6432805C : SharePoint Server 2010 Standard
// 88BED06D-8C6B-4E62-AB01-546D6005FE97 : SharePoint Server 2010 Enterprise Trial
// D5595F62-449B-4061-B0B2-0CBAD410BB51 : SharePoint Server 2010 Enterprise
Guid[] serverGuids = { new Guid("B2C0B444-3914-4ACB-A0B8-7CF50A8F7AA0"),
new Guid("3FDFBCC8-B3E4-4482-91FA-122C6432805C"),
new Guid("88BED06D-8C6B-4E62-AB01-546D6005FE97"),
new Guid("D5595F62-449B-4061-B0B2-0CBAD410BB51") };
// If a Server ID cannot be detected we are running on Foundation.
bool isServer = SPFarm.Local.Products.Any(productGuid => serverGuids.Contains(productGuid));
return isServer
}
这个方法优点是非常精确,缺点是比较麻烦,需要查找SharePoint产品的ID,如果既支持2010,又要支持2013,就要查不同的产品ID,写不同的代码。
第二个判断当前SharePoint是Server版本还是Foundation版本的方法是查找Farm中的feature定义,有些feature是Server中存在而Foundation中不存在的。例如有个Publishing feature。因此可以通过判断这个feature是否存在来判断是Server版本还是Foundation版本。这个方法的优点是简单,而且不论SharePoint 2010还是2013,都可以用。但是不保证后面的版本比如出了2015,会不会把这个feature加到Foundation中,因此保险的做法是多判断几个Foundation中没有的feature,以下是代码(使用了Publishing和TemplateDiscovery这两个feature):
bool IsSharePointServer(){
bool isServer = false;
SPFeatureDefinitionCollection features = SPFarm.Local.FeatureDefinitions;
if (features["Publishing"] != null && features["TemplateDiscovery"] != null)
{
isServer= true;
}
return isServer;
}
第二个需要考虑的问题就是一些程序集是只有Server版本上才有的,例如支持Metadata的程序集Microsoft.SharePoint.Taxonomy,在Foundation中是找不到的,但是这并不影响开发,因为我们在Server上开发,所以VS可以引用这个程序集,也可以正常使用其中的类,编译也没有问题。问题在于,这样写出来的代码,在Foundation上运行会出现无法找到dll的错误,导致代码无法使用。解决的办法就是,在写代码的时候,需要判断当前的SharePoint是Server版本还是Foundation版本的,如果是Foundation版本,就不要运行这类代码,举个例子:
void DoSomethingOnBothServerAndFoundation()
{
if(IsSharePointServer())
{
//Server
TaxonomyField taxField = ...; //TaxonomyField是在Microsoft.SharePoint.Taxonomy.dll中定义的,这里需要加载程序集
}
else
{
//Foundation
...
}
}
写好这样的代码之后,编译部署,在Server上运行,都没有问题,但是放到Foundation上运行,还是会报出无法找到dll的错误(An exception has occurred. ExceptionType: 'FileNotFoundException' ExceptionMessage: 'Could not load file or assembly 'Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. The system cannot find the file specified.')。原因在于运行时,JIT在编译一个方法的时候,它会载入这个方法中引用的所有类型所在的程序集。因此JIT在编译这个方法的时候,不论代码中有没有判断当前的SharePoint是Server还是Foundation,都会去载入Microsoft.SharePoint.Taxonomy程序集,因此在Foundation上运行失败。解决办法是针对不同的平台写不同的方法,在调用方法之前做判断。
void DoSomethingOnBothServerAndFoundation()
{
if(IsSharePointServer())
{
Method_Server();
}
else
{
Method_Foundation();
}
}
void Method_Server()
{
//Server
TaxonomyField taxField = ...; //TaxonomyField是在Microsoft.SharePoint.Taxonomy.dll中定义的,这里加载程序集
... ...
}
void Method_Foundation()
{
//Foundation
... ...
}
这样的话,方法“Method_Server()”在Foundation环境上就不会运行,JIT也不会试图加载Microsoft.SharePoint.Taxonomy.dll,也不会出错了,就可以正常的运行在Server和Foundation上了。