I'm developing Asp.Net Core MVC Web Application where I have to check if "EndOfSubscription" of any user is over daily. I have to set all users as "Expired" and then send an email to that user.
The whole process should be implemented as background task. Now, it works successfully everyday and it sets the users as "Expired" fine. But my problem is how can I send the email after setting the user as "Expired" immediately. Since I have to use (await) to send an email but I Knew that's a bad practice to use (await) for void methods. And i tried to do extension method but it didn't works as expected.
Here is my startup file.
public void ConfigureServices(IServiceCollection services)
{
---------- Lines of Code ----------
services.AddSingleton<IEmailSender, EmailSender>();
services.Configure<EmailOptions>(Configuration);
services.AddHangfire(config => config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddHangfireServer();
services.AddScoped<IExpirationJob, ExpirationJob>();
}
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env,
IRecurringJobManager recurringJobManager,
IServiceProvider serviceProvider)
{
---------- Lines of Code ----------
app.UseHangfireDashboard();
//app.UseHangfireDashboard("/hangfire", new DashboardOptions()
//{
// Authorization = new[] { new CustomAuthorizeFilter() }
//});
app.UseAuthentication();
app.UseAuthorization();
recurringJobManager.AddOrUpdate(
"End Users Subscription",
() => serviceProvider.GetService<IExpirationJob>().SetExpired(),
Cron.Minutely
);
}
}
}
Here is ExpiredUsersServices file
public interface IExpirationJob
{
void SetExpired();
}
public class ExpirationJob : IExpirationJob
{
private readonly ApplicationDbContext _db;
private readonly IEmailSender _emailSender;
public ExpirationJob(ApplicationDbContext db, IEmailSender emailSender)
{
_db = db;
_emailSender = emailSender;
}
public void SetExpired()
{
foreach(var item in _db.Institution)
{
if (item.EndOfSubscriptionDate <= DateTime.Today)
{
item.Status = SD.StatusExpired;
//await _emailSender.SendEmailAsync( item.Admin.Email, "Your Account is Expired !", "Your subscription is over and your account is expired.");
}
}
await _db.SaveChangesAsync();
}
}
Any help is appreciated.
you can set Task as the return type for your method:
public interface IExpirationJob
{
Task SetExpired();
}
public class ExpirationJob : IExpirationJob
{
private readonly ApplicationDbContext _db;
private readonly IEmailSender _emailSender;
public ExpirationJob(ApplicationDbContext db, IEmailSender emailSender)
{
_db = db;
_emailSender = emailSender;
}
public async Task SetExpired()
{
foreach(var item in _db.Institution)
{
if (item.EndOfSubscriptionDate <= DateTime.Today)
{
item.Status = SD.StatusExpired;
await _emailSender.SendEmailAsync( item.Admin.Email, "Your Account is Expired !", "Your subscription is over and your account is expired.");
}
}
await _db.SaveChangesAsync();
}
}
With this approach you'll have to change the caller of this method to await it.