asp.net core dependency injection issue - AddScoped not creating a new instance - asp.net-core

I've been using asp.net core dependency injection and I have seen an not expected behavior, at least for me. I'm adding a new service to the container like this:
services.AddScoped<IMyClass>(provider =>
{
return new MyClass(
"anyValue"
});
After that, I inject the class into another class to use it:
public class AnotherClass(IMyClass xxx){
}
The thing is that there are a couple configurations that are made on the MyClass constructor based on request information. The problem is that I've seen the MyClass constructor be executed at the application startup only. After that, the class seems to use the same instance for all calls. As I'm using Scoped service I'm expecting to have a new instance for each request, am I wrong?
Thanks.

Ok. The problem was that the class that was receiving the injection was added to the container as singleton. I just changed it to Scoped and everything worked well.
Thanks!

Related

.NET Core Service Layer or DAO Scoped, or both?

When creating a .NET application where the controller calls a service, then the service calls a DAO for the database work, and I'm using Entity Framework Core 6.0 for the database services, do I also add the service layer objects in ConfigureServices, or just the data layer, and pass them in to constructors?
I'm not sure this is exactly a preference, rather I'm worried about multithreading, specifically.
The scheme is: API -> Controller -> Service -> DAO -> Database then back for the result.
Sample code:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CRM_MSCRMContext>();
services.AddScoped<HomeService>();
}
See above, I've added both the service that calls the context, as well as the context.
I'm injecting the DAO using the constructor:
Sample code:
public CRMDAO(CRM_MSCRMContext crmContext)
{
_crmContext = crmContext;
}
And I could be injecting the service into the controller, if I add to Scoped. Otherwise I think I'm just instantiating new in the constructor anyway:
public HomeController(HomeService homeService)
{
_homeService = homeService;
}
or I could use a constructor and forget injection here:
public HomeController()
{
_homeService = new HomeService();
}
Why would one be better than the other from a multithreading or database connection standpoint? I understand that this is going to be scoped per-request, so maybe it's no different than using the constructor to New the service object on every request anyway from the controller?
Thank you,
Dan Chase
OK so after reading documentation and experimenting, I found it seems to be all or nothing. I had to add everything in ConfigureServices, all DAO's and all Services, as well as all Contexts. Otherwise I kept getting "Unable to resolve while attempting to activate" errors. I also had to move everything to an Interface, or it doesn't seem to work at all.
If anyone has any tips let me know, but I figured best to answer my own question than to delete, because someone might be able to fill in more info.

Autofac Multitenant Database Configuration

I have a base abstract context which has a couple hundred shared objects, and then 2 "implementation" contexts which both inherit from the base and are designed to be used by different tenants in a .net core application. A tenant object is injected into the constructor for OnConfiguring to pick up which connection string to use.
public abstract class BaseContext : DbContext
{
protected readonly AppTenant Tenant;
protected BaseContext (AppTenant tenant)
{
Tenant = tenant;
}
}
public TenantOneContext : BaseContext
{
public TenantOneContext(AppTenant tenant)
: base(tenant)
{
}
}
In startup.cs, I register the DbContexts like this:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
Then using the autofac container and th Multitenant package, I register tenant specific contexts like this:
IContainer container = builder.Build();
MultitenantContainer mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);
mtc.ConfigureTenant("1", config =>
{
config.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
});
mtc.ConfigureTenant("2", config =>
{
config.RegisterType<TenantTwoContext>().AsSelf().As<BaseContext>();
});
Startup.ApplicationContainer = mtc;
return new AutofacServiceProvider(mtc);
My service layers are designed around the BaseContext being injected for reuse where possible, and then services which require specific functionality use the TenantContexts.
public BusinessService
{
private readonly BaseContext _baseContext;
public BusinessService(BaseContext context)
{
_baseContext = context;
}
}
In the above service at runtime, I get an exception "No constructors on type 'BaseContext' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'". I'm not sure why this is broken....the AppTenant is definitely created as I can inject it other places successfully. I can make it work if I add an extra registration:
builder.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
I don't understand why the above registration is required for the tenant container registrations to work. This seems broken to me; in structuremap (Saaskit) I was able to do this without adding an extra registration, and I assumed using the built in AddDbContext registrations would take care of creating a default registration for the containers to overwrite. Am I missing something here or is this possibly a bug in the multitenat functionality of autofac?
UPDATE:
Here is fully runable repo of the question: https://github.com/danjohnso/testapp
Why is line 66 of Startup.cs needed if I have lines 53/54 and lines 82-90?
As I expected your problem has nothing to do with multitenancy as such. You've implemented it almost entirely correctly, and you're right, you do not need that additional registration, and, btw, these two (below) too because you register them in tenant's scopes a bit later:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
So, you've made only one very small but very important mistake in TenantIdentitifcationStrategy implementation. Let's walk through how you create container - this is mainly for other people who may run into this problem as well. I'll mention only relevant parts.
First, TenantIdentitifcationStrategy gets registered in a container along with other stuff. Since there's no explicit specification of lifetime scope it is registered as InstancePerDependency() by default - but that does not really matter as you'll see. Next, "standard" IContainer gets created by autofac's buider.Build(). Next step in this process is to create MultitenantContainer, which takes an instance of ITenantIdentitifcationStrategy. This means that MultitenantContainer and its captive dependency - ITenantIdentitifcationStrategy - will be singletons regardless of how ITenantIdentitifcationStrategy is registered in container. In your case it gets resolved from that standard "root" container in order to manage its dependencies - well, this is what autofac is for anyways. Everything is fine with this approach in general, but this is where your problem actually begins. When autofac resolves this instance it does exactly what it is expected to do - injects all the dependencies into TenantIdentitifcationStrategy's constructor including IHttpContextAccessor. So, right there in the constructor you grab an instance of IHttpContext from that context accessor and store it for using in tenant resolution process - and this is a fatal mistake: there's no http request at this time, and since TenantIdentitifcationStrategy is a singleton it means that there will not ever be one for it! So, it gets null request context for the whole application lifespan. This effectively means that TenantIdentitifcationStrategy will not be able to resolve tenant identifier based on http requests - because it does not actually analyze them. Consequently, MultitenantContainer will not be able to resolve any tenant-specific services.
Now when the problem is clear, its solution is obvious and trivial - just move fetching of request context context = _httpContextAccessor.HttpContext to TryIdentifyTenant() method. It gets called in the proper context and will be able to access request context and analyze it.
PS. This digging has been highly educational for me since I had absolutely no idea about autofac's multi-tenant concept, so thank you very much for such an interesting question! :)
PPS. And one more thing: this question is just a perfect example of how important well prepared example is. You provided very good example. Without it no one would be able to figure out what the problem is since the most important part of it was not presented in the question - and sometimes you just don't know where this part actually is...

