在SharePoint中使用WorkItem方式批量处理Item

来源:互联网 发布:linux 电源按钮 编辑:程序博客网 时间:2024/05/19 08:01

我们知道SharePoint使用timer job来定时处理一些任务,只需要继承SPJobDefinition类,然后重写Execute方法,就可以创建出自己的timer job了。我们经常使用timer job来处理列表中的item,例如定时更新item的状态等等,这样的操作一般来讲是在Execute方法中获取需要处理的item,然后遍历这些item来执行一些操作。如果我们需要一些更大的灵活性来处理item,比如按照需要动态的添加需要处理的item,指定处理item的时间,或者动态移除一些不再需要处理的item,可以使用SharePoint提供的另一种专门为了批量处理item而设计的timer job:work item timer job (SPWorkItemJobDefinition)。这种方式允许你以队列的的方式批量处理item,而且是异步处理。这种方式相对于常用的timer job,处理item更加灵活方便,可以根据需要将待处理的item添加到队列中或者从队列中移除,指定下次运行时间等等。

首先介绍一下如何创建一个Work Item Timer Job,其实很简单,与创建SPJobDefinition类似,在project中添加一个类WorkItemJob,继承SPWorkItemJobDefinition,然后需要重写一些方法和属性:

public class WorkItemJob : SPWorkItemJobDefinition    {        public static readonly string WorkItemJobDisplayName = "WorkItemJob Demo";        public static readonly Guid WorkItemTypeId = new Guid("{B5597728-498B-4123-9C0E-DA6640CE0BC9}");        public override string DisplayName        {            get            {                return WorkItemJobDisplayName;            }        }        public override Guid WorkItemType()        {            return WorkItemTypeId;        }        public override int BatchFetchLimit        {            get            {                return 50;            }        }        #region 构造函数        public WorkItemJob() { }        public WorkItemJob(string name, SPWebApplication webApplicaiton) : base(name, webApplicaiton) { }        #endregion        protected override bool ProcessWorkItem(SPContentDatabase contentDatabase, SPWorkItemCollection workItems, SPWorkItem workItem, SPJobState jobState)        {                    }    }
其中DisplayName是timer job的名字,WorkItemType方法返回的是timer job的唯一标识,这个在之后的AddWorkItem方法中需要使用,BatchFetchLimit是一次timer job运行处理的work item的数量。我们需要重写的是ProcessWorkItem方法来实现自己的逻辑。

有了work item timer job之后,就可以使用SPSite.AddWorkItem这个方法将需要处理的item添加到队列中,这个方法需要的参数比较多,以下代码是使用一个控制台程序,将Tasks列表中的一个item添加到队列中:

class Program    {        static void Main(string[] args)        {            SPSecurity.RunWithElevatedPrivileges(() =>            {                using (SPSite site = new SPSite("http://sp2013test"))                {                    using (SPWeb web = site.OpenWeb())                    {                        SPList list = web.Lists["Tasks"];                        SPListItem item = list.GetItemById(1);                        SPUser user = web.SiteUsers[@"demo\administrator"];                        Guid workItemId = Guid.NewGuid();                        site.AddWorkItem(                            workItemId,                            DateTime.Now.ToUniversalTime(),  //指定运行时间,这里需要指定UTC时间                            new Guid("{B5597728-498B-4123-9C0E-DA6640CE0BC9}"), //Work item timer job中定义的WorkItemTypeId                            web.ID,                            list.ID,                            item.ID,                            true,                            item.UniqueId,                            item.UniqueId,                            user.ID,                            null,                            "Text you can use in timer job",                            Guid.Empty);                    }                }            });        }    }

其中各个参数的具体解释可以参考微软文档,需要注意的是,执行AddWorkItem方法需要提升权限到Site Collection Administrator。执行以上代码我们就添加了一个work item,这个work item将会在指定的时间执行,因为现在我们的ProcessWorkItem方法是空的,所以timer job什么都不做。我们加上一些逻辑来更新一个item的title:

protected override bool ProcessWorkItem(SPContentDatabase contentDatabase, SPWorkItemCollection workItems, SPWorkItem workItem, SPJobState jobState)        {            if (workItem != null)            {                using (SPSite site = new SPSite(workItem.SiteId))                {                    using (SPWeb web = site.OpenWeb(workItem.WebId))                    {                        try                        {                            SPList list = web.Lists[workItem.ParentId]; //获取list                            SPListItem item = list.GetItemByUniqueId(workItem.ItemGuid); //获取待处理的item                            string data = workItem.TextPayload;  //获取AddWorkItem方法“strTextPayload”参数传入的字符串数据                            string newTitle = string.Format("{0} - {1}", data, DateTime.Now.ToLongTimeString());                             item["Title"] = newTitle;  //更新item的title                            item.Update();                            //使用UpdateWorkItem的方法,指定下次运行的时间,需要使用UTC时间,这里指定4分钟之后再次运行                            workItems.UpdateWorkItem(workItem.Id, DateTime.Now.AddMinutes(4).ToUniversalTime(), null, "run again");                        }                        catch (Exception)                        {                            throw;                        }                        finally                        {                            //以下注释的代码用来删除workitem,即将其从队列中移除                            //workItems.SubCollection(site, web, 0, (uint)workItems.Count).DeleteWorkItem(workItem.Id);                        }                                            }                }            }           return true;        }

需要注意两个地方,一个是在使用AddWorkItem方法添加workitem的时候是可以传递数据给ProcessWorkItem方法的,使用“strTextPayload”这个参数指定需要传入的字符串。

另外一个是在如果想再次处理这个work item,需要使用UpdateWorkItem方法指定下次运行时间,同时也可以指定TextPayload,如果不需要处理这个work item,可以使用DeleteWorkItem方法将其从队列中删除,具体参见finally代码块。

运行之后,item的title会根据指定的时间而更新,将最新的时间显示在title上:

第一次运行:


第二次运行:



第三次运行:


可以看到,采用work item timer job的方式,不仅可以批量处理item,可以指定下次的运行时间,在处理item的时候很灵活方便。

以下是一些可能使用workitem方式的场景

1. 一些耗时的操作,有的时候用户每创建一个item,都要对应执行一些耗时的操作,比如创建一个相应的站点,访问AD,数据库或者其他资源等等。

2. 定时批量处理item。如果workitem没有从队列中移除,会一直处理下去。因此可以批量更新item的状态等等。

参考:点击打开链接

0 0
原创粉丝点击