眼下正好有一个SP项目需要用到计时器功能,本人平常忘性大,所以学一点记录一点,其中参考了不少网络上的好文章,因为怕麻烦,我就不引用看过的博客的链接了,忘各路大神莫怪。 sharepoint 计时器类似于Windows 任务计划一样,可以按分,时,天,周,月去自动执行你布置的任务,你可以到sharepoint 管理中心去查看及更改你的计时规则,值得注意的是,每当你部署一个计时器的时候,你需要到服务器中的“服务”中,有一个叫“SharePoint Timer Service”的服务,你需要重启一下,更新后的计时器才会显效,其余的话不说了,下面就跟我一起去学习此功能吧。
1 添加新项目,打开vs2013‘文件’->‘新建’->‘项目’,我建了一个“OneTimeJob”的空项目
2 我选择“部署为场解决方案”
3 创建一个计时器任务类“OneTimeJob.cs”
4 继承SPJobDefinition ,需要引用Microsoft.SharePoint.Administration; 如下图
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 namespace OneTimeJob { class OneTimeJob : SPJobDefinition { /// <summary> /// 构造函数 /// </summary> public OneTimeJob() : base() { } /// <summary> /// 带有参数1的构造函数,适合其他的指定站点集,我是猜的,反正我没用过这个 /// </summary> /// <param name="jobName"></param> /// <param name="service"></param> /// <param name="server"></param> /// <param name="targetType"></param> public OneTimeJob(string jobName, SPService service, SPServer server, SPJobLockType targetType) : base(jobName, service, server, targetType) { } /// <summary> /// 带有参数2的构造函数,适合部署的本站点集 /// </summary> /// <param name="jobName"></param> /// <param name="webApplication"></param> public OneTimeJob(string jobName, SPWebApplication webApplication) : base(jobName, webApplication, null, SPJobLockType.ContentDatabase) { this.Title = jobName; } /// <summary> /// 执行逻辑的方法 /// </summary> /// <param name="contentDbId"></param> public override void Execute(Guid contentDbId) { //我把邮箱地址,和发送内容存储在"TestWeb"网站下的"TestList"的列表上 string EmailTo = ""; string EmailBody = ""; SPWeb web = null; SPSecurity.RunWithElevatedPrivileges(delegate()//提升权限,模仿管理员权限在读取列表 { SPWebApplication webApplication = this.Parent as SPWebApplication;//实例化一个应用管理,只能翻译成这样了,将就看吧,反正我都是猜的 SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];//通过GUID找到内容数据库 web = contentDb.Sites[0].OpenWeb("/TestWeb/");//因为我只创建了一个站点集,就用Sites[0],然后找到我要的Web using (web) { SPList list = web.GetList(web.Url + "/Lists/TestList/AllItems.aspx");//找到我要的列表 SPQuery query = new SPQuery(); query.Query = "";//为空时表示搜出所有列表,caml语句不在此讲解 SPListItemCollection items = list.GetItems(query); if (items != null && items.Count > 0) { foreach (SPListItem item in items) { if (Convert.ToString(item["Title"]) == "测试用计时器发邮件") //找到我存储字段值的地方 { EmailTo = Convert.ToString(item["EmailTo"]); EmailBody = Convert.ToString(item["EmailBody"]); } } } } //接下来就是发送邮件了,我得先吐槽一下,sharepoint自带了一个发送邮件功能,叫"Microsoft.SharePoint.Utilities.SPUtility.SendEmail()", //我曾经用它发送了一个html邮件,内容多时,总有一个字符解析乱码,太NM坑了,有兄弟有解决路子的,别忘分享给我啊,所以我还是用成熟一点的技术来发送邮件。 SendEmail(EmailTo, "测试计时器发送的邮件", EmailBody, ""); }); } /// <summary> /// 发送邮件 /// </summary> /// <param name="mailTo">要发送的邮箱</param> /// <param name="mailSubject">邮箱主题</param> /// <param name="mailContent">邮箱内容</param> /// <returns>返回发送邮箱的结果</returns> public bool SendEmail(string mailTO, string mailSubject, string mailContent, string _path) { // 设置发送方的邮件信息,例如使用网易的smtp string smtpServer = "192.168.1.1"; //SMTP服务器 string mailFrom = "黑不到我吧"; //登陆用户名 string userPassword = "119";//登陆密码 // 邮件服务设置 SmtpClient smtpClient = new SmtpClient(); smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;//指定电子邮件发送方式 smtpClient.Host = smtpServer; //指定SMTP服务器 smtpClient.Credentials = new System.Net.NetworkCredential(mailFrom, userPassword);//用户名和密码 // 发送邮件设置 MailMessage mailMessage = new MailMessage(); // 发送人和收件人 mailMessage.From = new MailAddress(mailFrom, "测试站点"); mailMessage.To.Add(new MailAddress(mailTO, mailTO));//添加发件人 mailMessage.Subject = mailSubject;//主题 mailMessage.Body = mailContent;//内容 mailMessage.BodyEncoding = Encoding.UTF8;//正文编码 mailMessage.IsBodyHtml = true;//设置为HTML格式,可以发送html内容的邮件 mailMessage.Priority = MailPriority.High;//优先级 //添加邮件附件 FileInfo fi; if (!string.IsNullOrEmpty(_path)) { fi = new FileInfo(_path); if (fi.Exists) { System.Net.Mail.Attachment firstatt = new System.Net.Mail.Attachment(_path, System.Net.Mime.MediaTypeNames.Application.Octet); System.Net.Mime.ContentDisposition disposion = new System.Net.Mime.ContentDisposition(); disposion.CreationDate = System.IO.File.GetCreationTime(_path); disposion.ModificationDate = System.IO.File.GetLastWriteTime(_path); disposion.ReadDate = System.IO.File.GetLastAccessTime(_path); mailMessage.Attachments.Add(firstatt); } } try { smtpClient.Send(mailMessage); // 发送邮件 return true; } catch (SmtpException ex) { return false; } } } }
5 在Features 文件夹中添加功能,创建一个 Feature 文件,范围选择“Site”,表示你的计时器作用在部署的网站集上,在存取列表值的时候我们一般会通过Site,筛选你要的Web,再通过Web筛选到与你要交互的list.
6 给新建的Feature添加一个事件接收器,如下图:
7 添加后,会在其文件下面多出一个“Feature1.EventReceiver.cs”的类文件
8 需要override其中的两个函数
override void FeatureDeactivating(SPFeatureReceiverProperties properties) 删除timer job函数
override void FeatureActivated(SPFeatureReceiverProperties properties),部署timer job函数
namespace OneTimeJob.Features.Feature1 { /// <summary> /// 此类用于处理在激活、停用、安装、卸载和升级功能的过程中引发的事件。 /// </summary> /// <remarks> /// 附加到此类的 GUID 可能会在打包期间使用,不应进行修改。 /// </remarks> [Guid("ed228c48-b397-4755-be4f-a9ffa609c177")] public class Feature1EventReceiver : SPFeatureReceiver { // 取消对以下方法的注释,以便处理激活某个功能后引发的事件。 public override void FeatureActivated(SPFeatureReceiverProperties properties) { //实例化对应的站点集 SPSite site = properties.Feature.Parent as SPSite; string Job_Name = "OneTimeJobTest";//指定计时器名称 //遍历此站点集下的所有计时器,如果发现重名的将删除,确保计时器名称的唯一性 foreach (SPJobDefinition job in site.WebApplication.JobDefinitions) { if (job.Name == Job_Name)//匹兑到部署时的计时器名称,然后删除 { job.Delete(); } } //添加计时器 OneTimeJob Doc = new OneTimeJob (Job_Name, site.WebApplication);//实例化任务类 //设置计时器属性,这个可以发布后在sharepoint管理器中的"监控"中重新定义。 SPMinuteSchedule schedule = new SPMinuteSchedule(); schedule.BeginSecond = 0; schedule.EndSecond = 59; schedule.Interval = 5; Doc.Schedule = schedule; Doc.Update(); } // 取消对以下方法的注释,以便处理在停用某个功能前引发的事件。 public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { //实例化对应的站点集 SPSite site = properties.Feature.Parent as SPSite; //遍历此站点集下的所有计时器 foreach (SPJobDefinition job in site.WebApplication.JobDefinitions) { if (job.Name == "OneTimeJobTest")//匹兑到部署时的计时器名称,然后删除,为了方便理解,计时器名称我没用全局变量 { job.Delete(); } } } // 取消对以下方法的注释,以便处理在安装某个功能后引发的事件。 //public override void FeatureInstalled(SPFeatureReceiverProperties properties) //{ //} // 取消对以下方法的注释,以便处理在卸载某个功能前引发的事件。 //public override void FeatureUninstalling(SPFeatureReceiverProperties properties) //{ //} // 取消对以下方法的注释,以便处理在升级某个功能时引发的事件。 //public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters) //{ //} } }
9 此时计时器已经写好了,我们可以部署了,部署之后,打开服务器的“服务”,重启“SharePoint Time Service”,如图
10 “sharepoint 管理中心”的“监控”->“计时器作业”->"复查作业定义",可以看到我们的计时器
11 点击进去后,你可以重新定义计时器的属性
12 看一下我列表上存储的值
13 我去收一下我的邮件
14 下面我们来讲一下部署,用VS可以直接部署成功,但是我们的生产环境中,特别是客户的生产环境中,一般不会去装VS,所以我们会用选用wsp文件去部署,
通常情况,我们第一步先用命令安装wsp文件包,如:stsadm -o addsolution -filename C:\OneTimeJob.wsp
然后我们再部署此wsp,如:stsadm -o deploysolution -name OneTimeJob.wsp -immediate -url http://sharepoint2013/ -allowGacDeployment
那么问题来了,报错啦,显示“此解决方案不包含 Web 应用程序范围的资源,无法将其部署到特
定的 Web 应用程序”,如图
15 哈哈,蛋疼了吧,它不按规则出牌了,那我们来找下原因,我们打开“sharepoint管理器”找到此wsp包,如图
16 “包含Web应用程序资源”为“否”,跟以前不一样了吧,这种情况我们只能“全局部署”,网上有很多坑,好不容易找到正确的命令:stsadm -o deploysolution -name OneTimeJob.wsp -local -allowGacDeployment,部署后如图
17 因为是全局部署,所以每个网站集都包含此Feature,所以我们要去对应的网站中“网站集功能”中激活此Feature,如图
18 点击激活,发现:擦,又报错了,又掉下来一个坑,如图
19 看来它还挺任性的,那么接下来我们就去解决这个问题吧,既然不给用手去抚摸,那我们就下去命令,让它乖乖服从
stsadm -o activatefeature -id 7bff6c03-76ea-40b5-a339-b9fe6bc1c453 -url http://sharepoint2013/ -force
20 id 指的是Feature 的id,点开Feature设计器中的清单,能找到此id 如图
21 命令一下,这个世界从此顺心了
啦啦啦啦啦,德玛西亚