The type 'FluentValidation.IValidator' is not an open generic class - autofac

On an ASP.NET Core application I am registering
services.Scan(x => x.FromAssembliesOf(typeof(Startup))
.AddClasses(y => y.AssignableTo(typeof(IValidator)))
.AsImplementedInterfaces()
.WithScopedLifetime());
I tried to replicate this using Autofac so I used:
builder
.RegisterAssemblyTypes(typeof(Startup).Assembly)
.AsClosedTypesOf(typeof(IValidator))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
But I got the following error:
Unhandled Exception: System.ArgumentException:
The type 'FluentValidation.IValidator' is not an open generic class or interface type so it won't work with methods that act on open generics.
What am I doing wrong?

Instead of AsClosedTypesOf use a Where clause to filter out and register just the types that implement IValidator. AsClosedTypesOf is specifically there to support open generics. There are plenty of examples in the Autofac docs to help you out.

Related

Get_It Flutter Multiple Abstract Class Registration

We are using the package get_it:^7.1.3 for dependency injection.
I want to register some classes with the same abstract class (like they were interfaces) and get them like:
List<AbstractLass> allClassesWhichImplementAbstractClass=di.sl.get<AbstractLass>();
Therefore I'd like to register it the following way:
sl.registerLazySingleton<AbstractLass>(() =>
AbstractLassImpl1());
sl.registerLazySingleton<AbstractLass>(() =>
AbstractLassImpl2());
But as I do that, I'll get an exception :
ArgumentError (Invalid argument(s): Object/factory with type AbstractLass is already registered inside GetIt. )
There is another solution where I register just the implementation the following way:
sl.registerLazySingleton<AbstractLassImpl1>(() =>
AbstractLassImpl1());
sl.registerLazySingleton<AbstractLassImpl2>(() =>
AbstractLassImpl2());
which works but then I would not access both by using their abstract class (if that is possible)
Can someone help me?
You can do it by providing instanceName parameter like so:
sl.registerLazySingleton<AbstractClass>(() =>
AbstractClassImpl1(), instanceName: 'implementation1');
sl.registerLazySingleton<AbstractClass>(() =>
AbstractClassImpl2(), instanceName: 'implementation2');
And use it also with the same name included:
sl.get<AbstractClass>(instanceName: 'implementation1');
You can only register one object using registerLazySingleton() due to its Singleton behaviour.
If you want to register multiple interfaces with different implementation, try using registerFactory(), etc.

Autofac RegisterAssemblyTypes tries to resolve all public types

Quick question: I've been using autofac with asp.net core in a project and I've noticed that it tries to resolve all types during configuration after updating it to the latest nuget package (going from Autofac.Extensions.DependencyInjection 5.0.1 to 7.0.2). Btw, here's the code that was being used to register the types:
builder.RegisterAssemblyTypes(typeof(Utilizador).Assembly)
.AsImplementedInterfaces()
.AsSelf();
Until now, I wasn't seeing this behavior. The problem with this new approach is that it will try to resolve types that will never be injected through DI. For instance, it complains about public classes that don't have public constructors event though those classes will never be created through DI.
Can someone point me to when this change happened?
Does this mean that now I must filter the types I need explicitly?
Thanks.
This is nothing new.
You can filter those out with something like below:
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(type => type.GetConstructors(BindingFlags.Public).Any())
.AsImplementedInterfaces();

Wicket LambdaModel and NumberTextField cannot resolveType

After switching to LambdaModel as an alternative to PropertyModel in one of my forms in my Wicket 8 application I have failing submit tests stating:
java.lang.ClassCastException: java.lang.String cannot be cast to
java.math.BigDecimal
My Form Panel has a NumberTextField which in my working scenario is bound to a PropertyModel.
THIS WORKS
form.add(new NumberTextField<BigDecimal>("myBigDecimalField", new PropertyModel<>(getModel(), "myBigDecimalField")));
THIS DOES NOT WORK
form.add(new NumberTextField<BigDecimal>("myBigDecimalField", LambdaModel.of(getModel(), MyClass::getMyBigDecimalField, MyClass::setMyBigDecimalField)));
The problem is that LambdaModel does not implement IObjectClassAwareModel as PropertyModel does and so when the NumberTextField tries to resolve the type in AbstractTextComponent#152 and subsequentially checks in getModelType if the model is an instance of IObjectClassAwareModel it will not work, as LambdaModel does not implement this interface.
Is this intended that LamdaModel does not implmement IObjectClassAwareModel.
BTW I know that I can fix this issue with explicitly declaring the type class of the NumberTextField.
Regretfully it's quite hard to retrieve any type information from lambdas.
See here for an explanation:
Java: how to resolve generic type of lambda parameter?
So for now it's recommended to pass the type to the component.

Can't set up entity framework core

I'm trying to set up a db context in a .net core F# web app. As part of this I need to convert the following in to F#:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
My F# version is:
services.AddDbContext<ApplicationDbContext>(fun (options: DbContextOptionsBuilder) ->
options.UseSqlite(this.Configuration.GetConnectionString("DefaultConnection")))
However, I am getting the following exception:
No overloads match for method 'AddDbContext'. The available overloads are shown below (or in the Error List window).property Startup.Configuration: IConfigurationRoot
What could the problem be?
The problem was that I hadn't added a constructor for ApplicationDbContext that takes a DbContextOptions as a parameter. After changing the default constructor to
type ApplicationDbContext(options: DbContextOptions<ApplicationDbContext>) =
inherit IdentityDbContext<ApplicationUser>(options)
I could compile
UseSqlite return Microsoft.EntityFrameworkCore.DbContextOptionsBuilder value, so you need ignore it to match Action<DbContextOptionsBuilder>.
services.AddDbContext<ApplicationDbContext>(fun (options: DbContextOptionsBuilder) ->
options.UseSqlite(this.Configuration.GetConnectionString("DefaultConnection")) |> ignore)

How do I register an interface to the EntityFramework.UserStore<TUser> constructor?

I have been following this post to learn about DI with AutoFac. My DB context is registered in Startup.cs like this:
builder.RegisterType<MyDb>().As<IMyDbCtx>().InstancePerRequest();
I also followed the instructions to create the ApplicationUserStore class, and registered this type like so:
builder.RegisterType<ApplicationUserStore>().As<IUserStore<ApplicationUser>>().InstancePerRequest();
This was all fine until I realized that ApplicationUserStore is expecting a concrete DbContext in it's constructor to pass to its base constructor:
public ApplicationUserStore(MyDb context)
: base(context)
{
}
When I run the application and try loading the registration page, this is the error I see:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'TestApp.Service.IdentityConfig.ApplicationUserStore' can be invoked with the available services and parameters:
Cannot resolve parameter 'TestApp.Data.MyDb context' of constructor 'Void .ctor(MyApp.Data.MyDb)'.
This is breaking, I assume, because I already set up MyDb as a IMyDbCtx, so it won't accept the concrete type. This is good because I don't want to be inconsistent by injecting abstractions in some spots and implementations in others.
Does anyone have any ideas on how I can pass in an IMyDbCtx to the UserStore ctor, particularly with AutoFac?
This is not an ideal solution, but I decided to cast the interface to the concrete type when the parameter is passed to the base constructor:
public ApplicationUserStore(IMyDbCtx context)
: base((MyDb)context)
{
}
You can register your type MyDb under as many aliases as you wish:
builder.RegisterType<MyDb>()
.As<MyDb>()
.As<IMyDbCtx>()
.InstancePerRequest();
In this case Autofac can resolve Application User Store. But it kills the whole idea of dependency injection, because you feed the concrete type.