Lost scope using DependencyResolver in another class library, using Castle Windsor and FluentNhibernate and NHibernate - nhibernate

In my WCF project I register my interface using Castle Windsor in the global.asax:
Component.For<IStrategy>()
.ImplementedBy<MyStrategy>()
.LifestylePerWcfOperation(),
Then later on in the same file I configure NHibernate using FluentNhibernate using a provider:
FluentConfiguration configuration = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(myConnString)
.Provider<ConnectionProvider>())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TenantMap>()) etc etc
However this ConnectionProvider is hosted in a common shared dll library as there are other WCF services that need to use it. I want to register this dependency as below but it doesn't work which means I have to manually new up a instance.
public ConnectionProvider()
{
// doesnt work
using (IDependencyScope scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
_myStrategy = scope.GetService<IStrategy>();
}
}
Is there anyway to make this work? Its like its lost scope as its in another assembly now. In the same assembly the DependencyScope works fine and creates an instance, but I want to keep it in a shared dll.
EDIT: The error I get is "System.Web.Http.Dependencies.EmptyResolver" on a watch on this bit of code: GlobalConfiguration.Configuration.DependencyResolver

I can see several problems with the code above:
1) You are registering IStrategy,MyStrategy with a per WcfOperation lifestyle. This means that windsor will create a strategy for each WcfOperation. On the otherhand you are trying to manually set the lifestyle of the component by using scope.GetService. For scope.GetService to work you will need a lifestyle scoped.
2) Assuming that the code for ConnectionProvider above is the constructor, it seems that the constructor is trying to get something from the container. This is in general a bad idea, and even worse when using an Ioc container like windsor. Instead pass the IStrategy to the constructor (inject it).
3) Seeing that you are calling the container a constructor here, probably means that you are not adhering to the principle that there should be only 3 calls to the container, 1 to register component, 1 to retrieve a top level component, and 1 to release the container.
I suggest you read a bit more about depedency injection and Ioc containers in general to fully understand how to work with this container.

Related

Can I create an object from the DI container/Lamar in .NET 6.0 minimal hosting, preserving singletons?

We have migrated from a windows Framework 4.7 application to .NET 6.0. Lamar is added for Dependency Injection. We are trying to finalize a refactor to the latest "one-file" program.cs but are getting unexpected System.ObjectDisposedException: 'Cannot access a disposed object'. In all cases, the error is against a Func<T> during object creation.
All our tests are running correctly using the same environment, except to start the tests we (a) create the DI container and (b) use the container to create an object that loads the singletons (from MongoDB):
Container = new Container(registry);
var start = Container.GetInstance<HomeService>();
In the program.cs, we configure the container, but do not get to see it created, or access it inside program.cs. Instead we create HomeService from IServiceProvider during the first use of a controller. Here we were trying to limit the lifecyle scope during creation:
using (var scope = _container.CreateScope())
{
scope.ServiceProvider.GetService<INewHomeService>();
}
For test, we use the same loading steps, except for adding controllers/mvc, of course (i.e. NOT using builder.Services.AddControllers(); and builder.Services.AddMvc() for (integration) testing).
We have tried a lot of different things, like creating our object independently to the startup, but that did not align the singletons. We can get functionality by using static instead, but then we lose dynamic change access.
Some great tips like Resolving instances with ASP.NET Core DI from within ConfigureServices and https://andrewlock.net/exploring-dotnet-6-part-10-new-dependency-injection-features-in-dotnet-6/ but I can't see the specific example to get the live container just after initial creation.
Is it possible that the issue is just the difference between the lifecycle management of the new .NET DI implementation? As this is configuration at the composition root, if we can configure as per our testing approach, it should solve our problem. Other solutions welcome!
The problem 'Cannot access a disposed object' was being caused by a lifecycle mismatch between retained context and the controller access. The code retained a handle on the state object, that had a handle on the factory using FUNC. As we did not configure the Func as anything, it was transient during the controller graph creation, and so was disposed when the controller request ended.
To solve, we tried registering ALL of the FUNC, per How to use Func<T> in built-in dependency injection which was a large task as we had a few factories throughout an old codebase.
The better solution was to create a factory in the composition root, and use an injected IserviceProvider (or with Lamar an IContainer). This is a simple workaround.
With our creation concern, the creation of our object after the completion of the startup process is working correctly as a lazy validation of the first controller access.

Supplying IOptions to Autofac Module

Short version:
Simply put i would like to inject IOptions<TModuleOptions> (or just TModuleOptions) into an autofac module, but I cannot figure out how to do so without manually wiring up the options class (which sort of defeats the point).
Is this even possible, and how?
The longer version:
I have an ASP.NET Core 3.1 project using Autofac as the DI container, and a module that requires some configuration options. Like a name and a URL for instance.
In the startup i have something like:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ModuleOptions>(Configuration.GetSection(ModuleOptions.ModuleSettings));
// Stuff remove for brevity
}
public void ConfigureContainer(ContainerBuilder builder)
{
ModuleOptions options = options; // It would be nice with a way to get this here or have it resolved "automagically".
builder.RegisterModule(new CustomModule());
}
I tried different things, but I can't really see how i might go about doing it in a "nice" manner.
The closet I have gotten is by doing the configuration binding manually like so:
var options = this.Configuration.GetSection("Something").Get<ModuleOptions>();
It works, but "feels" like its not the "idiomatic" .net core way of handling things.
Is it possible to achieve what I want using the DI container similar to how I would do it if I was using the MS DI or RegisterType(context => context.Resolve<IOptions<TModuleOptions>>()) ?
You can't supply IOptions<T> to a module like that because it's a circular dependency. A module executes registrations... but in order to resolve the IOptions<T> you need to build the container, which means you can't register things anymore.
If you think about it, that's actually correct behavior, because technically the IOptions<T> could end up causing something different to be registered, which would affect the IOptions<T>, which would change what gets registered, which would affect the IOptions<T>... yeah.
For bootstrap/app startup code, unfortunately you really can't over-DI it. Your mechanism of getting options from configuration is probably as good as it gets.
The reason you can kind of DI things into Startup is because internally the .NET Core hosting mechanism builds two containers. The first is super barebones and has config, logging, and hosting things in it; the second is the one you build as part of Startup and is your app container.
Anyway... yeah, the best you'll get is the config reading, and I'd recommend sticking with that.

