I am trying to inject a repository into an action filter, but getting the following error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'...ISqlRepository' while attempting to activate
'...MyActionFilterAttribute'.
I'm trying to follow Steve Smith's pattern from here. Everything works fine until I add the ISqlRepository reference to the constructor.
Here are the relevant code bits:
Startup.cs
services.AddScoped<MyActionFilterAttribute>();
MyActionFilterAttribute.cs (I realize that I'm implementing IResultFilter here. I'm just trying to stick as close to the example).
public class MyActionFilterAttribute: IResultFilter
{
private ILogger _logger;
private ISqlRepository _sql;
public MyActionFilterAttribute(ILoggerFactory loggerFactory, ISqlRepository sql)
{
_logger = loggerFactory.CreateLogger<LoaderActionFilterAttribute>();
_sql = sql;
}
MyController.cs
[Route("api/[controller]")]
[ServiceFilter(typeof(MyActionFilterAttribute))]
public class MyController: Controller
You'll need to register your repository as you usually would with ioC:
services.AddScoped<ISqlRepository,SqlRepository>();
Then you'll need to do property injection to the attribute.
Looks like this -
public class MyActionFilterAttribute: IResultFilter
{
public static Func<ISqlRepository> GetSqlRepo;
private ISqlRepository _sql;
public MyActionFilterAttribute()
{
_sql = GetSqlRepo();
}
}
In your startup, you'll have access to your service collection, so can do the following
MyActionFilterAttribute.GetSqlRepo = () => services.GetService<ISqlRepository>()
You need to add ISqlRepository to your services:
services.AddScoped<ISqlRepository,SqlRepository>();
The reason the sample project referenced did not have to do this is because ILoggerFactory is added via the framework.
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 an ASP.NET Core Web application that has an interface in the application that inherits a class from the interface.
I am trying to use the interface by dependency injection in the controller constructor, but I always get the following error
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'DependenceInjection_Dapper.Services.SendSMS' while attempting to
activate 'DependenceInjection_Dapper.Controllers.HomeController'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
The interface codes are as follows:
public interface IsmsSender
{
string sendSms();
}
The class codes are as follows:
public class SendSms : IsmsSender
{
public string sendSms()
{
return "send sms";
}
}
And the following code is added in the program.cs file:
builder.Services.AddTransient<IsmsSender, SendSms>();
Also, the manufacturer of the controller is as follows:
public class HomeController : Controller
{
private readonly IsmsSender _smsSender;
public HomeController(SendSms smsSender)
{
_smsSender = smsSender;
}
public IActionResult Index()
{
ViewBag.send = _smsSender.sendSms();
return View();
}
}
However, I always get an error.
I behaved exactly according to the Microsoft documentation, but the problem was not solved.
You are injecting the concrete type instead of the interface, which is what you registered. Do this instead:
public class HomeController : Controller
{
private readonly IsmsSender _smsSender;
public HomeController(IsmsSender smsSender)
{
_smsSender = smsSender;
}
public IActionResult Index()
{
ViewBag.send = _smsSender.sendSms();
return View();
}
}
Always keep in mind that what matters for the container is the "registration type", not the concrete type. What this line says:
builder.Services.AddTransient<IsmsSender, SendSms>();
Is basically:
Whenever someone asks for an IsmsSender, give a SendSms instance to them
Nothing is said about consumers asking for SendSms.
It is possible to register the concrete type itself, though that's not usual and not recommended when you already have an abstraction in place: you want to rely on abstractions instead of concrete classes to reduce coupling in your implementation and make it more testable.
To register the concrete class itself, you'd just omit the first generic parameter:
builder.Services.AddTransient<SendSms>();
This now means that people must ask for SendSms directly, and IsmsSender won't be resolvable anymore.
The problem comes from your consturctor
public HomeController(SendSms smsSender)
{
_smsSender = smsSender;
}
should be
public HomeController(ISendSms smsSender)
{
_smsSender = smsSender;
}
you registred your ISmendSms as Sendsms in the depenency injection phase.
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?
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