在ASP.NET Web API项目中使用Hangfire实现后台任务处理
当前项目中有这样一个需求:由前端用户的一个操作,需要触发到不同设备的消息推送。由于推送这个具体功能,我们采用了第三方的服务。而这个服务调用有时候可能会有延时,为此,我们希望将消息推送与用户前端操作实现异步执行,就是希望在后台自动执行,不阻塞前端用户的操作,而且最好能实现失败重试等功能。
经过一些研究比较,我们发现使用Hangfire这个组件可以较好地实现这个需求。为了给大家做一个演示,我这里简化了代码,做一个范例程序。
我在这里不准备详细介绍Hangfire的基本用法,有兴趣的同学们可以参考官方网站 http://hangfire.io/ 和文档 http://docs.hangfire.io/en/latest/


第一步:创建ASP.NET Web API项目


第二步:安装必要的nuget package
打开Nuget Package Manager Console

首先安装Hangfire组件(Core,MemoryStorage),注意,因为后者是依赖前者的,所以我们只需要运行下面的命令即可
Install-Package Hangfire.MemoryStorage

Storage就是存储的意思,Hangfire的后台任务是需要一个地方保存起来,它默认支持SQL Server Storage和MemoryStorage。采用MemoryStorage无疑是最简单的(不需要有任何外部的依赖)。当然,最大的问题就是,因为是放在内存中的,万一网站出现问题重启,那么没有执行完的任务是会消失的。
如果要使用SQL Server的话,可以参考 http://docs.hangfire.io/en/latest/configuration/using-sql-server.html ,甚至还可以结合MSMQ来提高可用性 http://docs.hangfire.io/en/latest/configuration/using-sql-server-with-msmq.html
接下来为当前项目启用Owin的支持。关于什么是OWin,我这里也不准备多做说明,有兴趣的同学可以参考 : http://www.cnblogs.com/dudu/p/what-is-owin.html 和 http://owin.org/ 还有 http://www.asp.net/aspnet/overview/owin-and-katana/an-overview-of-project-katana
Install-Package Microsoft.Owin.Host.SystemWeb

第三步:添加Owin Startup Class

修改Startup.cs为下面这样的代码
using Hangfire;
using Hangfire.MemoryStorage;
using Microsoft.Owin;
using Owin; [assembly: OwinStartup(typeof(WebApplicationWebApiHangfireSample.Startup))] namespace WebApplicationWebApiHangfireSample
{
/// <summary>
/// 演示Hangfire的配置
/// 作者:陈希章
/// </summary>
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 //指定Hangfire使用内存存储后台任务信息
GlobalConfiguration.Configuration.UseMemoryStorage();
//启用HangfireServer这个中间件(它会自动释放)
app.UseHangfireServer();
//启用Hangfire的仪表盘(可以看到任务的状态,进度等信息)
app.UseHangfireDashboard(); }
}
}
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
第四步:实现一个简单的Web API,启动后台任务

using Hangfire;
using System;
using System.Diagnostics;
using System.Web.Http; namespace WebApplicationWebApiHangfireSample.Controllers
{
/// <summary>
/// 用来公开给前端用户调用的API
/// 作者:陈希章
/// </summary>
public class MessageController : ApiController
{
/// <summary>
/// 这个是用来发送消息的静态方法
/// </summary>
/// <param name="message"></param>
public static void Send(string message)
{
EventLog.WriteEntry("EventSystem", string.Format("这是由Hangfire后台任务发送的消息:{0},时间为:{1}", message, DateTime.Now));
} public IHttpActionResult Post(string content)
{
//这里可以做一些业务判断或操作 //然后需要推送的时候,调用下面的方法即可
BackgroundJob.Enqueue(() => Send(content)); //最后返回(这里是立即返回,不会阻塞)
return Ok();
}
}
}
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
第五步:进行测试
我使用Fiddler来模拟客户端调用

我们可以很容易地发起大量的请求,例如下面这样

很快就在Dashboard中看到任务状态(有1000个任务)

