How safe to use HttpContext when self hosting in web app/service

netcore

(Calvin) #1

I have a bunch of micro services in .NET Core and I plan to host message handlers there. The internal service layers of these services will be called by both web api controllers and the message handler.

Some of the data are set in current httpContext in web api level (through filters etc) and service layer gets data through httpContext.Current. For example, my AuthenticationFilter sets UserIdentity to the current httpContext so that server layers get current user info there. We also use Items collection. This works fine since each web api request is distinct and separated from each other.

But now we have message handlers that are invoked by NServiceBus. Since they are not through the normal MVC pipeline, I wonder what’s the implication on their HttpContext. Does each invocation have brand new and district HttpContext? Can I still pass message-specific data in httpContext.Current?

This is .net core 2.0. Thanks!


(Mauro Servienti) #2

Hi Calvin,

When a message will be delivered to such an endpoint the message handling
context will be totally disconnected from the WebApi HttpContext, in
message handlers there won’t be any HttpContext available.
On the hand when sending out a message while in the context of an incoming
HttpRequest obviously the HttpContext will be available.

.m


(Calvin) #3

Thanks M. Yes this is about handling incoming messages only.

I understand there is no HttpContext available in message handlers. But I plan to inject a IHttpContextAccessor instance and use that instance to get current HttpContext in each handler invocation. So what I want to confirm is that if the HttpContext instance I obtained from the injected IHttpContextAccessor is unique and properly disposed in each invocation.

This actually sounds a question to Asp.Net. But since self-hosting in web app is common, I want to hear from your experience.

Thanks.


(Ramon Smits) #4

as Mauro stated, it is disconnected. Just think about your message handler is not running in the same process

There is no way to get the http context within a handler. If you need meta data, that data should be added during the sending of a message. You can add that data to your message itself but if you want to have a generic approach then you can add message headers based on values from the http context.

There are multiple ways in adding headers as message type options, mutators, and behaviors which is all documented at the following location:

You mention authentication which in general should be tried to be done BEFORE sending a messsage especially as you own the sending part. For example, when you send a message you check authentication before sending.

Does that help and does it make sense?

— Ramon


(Calvin) #5

Thank you all.

It turned out that the behavior is a little different depending on when I start the endpoint. If I start my endpoint during web app start up (ConfigureService), I will get null back from the injected IHttpContextAccessor. However, if I start the endpoint by the first http request, I will have a http context (from IHttpContextAccessor) and will always have access to it. I had mixed results in my test regarding if this context is distinct with different invocation, but I’m convinced that HttpContext isn’t reliable in message handler to pass ambient context. I will look into AsyncLocal<> for that.


(Ramon Smits) #6

That is what we mentioned, it isn’t available when processing a message. Assume that your message is processed in another process. A message is stored on disk, out of process, and then read ‘later’. You seem to be applying messaging and making it fit in a way that doesn’t seem correct.

I really suggest you don’t use AsyncLocal<> and to just add meta data when sending the message as shared in my previous comment.

Maybe you can share your motivation on doing this? Maybe there is another solution that you can consider but we can only give you other solutions if you provide us with more information.

– Ramon


(Calvin) #7

Hi Ramon,

I do add some info to my custom message header already - security token, app keys etc. These headers will be passed from the senders and received by the handler.

My message handlers and my web service reside in the same web api project. The web api layer can accept Rest request then pass it to the internal business layer which also calls DB layer. I have a feature in my DbContext to get current user info from an ambient context so that I can auto populate the “UpdatedBy” field in the table. This “auto stamping” has been working well and my developers don’t have to set these audit fields.

Now the message handlers will act as another interface to receive requests then simply pass them to the same business layer (DRY principle right?). Please note at this time all data have been transferred to my existing domain models already. Now I have a problem in the DbContext - how do I get current user info? My current implementation uses HttpContext.User which wont’ work anymore. That’s why I’m looking for another way to pass this context info.

I would love to hear your thoughts on this. Passing these context data explicitly either as method parameters or as domain models meta data is my last option.

Thanks!


(Mauro Servienti) #8

Calvin,

The easiest option is to perform authentication at message sender site,
before sending the message take the current user identifier, sign it, and
put it into message headers, or add it as an encrypted property to the
message itself.

When message is received the receiver can then verify the signature and
rebuild the current user identity and use it as you are doing in your
domain.

.m


(Ramon Smits) #9

Seems this is the solution:

In the past we had a feature that would set this automatically for an incoming message. This was removed, but can be easily done via the following example:

If you make sure that your existing code uses not httpcontext, but the generic Thread.CurrentPrincipal it seems your issue is solved.

– Ramon


(Calvin) #10

Thank you for these links. Unfortunately we are using .NET Core and async methods extensively. Thread.CurrentPrincipal no longer works for async calls.

I tested with asynclocal<> and it worked pretty well for me for my async calls. Any reason you are against using it?


(Ramon Smits) #11

I’m not against the usage of it, using that to add meta data to your message is fine but you cannot use it to read meta data during your message processing itself. The sending is isolated from the receiving.

– Ramon