I am having a weird problem using Unity as an IOC container and im out of ideas of what could cause it. I have a service dependency in my webapi controller but it randomly fails to resolve this dependency. Sometimes i have to start my application 3 or 4 times and then it suddenly works again.
The error I am getting is:
Resolution of the dependency failed, type = "Base.WebApi.Controllers.ApiUsersController", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type IApiUserService does not have an accessible constructor. ----------------------------------------------- At the time of the exception, the container was: Resolving Base.WebApi.Controllers.ApiUsersController,(none) Resolving parameter "apiUserService" of constructor Base.WebApi.Controllers.ApiUsersController(Base.BLL.Services.User.IApiUserService apiUserService) Resolving Base.BLL.Services.User.IApiUserService,(none)
For initializing and registering my types in unity i use the following:
public static void RegisterTypes(IUnityContainer container)
{
var myAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("Base") && !a.FullName.StartsWith("Base.WebApi")).ToArray();
container.RegisterType(typeof(Startup));
container.RegisterTypes(
UnityHelpers.GetTypesWithCustomAttribute<UnityIoCSingletonLifetimedAttribute>(myAssemblies),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled,
null
).RegisterTypes(
UnityHelpers.GetTypesWithCustomAttribute<UnityIoCTransientLifetimedAttribute>(myAssemblies),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.Transient);
}
As you can see i am using singletone and transient named attributes to define the way my dependencies should be resolved.
My controller looks like this:
public class ApiUsersController : ODataController
{
private readonly IApiUserService _apiUserService;
public ApiUsersController(IApiUserService apiUserService)
{
_apiUserService = apiUserService;
}
public IQueryable<ApiUserEntity> Get()
{
return this._apiUserService.GetUsers();
}
}
as you can see it has a dependency on user service which looks like this:
[UnityIoCTransientLifetimed]
public class ApiUserService : BaseService, IApiUserService
{
private readonly IUserRepository _userRepository;
public ApiUserService(IUserRepository userRepository, IUnitOfWork uow) : base(uow)
{
_userRepository = userRepository;
}
}
The api user repository looks like this:
[UnityIoCTransientLifetimed]
public class UserRepository : GenericRepository<ApiUserEntity>, IUserRepository
{
public UserRepository(IUnitOfWork unitOfWork, IDomainContext context) : base(unitOfWork, context)
{
}
Extending the following GenericRepository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly BaseContext Context;
public GenericRepository(IUnitOfWork unitOfWork, IBaseContext context)
{
// register this repository with the unit of work.
unitOfWork.Register(this);
Context = (BaseContext)context;
}
With my unit of work that looks like this:
[UnityIoCSingletonLifetimed]
public class UnitOfWork : IUnitOfWork
{
private readonly Dictionary<string, IRepository> _repositories;
// unit of work class is responsible for creating the repository and then dispossing it when no longer needed.
public UnitOfWork()
{
_repositories = new Dictionary<string, IRepository>();
}
}
However it sometimes works and sometimes it doesnt and i cant figure out why or where to look.
Finally solved it thanks to some suggestions. Looking at the documentation for
AppDomain.CurrentDomain.GetAssemblies()
it says the following:
Gets the assemblies that have been loaded into the execution context of this application domain.
Which basically means that it only loads the assemblies when they are actually needed.
The way i solved it was by using the more reliable GetReferencedAssemblies which loads all assemblies even if they are not being used.
var allAssemblies = new ReadOnlyCollection<Assembly>(
BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList());
Restarted tons of times and not one resolve crash :) Thanks everyone! For everyone looking for more information check out this SO answer: Difference between AppDomain.GetAssemblies and BuildManager.GetReferencedAssemblies
Related
I am trying to add a new page in the public store of nopCommerce. For that I have create Entity, model, factory, controller, Interface and service etc.
But as soon as I am running my nopCommerce project, it shows me following error.
Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 'No accessible constructors were found for the type 'Nop.Web.Factories.SupportRequestModelFactory'.'
I'm using nopCommerce version 4.50 version.
What are the causing of this error and how can it be resolved?
Here is a picture about that error.
I tried to find the error in Controller and factory, but couldn't find the exact solution for this!
NoConstructorsFoundException happens when you don't have a public constructor for a class. To resolve this issue make sure you have a public constructor in your SupportRequestModelFactory class and pass all the necessary services in the parameter of the public constructor.
Here is an Example:
public partial class SupportRequestModelFactory : ISupportRequestModelFactory
{
private readonly ILocalizationService _localizationService;
private readonly ILocalizedModelFactory _localizedModelFactory;
public SupportRequestModelFactory(
ILocalizationService localizationService,
ILocalizedModelFactory localizedModelFactory)
{
_localizationService = localizationService;
_localizedModelFactory = localizedModelFactory;
}
}
Also, make sure you have registered your model factory in the ConfigureServices.
public class NopStartup : INopStartup
{
public virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddScoped<ISupportRequestModelFactory, SupportRequestModelFactory>();
}
}
I have upgraded Unity from v4.0.1 to v5.11.3 in a (.NET 4.5.2) project that worked fine before but since my upgrade I am getting the following exception:
Resolution failed with error: Failed to select a constructor for System.String
The class I am trying to resolve has a String constructor and I have registered it with an InjectionConstructor. See code below:
// Multiple IDbContext registrations happen when the application is initialized
container.RegisterType<IDbContext, AuthenticationContext>(typeof(AuthenticationContext).ToString(), new InjectionConstructor(AppConstants.DatabaseKey));
container.RegisterType<IDbContext, ApplicationContext>(typeof(ApplicationContext).ToString(), new InjectionConstructor(AppConstants.DatabaseKey));
public class DbContextFactory : IDbContextFactory
{
private readonly IUnityContainer _container;
public DbContextFactory(IUnityContainer container)
{
_container = container;
}
public IDbContext CreateDbContext<TDbContext>() where TDbContext : IDbContext
{
var key = typeof(TDbContext).ToString();
return container.Resolve<TDbContext>(key);
}
}
public class AuthenticationContext : DbContextWrapper
{
public AuthenticationContext(string connectionString) : base(connectionString)
{
}
}
public class DbContextWrapper : IDbContext
{
public DbContextWrapper(string connectionString)
{
}
}
How should I interpret the exception? Failed to select a constructor for String, makes me think the registration was successful and that it is looking for a constructor that accepts a String but cannot find it? Which is strange because my AuthenticationContext only has one constructor which accepts... a string!
I tried clarifying a full code example on dotnetfiddle, but there I am getting an "Operation could destabilize the runtime" exception when initializing the UnityContainer. See https://dotnetfiddle.net/xuX57K
So the new exception message I got after enabling debug mode through container.EnableDebugDiagnostic(); got me thinking... It's saying I must configure the container to supply the string value for the constructor, of which I am sure I did. So that implies it is actually not even considering using my registration. When debugging the container registrations I saw my registration was there so that could not be the problem either.
Then I realized that Unity registers all types by default so it was trying to create an instance of AuthenticationContext and hence it failed because when it uses an implicit registration it has no idea of what to do with the required string parameter.
The error is in the DbContextFactory and this fixed it:
public IDbContext CreateDbContext<TDbContext>() where TDbContext : IDbContext
{
var key = typeof(TDbContext).ToString();
// This is wrong because it is trying to resolve AuthenticationContext for a given name.
// But it should resolve a registration for IDbContext for that name since that is
// how it was registered!
// return container.Resolve<TDbContext>(key);
return container.Resolve<IDbContext>(key);
}
I was a long time user of Autofac that recently switched to Simple Injector for my DI container needs. When I used Autofac, I was able to do something I'm still not able to do with Simple Injector, maybe because I do not yet perfectly understand the API.
Let's say I have the service IEntityRepository of TEntity and TDbContext. It's implementation looks like that:
public class EntityRepository<TEntity, TDbContext> : IEntityRepository<TEntity, TDbContext>
where TDbContext : IEntityDbContext where TEntity : class
{
public EntityRepository(TDbContext dbContext)
{
}
}
With Autofac, I was able to register the open generic implementation EntityRepository as the open generic interface IEntityRepository, so when I would inject say, IEntityRepository of Product and IProductsDbContext, the DI container would automatically guess that I inject through the constructor an instance of ProductsDbContext.
Is this possible with Simple Injector? I tries these, but it still fails:
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>).Assembly);
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>));
Thanks in advance for you help!
EDIT:
So here's a full exemple with Autofac as requested by Steven. Create a new .NET Core Console Application. You'll need to install the NuGet Package Autofac.
Program.cs:
internal class Program
{
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<ProductsDbContext>().AsImplementedInterfaces();
builder.RegisterGeneric(typeof(EntityRepository<,>)).As(typeof(IEntityRepository<,>));
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var productsRepository = scope.Resolve<IEntityRepository<Product, IProductsDbContext>>();
Console.WriteLine($"Resolved IEntityRepository is of type: {productsRepository.GetType()}");
}
}
}
ProductsDbContext.cs
public class ProductsDbContext : IProductsDbContext
{
public void Dispose()
{
// Demo, do nothing.
}
public int SaveChanges()
{
throw new System.NotImplementedException();
}
}
Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
EntityRepository.cs
public class EntityRepository<TEntity, TDbContext> : IEntityRepository<TEntity, TDbContext>
where TDbContext : IEntityDbContext where TEntity : class
{
private readonly TDbContext _dbContext;
public EntityRepository(TDbContext dbContext)
{
_dbContext = dbContext;
Console.WriteLine($"Database context is of type {dbContext.GetType()}.");
}
public IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> whereClause)
{
throw new NotImplementedException();
}
}
IEntityDbContext.cs
public interface IEntityDbContext : IDisposable
{
int SaveChanges();
}
IProductsDbContext.cs
public interface IProductsDbContext : IEntityDbContext
{
}
IEntityRepository.cs
public interface IEntityRepository<TEntity, TDbContext> where TDbContext : IEntityDbContext where TEntity : class
{
IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> whereClause);
}
The final console output should ressemble to:
Database context is of type
GenericTypeDiTester.DbContexts.ProductsDbContext. Resolved
IEntityRepository is of type:
GenericTypeDiTester.Repositories.EntityRepository`2[GenericTypeDiTester.Models.Product,GenericTypeDiTester.Interfaces.DbContexts.IProductsDbContext]
You can download the full example there: https://drive.google.com/file/d/1UkIYxLsY6YGwo5jOB5TyyncXc6yho8X5/view?usp=sharing
EDIT 2:
The problem wasn't with the Simple Injector library at the end. It seems that mixing the usage of Microsoft.DependencyInjection and SimpleInjector isn't really a good thing. As suggested by Steven, you should exclusively use SI to register the majority of your services and in rare case, MS.DI (by example for using AddDbContext).
As for my part, I have in my project MediatR, a library that implements the Mediator pattern. This library offers a NuGet package with an extension method AddMediatR for the IServiceCollection of MS.DI, which is supposed to register all handlers properly, but it wasn't the case for me. So I ended up registering the module all by myself using SI.
At the end it everything worked perfectly. You really need to call these lines at the end of the registering process: EnableSimpleInjectorCrossWiring and UseSimpleInjectorAspNetRequestScoping. Nothing else must be registered using the IServiceCollection afterwards. That way, the cross wiring of both DI framework ends up to work beautifully.
The way to register this in Simple Injector is:
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>));
container.Register<IProductsDbContext, ProductsDbContext>();
There is no AsImplementedInterfaces equivalent in Simple Injector, although there are several ways to achieve rhe same. In the case that ProductsDbContext has multiple interfaces that need to be registered, the most obvious way is to register each interface explicitly:
container.Register<IProductsDbContext, ProductsDbContext>();
container.Register<IUsersDbContext, ProductsDbContext>();
container.Register<ICustomersDbContext, ProductsDbContext>();
Here is my class where dependencies are resolved
namespace TestProj
{
public static class Bootstrapper
{
public static void Run()
{
SetAutofacWebAPI();
}
private static void SetAutofacWebAPI()
{
var builder = new ContainerBuilder();
builder.RegisterType<UserService>().As<IUserService>().InstancePerRequest();
builder.RegisterType<Encryption>().As<IEncryption>().InstancePerRequest();
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));
}
}
}
In the Global.asax, I have this : Bootstrapper.Run();
Here is my UserService class:
public class UserService : IUserService
{
private readonly IEncryption _Encryption;
public UserService(Encryption Encryption)
{
_Encryption = Encryption;
}
//Rest of the service here
}
the Encryption class is a similar one.
And the controller is here :
public class UserController : Controller
{
private readonly IUserService _UserService;
public AccountController(UserService UserService)
{
_UserService = UserService;
}
public JsonResult GetLoginLogs(int Id)
{
var Logs = _UserService.GetLoginLogById(Id);
return Json(Logs, JsonRequestBehavior.AllowGet);
}
//The rest of the controller
}
here is the version info:
Autofac : 3.5.2
MVC : 4.0.40804.0
DOTNET : 4
And then, when try localhost:5000/Account/GetLoginLogs/1 this exception comes up:
No parameterless constructor defined for this object.
Someone please help. I am in seriously in trouble!
I think you are confusing how you registered the dependencies.
Update from comments by #Amy:
You also failed to register your MVC controllers
// You can register controllers all at once using assembly scanning...
builder.RegisterControllers(Assembly.GetExecutingAssembly());
Source: documentation
Also use the interfaces instead of the concrete classes when explicitly injecting into the dependent classes as that is what you registered with the container.
public class UserService : IUserService {
private readonly IEncryption _Encryption;
public UserService(IEncryption Encryption) {
_Encryption = Encryption;
}
//Rest of the service here
}
public class UserController : Controller {
private readonly IUserService _UserService;
public AccountController(IUserService UserService) {
_UserService = UserService;
}
public JsonResult GetLoginLogs(int Id) {
var Logs = _UserService.GetLoginLogById(Id);
return Json(Logs, JsonRequestBehavior.AllowGet);
}
//The rest of the controller
}
Actually, I believe the exception you get is not misleading if you get deeper into it and analyze the exception message and stack trace. You would find exactly which service could not be found and created by the container - in this case it would be UserService in AccountController (and later, Encryption in UserService as well). The exception with "no parameterless contructor found" simply says that in existing contructor with parameters there is one or more parameters which cannot be resolved by the container, and, because the parameterless constructor is missing, required type cannot be created.
It can also mean you forgot to register your controllers in the container, so the Autofac has no idea it should inject any dependecies into the controllers.
Going further - Autofac is very explicit with the registrations - you can only inject/resolve what you registered at the start up of the application.
If you simply use builder.RegisterType<UserService>() - without any As<> you can only inject UserService directly. But when you add .As<>: builder.RegisterType<UserService>().As<IUserService>(), you cannot inject UserService anymore, but IUserService. To keep the possibility to inject UserService you would have to use AsSelf(): builder.RegisterType<UserService>().As<IUserService>().AsSelf(). Then, you can inject both IUserService and UserService. Keep in mind Autofac registration API is fluent, you can amend as many As<> as you want.
In Dependecy Injection world we do not like tidly coupled components, so injecting concrete classes, instead of interfaces - like you did - is not recommended - you should use interfaces wherever it is possible. So your registrations are correct, but you should inject IUserService instead of UserService and IEncryption instead of Encryption in your components.
It would ease potential unit testing of these components, allowing you mocking up dependencies easily.
Also, you should register your controllers as well:
builder.RegisterControllers(Assembly.GetExecutingAssembly());
I have a web project containing 3 layers: Web (MVC5), BusinessLayer, DataAccess. I use StructureMap 4, Structuremap.MVC5 and StructureMap.WebApi2 to provide the default IoC configuration.
This is my configuration:
public static class IoC {
public static IContainer Initialize() {
var container = new Container(c => c.AddRegistry<DefaultRegistry>());
return container;
}
}
public class DefaultRegistry : Registry {
public DefaultRegistry() {
this.IncludeRegistry<DataAccessLayerRegistry>();
this.IncludeRegistry<BusinessLayerRegistry>();
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
}
}
The DataAccessLayerRegistry and BusinessLayerRegistry don't really do anything apart from scanning their respective dlls with DefaultConventions
Everything else is as generated by templates.
I inject dependencies in such hierarchical way:
Web:
public class HomeController : Controller
{
private ITestClass _myTest;
public HomeController(ITestClass testClass)
{
_myTest = testClass;
}
}
BusinessLayer:
public class TestClass : ITestClass
{
public TestClass(ITestValueRepository repo)
{
}
}
DataAccess:
public class TestValueRepository : ITestValueRepository
{
IMyContext _dbContext;
public TestValueRepository(IMyContext dbContext)
{
_dbContext = dbContext;
}
}
This all works fine and the dependencies are resolved correctly but when there is an error in one of the constructors somewhere down the road, for example an error creating the IMyContext instance (which is an EntityFramework DbContext), I don't get to see the real exception that happened there (for example issue with EF configuration). Instead this is what I see:
No parameterless constructor defined for this object.
[InvalidOperationException: An error occurred when trying to create a
controller of type 'XXX.Web.Controllers.HomeController'. Make sure
that the controller has a parameterless public constructor.]
There is no inner exception nor additional stack trace info that could lead to the real problem. Why is StructureMap hiding the real exception? Is there any way that I can set the StructureMap configuration to make it throw the real exceptions?