StructureMap error when use with MVC in constructor - c#

When I install StructureMap for my project and use:
public class IndexController : Controller
{
private readonly IMapper<UserModel, UserDto> _mapper;
public IndexController(IMapper<UserModel, UserDto> mapper)
{
_mapper = mapper;
}
public ActionResult Index()
{
List<UserDto> userDb = UserDb.GetAll();
UserModel userModel = _mapper.Map(userDb[0]);
return View();
}
}
After run with an server error message:
No parameterless constructor defined for this object. Description: An
unhandled exception occurred during the execution of the current web
request. Please review the stack trace for more information about the
error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
...
But I don't know much about the principle of dependency inversion. Please help me to resolve this.
This is ObjectFactory :
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
// x.For<IExample>().Use<Example>();
});
return ObjectFactory.Container;
}
}
What do I need to do next?

You need to tell StructureMap how to wire up all types that don't follow the default convention (which you use in your scan). The default convention is to wire up all interfaces to concrete implementations with the same name as the interface (minus the "I" prefix).
In your case you need to tell StructureMap to wire up all needed closed generic types of IMapper using:
x.For(typeof(IMapper<,>)).Use(typeof(MyConcreteMapper<,>);
Put the line above where you currently have the x.For<IExample>().Use<Example().

Related

An unhandled exception occurred while processing the request in ASP.NET Core dependency injection

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.

Injecting Repository into ActionFilter

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.

How to use FluentValidation with LightInject in asp.net web-api project

I'm trying to inject a service using the IoC container into a Validation class. See the example below:
[Validator(typeof(UserPayloadValidator))]
public class UserPayload
{
public int UserId { get; set; }
}
public class UserPayloadValidator : AbstractValidator<UserPayload>
{
private IUserService _userService;
public UserPayloadValidator(IUserService userService)
{
_userService = userService;
RuleFor(x => x.UserId).Must(BeUnique).WithMessage("This user already exists");
}
private bool BeUnique(int userId)
{
var user = _userService.GetUser(userId);
return user == null;
}
}
At this point I was hoping everything would auto-magically work and the userService would be injected into the validation class. Instead, I get an exception complaining about a parameter-less constructor not being found.
After some reasearch I've attempted to create a ValidationFactory as in the example linked.
public class LightInjectValidationFactory : ValidatorFactoryBase
{
private readonly ServiceContainer _serviceContainer;
public LightInjectValidationFactory(ServiceContainer serviceContainer)
{
_serviceContainer = serviceContainer;
}
public override IValidator CreateInstance(Type validatorType)
{
return _serviceContainer.TryGetInstance(validatorType) as IValidator;
}
}
and in the LightInject configuration
//Set up fluent validation
FluentValidationModelValidatorProvider.Configure(httpConfiguration, provider =>
{
provider.ValidatorFactory = new LightInjectValidationFactory(container);
});
This results in an exception:
Unable to resolve type: FluentValidation.IValidator`1
I guess the IoC container doesn't know how to resolve the correct instance for the validator.
Any ideas are much appreciated.
Thanks to the comment above I realized I wasn't actually registering the validator in container. This can be done like this for all the validators:
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
Please note that UserPayloadValidator needs to be just one of your validators. Based on this type, FindValidatorsInAssembly can infer all the other available validators.
Also, in the validation factory you should use TryGetInstance instead of GetInstance in case the factory tries to instantiate non existant validators (parameter in the controller for which validators do not exist)
I have found solution for all validation classes use injected service.
Replace below code
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
With
FluentValidation.AssemblyScanner findValidatorsInAssembly = FluentValidation.AssemblyScanner.FindValidatorsInAssembly(typeof(UserPayloadValidator).Assembly);
foreach (FluentValidation.AssemblyScanner.AssemblyScanResult item in findValidatorsInAssembly)
{
container.Register(item.InterfaceType, item.ValidatorType);
}
Using this your all validator classes use injected service.

StructureMap 4 hiding real exceptions - how do I make it throw the correct ones?

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?

Make sure that the controller has a parameterless public constructor error

I have followed this tutorial which has worked great, until I modified my DbContext to have an additional constructor. I am now having issues with the resolution and not sure what to do to fix this. Is there an easy way to force it to grab the parameterless constructor or I am approaching this incorrectly?
DbContext with two constructors:
public class DashboardDbContext : DbContext
{
public DashboardDbContext() : base("DefaultConnection") { }
public DashboardDbContext(DbConnection dbConnection, bool owns)
: base(dbConnection, owns) { }
}
SiteController constructor:
private readonly IDashboardRepository _repo;
public SiteController(IDashboardRepository repo)
{
_repo = repo;
}
Repository:
DashboardDbContext _context;
public DashboardRepository(DashboardDbContext context)
{
_context = context;
}
UnityResolver code:
public class UnityResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = _container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
_container.Dispose();
}
}
WebApiConfig:
var container = new UnityContainer();
container.RegisterType<IDashboardRepository, DashboardRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
Error from WebApi Call:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'SiteController'. Make sure that the controller has a parameterless public constructor.
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()
InnerException: System.ArgumentException: Type 'Dashboard.Web.Controllers.SiteController' does not have a default constructor.
at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
The tutorial was great and has been working well for me up until I added the second constructor.
What's happening is that you're bitten by this problem. Basically, what happened is that you didn't register your controllers explicitly in your container. Unity tries to resolve unregistered concrete types for you, but because it can't resolve it (caused by an error in your configuration), it return null. It is forced to return null, because Web API forces it to do so due to the IDependencyResolver contract. Since Unity returns null, Web API will try to create the controller itself, but since it doesn't have a default constructor it will throw the "Make sure that the controller has a parameterless public constructor" exception. This exception message is misleading and doesn't explain the real cause.
You would have seen a much clearer exception message if you registered your controllers explicitly, and that's why you should always register all root types explicitly.
But of course, the configuration error comes from you adding the second constructor to your DbContext. Unity always tries to pick the constructor with the most arguments, but it has no idea how to resolve this particular constructor.
So the real cause is that you are trying to use Unity's auto-wiring capabilities to create the DbContext. DbContext is a special type that shouldn't be auto-wired. It is a framework type and you should therefore fallback to registering it using a factory delegate:
container.Register<DashboardDbContext>(
new InjectionFactory(c => new DashboardDbContext()));
In my case, it was because of exception inside the constructor of my injected dependency (in your example - inside DashboardRepository constructor). The exception was caught somewhere inside MVC infrastructure. I found this after I added logs in relevant places.
I had the same issue and I resolved it by making changes in the UnityConfig.cs file In order to resolve the dependency issue in the UnityConfig.cs file you have to add:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
I had the same problem. I googled it for two days. At last I accidentally noticed that the problem was access modifier of the constructor of the Controller.
I didn’t put the public key word behind the Controller’s constructor.
public class MyController : ApiController
{
private readonly IMyClass _myClass;
public MyController(IMyClass myClass)
{
_myClass = myClass;
}
}
I add this experience as another answer maybe someone else made a similar mistake.
Sometimes because you are resolving your interface in ContainerBootstraper.cs it's very difficult to catch the error. In my case there was an error in resolving the implementation of the interface I've injected to the api controller. I couldn't find the error because I have resolve the interface in my bootstraperContainer like this:
container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
then I've adde the following line in my bootstrap container : container.RegisterType<MyController>();
so when I compile the project , compiler complained and stopped in above line and showed the error.
If you are using UnityConfig.cs to resister your type's mappings like below.
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IProductRepository, ProductRepository>();
}
You have to let the know **webApiConfig.cs** about Container
config.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(UnityConfig.Container);
I really, really hope this answer helps someone else from wasting a day and a half of messing around with; Ninject, MVC design pattern, Global.asax, Web Common files etc etc.
The error itself was completely misleading in my case.
My entire application was working sound with the exception of when I called one particualr controller lets call TestController.
Test controller was using Ninject to inject an interface lets call ITest like so -
public class TestController : ApiController
{
private readonly ITest _test;
public TestController (ITest test)
{
_test= test;
}
I was making a simple GET request to one of the methods in TestController and was getting the aforementioned error for this threads question.
I eventually boiled it down to the error only occuring when ITest was injected as a parameter (as I tested a different interface and it worked soundly!)
This led me to check the Test class and realsied that I had injected an instance of itself into it! Like so -
public class Test: ITest
{
private readonly ITest_test;
public Test(ITest test)
{
_test = test;
}
Thus resulting in the entire call falling over as an unhandled exception and returning a completely bizarre error that didn't help me at all!
If you have an interface in your controller
public myController(IXInterface Xinstance){}
You must register them to Dependency Injection container.
container.Bind<IXInterface>().To<XClass>().InRequestScope();
I've got this error when I accidentally defined a property as a specific object type, instead of the interface type I have defined in UnityContainer.
For example:
Defining UnityContainer:
var container = new UnityContainer();
container.RegisterInstance(typeof(IDashboardRepository), DashboardRepository);
config.DependencyResolver = new UnityResolver(container);
SiteController (the wrong way - notice repo type):
private readonly DashboardRepository _repo;
public SiteController(DashboardRepository repo)
{
_repo = repo;
}
SiteController (the right way):
private readonly IDashboardRepository _repo;
public SiteController(IDashboardRepository repo)
{
_repo = repo;
}
In my case, Unity turned out to be a red herring. My problem was a result of different projects targeting different versions of .NET. Unity was set up right and everything was registered with the container correctly. Everything compiled fine. But the type was in a class library, and the class library was set to target .NET Framework 4.0. The WebApi project using Unity was set to target .NET Framework 4.5. Changing the class library to also target 4.5 fixed the problem for me.
I discovered this by commenting out the DI constructor and adding default constructor. I commented out the controller methods and had them throw NotImplementedException. I confirmed that I could reach the controller, and seeing my NotImplementedException told me it was instantiating the controller fine. Next, in the default constructor, I manually instantiated the dependency chain instead of relying on Unity. It still compiled, but when I ran it the error message came back. This confirmed for me that I still got the error even when Unity was out of the picture. Finally, I started at the bottom of the chain and worked my way up, commenting out one line at a time and retesting until I no longer got the error message. This pointed me in the direction of the offending class, and from there I figured out that it was isolated to a single assembly.
Install Nuget Package Unit.WebAP instead of Unity.MVC5 Make sure the correct unity package is installed using nuget
I Installed Unity.MVC5 and was facing similar exception "parameterless constructor"
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<ICar, Tesla>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}

Categories