How do I auto-register/resolve services by their interface?

I'm developing a MVC .NET Core 3/Angular/Entity Framework application. My application will likely have a lot of repositories in it. To support this I would like to resolve the service (repository) by its default interface (i.e. I request IRepository and the DI resolver gives me Repository). I know I can manually wire up the dependencies, but all of my DI frameworks in the past have had a means of auto-registering/resolving based on patterns or the like.
For example, with Castle Winsdor I could wire it up like this:
container.Register(Classes
.FromAssemblyNamed("MyLibary.Repository")
.InNamespace("MyLibrary.Repository")
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
This would register all classes in the MyLibrary.Repository namespace to be resolved by their default interfaces they implement. How can this be done in .NET Core 3? If this isn't built-in, I'm assuming I will have to use reflection to query all the classes in the assembly, iterate through each class and register it by its interface it implements.
I would recommend AutoRegisterDI lib to not reinvent a bicycle. It's fast, simple and based on Microsoft Dependency Injection. This benchmark will show you the speed difference.
And this is the article about how to use it
Install this package:
NetCore.AutoRegisterDi
Add this code to your program.cs:
builder.Services.RegisterAssemblyPublicNonGenericClasses()
.Where(c => c.Name.EndsWith("Service"))
.AsPublicImplementedInterfaces(ServiceLifetime.Scoped); // default is Transient
If you have a Singleton service , add [RegisterAsSingleton] on top of your service class.
If you want to ignore injection of an particular interface add this line after .Where() :
.IgnoreThisInterface<IMyInterface>()
you can do this with reflection in c#.first create an extension method like this :
public static void AddScopedServices(this IServiceCollection serviceCollection)
{
}
and use it in startup.cs ,ConfigureServices method : services.AddScopedServices();
now to implement this method like this:
var allProviderTypes = System.Reflection.Assembly.GetAssembly(typeof(ICartRepository))
.GetTypes().Where(t => t.Namespace != null).ToList();
foreach (var intfc in allProviderTypes.Where(t => t.IsInterface))
{
var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name.Substring(1) == c.Name);
if (impl != null) serviceCollection.AddScoped(intfc, impl);
}
you just need to put all your interfaces in a namespace and introduce one of them in this method ,in my case I used ICartRepository ,so it takes all interfaces and search for classes which inherit from that interface.
one point you need to consider is that class names must be like interfacenames without 'I' in the beginning ,like 'CartRepository'
I recently got tired of writing the same old
services.AddTransient<IInterface,IImplementation>
so I created a simple library to help me auto-register services.
You can check it out here.
Register the library in Startup.cs
There are 3 interface -> ITransient, IScoped, ISingleton generic and non-generic versions.
Let's say you want to register service "TestService" as transient.
TestService: ITransient<ITestService>, ITestService
Inherit ITransient interface and its done.
For more detailed information please refer to the Readme section.
Currently it lacks registering services with implementation factory, but it's something I'm willing to do in the near future.

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...

Castle 3.0 WCF Facility - Not resolving paramters in service constructor

I'm trying to have Castle (3.0) inject constructor params into a WCF service, like this
ServiceHostBase clientServiceHost = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory()
.CreateServiceHost(typeof(IClientExchange).AssemblyQualifiedName, new Uri[0]);
However I get the following exception 'The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor.'
The service impl of type ClientExchange takes a constructor param of type IProviders
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ClientExchangeService : ExchangeService, IClientExchange
{
public ClientExchangeService(IProviders providers)
: base(providers) { }
}
My windsor installer looks like this:
container.AddFacility<WcfFacility>()
.Register
(
Component.For<IProviders>().Instance(Providers.DbInstance),
Component.For<IClientExchange>().ImplementedBy<ClientExchangeService>(),
);
At the moment it seems like WCF is trying to new up the service without castle providing the dependency. Tried a few alternative examples out there but many are for previous versions of castle pre 3.0. I must be missing a hook somewhere? How do I tell WCF to defer construction responsibility to castle?
I think this: how do i pass values to the constructor on my wcf service might be the answer to your problem. Or, for something more Windsor specific this might help: Dependency Injection in WCF Using Castle Windsor.
UPDATE
OK, so I think I have figured this out. First of all the problem is this attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
If you do not specify that Windsor will be able to inject the dependencies into the constructor perfectly fine - with that it cannot.
From looking at the description of that attribute here I see that you want your service to be a singleton so since that is the default for Windsor you can simply remove that attribute and it should start working for you and behave as you expect.
There are two other lifestyles that you may be interested in that are specifically for WCF:
LifestylePerWcfOperation()
LifestylePerWcfSession()
(specify them in the normal place - more information is available here)
Incidentally, you do not have to do the ServiceHostBase stuff at all, instead you can use the AsWcfService extension method like so (personally I prefer this way of doing it):
container
.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
.Register(
Component
.For<IProviders>()
.Instance(Providers.DbInstance),
Component
.For<IClientExchange>()
.ImplementedBy<ClientExchangeService>()
.AsWcfService(new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new BasicHttpBinding())
.At("http://localhost:8000/ClientExchangeService"))));