0

With StructureMap, I am registering an interface as follow:

public class PersistenceRegistry : Registry
{
    public PersistenceRegistry()
    {
        For<IClearableSessionProvider>().HybridHttpOrThreadLocalScoped().Use<FirebirdSessionProvider>();   
    }
}

I would like to know if it is possible to detect by any ways if the resolved instance is resolved from an HttpContext or a "ThreadContext". I don't even need to have access to the context. I just want to know whether I am in the context of an HttpRequest or from a background thread.

I tried several things consisting of injecting the HttpContext if it exists, but whatever I tried, I always get a null reference.

I tried to register an IHttpContextProvider:

public interface IHttpProvider
{
    HttpContext GetHttpContext();
}

public class HttpProvider
{
    HttpContext GetHttpContext()
    {
        return HttpContext.Current;
    }
}

But HttpContext.Current is always null (even once I get into the controller call).

I tried to register an HttpContextWrapper but also always null:

For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current))

I am using StructureMap-2.6.3.0. I am not sure how to formulate correctly but the app is built upon OWIN (which explains why my attempts always return null if I understand correctly what I have been reading before coming here).

fharreau
  • 2,105
  • 1
  • 23
  • 46
  • Why are you targeting .NET Framework 4.7.2? – Dai Nov 14 '22 at 14:22
  • @Dai: it is a legacy application. – fharreau Nov 14 '22 at 14:26
  • Just because it's legacy doesn't mean you can't take 15 seconds to retarget it to .NET Framework 4.8. There is _no good reason_ to continue to target 4.7.2 when 4.8 is fully backwards compatible (and we're up to 4.8.1 now too). – Dai Nov 14 '22 at 14:44
  • I can give it a try but does it have a chance to solve the issue? – fharreau Nov 14 '22 at 14:48
  • Oh, no - I'm just being an curmudgeon – Dai Nov 14 '22 at 14:50
  • _"I just want to know whether I am in the context of an HttpRequest or from a background thread."_ - sort-of: `HttpContext.Current` is a wrapper over `System.Runtime.Remoting.Messaging.CallContext.HostObject` which does gnarly stuff with `System.Threading.Thread.ExecutionContext`. _At most_ you can find out if the current `Thread` is associated with a `HttpContext` or not - but that's it (i.e. AFAIK, you can't enumerate all active `HttpContext` instances and get their associated threads) - I'm unsure what your real objective is here... – Dai Nov 14 '22 at 14:53
  • I want to know if my resolved instance, registered with `HybridHttpOrThreadLocalScoped` is resolved from a `BackgroundThread` or a `HttpContext`. I don't care to actually access the HttpContext. – fharreau Nov 14 '22 at 15:01
  • But why? What problem are you trying to solve? – Dai Nov 14 '22 at 15:02
  • The same service is injected into my controllers and my background workers. For transaction management, it would like to know which context is calling the service. – fharreau Nov 14 '22 at 15:07
  • ...that sounds like you have a fundamental design problem because, primarily, _it shouldn't matter_, and secondarily: whatever your "transaction management" types are, they have no business knowing anything about `HttpContext`. You should move those to a separate project that doesn't reference `System.Web.dll` at all to prevent that from happening. – Dai Nov 14 '22 at 15:10
  • The application possibly has a design issue, but I have to deal with it now. And as I said, I don't care having access to the HttpContext... – fharreau Nov 14 '22 at 15:15
  • The short answer is that it's impossible: .NET does not _reify_ the call-stack to allow runtime introspection, nor does it support any kind of _ambient context_ (except for thread-unsafe hacks implemented using thread-local-storage and async-local). Have you considered just having a separate DI service for web call-sites and another for non-web call-sites? – Dai Nov 14 '22 at 15:18
  • `Have you considered just having a separate DI service for web call-sites and another for non-web call-sites? ` => not yet, but that's a lead. But I was hoping a solution from `structuremap`. It knows if it resolving an instance from an HttpContext or a background thread – fharreau Nov 14 '22 at 15:23
  • If you're referring to `StructureMap.MVC5`, I believe it does it by using a `HttpModule` to bind a container to a `HttpContext` from the very beginning in the `HttpContext` lifespan - which means what really matters is the circumstances of a container's creation. But what do you mean by "background thread"? All threads in ASP.NET are _background threads_ (insofar as they aren't Win32 _foreground threads_). – Dai Nov 14 '22 at 15:28
  • With the use of `HybridHttpOrThreadLocalScoped`, StructureMap associates the instance with the HttpContext if it exists or fallbacks to the calling thread otherwise (https://stackoverflow.com/a/3018592/2183236) – fharreau Nov 14 '22 at 15:32
  • 1
    I'm not too familiar with StructureMap, but it sounds like a _thread-local-scoped container_ can't be passed between threads and will break when used with `async`/`await`+`ConfigureAwait(false)` (though that's unsurprising as that QA you linked-to is from 2010 which predates `await`. I don't think it's wise to do this in projects today. – Dai Nov 14 '22 at 15:34
  • Yup we have an issue with that too, but we found a workaround. And fortunatelly, we are not using so much async/await APIs (Legacy app with no budget for major refactor T_T). – fharreau Nov 14 '22 at 15:39
  • Migrating to .NET 4.8 does not change anything by the way (with my `IHttpContextProvider` test). – fharreau Nov 14 '22 at 15:42

0 Answers0