Quick question - I’m currently using the OrmLiteConfig.InsertFilter / UpdateFilter hooks to perform auditing. When using an Asp.net host I’m using the RequestContext.Instance.Items to store the CurrentUserId from the session as part of a global filter and this can then be picked up in the filter.
However I want to do a similar things when the request originates from the MqServer, I have the UserId in the request items, but the problem is RequestContext is not relevant as its not Asp.Net originated. Therefore I wondering if there is a static context I can use to store the UserId when the request originates from the Mq Server? Or alternatively can I can get at the current request from the Ormlite filters?
Ideally I’d use IRequest.Items to store items for the current request for both HTTP + MQ Requests but you should still be able to use RequestContext.Instance for MQ Requests, but it will fallback to using ThreadStatic.
The reason it wasn’t working for the MQ is that a message was waiting in the queue and I was starting the MQ server during the initialization which meant that this was fired.
if (!ServiceStackHost.IsReady())
return new Dictionary<object, object>();
However I’ve just noticed another small problem is that if an exception occurs during a normal service call it seems the RequstContext is lost? Is this behavior by design?
Ahh ha, I think it’s down to the continuations in the servicerunner…
return taskResponse.ContinueWith(task =>
{
if (task.IsFaulted)
{
var ex = task.Exception.UnwrapIfSingleException();
//Async Exception Handling
var result = HandleException(request, requestDto, ex);
if (result == null)
return ex;
return result;
}
Its looses the synchronization context. This would need ContinueWith(…, TaskScheduler.FromCurrentSynchronizationContext()) specified.
Obviously on MQ calls there is no SyncronizationContext so it would need to be created when
SynchronizationContext.Current is null.
I’ll go ahead and implement this in my own IServiceRunner, but is there scope to do some work on an async service runner in the future?
I did this - however still not quite there and looking for some advise. The reason I wan’t to preserve data in the RequestContext is due to logging. I’m storing the current correlation Id into the RequestContext so I can hydrate any logging requests (Serilog enricher) with this information.
I have implemented a custom service runner (as mentioned above) which includes TaskScheduler.FromCurrentSynchronizationContext() on the continuation and the context is preserved down the ServiceExceptionHandlers which is good. However where an error is also logged internally for example in MessageHandler the context is lost. Looking at the code appears that their are continuations in a few places ie / ServiceGateway / ServiceController etc.
Obviously I want to keep any modification to a minimum - so look for some advise on this issue?
I suppose I could just switch off service stack logging but this does not feel right.
Unfortunately there are several ContinueWith overloads used that would need to be overridden which I’d prefer to be maintained in a different class to avoid polluting the AppHost, which could be configured with:
class AsyncContext
{
public virtual Task ContinueWith(IRequest req, Task task, Action<Task> fn)
{
return task.ContinueWith(fn);
}
public virtual Task<Task<object>> ContinueWith(IRequest req, Task<object> task, Func<Task<object>, Task<object>> fn)
{
return task.ContinueWith(fn);
}
public virtual Task<object> ContinueWith(IRequest req, Task task, Func<Task, object> fn)
{
return task.ContinueWith(fn);
}
}
HostContext.Async = new AsyncContext();
Which you could override with your own custom impl, e.g:
You are the man. This hook would hit the nail on the head. If I can maintain the context throughout then problem solved.
I presume the ContinueWith wrapper would be referenced from all places throughout the chain including ServiceGateway, ServiceController and ServiceRunner?