zoukankan      html  css  js  c++  java
  • mvc中使用Hangfire处理后台任务

    考虑下如下代码,在数据保存后,需要发送邮件,发送邮件是个耗时的工作。

    我们的目的是,数据保存成功后,就可以返回响应了,发送邮件不重要,不需要等待邮件发送成功

    [HttpPost]
    public ActionResult Create(Comment model)
    {
        if (ModelState.IsValid)
        {
            _db.Comments.Add(model);
            _db.SaveChanges();
     MailMessage message = new MailMessage();          
            message.To.Add("xx@126.com");          
                message.Subject = "主题是";
                message.Body = string.Concat(HtmlEmailHeader, Body, HtmlEmailFooter);
                message.BodyEncoding = System.Text.Encoding.UTF8;
                message.From = new MailAddress(From);
                message.SubjectEncoding = System.Text.Encoding.UTF8;
                message.IsBodyHtml = true;
    
                SmtpClient client = new SmtpClient("relay.mail.server");
            client.Send(Message);//耗时操作 
    }
    return RedirectToAction("Index");
    }

    改成异步是否能达到这个效果呢?

    答案是否定的!!虽然加入了异步方法,但是只有action里所有的代码执行完毕后才能返回响应!

    await(await表达式表示等待异步方法执行完,并取返回值,因此遇到await关键字,会阻塞线程) 后面的异步方法还是要执行完毕后,才会继续执行下面的代码,跟同步方法一样,并不会节省时间。

    所以异步可以提高效率/吞吐量,但是不能节省时间。

    [HttpPost]
    public async  Task<ActionResult> Create(Comment model)
    {
        if (ModelState.IsValid)
        {
            _db.Comments.Add(model);
            _db.SaveChanges();
    

    //异步范例1

    HttpClient client = new HttpClient();
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
    Console.WriteLine("上面的异步方法是否执行完跟我没关系,我还是执行到这里了");
    string urlContents = await getStringTask;//必须等client.GetStringAsync执行完

    Console.WriteLine(urlContents.Length.ToString());上面的语句执行完才轮到我。

    //异步反例2
           MailMessage message = new MailMessage();          
            message.To.Add("xx@126.com");          
                message.Subject = "主题是";
                message.Body = string.Concat(HtmlEmailHeader, Body, HtmlEmailFooter);
                message.BodyEncoding = System.Text.Encoding.UTF8;
                message.From = new MailAddress(From);
                message.SubjectEncoding = System.Text.Encoding.UTF8;
                message.IsBodyHtml = true;
    
                SmtpClient client = new SmtpClient("relay.mail.server");
    
              await  client.SendMailAsync(message);  //await 这里会阻塞线程,直到邮件发送完毕
        }
           return RedirectToAction("Index");//发送完邮件才执行到这里!
    }

    可以用后台线程吗?

    答案也是否定的!

    IIS工作线程是用于处理请求的,不适合运行后台任务,当应用程序池回收的时候,会丢掉。

    最后,介绍 Hangfire 

    http://docs.hangfire.io/en/latest/tutorials/send-email.html#id3

    mvc项目,添加nuget包 hanfire

    安装包完毕后,可以看到,默认使用了sqlserver作为存储,并依赖Owin

    mvc根目录创建startup.cs,并配置sqlserver连接字符串

    using Hangfire;
    using Microsoft.Owin;
    using Owin;
    using System;
    
    [assembly: OwinStartupAttribute(typeof(HangFire.Startup))]
    namespace HangFire
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                string connectionStr = "Database=yourdb;Server=.;Uid=xxx;Pwd=xxx;Enlist=False;Pooling=true;Connection Reset=false;Trusted_Connection=no;Connect TimeOut=3000;";
                GlobalConfiguration.Configuration
                    .UseSqlServerStorage(connectionStr);
    
                BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));//测试
    
                app.UseHangfireDashboard();
                app.UseHangfireServer();
            }
        }
    }

    运行mvc项目,因为在startup.cs里,加了BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));//测试

    所以Hangfire第一次执行的时候,会在sqlserver里创建相关的表

     

    下面把发邮件的action改造下

    [HttpPost]
    public ActionResult Create(Comment model)
    {
        if (ModelState.IsValid)
        {
            _db.Comments.Add(model);
            _db.SaveChanges();
     MailMessage message = new MailMessage();          
            message.To.Add("xx@126.com");          
                message.Subject = "主题是";
                message.Body = string.Concat(HtmlEmailHeader, Body, HtmlEmailFooter);
                message.BodyEncoding = System.Text.Encoding.UTF8;
                message.From = new MailAddress(From);
                message.SubjectEncoding = System.Text.Encoding.UTF8;
                message.IsBodyHtml = true;
    
                SmtpClient client = new SmtpClient("relay.mail.server");
                BackgroundJob.Enqueue(() => client.Send(message));//发送工作交给Hangfire去后台处理了 
      } 
    return RedirectToAction("Index");//不管邮件是否发送成功就返回响应了
    }
    

      

  • 相关阅读:
    react 入坑笔记(五)
    练习
    高级指令
    进阶指令
    基础指令
    VMware 备份操作系统
    Ubuntu 用户的切换
    形态学转换
    图像模糊
    域名拆分 tld
  • 原文地址:https://www.cnblogs.com/imust2008/p/6813128.html
Copyright © 2011-2022 走看看