Issue with service method call in .NET Background Service , Issue with Scope

83 views Asked by At

I'm facing a weird issue not sure, it's related to scope or async-await.

Basically, I've a Background service (singleton), which is registered as:

services.AddHostedService<JobBackgroundService>();

the implementation, is simple as below:

public JobBackgroundService(
      ILogger<JobBackgroundService> logger,
      IServiceProvider serviceProvider)
{
          _logger = logger;
          _serviceProvider = serviceProvider;
}

...
using var scope = _serviceProvider.CreateScope();
var _detailServiceAsync = scope.ServiceProvider.GetRequiredService<IDetailServiceAsync>(); 
JsonSerializerOptions options = new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
};
var deserializedMessage = JsonSerializer.Deserialize<NotificationObject>(<custom-notification-as-string>, options);
await _detailServiceAsync.OnCreated(deserializedMessage);

the above code works as expected.(data stored in detail table)!!

Now I've a requirement to introduce a new IMessageService (via NuGet) and after invoking the _detailServiceAsync.OnCreated, need to Invoke SendAsync method of messageService based on result.

I changed my code as below :

public JobBackgroundService(
      ILogger<JobBackgroundService> logger,
      IServiceProvider serviceProvider)
{
    _logger = logger;
    _serviceProvider = serviceProvider;
}

...
using var scope = _serviceProvider.CreateScope();
var _detailServiceAsync = scope.ServiceProvider.GetRequiredService<IDetailServiceAsync>();
var _messageService = scope.ServiceProvider.GetRequiredService<IMessageService>(); //<<< Changed code
JsonSerializerOptions options = new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
};
var deserializedMessage = JsonSerializer.Deserialize<NotificationObject>(<custom-notification-as-string>, options);
var result = await _detailServiceAsync.OnCreated(deserializedMessage);
if(result)
    await _messageService.SendAsync(deserializedMessage); //<<< Changed code

This doesn't work, SendAsync does execute, but I don't see data in DB and there is no error/exception as well.

However for testing : if I move the _messageService.SendAsync call above _detailServiceAsync.OnCreated, Then both functions works. Data does get stored in DB(message & detail tables).

await _messageService.SendAsync(deserializedMessage); //<<< moved up
var result = await _detailServiceAsync.OnCreated(deserializedMessage);

I tried calling the SendAsync as callback function, but still same issue.,

I tried passing IMessageService to DetailService and called SendAsync inside OnCreated method, but then also same issue. Looks like SendAsync just doesn't work as soon as _detailServiceAsync.OnCreated invoked/executes.

Not sure what I'm missing here ?

Updated part below :

After debugging more, the reason found is the order of dbcontext SaveChanges. Currently there are 2 dbContext in picture : one is MyAppDbContext & another one is ExternalAppDbContext added by NuGet package (in it own implementation) exposed as Middleware.

My application dbContext is added as services.AddDbContextPool<MyAppDbContext>(...) and NuGet DbContext is added as serviceCollection.AddDbContext<ExternalAppDbContext>(....)

So when MyAppDbContext.SaveChanges(); gets called first, then ExternalAppDbContext saveChanges doesn't work., but if order is reversed : means MyAppDbContext.SaveChanges(); called after external one, then everything works as expected.

though my problem is solved, but still curious to know : what is leading to this behavior, is it something with EFCore or the way context is being added to MyApp. Online research didn't help much, so posting here to get some insights and to know the root-cause of it.

0

There are 0 answers