"proceed.Invoke(invocation)" calls again "AsyncInterceptorBase.InterceptAsync"
See original GitHub issueI am using IAsyncInterceptor
with the built-in .Net Core (3.1) IServiceCollection
to inject transactional behavior around my services and I am facing a very strange issue:
For some services, but not all of them (despite they are all registered the same way), in my implementation of AsyncInterceptorBase.InterceptAsync
, the call to proceed.Invoke(invocation);
internally recall InterceptAsync
, as you can see on this debugger screenshot:
Here is the associated call stack:
Here is how I register my services:
public static IServiceCollection AddProxy<TInterface, TImplementation>(this IServiceCollection services, ServiceLifetime lifetime)
{
// Register the service implementation
services.Add(new ServiceDescriptor(typeof(TImplementation), typeof(TImplementation), lifetime));
// Register the mapping interface <-> implementation
services.Add(new ServiceDescriptor(typeof(TInterface), serviceProvider =>
{
// Get a new interceptor instance
var interceptor = serviceProvider.GetRequiredService<EndonextAsyncInterceptor>();
var hasTransactionAttributes = typeof(TImplementation)
.GetMethods()
.SelectMany(m => m.GetCustomAttributes(typeof(TransactionAttribute), false))
.Any();
// Inject the DbContext if necessary
if (hasTransactionAttributes)
{
interceptor.DbContext = serviceProvider.GetRequiredService<EndonextDbContext>();
}
// Get the proxy generator and the service implementation instances
var proxyGenerator = serviceProvider.GetRequiredService<ProxyGenerator>();
var actual = serviceProvider.GetRequiredService<TImplementation>();
// Return the proxy
return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(TInterface), actual, interceptor);
}, lifetime));
return services;
}
IServiceCollection services;
services
.AddTransient<AsyncInterceptor>()
.AddSingleton<ProxyGenerator>()
.AddWithProxy<IService, Service>(ServiceLifetime.Scoped);
Here is the way I get my service instance:
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IService>();
await service.MyCallAsync();
}
And here is my simplified implementation of the IAsyncInterceptor
:
public class AsyncInterceptor : AsyncInterceptorBase
{
private readonly ILogger<AsyncInterceptor> _logger;
public AsyncInterceptor(ILogger<AsyncInterceptor> logger)
{
_logger = logger;
}
protected override async Task InterceptAsync(IInvocation invocation, Func<IInvocation, Task> proceed)
{
LogEntry(invocation);
bool inError = false;
try
{
await this.BeginTransactionAsync(invocation);
await proceed.Invoke(invocation);
}
catch (Exception)
{
inError = true;
throw;
}
finally
{
await this.CommitTransactionAsync(invocation, inError);
}
LogExit(invocation);
}
}
I only use IInvocation in the BeginTransaction
and CommitTransaction
for reflection purpose (getting an attribute associated to the invoked method).
I did not found any obvious difference between my services declaration, implementation nor, registration.
Do you have an idea of what is going on?
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
Looks related to some of the things you fixed for me so the upgrade fixing it makes sense to me!
On Fri, Dec 18, 2020, 4:05 AM James Skimming notifications@github.com wrote:
Yes I am using the 1.7.0 version. I migrated to 2.0.21-alpha and it apparently solves the case, no matter the order of execution of my HostedServices. It’s good for me !
Thank you for this great package by the way ! Can’t wait for the 2.0 version 😄.