第一步: 創(chuàng)建.net core mvc 應(yīng)用? ?
為什么要?jiǎng)?chuàng)建MVC 呢?? 因?yàn)?可以 采用登錄進(jìn)行控制hangfire 的權(quán)限控制,如果 不需要權(quán)限的話 api 應(yīng)用也是可以的
第二步: 下載相關(guān)的hangfire? dll? ?(采用的是sqlserver 進(jìn)行管理任務(wù))
Hangfire.AspNetCore 、Hangfire.RecurringJobExtension、Hangfire.Sqlserver

第三步: 配置Hangfire
1.ConfigureServices
```
public void ConfigureServices(IServiceCollection services)
? ? ? ? {
//配置啟用cookie
? ? ? ? ? ? services.Configure<CookiePolicyOptions>(options =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? // This lambda determines whether user consent for non-essential cookies is needed for a given request.
? ? ? ? ? ? ? ? options.CheckConsentNeeded = context => false;
? ? ? ? ? ? ? ? options.MinimumSameSitePolicy = SameSiteMode.None;
? ? ? ? ? ? });
//配置權(quán)限
? ? ? ? ? ? services.AddMvc(opt =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? opt.Filters.Add<AdminAuthFilter>();
? ? ? ? ? ? }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
? ? ? ? ? ? services.AddScoped<IMessageService, MessageService>();
? ? ? ? ? ? //注入hangfire 服務(wù)
? ? ? ? ? ? services.AddHangfire(x =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection"));
? ? ? ? ? ? ? ? x.UseRecurringJob(new JobProvider());
? ? ? ? ? ? ? ? x.UseConsole();
? ? ? ? ? ? ? ? x.UseFilter(new LogEverythingAttribute());
? ? ? ? ? ? });
? ? ? ? ? ? ApiConfig.HangfireLogUrl = Configuration["HangfireLogFileUrl"];
? ? ? ? ? ? //GlobalJobFilters.Filters.Add(new LogEverythingAttribute());
? ? ? ? ? ? //GlobalConfiguration.Configuration.UseAutofacActivator(container);
? ? ? ? ? ? //add dbcontext
? ? ? ? ? ? services.AddDbContextPool<JobsDbContext>(options =>
? ? ? ? ? ? ? ? options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
? ? ? ? ? ? services.AddAuthentication(o =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? o.DefaultAuthenticateScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;
? ? ? ? ? ? ? ? o.DefaultChallengeScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;
? ? ? ? ? ? ? ? o.DefaultSignInScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;
? ? ? ? ? ? ? ? o.DefaultSignOutScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;
? ? ? ? ? ? }).AddCookie(CookieJobsAuthInfo.AdminAuthCookieScheme, o =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? o.LoginPath = "/Login";
? ? ? ? ? ? });
? ? ? ? ? ? //泛型注入到di
? ? ? ? ? ? services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
? ? ? ? ? ? services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
? ? ? ? ? ? services.AddSession();
? ? ? ? ? ? services.AddScoped<IUserService, UserService>();
? ? ? ? ? ? services.AddScoped<IAuthService, AuthService>();
? ? ? ? }
```
其中
JobProvider:
public class JobProvider : IConfigurationProvider
? ? {
? ? ? ? public IEnumerable<RecurringJobInfo> Load()
? ? ? ? {
? ? ? ? ? ? var result = new List<RecurringJobInfo>();
? ? ? ? ? ? var assembly = Assembly.GetEntryAssembly();
? ? ? ? ? ? if (assembly == null) return result;
? ? ? ? ? ? foreach (var type in assembly.GetTypes())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? foreach (var method in type.GetTypeInfo().DeclaredMethods)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //if(!method.IsDefined(typeof(RecurringJobInfo),false))
? ? ? ? ? ? ? ? ? ? //? ? continue;
? ? ? ? ? ? ? ? ? ? var attribute = method.GetCustomAttribute<RecurringJobAttribute>(false);
? ? ? ? ? ? ? ? ? ? if (attribute == null) continue;
? ? ? ? ? ? ? ? ? ? if (string.IsNullOrWhiteSpace(attribute.RecurringJobId))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? attribute.RecurringJobId =method.GetRecurringJobId();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? result.Add(new RecurringJobInfo()
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? RecurringJobId = attribute.RecurringJobId,
? ? ? ? ? ? ? ? ? ? ? ? Cron = attribute.Cron,
? ? ? ? ? ? ? ? ? ? ? ? Queue = attribute.Queue,
? ? ? ? ? ? ? ? ? ? ? ? Enable = attribute.Enabled,
? ? ? ? ? ? ? ? ? ? ? ? Method = method,
? ? ? ? ? ? ? ? ? ? ? ? TimeZone = TimeZoneInfo.Local
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return result;
? ? ? ? }
? ? }
LogEverythingAttribute:
public class LogEverythingAttribute : JobFilterAttribute, IClientFilter, IServerFilter, IElectStateFilter, IApplyStateFilter
? ? {
? ? ? ? private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();
? ? ? ? public void OnCreating(CreatingContext filterContext)
? ? ? ? {
? ? ? ? ? ? Logger.InfoFormat("Creating a job based on method `{0}`...", filterContext.Job.Method.Name);
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnCreating-{(filterContext.Job.Method.Name)}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Creating a job based on method `{filterContext.Job.Method.Name}`... . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss}");
? ? ? ? }
? ? ? ? public void OnCreated(CreatedContext filterContext)
? ? ? ? {
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnCreated-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Job that is based on method `{filterContext.Job.Method.Name}` has been created with id `{filterContext.BackgroundJob?.Id}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? ? ? Logger.InfoFormat(
? ? ? ? ? ? ? ? "Job that is based on method `{0}` has been created with id `{1}`",
? ? ? ? ? ? ? ? filterContext.Job.Method.Name,
? ? ? ? ? ? ? ? filterContext.BackgroundJob?.Id);
? ? ? ? }
? ? ? ? public void OnPerforming(PerformingContext filterContext)
? ? ? ? {
? ? ? ? ? ? Logger.InfoFormat("Starting to perform job `{0}`", filterContext.BackgroundJob.Id);
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnPerforming-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Starting to perform job `{filterContext.BackgroundJob.Id}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? }
? ? ? ? public void OnPerformed(PerformedContext filterContext)
? ? ? ? {
? ? ? ? ? ? Logger.InfoFormat("Job `{0}` has been performed", filterContext.BackgroundJob.Id);
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnPerformed-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Job `{ filterContext.BackgroundJob.Id}` has been performed . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? }
? ? ? ? public void OnStateElection(ElectStateContext context)
? ? ? ? {
? ? ? ? ? ? var failedState = context.CandidateState as FailedState;
? ? ? ? ? ? if (failedState != null)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Logger.WarnFormat(
? ? ? ? ? ? ? ? ? ? "Job `{0}` has been failed due to an exception `{1}`",
? ? ? ? ? ? ? ? ? ? context.BackgroundJob.Id,
? ? ? ? ? ? ? ? ? ? failedState.Exception);
? ? ? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateElection-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` has been failed due to an exception `{(JsonConvert.SerializeObject(failedState.Exception))}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
? ? ? ? {
? ? ? ? ? ? Logger.InfoFormat(
? ? ? ? ? ? ? ? "Job `{0}` state was changed from `{1}` to `{2}`",
? ? ? ? ? ? ? ? context.BackgroundJob.Id,
? ? ? ? ? ? ? ? context.OldStateName,
? ? ? ? ? ? ? ? context.NewState.Name);
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateApplied-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` state was changed from `{context.OldStateName}` to `{context.NewState.Name}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? }
? ? ? ? public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
? ? ? ? {
? ? ? ? ? ? Logger.InfoFormat(
? ? ? ? ? ? ? ? "Job `{0}` state `{1}` was unapplied.",
? ? ? ? ? ? ? ? context.BackgroundJob.Id,
? ? ? ? ? ? ? ? context.OldStateName);
? ? ? ? ? ? WriteLog(
? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateUnapplied-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",
? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` state `{context.OldStateName}` was unapplied . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 寫入文本
? ? ? ? /// </summary>
? ? ? ? /// <param name="path">路徑</param>
? ? ? ? /// <param name="message"></param>
? ? ? ? public void WriteLog(string path,string message)
? ? ? ? {
? ? ? ? ? ? var fileUrl = path;
? ? ? ? ? ? if (!File.Exists(fileUrl))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? File.Create(fileUrl).Close();
? ? ? ? ? ? }
? ? ? ? ? ? FileStream fs = new FileStream(fileUrl, FileMode.Append);
? ? ? ? ? ? byte[] data = System.Text.Encoding.Default.GetBytes(message??"");
? ? ? ? ? ? fs.Write(data, 0, data.Length);
? ? ? ? ? ? fs.Close();
? ? ? ? }
? ? }
2.?Configure 配置
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
? ? ? ? {
? ? ? ? ? ? if (env.IsDevelopment())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? app.UseDeveloperExceptionPage();
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
? ? ? ? ? ? ? ? app.UseHsts();
? ? ? ? ? ? }
? ? ? ? ? ? //app.UseHttpsRedirection();
? ? ? ? ? ? //app.UseMvc();
? ? ? ? ? ? app.UseStaticFiles();
? ? ? ? ? ? //app.UseHangfireServer();//啟動(dòng)hangfire 服務(wù)
? ? ? ? ? ? app.UseAuthentication();
? ? ? ? ? ? app.UseSession();
? ? ? ? ? ? app.UseMvc(routes =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? routes.MapRoute(
? ? ? ? ? ? ? ? ? ? name: "default",
? ? ? ? ? ? ? ? ? ? template: "{controller=Login}/{action=Index}");
? ? ? ? ? ? ? ? routes.MapRoute(
? ? ? ? ? ? ? ? ? ? name: "areas",
? ? ? ? ? ? ? ? ? ? template: "{area:exists}/{controller=Login}/{action=Index}/{id?}");
? ? ? ? ? ? });
? ? ? ? ? ? //配置任務(wù)屬性
? ? ? ? ? ? var jobOptions = new BackgroundJobServerOptions()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Queues = new[] { "default", "apis", "job" },//隊(duì)列名稱,只能小寫
? ? ? ? ? ? ? ? WorkerCount = Environment.ProcessorCount * 5,//并發(fā)任務(wù)數(shù)
? ? ? ? ? ? ? ? ServerName = "hangfire"http://服務(wù)器名稱
? ? ? ? ? ? };
? ? ? ? ? ? app.UseHangfireServer(jobOptions);
? ? ? ? ? ? //配置hangfire訪問(wèn)權(quán)限
? ? ? ? ? ? var options = new DashboardOptions()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Authorization = new[] { new HangfireAuthorizationFilter() },
? ? ? ? ? ? };
? ? ? ? ? ? app.UseHangfireDashboard("/hangfire", options);//啟動(dòng)hangfire 面板
? ? ? ? ? ? //HandfireExtension.Register();
? ? ? ? ? ? //app.Run(ctx =>
? ? ? ? ? ? //{
? ? ? ? ? ? //? ? ctx.Response.Redirect($"{Configuration["WebRootUrl"]}/hangfire"); //可以支持虛擬路徑或者index.html這類起始頁(yè).
? ? ? ? ? ? //? ? return Task.FromResult(0);
? ? ? ? ? ? //});
? ? ? ? }
第四步:
具體樣例

第五步:
dotnet core 部署在 iis 上,如果不設(shè)置 閑置超時(shí)的話? iis 會(huì) 自動(dòng)閑置
可根據(jù)項(xiàng)目情況 調(diào)整 或? 轉(zhuǎn)換成 windows service 或計(jì)劃任務(wù)

結(jié)尾:
github demo 地址:https://github.com/xiehanbing/JobHangfire