Git Product home page Git Product logo

Comments (20)

maximcus avatar maximcus commented on June 7, 2024 1

Yes that works if the handler completes synchronously. If it's async then it won't flow to the controller.

@davidfowl , can you please elaborate on this. Did you mean that ExecutionContext can be lost between PreRequestHandlerExecute and the next step if Action (on a Controller) processing the request is an async method? If so then why?

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

Why not use httpContext.Items?

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

httpContext will not be propagated across async/await. So we need to set AsyncLocal. And if we set it in middleware or http module - it will be reset before the controller execution

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

httpContext will not be propagated across async/await

What exactly do you mean by that?

So we need to set AsyncLocal

The IIS pipeline isn't a single asynchronous call chain and I don't know if ASP.NET captures and restores the execution context when pipeline events execute.

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

Sorry for mixing up the issues. I think there are two I mostly concerned of:

  1. The context set in middleware will not be propagated to the Controller execution (when running in IIS) and will propagate when running as a self host.
  2. If we will take dependency on HttpContext.Current.Items in middleware (making a special case for IIS) to set context - this context will not propagate into await part of controller when it will run any async task. So we will not be able to correlate telemetry from those parts with the initial request.

I know the limitation of HttpModule and that Begin callback will not always execute on the same managed thread as other callbacks. But it is a separate issue.

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

The context set in middleware will not be propagated to the Controller execution (when running in IIS) and will propagate when running as a self host.

By "context" you mean async local right?

If we will take dependency on HttpContext.Current.Items in middleware (making a special case for IIS) to set context - this context will not propagate into await part of controller when it will run any async task. So we will not be able to correlate telemetry from those parts with the initial request.

I don't get that part (forgive me). If you set state in httpContext.Items, why wouldn't that flow to the controller action? Also it should be available in HttpContext.Current...

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

In this code condition if (System.Web.HttpContext.Current != null) be false. So I need a callback before the Controller execution where I can set the AsyncLocal context. Middleware is a perfect place, but it doesn't work in IIS as this context will be cleared by the host (actually I only checked that CallContext will be cleaned, not AsyncLocal. But I assume it will also be cleaned up. And ideally I want to be able to correlate older FWs as well).

So far the only solution I know if to register Action Filter (like I explained here). It will give the callback I need. However it looks like overkill to register both - middleware for time and other middlewares tracking and Action Filter for correlation inside the Controller.

        public async Task<ActionResult> Index()
        {
            System.Web.HttpContext.Current.Items["a"] = "ctx";

            HomeController.ctx.Value = "ctx";

            HttpClient client = new HttpClient();
            await client.GetStringAsync("http://bing.com").ContinueWith((a) => 
            {
                if (System.Web.HttpContext.Current != null)
                {
                    var ctxValue = System.Web.HttpContext.Current.Items["a"];
                }

                var alCtxValue = HomeController.ctx.Value;
            });

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

Why not just always store the context in the httpContext? Don't use async locals when you're in System.Web...

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

Because the httpcontext is null inside the .ContinueWith. See the example above. So a lot of telemetry will not be correlated. HttpContext is using SynchronizationContext that is not propagated in tasks well.

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

But it does work without the .ContinueWith right?

await client.GetStringAsync("http://bing.com");
            
if (System.Web.HttpContext.Current != null)
{
    var ctxValue = System.Web.HttpContext.Current.Items["a"];
}

var alCtxValue = HomeController.ctx.Value;

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

ContinueWith does not preserve the SynchornizationContext (which is the thing that sets httpcontext.current in ASP.NET).

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

yes, I have Http Context before and after the await in your example. However it's not enough.

For instance, when on FW 4.5 we collect http calls using EventSource exposed by HttpWebRequest - those event source calls happens in async context and not being correlated.

Also quite often I need to correlate exception happened in those ContinueWith.

Yes, sorry I meant SynchronizationContext, not LogicalCallContext

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

I've updated the title of the bug to accurately reflect the request. I don't think it's katana's job to flow the execution context across IIS events.

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

Thank you! I do not know enough, but my understanding was that middleware and Controller executes in the same managed thread and Katana explicitly clear up context when in IIS. It would be great if it will not do it when possible

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

Thank you! I do not know enough, but my understanding was that middleware and Controller executes in the same managed thread and Katana explicitly clear up context when in IIS

It doesn't have anything to do with the same thread per se but the fact that they run in different IIS events is the problem. The execution context isn't preserved between these 2 events. You can see this by looking at the "call stack" during controller execution. You'll see the middleware pipeline isn't there.

from aspnetkatana.

SergeyKanzhelev avatar SergeyKanzhelev commented on June 7, 2024

Just discussed it with @lmolkova. So re-setting the AsyncLocal in PreRequestHandlerExecute will solve the issue? If so - we can close the issue as it is a good workaround for me

from aspnetkatana.

davidfowl avatar davidfowl commented on June 7, 2024

Yes that works if the handler completes synchronously. If it's async then it won't flow to the controller.

from aspnetkatana.

muratg avatar muratg commented on June 7, 2024

@SergeyKanzhelev I assume you got unblocked, so closing this. But if that's not the case, let me know and I'll reactivate.

from aspnetkatana.

ysmoradi avatar ysmoradi commented on June 7, 2024

Using something like HttpContext.Current is not a good idea at all. It does not work outside IIS, and inside IIS it has a lot of limitations. I've configured Owin, web API, OData, signalr, entity framework with Autofac, and I pass a per request instance of my own ILogger into all classes I need logging using constructor injection, so in my continueWith call I've a direct reference to my ILogger. Combining this with DRY concept will make a very powerful approach for logging which works anywhere

from aspnetkatana.

ysmoradi avatar ysmoradi commented on June 7, 2024

Remember that things have changed too in .NET Core. my approach is working fine on .NET Core 2 too

from aspnetkatana.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.