SharePoint高效编程技巧

刚统计了一下自己的sharepoint代码,发现代码数量也上六位数了,虽然大多是编译器自己生成的内容,但是自己也积累了一些东东,今天查阅新版的2010的SDK发现内部总结了一些,决定结合最佳实践,写一些自己的心得,或许这些心得已经有人写过,不过抒发一下自己的感想,希望大家看后能够有所启发,尽量写出忧患较少的代码,少埋地雷,为系统的稳定高速运行,建立一个好的代码基础,权当是抛砖引玉吧。  (1),关于匿名的调用和使用以及最高委托。   在开发当中不可避免的需要用到匿名用户来处理一些相关的操作,比如你在主页上,读取的信息,通知的,如果你的有些页面是开放匿名的,那么你执行在这些匿名页面上面的代码,就是以匿名方式运行的,当然,大部分时候我们原来喜欢利用最高委托来实现我们需要的效果,相当于,提升部分读取数据的代码域的权限,在执行完成以后,再回到匿名级别。代码很简单,如下:    SPSecurity.RunWithElevatedPrivileges(delegate()   {   using (SPSite site = new SPSite(SPContext.Current.Site.Url))   {   using (SPWeb web = site.RootWeb)   {  //在这里面执行你需要进行的操作。  }  }  }  });    在这种方式下,如果你尝试在匿名委托区里面获取当前的用户,你会发现你得到的是网站集管理员的。    这种方式当然是在你可以控制的范围内的,并且的确可以解决我上面所说的问题,但是你可否想过,如果你在一个IIS的工作进程当中调用sharepoint的对象模型,那么执行的用户又会是什么呢?这里给出一段SDK中的代码,很好的解释了在windown api层次,对windows模拟的用户的测试。    // This sample demonstrates the use of the WindowsIdentity class to impersonate a user.  // IMPORTANT NOTES:  // This sample requests the user to enter a password on the console screen.  // Because the console window does not support methods allowing the password to be masked,  // it will be visible to anyone viewing the screen.  // On Windows Vista and later this sample must be run as an administrator.       using System;  using System.Runtime.InteropServices;  using System.Security.Principal;  using System.Security.Permissions;  using Microsoft.Win32.SafeHandles;  using System.Runtime.ConstrainedExecution;  using System.Security;      public class ImpersonationDemo  {   [DllImport(“advapi32.dll”, SetLastError = true, CharSet = CharSet.Unicode)]   public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,   int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);     [DllImport(“kernel32.dll”, CharSet = CharSet.Auto)]   public extern static bool CloseHandle(IntPtr handle);     // Test harness.   // If you incorporate this code into a DLL, be sure to demand FullTrust.   [PermissionSetAttribute(SecurityAction.Demand, Name = “FullTrust”)]   public static void Main(string[] args)   {   SafeTokenHandle safeTokenHandle;   try   {   string userName, domainName;   // Get the user token for the specified user, domain, and password using the   // unmanaged LogonUser method.   // The local machine name can be used for the domain name to impersonate a user on this machine.   Console.Write(“Enter the name of the domain on which to log on: “);   domainName = Console.ReadLine();     Console.Write(“Enter the login of a user on {0} that you wish to impersonate: “, domainName);   userName = Console.ReadLine();     Console.Write(“Enter the password for {0}: “, userName);     const int LOGON32_PROVIDER_DEFAULT = 0;   //This parameter causes LogonUser to create a primary token.   const int LOGON32_LOGON_INTERACTIVE = 2;     // Call LogonUser to obtain a handle to an access token.   bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),   LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,   out safeTokenHandle);     Console.WriteLine(“LogonUser called.”);     if (false == returnValue)   {   int ret = Marshal.GetLastWin32Error();   Console.WriteLine(“LogonUser failed with error code : {0}”, ret);   throw new System.ComponentModel.Win32Exception(ret);   }   using (safeTokenHandle)   {   Console.WriteLine(“Did LogonUser Succeed? ” + (returnValue ? “Yes” : “No”));   Console.WriteLine(“Value of Windows NT token: ” + safeTokenHandle);     // Check the identity.   Console.WriteLine(“Before impersonation: “   + WindowsIdentity.GetCurrent().Name);   // Use the token handle returned by LogonUser.   using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(safeTokenHandle.DangerousGetHandle()))   {     // Check the identity.   Console.WriteLine(“After impersonation: “   + WindowsIdentity.GetCurrent().Name);   }   // Releasing the context object stops the impersonation   // Check the identity.   Console.WriteLine(“After closing the context: ” + WindowsIdentity.GetCurrent().Name);   }   }   catch (Exception ex)   {   Console.WriteLine(“Exception occurred. ” + ex.Message);   }     }  }  public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid  {   private SafeTokenHandle()   : base(true)   {   }     [DllImport(“kernel32.dll”)]   [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]   [SuppressUnmanagedCodeSecurity]   [return: MarshalAs(UnmanagedType.Bool)]   private static extern bool CloseHandle(IntPtr handle);     protected override bool ReleaseHandle()   {   return CloseHandle(handle);   }  }  (2),避免重复的构造SPWeb, SPSite这些大对象  我们在写一些测试的程序片段的时候,我们会发现,当我们用在new SPSite的时候,硬盘会一阵狂响,然后w3wp.exe进程就开始吃进内存,有些时候new SPSite大对象必要,有些时候却是没有必要,大家大可在上下文存在的情况下,调用类似如下的方法,从上下文当中,取出这些已经建立好的对象的句柄,然后就可以直接进行使用。  SPWebApplication webApplication = SPWebApplication.Lookup(new Uri(“http://localhost/”);  SPFarm farm = webApplication.Farm;  SPContentDatabase content = webApplication.ContentDatabases[0];    上面取出了应用程序,场,以及内容数据库对应的大对象的句柄,那么对SPSite和SPWeb的取,就不再是问题,具体的可以参看SDK里面这几个类。  这里要强调一下在我们常用的eventhandler里面的的一些和这些大对象的代码。  实际上我们的eventhander在系统当中,是被堆到spv3timer里面来进行处理的,相当于我们每一次对item的操作,其触发的事件,是在后台进行执行的,那么他所操作的代码,就不是在前端进程里面进程处理,所以我们对其中的一些处理就可以优化如下  原始的非常不效率的写法(在eventHandler中):  using (SPSite site = new SPSite(properties.WebUrl))   {   using (SPWeb web = site.OpenWeb())   {   SPList list = web.Lists[properties.ListId];   SPListItem item = list.GetItemByUniqueId(properties.ListItemId);   // Operate on an item.   }   }    改进后的写法:  // Retrieve SPWeb and SPListItem from SPItemEventProperties instead of  // from a new instance of SPSite.  SPWeb web = properties.OpenWeb();  // Operate on the SPWeb object.  SPListItem item = properties.ListItem;  // Operate on an item.    (3)大对象的销毁,销毁,还是销毁    我们知

道,我们可以借助using 来控制对象的作用域,当然,前提是这个对象是继承与IDispose接口,所以我们非常常用的几个大对象,也就大多采用using 的方式来进行使用,当然我们也可以用类似于C++里面的写法,手工的在finally里面进行对象的销毁处理。  做法一:是我们大家一般使用的标准做法,没问题。  using(SPSite oSPsite = new SPSite(“http://server”))  {   using(SPWeb oSPWeb = oSPSite.OpenWeb())   {   str = oSPWeb.Title;   str = oSPWeb.Url;   }  }  做法二:  大家可以看出,在一个里面我们不但new spite还有web ,而域控制的只是web,那么site肯定是溢出了。非常垃圾的写法,  void CombiningCallsLeak()  {   using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())   {   // … New SPSite will be leaked.   } // SPWeb object web.Dispose() automatically called.  }    做法三:  还有这种直接不new就引用上下文的句柄的方式,也是非常致命的,因为他的代码一执行完,上下文的web就被销毁,系统自身的肯定还需要进行一些操作,所以这种写法必然是在代码跑完不出异常,然后页面就莫名奇妙的出错,当然,你如果RP十分好的话,也可能这种问题不出现。  using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { … }    最佳的using做法:  void CombiningCallsBestPractice()  {   using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))   using (SPWeb web = siteCollection.OpenWeb())   {   // Perform operations on site.   } // SPWeb object web.Dispose() automatically called; SPSite object    // siteCollection.Dispose() automatically called.  }    最佳的try catch手工做法  SPSite oSPSite = null;  SPWeb oSPWeb = null;    try  {   oSPSite = new SPSite(“http://server”);   oSPWeb = oSPSite.OpenWeb(..);     str = oSPWeb.Title;  }  catch(Exception e)  {   // Handle exception, log exception, etc.  }  finally  {   if (oSPWeb != null)   oSPWeb.Dispose();     if (oSPSite != null)   oSPSite.Dispose();  }    (4),关于大容量的list的处理  对于SPList列表库,在数量超过5k以后,性能就开始急剧衰减的问题,其实很多地方都谈过,衰减的主要体现是在遍历所有item的情况下出现的,对于插入和删除的操作,没有什么影响,曾经写过一个程序来测试一百万条数据的检索和查询,在配置了个别列的索引,仍旧没有根本的改变,现在主要说一下主要推荐采用的方式,query,可以基本上忽略条数的限制,缺点就是对于一些自定义列的查询比较无力,在2010版本里面,提供了可以直连sql的list,从根本上解决了大容量的条目的问题。  下面是典型的query代码    SPQuery query = new SPQuery();  SPListItemCollection spListItems ;   string lastItemIdOnPage = null; // Page position.  int itemCount = 2000     while (itemCount == 2000)  {   // Include only the fields you will use.   query.ViewFields = “”;    query.RowLimit = 2000; // Only select the top 2000.   // Include items in a subfolder (if necessary).   query.ViewAttributes = “Scope=”Recursive””;   StringBuilder sb = new StringBuilder();   // To make the query order by ID and stop scanning the table, specify the OrderBy override attribute.   sb.Append(“”);   //.. Append more text as necessary ..   query.Query = sb.ToString();   // Get 2,000 more items.      SPListItemCollectionPosition pos = new SPListItemCollectionPosition(lastItemIdOnPage);   query.ListItemCollectionPosition = pos; //Page info.   spListItems = spList.GetItems(query);   lastItemIdOnPage = spListItems.ListItemCollectionPosition.PagingInfo;   // Code to enumerate the spListItems.   // If itemCount    itemCount = spListItems.Count;    }    (5),关于对象的cache的问题。   在企业级别的应用当中,由于对象模型本身的速度限制,不得不采用一些缓存的方式来提升整体的性能,在小容量数据的存储时,我们一般采用static变量来处理,并且自己维护一个缓存的队列,来解决,但是大部分的页面应用当中,我们采用cache来进行处理,有些时候大家可能忽略一些线程上面的问题,在大量用户同时访问页面,并且对一群对象进行update操作的时候,有能造成拥堵,大家都知道asp.net是线程安全的,同样,我们的update操作也是,如果用户操作量比较大,那么update就要在不用的用户线程之间进行切换,所以在这里建议采用下面的方式来进行:  public void CacheData()  {   SPListItemCollection oListItems;     lock(_lock)    {   oListItems = (SPListItemCollection)Cache[“ListItemCacheName”];   if(oListItems == null)   {   oListItems = DoQueryToReturnItems();   Cache.Add(“ListItemCacheName”, oListItems, ..);   }   }  }

Sharepoint里面的自定义类型字段

你用百度或者google搜索一下,肯定显示出来的东西一大堆,然后你就会发现,其中有90%是雷同或者是完全照抄,然后你再看中文版本的东西,然后用英文搜索之,最后发现中文里面大多有价值的东西都是英文直接照抄翻译过来的,比较有水平的技术人员一般都写上了原英文名的出处和作者,而大多只是翻译过来,稍加修改,然后就打上了自己的名字,最后你根据文章做起来,错误百出,而且大多数解决办法还得靠英文原文或者下面的问题回答来解决,这是最早在技术论坛里面的看blog的感觉。当然,目前也有这种感觉,所以有些牛人就说,你要看学技术,别学着忽悠翻译和转载,理解才是王道。
谨记教诲,东西只有自己消化了的,才是自己的。
说起内容类型,一般只要是SharePoint的初级介绍文章,都会有所涉及,大意是这样:SharePoint用来扩展现有的字段类型不足,为开发人员预留的扩展接口。要自己做一个自定义类型字段,其实不难,用VS里面的SharePoint模板就可以迅速建立一个起来。当然,详细的分来,自定义类型字段,也就是CustomerField里面大致有这么几个组成部分。
1,域的值:我们知道,每一个字段里面都存储着一堆的值,而这些值是什么样子的?就是用这个类来进行描述的,比如说:一个SPFieldLookup的值类,就是SPFieldLookupValue。具体的可以在WSS3.0的SDK里面查到,只要搜索SPField就可以看到系统目前定义的所有SPField。当然,你要是怕麻烦,也可以写一小段的代码来实现,以下代码列出的当前的web下的所有的内容类型的SPField类型,以及其对应的value的类型。

using (SPSite site = new SPSite(strSiteUrl))
{
foreach (SPField fi in site.RootWeb.Fields)
{
Console.WriteLine("域标题:" + fi.Title.ToString());
Console.WriteLine("域名称:" + fi.InternalName.ToString());
Console.WriteLine("域类型:" + fi.GetType().ToString());
if (fi.FieldValueType != null)
{
Console.WriteLine("域对应的值类型:" + fi.FieldValueType.FullName);
}
Console.WriteLine("------");
}
}

这里还需要注意的一个问题是重写FieldValue的时候,如果是重写的多行的Field的Value,那么值里面的属性顺序是用0开始,逐个递增,构造函数里面要给进数量,调用基类来构造。
2,域的本体:这里就决定了你的域的名字,从哪个基类集成过来,以及你的域的基础性质,只要是SPField的域,一般都可以继承过来重写,然后加以使用,SharePoint同样也提供了专门用来扩展的基类型,具体的可以查SDK得到。这里还需要注意的地方是有一个特殊的SPFieldMultiColumn 是系统专门预留给编程人员使用的扩展接口,里面内容实际上是多值的,而且值是以;#分割的。十分类似于查阅项里面的多值的情况。
3,域在使用时的展现(可带ascx):一般这里都继承于BaseFieldControl,继承下来的这个Control可以当作一个十分类似于WebPart的Control来处理,不过这里需要注意的是,怎样把你在控件里面设定的值,和域本体里面的值进行存取的交互。换句话说,这个Control只是用来便于展现和设定你的Field的值,真实的值还是转化以后存储到了你的Field里面,而不是控件模板里面。
所以这里有一个十分重要的需要重写的属性Value,用来存和取你的数据。还有一个是DefaultTemplateName这个属性,用来定位你的asx的模板的。这里在展现的时候用的ascx控件模板,会用到一个特殊的类型,所有的控件都是放到这个节里面的,并且在后台里面根据控件的ID来取控件的句柄。
4,域在设定时的展现(可带ascx):调用机制比较复杂,负责联动前台的展示界面,以及后台设定的保存,数据的读取,所有的设定都是保存到Field本体里面,所以这里需要和Field本体有一个交互,最重要的函数应该是
public void OnSaveChange(SPField field, bool isNew) 所有在你控件里面设定好的值,都通过这个函数进行存储。
当然,在一开始对预存的值进行读取的操作也是必不可少的,函数采用的是
public void InitializeWithField(SPField field)
这里输入的参数相当于你当前设定的field的句柄,使用的时候用as转化为你定义的域类型就可以了。
在域设定的页面里面,同样采用的是模板的ascx,只是引用的模板不一样而已,具体的可以参看页面的代码。
5,域的定义:这里又是一个头疼的xml,一堆的属性,用来描述你的Field,好让SharePoint能够正确的识别,比较重要的有这么几个节

SharePoint2010SDK研究笔记

2010已然上市有一段时间了,但是本着微软产品的测试小白鼠精神,在去年就装了个RTM版本的,后来又开始陆续更新,自己起了个开发环境,写了两个demo,然后开始回头来,继续看SDK,因为所有有价值的资源,都基本来自SDK,原有组里的一个人就被拉去做SDK了,感觉2010的server08 sql08的绑定,直接制约了其本身的推广和使用,至少在用windows体系的产品,大多已然颇有微词,各种补丁,系统的稳定性,在客户没有成熟案例的时候,果然是不敢采用的。而且原有解决方案的升级,也是个比较严重的问题,曾经自己尝试过将自己07工程转化为10的SharePoint工程,各种失败和错误,而我自己用Stsdev的方案程序集却没有任何问题,所以过渡这个过程,必然是痛苦的,当然微软的哥们也在不断的完善和弥补。
   2010所带来的一些新的特性,的确是简化了开发,把开发变得更加傻瓜化,但是傻瓜化的过程当中,必然就有更多的制约,所以在扩展性和易用性之间要找到一个比较好的平衡点,还真是一个比较麻烦的过程。
   发了那么多的牢骚,在历经多次重做虚拟机以后,终于把sharepoint2010以及一堆乱七八糟的补丁给搞上了,下面开始从SDK的介绍顺序,来介绍自己所看到的一些新的特性。
  1,增强了的移动模块功能:
  手机和移动设备逐渐占据web这个不争的事实,已经然广大的厂商开放更多的兼容软件到移动争霸的版图内,其实在07中,对移动设备就有一定的支持,至不过功能十分有限,而且扩展十分麻烦,但是现在10增加的mobile特性,增色不少。
  (1),移动短信
  这个功能咋一看就是发个短信和通知,因为原有的ocs产品和outlook产品,已然能很好的支持消息和邮件的提醒了,这次专门提供了一个重写的SPAlert类,和一堆接口来兼容不同协议的sms和为手机发送短信的功能。当然,微软已然不忘深度集成了自己Outlook Message Service (OMS) protocol。其实原有的通知完全是在事件和代码里面来触发自己的短信发送的内容,此举虽然比较麻烦,但是定制性比较好,对接口依赖性都比较小,也能比较好的适应用户的需求,加了这个接口,除了代码好看一些以外,个人感觉没有什么实质性的用处。因为并发和队列的问题,瓶颈仍然在自己的短信接口处,而不在sharepoint.
  (2),mobile适配webpart
  这是一个非常牛逼的功能,遥想原来我们要做一个移动的页面,得自己收工修改系统默认的移动页面,而且还得为这个页面开发专门的webpart,相当于重写了自己的webpart,核心功能没有多少改变,还是在界面上折腾,用于适配不同的手机浏览器。当然,如果自己本身的程序对html4.0的支持不好的话,注定会非常的悲剧。而mobile的webpart适配特性,比较好的解决了这个问题,我们至于要在原有的webpart当中,增加对手机的重载就可以了,这在很大程序上解决了原来重复写两个webpart的问题。不过现在移动web在企业内的应用才开始逐步兴起,主流的门户,社交,b2b,的移动门户也都开始逐渐成熟。要大规模应用还需时日,当然,企业内部人手一个ipad+iphone,那么我们的应用都要做兼容,做第一批吃螃蟹人的还是比较爽的(虽然国内现在大多企业还没有脱离无纸办公,就让他们走入移动办公的时代,他们估计会崩溃的,其实还是体制,体制,还是体制问题)。
  (3)mobile文档查看器
  Word,pdf,xps,excel在网页上面直接的浏览,在web2.0后期就基本已经实现了,但是在手机上,大家要想直接打开word和pdf之类的文档,肯定还要借助于三方的工具,台式机采用的方式是装一个插件,转由客户端来处理已经下载的内容,但是移动设备的性能有限,不能一个浏览器占用很多的资源,就要求转化在服务器进行处理,所有的东西以html方式推送以获得广泛的适用性和兼容性(做移动浏览器可以不兼容某些控件,但是不可能不兼容html)。实际上也就是在服务端,把各种格式的文件转化推送为html的,office系列的文件格式目前依然不是问题,关键在于其他的格式,大家常见的百度文库,新浪的文库的做法,十分值得借鉴。这里moss就开放了一个注册,大家可以将自己的对某种类型的文件查看,跳转到自己的针对这种文件的查看的页面当中去,做法十分类似于httpHandler的截获处理的方式。不过这里更加简单,就是跳转到页面,而不是注册你的处理的dll,也让大家有更多的灵活性。
  下面这个例子就是注册xps的查看器
   FeatureId=”XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX” />

  这里是在注册对windows mobile系统的手机请求处理

  这里是在注册对docx文件的处理。

  2,重写了的BDC,现在叫BCS
  原来的BDC虽然有很好的想法,但是实际上使用起来,对BI的支持是十分有限的,10版本重写这部分的内容,希望能解决中看不中用的局面,原来的bdc是只能读不能回写,现在变了,只要外部数据可以写,那么你就可以借助于bcs回写(终于可以写了,原来就一个IdataReader,现在估计加了IdataWriter,不过权限的控制不知怎么做了,估计会比较麻烦了),原来用过BDC这块的内容,感觉用来演示和简单应用还行,但是到生产里面的话,实现需求的代价太大了,还不如自己写。对外部数据来源也扩展了好几种,但是用过后才知道,而且提供直接大lob二进制流,这个对性能的提升不是一点半点了。
  
  Business Data Connectivity (BDC) service
  BDC Connectors and the pluggable Connector Framework
  External lists
  External data columns
  
  (1)扩展的外部列表
  利用BCS的基础,原有的list得到了极大的加强,或许大家对5000以上大容量的列表的性能衰减,已然是非常无语,同样,在做企业的整合方案的时候,大家也都会在list库和数据库表之间进行权衡,更有甚者,我们还做过直接从content数据库当中读取列表库的内容,到自己的数据库表中,利用表中的itemid来关联大数据,从而借助于List来完成自己所需要的流程的挂载和数据的审批。所以借助于BCS的扩展,列表得到了扩展。
  
  BDC目前支持四种外部数据源扩展的方式,
  一种是对数据库,
  一种是对webservice
  一种是.net的model,
  一种是自定义(鬼才知道自定义的是什么)
  实际上BDC封装的就是我们在整个Mvc框架里面的所说的model,只不过这里他提供了简单的方式来连接外部的数据,不同的数据源他提供了不同的connect来对接数据,从而把各种数据都统一为了BDC实体。
  扩展的列表库就借助于BCS的这个特性,默认的系统当中有一个内容类型,而这个内容类型是专门用来承载已经定义好的数据实体的,那么我们就可以通过这个内容类型,扩展我们的数据到列表库当中了。同样借助于这种方式,扩展的外部数据列,也就不是问题了。
  3,全客户端对象
  原来我们开发的时候发现,我们所开发出来的内容,不管是啥子的,基本上都需要moss的环境来支持才可以运行,当大家在sharepoint的臃肿开发机上开发的时候,不得不上一个开发环境,我们所用.net的托管代码,都是在服务器上执行的,当然,还有一块是ECMAScript的脚本,这些服务端脚本都是在浏览器里面执行的,这个大家应该用得不多。
  说到这里,不得不想起在SHAREPOINT中对于大规模的数据和内容,而且跨越众多的分公司和机构的分布式问题。原来我也设计过超大规模的分省的方案,大家会发现,很多时候各省的接入方式不一样,而且vpn后的速度也不是十分的明显,最后折中的办法的按照省市在场中加多台的服务器组,各省的服务器分置在各省的机房,和总部通过vpn联系,并受控与主核心场,各省的application 和db都归属在各省的服务器上。目前这是我能想到的借助于SharePoint比较好的分布方式了,虽然性能有所提高,但是由于网络的限制,有些地区的vpn线路只有2mb,集成部署方案和更新的时候还是很慢,而且各省的爬网索引晚上的timerJob也总有挂掉的情况,于是不得不借助于自己所建立的中间层,来控制各个节点的内容。曾经也考虑过集中部署的方式,但是发现,以大数据量为主的交互内容,在地方网络资源有限的情况下,还是让信息的交互变得痛苦不堪。虽然优化了web part的代码,但是性能还是没有得到根本的解决。如果以Sharepoint的分布式解决方案来说,可以独立成文了,这里就不再继续偏题了。
  新的客户端对象模型,比原有moss提供web service的功能更加的强大,并且比ECMAScript的使用会更加的简单,大家可以利用客户端的对象模型,在远程的计算机上和服务端进行交互。托管的客户端代码都继承于ClientObject这个基类,命名空间Microsoft.SharePoint.Client.光说不练,还是来段代码吧。
  

  using System;
  using Microsoft.SharePoint.Client;
  
  namespace Microsoft.SDK.SharePointServices.Samples
  {
   class UsingClientContext
   {
   static void Main()
   {
   ClientContext clientContext = new ClientContext("http://MyServer/sites/MySiteCollection");
  
   Web oWebsite = clientContext.Web;
  
   clientContext.Load(oWebsite);
  
   clientContext.ExecuteQuery();
  
   Console.WriteLine(oWebsite.Title);
   }
   }
  }

  大家可以看到,通过context的交互,所有的操作都是在一次执行之后请求到客户端,然后在客户端执行,然后执行完更改以后再进行提交,这里肯定也有提供异步方式的执行方法ExecuteQueryAsync,要不然老傻傻的等在哪里,客户肯定是受不了的。不过目前所覆盖的对象还比较有限,但是基础的一些功能都能完成,具体的大家可以到SDK里面进行查询
  Server .NET Managed and Silverlight ECMAScript
  Microsoft.SharePoint.SPContext Microsoft.SharePoint.Client.ClientContext SP.ClientContext
  Microsoft.SharePoint.SPSite Microsoft.SharePoint.Client.Site SP.Site
  Microsoft.SharePoint.SPWeb Microsoft.SharePoint.Client.Web SP.Web
  Microsoft.SharePoint.SPList Microsoft.SharePoint.Client.List SP.List
  Microsoft.SharePoint.SPListItem Microsoft.SharePoint.Client.ListItem SP.ListItem
  Microsoft.SharePoint.SPField (including major derived classes) Microsoft.SharePoint.Client.Field SP.Field
  Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager SP.WebParts.LimitedWebPartManager
  4.强化的xslt客户端展现定制
  其实借助于xslt完全可以把xml数据展现成为你想要的任何html样式,关键就在于你的xslt怎么来转化,怎么来定义.其实微软内部有一种解决静态网站的方案就是用纯xslt+xml来构造页面,只不过所有的xml数据和xslt都得自己来设计和编写,大家都知道infopath的内容都是由xml构成的,所以借助于infoPath来定义xml数据是一种十分方便的形式。整体的解决方案就变成了infoPath+xslt+Form Service+SharePoint。对于静态来说,还是十分好用的,而且xslt引擎对于静态的处理,效率是很高的。
  5.同步框架引擎For SharePoint
  这块的内容还是在于同步不同设备和平台上面的数据,但是由于支持的问题,目前这个同步框架版本为4.0CTP,在SharePoint里面体现为,在GetListItemChangesWithKnowledge的时候内部封装用到了这个同步库。
  未完待续,,,

传说那是寂寞

总是在凌晨的时候才开始思绪万千,期待了多天的wow终于还是没能在凌晨准时开服。
他们都说其实我们玩的不是游戏,是寂寞。
他们都说我们等的不是游戏,是寂寞。

afk很久了,都不记得最后上线是在什么时候了,但是心理的那份牵挂总是难以放下,抑或是不愿放下。总想上去看看,听听,再看看周围的人。游戏本身,似乎已经不太重要。

曾记起红颜知己口口声声说我喜欢你,感觉又将失去一个可以宣泄情绪的人,无奈,无助,很多东西你无法改变,发乎于情,止乎于理,只能任其发展。拒绝,详细解说原由,好让其死心。朋友,看来也是做不成了。
师傅结束了失眠,步入了小女人的幸福生活,回去竟然连面都没有见到,也没有在夜晚凌晨三点的骚扰,地球上又少了一个寂寞的人,祝福他们。

和新公司的HR有一句没一句的聊着,卸下防御,卸下诸多的顾忌。其实事情本身复杂到终极,那就是简单。

生活的本身,其实简单就好。
wow临时论坛上面开始出现了大量的谩骂,阿门。
寂寞的人们,无眠。
最后打开寂寞的季节,开听。

人这种东西

每天半睡半醒的挤在城铁上加入上班的大军,然后半睡半醒的开始一天工作,只有坐在电脑前才开始有睡醒的感觉。

人无时无刻都在追求一些东西,值得的,不值得的,没得到的。
得到了,他们又开始追求新的东西。
他们追求自身所没有拥有的东西,忽略已经拥有的东西。
欲壑难填。

平衡总是理想的状态,在运动的事物当中,平衡只是界定在一定范围内的,
在如此失衡的世界里,他们只能利用理论和知识来平衡自己的内心。
于是发现看书的人挺多,随地吐痰的不少。

在大呼独立自主自由开放的同时,人们选择孤立,却又无法脱离社会并且选择群居。
向往世外桃源,却没有心境走入其中。
独善其身,可望而不可及。

这是一个喧闹而浮躁的时代,当人口在膨胀,资源在消耗,竞争在炙热。
一切都会在碰撞最激烈的地方,以其最原始的状态展现。
孰恶孰劣,皆可见分晓。

我承认我拥有以下特征:无品,无聊,无信仰。
不风趣,不特殊,不出众.
自卑,渴望认同,孤独。
平庸,自以为是。

ps:牢骚完毕!!!

三月-本不该是离别的时节

风有逝除却昨日温存,
雪易融难释峰顶冰苍。
云缭绕怎理林头锁屑,
夜深沉独梅竞相争艳。

日渐暖初释水融润土,
空息蓝净滤镜中尘埃。
凡人多春梦性情不改,
寻觅终有时勃然一身。

突然发现堆砌出来的诗句很是晦涩,不过借诗抒情也不失为一种发泄的途径,否则自己很可能就憋出问题了,虽然没有平仄对其和严格压韵。也没有什么深刻的意境。自己能从中看到和表达一些不愿吐露,却又不能不吐露的东西,也算是给日后回忆起来做个交代吧。
不觉当中,颓然间,不知不觉,时光如逝,自己每一次静下心来写日志,都不知道用什么词语来开头,好像总感觉我还在昨天,昨天的昨天。非软件公司已经呆了大半年了,技术上没有什么长进,倒是学会和别人勾心斗角,察言观色。一切东西都在虚虚实实真真假假间反复无常的变化着。
不知道是好还是坏,心里很久没有那种刺痛和思念的感觉了,可惜最近又如春天融化的冰河,泛滥不止,原以为已然心如止水,内里却如此禁不起诱惑。不如在完全陷入其中时及早抽身,以免再次拖着伤痕累累的疲态陷入沉寂。或许自己只是别人游戏当中的一颗棋子,被任意的挪动和使用,却没有任何的情感可言,冷漠本就是社会所存在的基本属性。所以应该是时候选择离开了,也许离开才是最好的选择。
每一次醒来,每一次有意识或无意识的,浮现的总是那个身影,不可及,甚至用双手都无法完全触碰和拥有,所以太过虚无和不切实际。习惯于那种痛和苦楚,并且学会习惯这种状态,然后再一次用时间去冲淡。
猎头找到去谈了两次,打算开比现在多30%薪水挖过去,一个比较大的项目,而且是个人比较擅长的领域,全国性的企业。offer基本已经算拿到了,可惜待遇还未见明细,许多东西还得从长计议。
人生若只如初见,又何必长相厮守。
留下的回忆,那将会永远的美丽。

一阵恶心

上个月上班无意间看了几个帖子,然后就突然一阵恶心袭来(请不要误解为有喜),然后就去厕所了。由于工作性质的关系,整日和网络以及计算机交互,对社会和实物后来的认识也大多由书本和网络而来。然后以书中理论去思考在网络上所反映出来的社会时,就觉得特别的憋闷,这是怎样的一个社会?
没有人能清楚的告诉你,各种媒体的洗脑和无脑,已经让大众变得无脑,无情而又麻木不仁,人们已经习惯了这样麻木的生活,无需反抗,因为他们已无产生这种想法的能力,很多人用阉割二字来形容如此。大家每日所纠结的东西,惯用的伎俩,尔虞我诈的这种无主流信仰主义,所带来的却是无尽的倒退。倾巢之下,皆如此。丧失了文化和信仰的大众是不可怕的,可怕的是占有社会绝对资源的主流群体也如此,肆意的掳掠资源,践踏自己以及国家民族的人格。当游人怀着对这个神秘古国的憧憬和来此朝圣,在最终满怀愤怒和失望的离开时。被同类化遭受鄙夷和唾弃,而地位低下的民族。是由你们自己所造成的,一个人要想得到别人的认可和尊重,首先需要尊重的应该是自己。
近日去体验集体面试,闲暇之余和几个做技术的同僚聊起来,说到其实每一个爱好技术的人都想衣食无牵,无后顾之忧的专心沉浸于技术之中,他们不用担心今天失业明天就吃不上饭,不用担心今天还能有个房子让你敲代码,明天就让你露宿街头。因为他们能够从技术中找到快乐,从技术中找到自我。当然,在生存都没有下限保障的环境里,当然还是以生存为主,工作只不过是用于维持生计的一种手段,至于技术,那只是生活的附属品,那不属于你的理想,不属于你的追求。
其实转念一想,如果你真执着的追求一种东西,那又岂是温饱和生计能够影响于你的。所以大师们都抛开衣食情欲,追求无上至高至境界。可惜就我所看到的做技术同事,大多以其极高的技术天赋,和极高的情商,在经营自己的技术和资本,他们可以每日只睡三个小时,钻研技术,并且以此作为最大的资本来进行商业逐利运作,以实用主义观点来看,任何无法产生价值的技术都不是有效的技术。于是这里的技术是为金钱和政治服务的,于简化人们的工作,于改善人民的生活并无直接的联系。
或许扎眼这么一看,以上的观点就显得太过于偏激而消极,片面而非常主观。所有脑海中总有一堆的问号,问号,还是无尽的问号。
不同的人总在选取不同的方式在社会中存活,他们总是利用各种手段来攫取或者夺取别人手中的资源,以免自己由于资源枯竭而被饿死,所以在绝对生存的驱使下,是没有任何道德可言的,但是对于满足了基本需要的智能动物确不简单如此,他们更多的是在往自己更高的欲求发展。对此,在道德的狼皮下干着各种各样的勾当。如果说法律和道德是统治阶级用于控制人民的工具和手段,那么同时也是他们的遮羞布。记得有次有个的哥聊天聊到,干部党员出问题了,自然是有中纪委去审查和调查,老百姓出问题了,那么就只能诉诸于法律,干同样的事情,有的是纪律问题,而有的是法律问题,至于所说的平等,基本上无从谈起。
如果一个女人总在你的面前说没有安全感,那么对于这个男人来说,你就是个悲剧,如果把爱情以安全感的限度来定义的话,一切的没安全都来源于物质生活的匮乏,所以即使现在你是潜力股,也没有任何可以投资的价值,因为这种女人终究是以物质来衡量曲线的。所以让经济基础决定上层建筑的唯物主义现实的女人,是自然界的天性和本能,无可厚非。于是乎卖肉女成为一种正当的职业,无论如何都是一种交易,你取所需,他取所得。在地球人抱怨没有真爱的时候,这就是一切真相最本质的面目,就如此吧,话说自从开始写墨水的笔记本以后,就很少再些blog了,偶尔发个牢骚。