DI Singleton Service Instantiates Twice - c#

I register a service as Singleton in the program.cs file like this.
builder.Services.AddSingleton<ITest, Test>();
and if I request an instance of it in program.cs
var testService = builder.Services.BuildServiceProvider()
.GetRequiredService<ITest>();
It creates a new object which is the first object, but when I request it through constructor injection in some other service it creates a new object again. Shouldn't it return the first object that it created while startup in Program.cs?
Note : This behavior is only if I request service in the program.cs other than that it returns the same object, even if I request it using IServiceProvider.GetRequiredService();
i have tested the same scenario in dot net 5 web api as well in which i register the service in ConfigureServices method of Startu.cs file
services.AddSingleton<ITest, Test>();
and request the service in Configure method like this
var test = app.ApplicationServices.GetRequiredService<ITest>();
and when i request it in constructor in some other service it will return the same object.
Why?

In your starup file, you don't have a service provider yet. You only have the Services property that allows you to define your services.
Since you want to instantiate one, you call builder.Services.BuildServiceProvider() which builds a service provider for you, that you then use to get a service. Inside that service provider, your service lives as singleton.
Then, you proceed in your application and the framework, being happy that you defined your services, then builds it's own service provider. Which you can access via app.ApplicationServices. That one, too, has a single instance of your class, since it's a singleton.
And from now on, since all your services and controllers use the service provider created by the framework, not the one you created manually in startup, all of them will get the same instance.

Related

Can't get AuthorizationMessageHandler in Blazor WebAssembly to work due to service lifetime issues

I cannot get an HttpClient with AuthorizationMessageHandler working.
I have a project set up using the Microsoft.AspNetCore.Components.WebAssembly.Authentication package, and wired up for OIDC. That's working fine. Now, I want to make an http call to an API in another domain, using the access token provided during the OIDC authentication.
Based on https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-5.0#typed-httpclient, this should be a simple task, but I'm having all sorts of problems with the service collection. Here's what I have to set up a typed HttpClient:
builder.Services.AddScoped<AuthorizationMessageHandler>();
builder.Services.AddHttpClient<IAuthorizationClient, AuthorizationClient>(client => client.BaseAddress = new Uri(authUrl))
.AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>().ConfigureHandler(new[] { authUrl }));
The issue here, for example, is that AuthorizationMessageHandler requires an IAccessTokenProvider in the constructor, which Blazor provides as a Scoped service. However, the HttpClientFactory is registered as a singleton service. When the HttpClientFactory tries to activate an instance of AuthorizationMessageHandler, it fails with the following error:
Cannot resolve scoped service 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler' from root provider.
Registering AuthorizationMessageHandler as a Singleton, I get:
Cannot consume scoped service 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider' from singleton 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler'.
Registering AuthorizationMessageHandler as a Transient, I get:
Cannot resolve 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler' from root provider because it requires scoped service 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider'.
I'm out of ideas on how to get this to work. All the examples in the referenced link above don't appear to work.
I've tried this with both net5.0 and net6.0, with the same result.

Instance scope of micro Service in API gateway

I want to change scope of service instance scope from Singleton to Transient(where it create instance every request) using service url but getting compile time error
Below is working code without service url
services.AddTransient(typeof(IUser), typeof(My.UserService));
Below is singleton scope with service url
services.AddSingleton(typeof(IUser), ServiceProxy.Create<IUser>(new Uri("fabric:/My.Microservices/MY.UserService")));
Now I want to add scope as Transient using service url like singleton, how?
Use the generic approach for registering your service, along with a factory delegate
services.AddTransient<IUser>(sp =>
ServiceProxy.Create<IUser>(new Uri("fabric:/My.Microservices/MY.UserService"))
);
In the above code, every time IUser is resolved the delegate will be invoked.

Why does the DatabaseInitializer get called twice?

