Navigation Menu

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

Deprecate WebApiRequestLifestyle #331

Closed
dotnetjunkie opened this issue Nov 21, 2016 · 6 comments
Closed

Deprecate WebApiRequestLifestyle #331

dotnetjunkie opened this issue Nov 21, 2016 · 6 comments

Comments

@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Nov 21, 2016

The Web API integration package contains the WebApiRequestLifestyle, but this lifestyle is a mere wrapper around the ExecutionContextScopeLifestyle (in fact, it's a sub class). It adds no extra behavior. The only difference between the WebApiRequestLifestyle and ExecutionContextScopeLifestyle is its name. This has been done because the name WebApiRequestLifestyle is much more obvious for developers creating a Web API application and since the name ExecutionContextScopeLifestyle is a bit confusing.

In v4 however we are renaming ExecutionContextScopeLifestyle to AsyncScopedLifestyle. Since this name is much more obvious, there is not much reason to keep the WebApiRequestLifestyle around and we should deprecate it. This makes the integration story for Simple Injector much simpler, because there are less scoped lifestyles to choose from.

@DaEkstrim
Copy link

DaEkstrim commented Mar 18, 2017

dotnetjunkie, since WebApiRequestLifestyle is pratically ExecutionContextScopeLifestyle, and since (according to the documentation) ExecutionContextScopeLifestyle can be used across threads, how does Simple Injecter differentiate between the threads handling two separate yet simultaneous calls to the same container?

What I mean is, if I have scoped service A, with an integer property X, and Thread 10 which is servicing Request 1, changes the value of property X to, let's say '2'. Will Thread 11, which is servicing Request 2, also see the change in property X on service A?

@dotnetjunkie
Copy link
Collaborator Author

ExecutionContextScopeLifestyle can be used across threads

That's not exactly accurate. The scope of an ExecutionContextScopeLifestyle will automatically flow with the logical flow of control of asynchronous methods, but you can't just pass it on from one thread to another (unrelated) thread. It is the .NET framework itself that will relate threads that are used for a single asynchronous operation.

The logical flow of control will be related to a request. This means that a scope will be related to the request as well, independent of how many threads are involved in the execution of that thread.

changes the value of property X to, let's say '2'. Will Thread 11, which is servicing Request 2, also see the change in property X on service A?

This asynchronous scoping ensures that scopes are isolated within a request. The same thread 10 can be used to serve both request A and request B, but when such thread will resolve from the container, it will do so within the context of the scope for that request. This means that both requests get their own independent value for X.

@DaEkstrim
Copy link

Ah, that's where I was missing a bit of important information: the threads have to be related for the ExecutionContextScopeLifestyle to be shared across said threads.

So while we're at it, can the ExecutionContextScopeLifestyle be used to handle cases where there's parallelism (for example a Parallel.ForEach nested in a Using{container.BeginExecutionScope})? Or would you suggest something different?

Btw, I agree with the deprecation of the WebApiRequestLifestyle, if it's fundamentally the same as the ExecutionContextScopeLifestyle. The change will surely clear up any former confusions between the two.

@dotnetjunkie
Copy link
Collaborator Author

the threads have to be related for the ExecutionContextScopeLifestyle to be shared across said threads.

To visualize the effect the best, just look at how the AsyncLocal<T> class works:

private static AsyncLocal<int> local = new AsyncLocal<int>();

public static Task DoSomething(int x)
{
    local.Value = x;
    await OtherMethod();

    // Now we might run on a different thread
    Assert.AreEqual(x, local.Value);
}

DoSomething might finish on a different thread than where it was started, but it runs in the same asynchronous context. DoSomething might be called in parallel by two different requests, and each request will have its own local value for AsyncLocal<int>.

The ExecutionContextScopeLifestyle works exactly the same way. The PCL version of this lifestyle even uses AsyncLocal<T> under the covers.

So while we're at it, can the ExecutionContextScopeLifestylebe used to handle cases where there's parallelism

That's a bit a difficult question, but in general I would advise the following:

In a multi-threaded application, each thread should get its own object graph. This means that you should typically call GetInstance() once at the beginning of the thread’s execution to get the root object for processing that thread (or request). The container will build an object graph with all root object’s dependencies. Some of those dependencies might be singletons; shared between all threads. Other dependencies might be transient; a new instance is created per dependency. Other dependencies might be thread-specific, request-specific, or with some other lifestyle. The application code itself is unaware of the way the dependencies are registered and that’s the way it is supposed to be.

In other words, in case you are calling services within a Parallel.ForEach loop, in general you should request that service from the container within the loop and call it. Since it is an anti-pattern for the application to call back into the container, this Parallel.ForEach loop should be abstracted away from the application and implemented in the Composition Root.

In case the Parallel.ForEach does not call into other services, and is mainly data centric, it is -from a DI perspective- fine to have it in your code.

@dotnetjunkie dotnetjunkie self-assigned this Mar 18, 2017
@kitsu
Copy link

kitsu commented Mar 6, 2018

The WebApi integration quick-start still generates WebApiRequestLifestyle: Recommend updating.

@dotnetjunkie
Copy link
Collaborator Author

@kitsu I'm happy to announce that this fix was already pushed and is planned to be rolled out with for v4.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants