7

I have a MVC application and I am trying to send an email using Hangfire and Postal. The email must be sent after a registration. The registration works properly, but the job I run remain enqueued and I not receive any email. So in my MVC controller I have the following code:

public async Task<ActionResult> Register(RegisterViewModel model)
{
    //register correctly the user

    //I send the email
    BackgroundJob.Enqueue(() => 
        NotifyRegistration(user.Id, user.UserName, user.Email)   
    );

    ...
 }

[AutomaticRetry(Attempts = 5)]
public async Task NotifyRegistration(string userId, string username, string email)
{
    //I calculate callbackUrl

    var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(@"~/Views/Emails"));
    var engines = new ViewEngineCollection();
    engines.Add(new FileSystemRazorViewEngine(viewsPath));

    var emailService = new EmailService(engines);

    var emailToSend = new NewRegisteredUserEmail
    {
        To = email, UserName = username, CallbackUrl = callbackUrl 
    };

    emailService.Send(emailToSend);
}

I cannot debug the NotifyRegistration method. I don't know why. I am using Postal, so EmailService is not my implementation. Here how I configured the smtp service:

<system.net>
  <mailSettings>
    <smtp deliveryMethod="Network">
      <network host="smtp.live.com" port="25" enableSsl="true" userName="***" password="***"></network>
    </smtp>
  </mailSettings>
</system.net>

If I run the hangfire dashboard I see the jobs enqued

enter image description here

But nothing else happened. What do I miss to send the email?

Thank you

UPDATE In the startup.cs I have written this:

var options = new SqlServerStorageOptions
{
    QueuePollInterval = TimeSpan.FromSeconds(1)
};

GlobalConfiguration.Configuration
     .UseSqlServerStorage("DbConnectionString", options)
     .UseFilter(new LogEmailFailureAttribute());

 app.UseHangfireDashboard();
 app.UseHangfireServer();

UPDATE 2 I transformed my NotifyRegistration in this way:

[AutomaticRetry(Attempts = 5)]
public async Task NotifyRegistration(string userId, string username, string email, EmailService emailService)
{
    //I calculate callbackUrl

    var emailToSend = new NewRegisteredUserEmail
    {
        To = email, UserName = username, CallbackUrl = callbackUrl 
    };

    emailService.Send(emailToSend);
}
Simone
  • 2,304
  • 6
  • 30
  • 79

3 Answers3

7

I Found the problem(s):

  1. The version of sql server was not supported. I was using 2005. Supported database is 2008R2 and later: http://docs.hangfire.io/en/latest/configuration/using-sql-server.html

  2. The method NotifyRegistration must be static: https://discuss.hangfire.io/t/jobs-in-enqueue-state-most-never-run/2367/4

.

[AutomaticRetry(Attempts = 5)]
public static void NotifyRegistration(string userId, string username, string email, EmailService emailService)
{
    //I calculate callbackUrl

    var emailToSend = new NewRegisteredUserEmail
    {
        To = email, UserName = username, CallbackUrl = callbackUrl 
    };

    emailService.Send(emailToSend);
}
Simone
  • 2,304
  • 6
  • 30
  • 79
1

Without seeing your Hangfire configuration...

Do you have app.UseHangfireServer(); anywhere? That is what tells Hangfire that it needs to do the executing - otherwise you're simply queuing as it expects something else to do the execution.

  • Yes I have it... However I have updated my post.... so you can see what I have done... – Simone Sep 16 '16 at 12:37
  • Just to rule things out, and because I have read that polling too frequently can cause issues, can you remove your custom polling and see if it executes? – user2120800 Sep 17 '16 at 02:44
  • Also see http://stackoverflow.com/questions/39485570/queuing-bankgroundjob-with-hangfire-within-an-async-action-in-asp-net-mvc-freeze Why is your method async Task instead of simply void? Because it was migrated over? Again - grasping at straws - but everything is worth a shot at this point. ;) – user2120800 Sep 17 '16 at 02:58
0

My guess is that is has something to do with either

  1. the call to HostingEnvironment.MapPath(), or
  2. some internal construction detail of the EmailService type.

What strikes me is that there is an awful lot going on in this method and it could be made significantly simpler if:

  1. rather than instantiating a new EmailService, you passed one into the containing class as an already instantiated dependency, and also
  2. rather than trying to divine the physical file path to your templates directory from within the method you passed it into the method as an argument.

If you were to perform this refactoring I would bet a not insignificant number of kittens that this problem would go away.

tom redfern
  • 30,562
  • 14
  • 91
  • 126
  • I had copied the method from their web site: http://docs.hangfire.io/en/latest/tutorials/send-email.html#installing-hangfire they also suggest not to pass complex type to method run in backgroundjob, due to serialization complexity... however, give me some minutes that I try your solution – Simone Sep 16 '16 at 12:40
  • I transformed the method as you said, but nothing changed and nothing raises an exception.. see the update 2 – Simone Sep 16 '16 at 12:47