I’ve inherited an MVC that currently does some setup work with the ApplicationStart method so that when the application comes back to life with an IIS Application pool this setup has already been carried out.
As pseudo-code:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Build Api autofac container
// Build MVC autofac container
// Resolve serviceOne from the MVC container
var serviceOne = (IServiceOne)DependencyResolver.Current.GetService(typeof(IServiceOne));
// Make setup call - includes external http calls and DbContext checking
serviceOne.syncToExternal();
// Resolve serviceTwo again from the MVC container
var serviceTwo = (IServiceTwo)DependencyResolver.Current.GetService(typeof(IServiceTwo));
// Make setup call - publishes application information to internal message queues so that we know it's running
serviceTwo.syncToInternalSystems();
}
}
In the ApplicationStart I run through the normal process of setting up Autofac containers; one for the MVC and one for the WebApi. In here the respective MVC or Api controllers, service classes and my DbContext are registered.
The setup work in the ApplicationStart needs a service and a DbContext which I resolve from the MvcContainer, as the WebApi one is not accessible at this point.
ServiceOne retrieves data from an external url and using this to seed / check the current contents of the database.
ServiceTwo reads back some of this data and publishes it to internal message queues within the company.
Once the Application_Start() has finished and the Home page has loaded: if I make a request which routes through the MVC then the DbCobntext's registered databaseInitialzer does not get called as it was run during the Application_Start, but if I make an /api request the databaseInitializer does get called.
I suspect that running the setup in ApplicationStart method is preventing a flag being set in the System.Data.Entity.Database which managed the Connection; hence when the DbContext is resolved from the Api Container it thinks the database hasn’t been initialised...?
Any help would be much appreciated.
My fallback will be to shift all of the setup into a seed method which runs when the databaseInitialiser/Migration is called; but it would be useful to know why the original version of the code was failing to execute as expected.
the ApplicationStart run every time the ApplicationPool starts, no matter what. You have to use another mechanism to populate your DB. Like Migrations.

URL WCF RestFul .net with spring

I need to call my service with the standard url restful:
http://localhost/users : getall user
http://localhost/user/1 : get user with id 1
But the standard URLs in WCF looks like:
http://localhost/Userservice.svc/getallusers
I would like to change this, but since I use the Spring.net framework in my service WCF, I must create my Custom ServiceHostFactory MyServiceHostFactory
Spring is used in my project to do the injection dependencies and thus nothing new object
I try to add a route in global.asax
RouteTable.Routes.Add(new ServiceRoute("Users", new MyServiceHostFactory(), typeof(UserService)));
But when i call my service http://localhost/users
, I receive the error: ServiceHost only supports class service types
I don't understand the problem and is it possible to resolve this problem ?
Thanks for your help

Custom ServiceHost with DI and InstanceContextMode.Percall

In my Managed Application, I currently have my WCF services running as:
SomeService service = new SomeService(container) //IUnityContainer
ServiceHost serviceHost = new ServiceHost(service, serviceAddress);
Whats the catch ? SomeService defined with:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single
This is not good anymore, I need to make it InstanceContextMode.PerCall.
When trying to .Open() If changing the InstanceContextMode to "PerCall" - it will throw:
System.InvalidOperationException: In order to use one of the ServiceHost constructors that takes a service instance, the InstanceContextMode of the service must be set to InstanceContextMode.Single. This can be configured via the ServiceBehaviorAttribute. Otherwise, please consider using the ServiceHost constructors that take a Type argument
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
My Main concern:
I run different types of services inside this managed application, It seems that this solution is good only if i run one type of service.
When more than one service instance will be needed (PerCall or PerSession) then passing a single service instance into the ServiceHost isn’t enough... which is the exception.
Controlling instance creation is managed by the IInstanceProvider.
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
This only answers half your question. You are using Unity. The management of creating the container needs to be part of the implementation. The most common solution is to use Unity.WCF which is also available as a NuGet package.
Note that Unity.WCF doesn’t support object lifetimes based WCF OperationContexts. There are multiple (more complicated) implementations like this that do.

Categories