但是很快(不到1秒钟的时间),这些任务就全部处理完了

我们可以在Windows事件日志中看到消息

以上就是我的简单演示例子。当然,如果还想要实现失败重试,或者更加有意思的一些功能(例如定时发送),可以继续参考官方文档。
这个范例代码可以通过这里下载 http://files.cnblogs.com/files/chenxizhang/WebApplicationWebApiHangfireSample.zip
在ASP.NET Web API项目中使用Hangfire实现后台任务处理的更多相关文章
- 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(4)
		
chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angula ...
 - 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(3)
		
chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angula ...
 - 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(2)
		
chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angula ...
 - 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(1)
		
chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angula ...
 - Web API项目中使用Area对业务进行分类管理
		
在之前开发的很多Web API项目中,为了方便以及快速开发,往往把整个Web API的控制器放在基目录的Controllers目录中,但随着业务越来越复杂,这样Controllers目录中的文件就增加 ...
 - ASP.NET Web API 2 中的属性路由使用(转载)
		
转载地址:ASP.NET Web API 2 中的属性路由使用
 - ASP.NET Web API 2中的错误处理
		
前几天在webapi项目中遇到一个问题:Controller构造函数中抛出异常时全局过滤器捕获不到,于是网搜一把写下这篇博客作为总结. HttpResponseException 通常在WebAPI的 ...
 - 在asp.net web form项目中添加webapi接口
		
我有一个支付宝服务网关是ASP.NET WEB FORM项目,但是最近这个网关需要对外提供几个接口,想了下,使用web api比较合适,实现很简单,GO 1,首先添加一个文件夹名字叫App_Start ...
 - 在ASP.NET Web API 2中使用Owin OAuth 刷新令牌(示例代码)
		
在上篇文章介绍了Web Api中使用令牌进行授权的后端实现方法,基于WebApi2和OWIN OAuth实现了获取access token,使用token访问需授权的资源信息.本文将介绍在Web Ap ...
 
随机推荐
- ES6中的const命令【转】
			
1.const声明一个只读常量,一旦声明,常量的值就不能改变 1 const PI=3.1415; 2 console.log(PI);//3.1415 3 4 PI=3;//Uncaught Typ ...
 - [转]FINDSTR正则表达式小结
			
前言:最近写了一个bat用于快速编译swf至目标目录,想利用FINDSTR命令通过匹配目标目录名称,匹配数量大概600多个,发现匹配耗时比较久,大概花费10余秒,因此还是放弃字符匹配,乖乖拼出全称来定 ...
 - Spark优化之二:集群上运行jar程序,状态一直Accepted且不停止不报错
			
如果运行Spark集群时状态一直为Accepted且不停止不报错,比如像下面这样的情况: 15/06/14 11:33:33 INFO yarn.Client: Application report ...
 - python 之 Django 基础篇
			
1,Django流程介绍 MTV模式 著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据 ...
 - LINQ 的使用
			
[转]链接:cnblogs.com/liqingwen/p/5832322.html LINQ 简介 语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framewo ...
 - 使div下的图片自适应div的大小
			
div img{ max-width:100%; height:auto; } 这里div 要给固定的宽度 开始这里还想了半天 用网上的方法也不行 问老大 又一句话就给我解决了...老大真男神啊!!! ...
 - Unity3D UGUI之fbx模型导入问题
			
在UI层添加了一个fbx的模型,但是在game模式和运行中无法看到这个fbx. Canvas上面有个Render Mode :Screen Space - Overlay.Screen Space ...
 - Linux tar文件打包
			
tar格式,会打包成一个文件,可以对多个目录,或者多个文件进行打包 tar命令只是打包,不会压缩,打包前后大小是一样的 tar命令 -c //打包 -x //解压 -f //指定文件 ...
 - 实践Html5的上传文件
			
技术点: 1.通过input的change事件获取文件信息: onchange = function() { this.files } 这个files属性是htmlInputElement接口的属性, ...
 - 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现
			
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...