Hangfire 在 dotnet core 中的 应用及部署

第一步: 创建.net core mvc 应用   

为什么要创建MVC 呢?  因为 可以 采用登录进行控制hangfire 的权限控制,如果 不需要权限的话 api 应用也是可以的


第二步: 下载相关的hangfire  dll   (采用的是sqlserver 进行管理任务)

Hangfire.AspNetCore 、Hangfire.RecurringJobExtension、Hangfire.Sqlserver

Hangfire 在 dotnet core 中的 应用及部署_第1张图片

第三步: 配置Hangfire

1.ConfigureServices

public void ConfigureServices(IServiceCollection services)

        {

//配置启用cookie

            services.Configure(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;

            });

//配置权限

            services.AddMvc(opt =>

            {

                opt.Filters.Add();

            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddScoped();

            //注入hangfire 服务

            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(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();

            services.AddSession();

            services.AddScoped();

            services.AddScoped();

        }


其中

JobProvider:

public class JobProvider : IConfigurationProvider

    {

        public IEnumerable Load()

        {

            var result = new List();

            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(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}`... . 时间为:{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}` . 时间为:{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}` . 时间为:{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 . 时间为:{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))}` . 时间为:{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}` . 时间为:{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 . 时间为:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

        }

        ///

        /// 写入文本

        ///

        /// 路径

        ///

        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();//启动hangfire 服务

            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?}");

            });

            //配置任务属性

            var jobOptions = new BackgroundJobServerOptions()

            {

                Queues = new[] { "default", "apis", "job" },//队列名称,只能小写

                WorkerCount = Environment.ProcessorCount * 5,//并发任务数

                ServerName = "hangfire"//服务器名称

            };

            app.UseHangfireServer(jobOptions);

            //配置hangfire访问权限

            var options = new DashboardOptions()

            {

                Authorization = new[] { new HangfireAuthorizationFilter() },


            };

            app.UseHangfireDashboard("/hangfire", options);//启动hangfire 面板

            //HandfireExtension.Register();

            //app.Run(ctx =>

            //{

            //    ctx.Response.Redirect($"{Configuration["WebRootUrl"]}/hangfire"); //可以支持虚拟路径或者index.html这类起始页.

            //    return Task.FromResult(0);

            //});

        }


第四步:

具体样例

Hangfire 在 dotnet core 中的 应用及部署_第2张图片

第五步:

dotnet core 部署在 iis 上,如果不设置 闲置超时的话  iis 会 自动闲置

可根据项目情况 调整 或  转换成 windows service 或计划任务

Hangfire 在 dotnet core 中的 应用及部署_第3张图片

结尾:

github demo 地址:https://github.com/xiehanbing/JobHangfire

你可能感兴趣的:(Hangfire 在 dotnet core 中的 应用及部署)