'Use NETCore ScopedService outside Controller
First, let me explain breafly what I have, what I want to achieve, how I did it so far, and why I'd like to improve my current implementation.
WHAT I HAVE
Basically, I have a .NET Core project that runs an API Service with some APIs.
Also, I have a class called MyFundamentalClass, which is used throughout the whole application: in fact, MyFundamentalClass implements the Singleton Pattern, having something like this:
public class MyFundamentalClass {
private static _myFundamentalClass = null;
public static MyFundamentalClass GetInstance() {
if (_myFundamentalClass == null)
_myFundamentalClass = new MyFundametalClass();
return _myFundamentalClass;
}
}
Reason why I want this Singleton Pattern is that this class is used in many occasion in the whole project; the alternative would be to instantiate the class in the ControllerAction, and then pass it basically EVERYWHERE: it's not sustainable.
THE PROBLEM
As you can imagine, here was the first problem: each request MUST HAVE its own instance of MyFundamentalClass. As you can imagine, static keyword does not work very well with that.
Why I'm telling this: if I want an instance of MyFundamentalClass in each ControllerAction, I should write something like this:
public async Task<ActionResult> GetUserData() {
MyFundamentalClass = new MyFundamentalClass();
return await MyFundametalClass.GetUserData();
}
So far so good, but as I said, I need the Singleton Pattern, so I should change the code into:
public async Task<ActionResult> GetUserData() {
MyFundamentalClass = MyFundamentalClass.GetInstance();
return await MyFundametalClass.GetUserData();
}
What's the problem? Two different API calls will overwrite the private field MyFundamentalClass._myFundamentalClass, mixing the context of the two API. HUGE PROBLEM!
MY CURRENT SOLUTION
What I found , the only way, was the use of AsyncLocal<MyFundamentalClass>. I've something like this:
public class RequestContext {
publicv static AsyncLocal<MyFundamentalClass> Instance = new AsyncLocal<MyFundamentalClass>(null);
}
// Then, in each ControllerAction
public async Task<ActionResult> GetUserData() {
var method = async () => {
RequestContext.Instance.Value = new MyFundamentalClass();
// Whatever I need to do
}
}
// Then, in the MyFundamentalClass
public MyFundamentalClass {
public MyFundamentalClass GetInstance() {
return RequestContext.Instance.Value;
}
}
With this solution, since the AsyncLocal context lives only thourghout the async context, it perfectly fits my need.
Though, why am I searching for something else? Because I feel like I am missusing the Dependency Injection and the whole ServiceProvider stuffs.
WHAT I AM LOOKING FOR
So.. I also come upon the services.AddScoped<MyFundamentalClass>() code (Link to Microsfot DOC).
By what it tells, it should perfectly fit my need: what is created by that AddScoped lives only for the API -> one API one instance.
But, problem is: how could I exploit the instance created by AddScoped with the Singleton Pattern?
I know that, with DependencyInject, in my Controller I can add the object in the constructor:
public class MyController : ControllerBase {
private MyFundamentalClass _myFundamentalClass;
public MyController(MyFundamentalClass myFundamentalClass) {
_myFundamentalClass = myFundamentalClass;
}
public async Task<ActionResult> GetUserData() {
return await _myFundamentalClass.GetUserData();
}
}
That feels much more correct, from a code point of view, but.. I don't have the SingletonPattern anymore, unless I still use the AsyncContext.
What I thought it was possible was to use:
public static IServiceProvider ServiceProvider;
public static WorkbenchViewModel GetInstance() {
ServiceProvider.GetService(typeof(WorkbenchViewModel));
}
But I have the same problem: each request has its own IServiceProvider, thus different API would override the value.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
