Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2294: batch processing loses HttpContext for main request. #2385

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

NicholasNoise
Copy link

@NicholasNoise NicholasNoise commented Dec 18, 2020

Issues

This pull request fixes issue #2294.

Description

HttpContext context = null;
IHttpContextFactory httpContextFactory = originalContext.RequestServices.GetRequiredService<IHttpContextFactory>();
if (httpContextFactory != null)
{
    context = httpContextFactory.Create(features);
}
else
{
    context = new DefaultHttpContext(features);
}

IHttpContextFactory(DefaultHttpContextFactory) service should not be used to create new HttpContext, because it resets current context to new one:
https://github.com/dotnet/aspnetcore/blob/master/src/Hosting/Hosting/src/Http/DefaultHttpContextFactory.cs#L73

Checklist (Uncheck if it is not completed)

  • Test cases added
  • Build and test with one-click build and test script passed

@KenitoInc KenitoInc added the Ready for review Use this label if a pull request is ready to be reviewed label Jan 22, 2021
@@ -727,7 +730,7 @@ public async Task SendAsync_CorrectlyHandlesCookieHeader()
var changesetRef = $"changeset_{Guid.NewGuid()}";
var endpoint = "http://localhost";

Type[] controllers = new[] { typeof(BatchTestCustomersController), typeof(BatchTestOrdersController), };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BatchTestCustomersController [](start = 48, length = 28)

Why did we get rid of the test that used two controllers? Isn't this still a valid scenario? Don't we need to make sure it works as expected?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added unused controller with #2379, it is just a cleanup.
So yes, it works as expected.

}
// Create a context.
// IHttpContextFactory should not be used, because it resets IHttpContextAccessor.HttpContext;
HttpContext context = new DefaultHttpContext(features);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HttpContext context = new DefaultHttpContext(features); [](start = 12, length = 55)

What are the ramifications of not using the context factory? Doesn't that mean that, if someone adds their own context factory, we don't use it for batch? Couldn't that be a problem if the developer is expecting their custom httpcontext to be used? Do we instead need a way to create the context from the factory without resetting the IHttpContextAccessor.HttpContext?

Copy link
Author

@NicholasNoise NicholasNoise Jan 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see any other reason to use the factory for creating HttpContext from a set of sub-requests, but dependency injection. And it is unclear why a global factory (that creates context for an actual http request) should be used to instance batch sub-contexts.

If the factory is used we should make a closure of original context after processing batch changesets like this one:

        /// <inheritdoc />
        public override async Task ProcessBatchAsync(HttpContext context, RequestDelegate nextHandler)
        {
            // Retrieve current httpcontext.
            var httpContextAccessor = context.RequestServices.GetService<IHttpContextAccessor>();
            var beforeContext = httpContextAccessor?.HttpContext;

            await base.ProcessBatchAsync(context, nextHandler);

            if (httpContextAccessor != null)
            {
                httpContextAccessor.HttpContext = beforeContext;
            }
        }

But still a closure is more like a workaround than THE solution.

Keyword new is kinda bad in common, especially in the name of DI, instead we can introduce an interface IBatchHttpContextFactory to create a context of the changeset (silly refactor)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mikepizzo & @NicholasNoise, I tested the pr with the two suggestions. I guess my question would be for Sub requests created during batch processing should we give users more control over the creation of the context? Since we do copy the features, headers, and cookie information. One of the issues with the current approach I do see is if the user used their own IHttpContextAccessor and IHttpContextFactory then this process would need them to do more refactors if they needed to change how batch sub requests are created by extending the BatchMiddleware.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @marabooy
Yeah, we should give more control of the context creation. But as I've pointed out IHttpContextFactory is not a way to do so. I suggest a new abstraction IBatchHttpContextFactory for this matter.

@mikepizzo
Copy link
Member

Hi @NicholasNoise -- thanks for the contribution!

As per my inline comments, I'm curious what the ramifications are if we don't use the injected HttpContextFactory. Eager to get your (and others') thoughts.

@NicholasNoise
Copy link
Author

@mikepizzo
How do I make this PR unblocked? =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ready for review Use this label if a pull request is ready to be reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants