I created some interceptors for request logging, response logging and exception with autofac and castle. Some methods can have request logs and some response logs or both. I want to wire up requests with exceptions and responses.
I mean I want to pass request id to other interceptors. I don't want to keep all of them in one interceptor. Is there a way to get unique id from invocation or shared variable on same invocation?
Let's check code below, I want to access same id to wire before and after logs.
public class BeforeAspect : IInterceptor
{
public BeforeAspect()
{
}
public void Intercept(IInvocation invocation)
{
System.Diagnostics.Debug.WriteLine("some id on before");
invocation.Proceed();
}
}
public class AfterAspect : IInterceptor
{
public AfterAspect()
{
}
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
System.Diagnostics.Debug.WriteLine("exact id like before");
}
}
Thanks in advance.
To get a unique identifier for the actual request you can introduce a new service that will provide this identifier.
For example let's call it IContextIdentifier
public interfac IContextIdentifier
{
String Identifer { get; }
}
And
public class BeforeAspect : IInterceptor
{
public BeforeAspect(IContextIdentifier contextIdentifier)
{
this._contextIdentifier = contextIdentifier;
}
private readonly IContextIdentifier _contextIdentifier;
public void Intercept(IInvocation invocation)
{
System.Diagnostics.Debug.WriteLine($"id is {this._contextIdentifier.Identifier}");
invocation.Proceed();
}
}
the concrete implementation of IContextIdentifier
could be as simple as :
public class SimpleContextIdentifier : IContextIdentifier
{
public SimpleContextIdentifier()
{
this.Identifier = Guid.NewGuid().ToString();
}
public String Identifier { get; private set; }
}
Then you register the ContextIdentifier
as InstancePerLifetimeScope
to have a unique instance per request.
builder.RegisterType<SimpleContextIdentifier>()
.As<IContextIDentifier>()
.InstancePerLifetimeScope();
You can also use the HttpContext.TraceIdentifier
property if you have access to an HttpContext;
HttpContext
public class HttpContextIdentifier : IContextIdentifier
{
public SimpleContextIdentifier(IHttpContextAccessor httpContextAccessor)
{
this._httpContextAccessor = httpContextAccessor;
}
private readonly IHttpContextAccessor _httpContextAccessor;
public String Identifier => this._httpContextAccsor.TraceIfentifier;
}
As far as I know there is no built-in solution to obtain the current method call identifier using Castle.Core interception framework. But you can use ConditionalWeakTable
on IInvocation
instance to get a unique identifier.
public class MethodCallIdentifier<T> : IMethodCallIdentifier
where T : class
{
private class Key
{
public Key()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; private set; }
}
public MethodCallIdentifier()
{
this._identifiers = new ConditionalWeakTable<T, Key>();
}
private readonly ConditionalWeakTable<T, Key> _identifiers;
public Guid GetUniqueIdentifier(T obj)
{
Key key = this._identifiers.GetOrCreateValue(obj);
return key.Id;
}
}
you should register MethodCallIdentifier
as single instance
builder.RegisterGeneric(typeof(MethodCallIdentifier<>))
.As(typeof(IMethodCallIdentifier<>))
.SingleInstance;
and then your interceptors can have a dependency on IMethodCallIdentifier<IInvocation>
I have not tried this solution, but it should work.