Ninject - Resolve instance per method call

I'm finding a solution to resolve an instance per method call.
Something like that:
public class ServiceAPI
{
public void ServiceAction()
{
//Call certain repository action
// Ex:
Kernel.Get<RepositoryA>().Insert();
}
}
public class RepositoryA
{
public void Insert(object a)
{
//Get logger per service call ?
var logger = Kernel.Get<RepositoryA>().Insert();
}
}
I wanna the logger instance created one time per service call and it will be used throughout the repository.
I try with Ninject.Extensions.NamedScope extensions but it haven't worked yet.
Can you have any way to deal with this scenario ?
It is not possible to achieve this by using a scoping mechanism. (InCallScope(), InNamedScope(...),...).
Scoping is only relevant when ninject is calling the constructor of a type.
Ninject cannot - ever - replace the instance that is already passed to an object.
If you want to do this you have to program it yourself.
Here's two design alternatives how you can achieve what you want:
instantiate an object tree per method invocation. If there's some service infrastructure like WCF or Web-API there are probably hooks which can be used to do so.
replace the object which should be instantiated per method call by a proxy. The proxy can then use Ninject to create the target for each method call and execute the method on it.
For proxying you can use tools like Castle DynamicProxy or LinFu. There's also Ninject.Extensions.Interception which may also be helpful.

Access Business Classes in WCF methods

I have an asmx web service I am converting to WCF. In the old structure I had a number of web service methods that accessed business classes to do the work. For example:
public DataSet GetAppointmentDataToConvert(string aAccessToken, string aStartingId)
{
//verify that the user is allowed to use this web service
if (!isAuthorized(aAccessToken))
{
throw new Exception("Not authorized");
}
cls256_BitEncryptionConversion cls256 = new cls256_BitEncryptionConversion();
return cls256.GetAppointmentDataToConvert(aStartingId);
}
This method initialized the cls256_BitEncryptionConversion class and called a method inside it to do the work, then returned the result.
I am trying to set up a WCF Service that will use the cls256_BitEncryptionConversion class, but despite both the class and the service being in the same namespace, my service method is unable to "see" the class. What am I doing wrong?
These are few tips for you to resolve it your self:
Make it sure that even they have the same namespace are they in the same project?
If they are in different project add it as you reference where you want to use it. And probably add a using directive if necessary.
I was able to resolve the issue by restructuring the project. I moved all the classes from the app_code folder into the root of the project.

Ninject MVC3 - how does the type gets resolved

Scenario:
I've set up the Ninject MVC3 using the link below:
https://github.com/ninject/ninject.web.mvc/wiki/Setting-up-an-MVC3-application
I followed Nuget version. And, code looks like below:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IService>().<Service>();
}
Could someone help me to understand when and where does the code below gets excuted?
var test=Kernel.Get<Service>();
Basically I'm trying to understand where do we resolve the concrete type.
UPDATE:
my question is more of where does the MVC use Kernel.Get() to resolve the given Interface to the concrete type.
Is this done by Ninject.MVC?
Kernel.Get<Service>() shouldn't be called anywhere. You should request an IService in the constructor of the controller that needs this dependency. When MVC requires this controller then it asks Ninject to create the controller instance and Ninject will inject the service into the controller.