I can't figure out why my dependency injection is not working as expected, when my controller is hit the constructor of MyFirstService
is being hit again and therefore I am hitting a different cancellation token to the one I wish to be when calling the StopFeeds()
method.
I have tried to add the controller in as a singleton and use the controller's StartFeed()
method to instantiate the class but no matter what I do with DI (general ctor DI, explicit property assignment, [FromServices]
and even directly passing in the service collection) when I hit stop feeds it will create another instance of MyFirstService
... Any ideas?
Interface:
public interface IFirstService : IService
{
OrderDto CreateOrder(Order order);
Task<string> ProcessOrder(string orderXml);
void ProcessLineItems(ref List<NewLineItem> items, ref int lineNum, Item i, string orderId);
NewOrderEvent NewOrderEvent(OrderDto newOrder, Order order, List<NewLineItem> lineItems);
}
MyFirstService :
public class MyFirstService : IFirstService
{
private SftpService _sftpService;
private readonly ITimer<MyService> _timer;
private readonly IMediator _mediator;
private readonly ILogger<MyService> _logger;
private readonly MyFirstConfig _iOptions;
private CancellationTokenSource CancellationTokenSource;
public MyService(IMediator mediator, ILogger<MyService> logger, IOptionsSnapshot<MyFirstConfig> iOptions)
{
_mediator = mediator;
_timer = new Timer<MyFirstService>(logger);
_logger = logger;
_iOptions = iOptions.Value;
CancellationTokenSource = new CancellationTokenSource();
CancellationTokenSource.Token.Register(FeedStopped);
}
private void CreateSftpService()
{
_sftpService = new SftpService(_iOptions.SftpOptions);
}
public void StartFeed()
{
CreateSftpService();
StartFeed(TimerSchedule);
}
public void StartFeed(TimeSpan timeSpan)
{
_timer.ScheduleCallback(timeSpan, ProcessOrderFeedAsync, CancellationTokenSource.Token);
}
public void StopFeed()
{
CancellationTokenSource.Cancel();
_sftpService.Dispose();
}
Startup:
services.Configure<MyFirstConfig>(Configuration.GetSection("FirstSection"));
services.Configure<MySecondConfig>(Configuration.GetSection("SecondSection"));
services.AddSingleton<IFirstService, MyFirstService>();
services.AddSingleton<ISecondService, MySecondService>();
var serviceProvider = services.BuildServiceProvider();
serviceProvider.GetRequiredService<IFirstService>().StartFeed();
serviceProvider.GetRequiredService<ISecondService>().StartFeed();
Controller: (I do handle other status codes, I stripped out the try/catch as they are irrelevant)
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using System.Threading.Tasks;
using SFTP.Services;
using System;
namespace API.Controllers
{
[Route("api/[controller]/")]
[ApiController]
public class MyController : Controller
{
[HttpPost]
[Route("feeds/start")]
public IActionResult StartFeed([FromServices] IFirstService myService)
{
myService.StartFeed();
return Ok();
}
[HttpPost]
[Route("feeds/stop")]
public IActionResult StopFeed([FromServices] IFirstService myService)
{
myService.StopFeed();
return Ok();
}
}
}
The issue was that a service provider was being generated and used to start the feeds as part of configure services so that when the dependency injection was resolving itself a new instantiation was being forced.
I have moved the logic in to the Configure()
method and IApplicationBuilder
now handles starting the feeds to generate the instance of each service:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyFirstConfig>(Configuration.GetSection("Next"));
services.Configure<MySecondConfig>(Configuration.GetSection("CustomGateway"));
services.AddSingleton<IFirstService, MyFirstService>();
services.AddSingleton<ISecondService, MySecondService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.ApplicationServices.GetRequiredService<IFirstService>().StartFeed();
}