Мне нужно отправить смс в фоновом режиме. Для этого я использую функцию HostedService для Asp.Net Core 2.x. Но приложение не может запуститься правильно. У меня есть работающий SMS-сервер. Я отправляю HTTP-запрос на этот сервер для отправки смс.
Вот мой интерфейс:
public interface ISmSHandlerForCashBaba
{
void SendSMS(string mobileNumber, string message);
}
Вот мой код реализации
public class SmSHandlerForCashBaba : ISmSHandlerForCashBaba, IHostedService, IDisposable
{
//The BufferBlock<T> is a thread-safe producer/consumer queue
private readonly IConfiguration _configuration;
private readonly ILogger logger;
private readonly IHttpClientFactory _clientFactory;
private string FullUrl;
private Task sendTask;
private CancellationTokenSource cancellationTokenSource;
public SmSHandlerForCashBaba(IHttpClientFactory clientFactory, IConfiguration configuration, ILogger<SmSHandlerForCashBaba> logger)
{
_clientFactory = clientFactory;
_configuration = configuration;
this.logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Starting background e-mail delivery");
cancellationTokenSource = new CancellationTokenSource();
//The StartAsync method just needs to start a background task (or a timer)
sendTask = Send(cancellationTokenSource.Token);
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
//Let's cancel the e-mail delivery
CancelSendTask();
//Next, we wait for sendTask to end, but no longer than what the web host allows
await Task.WhenAny(sendTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
private void CancelSendTask()
{
try
{
if (cancellationTokenSource != null)
{
logger.LogInformation("Stopping e-mail background delivery");
cancellationTokenSource.Cancel();
cancellationTokenSource = null;
}
}
catch
{
}
}
//This public method will be used by other services (such as a Controller)
//to post messages to the email sender service.
//They will be sent asynchronously in background
//TODO: make the Post method return an operation Guid so that the client can
//check whether the e-mail has been sent or not at a later time
public void SendSMS(string mobileNumber, string message)
{
var builder = new UriBuilder(_configuration["SmsService:url"]);
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
query["Username"] = _configuration["SmsService:userName"];
query["Password"] = _configuration["SmsService:password"];
query["To"] = mobileNumber;
query["Message"] = message;
builder.Query = query.ToString();
FullUrl = builder.ToString();
}
public async Task Send(CancellationToken token)
{
logger.LogInformation("E-mail background delivery started");
while (!token.IsCancellationRequested)
{
try
{
var request = new HttpRequestMessage(HttpMethod.Get, FullUrl);
//Let's wait for a message to appear in the queue
//If the token gets canceled, then we'll stop waiting
//since an OperationCanceledException will be thrown
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
logger.LogInformation($"E-mail sent to");
}
//as soon as a message is available, we'll send it
logger.LogInformation($"E-mail sent to");
}
catch (OperationCanceledException)
{
//We need to terminate the delivery, so we'll just break the while loop
break;
}
catch
{
#warning Implement a retry mechanism or else this message will be lost
logger.LogWarning($"Couldn't send an e-mail to");
}
}
logger.LogInformation("E-mail background delivery stopped");
}
public void Dispose()
{
CancelSendTask();
}
}
и его часть для внедрения зависимостей
services.AddSingleton<SmSHandlerForCashBaba>();
services.AddSingleton<IHostedService>(serviceProvider => serviceProvider.GetService<SmSHandlerForCashBaba>());
services.AddSingleton<ISmSHandlerForCashBaba>(serviceProvider => serviceProvider.GetService<SmSHandlerForCashBaba>());