I am pretty new to DI pattern. I was trying to implement DI in one of my controller classes. But the service is not resolved by Unity. Here is what I have done:
Using Unity.MVC5 package:I have the following class:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IProductServices, ProductServices>();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
I have registered my service in the above class.
next i called this class from global.asax as below:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityConfig.RegisterComponents();
}
Following is my controller:
private readonly IProductServices productServices;
/// <summary>
/// Public constructor to initialize product service instance
/// </summary>
public ProductController(IProductServices p)
{
this.productServices = p;
}
When i run the application, it throws an error saying the "there is no parameterless constructor present". Am i doing something wrong? Any help will be appreciated. All the tutorials I have researched do the same thing.
I finally found the reason. I was trying to implement unity in a Web API project using unity.mvc hoping that it would be the same. The error was resolved after the installed the unity.Asp.webapi package. Silly me.
Related
I am trying to inject the API dependency and MVC dependency. But when I try to inject the MVC Dependency I get the error:
The configuration is invalid. The following diagnostic warnings were
reported:
-[Lifestyle Mismatch] FeedbackDbRepository (Web Request) depends on ChatBotDbContext (Transient).
-[Disposable Transient Component] ChatBotDbContext is registered as transient, but implements IDisposable. See the Error property for
detailed information about the warnings. Please see
https://simpleinjector.org/diagnostics how to fix problems and how to
suppress individual warnings.
Which happens in the RegisterMvcDependencies() in here:
public static void RegisterWebApiDependencies()
{
//TODO: setup dependency injection for Web Api
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IAnswerGenerator, PxlAnswerGenerator>(Lifestyle.Singleton);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
}
public static void RegisterMvcDependencies()
{
//TODO: setup dependency injection for MVC
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IFeedbackRepository, FeedbackDbRepository>(Lifestyle.Scoped);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
This is my application_start():
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DependencyConfig.RegisterWebApiDependencies();
DependencyConfig.RegisterMvcDependencies();
}
It does work when I comment out RegisterMvcDependencies() how can I solve this?
EDIT ChatBotDbContext is registered here:
public class FeedbackDbRepository : IFeedbackRepository//TODO: implement IFeedbackRepository
{
private readonly ChatBotDbContext _context;
public FeedbackDbRepository(ChatBotDbContext context)
{
_context = context;
}
//Tip1: use async await
//Tip2: use SaveChangesAsync() instead of SaveChanges()
public async Task AddAsync(Feedback newFeedback)
{
_context.Feedbacks.Add(newFeedback);
await _context.SaveChangesAsync();
}
}
ChatBoxDBContext:
public class ChatBotDbContext : DbContext //TODO: inherit from some other class
{
public ChatBotDbContext()
: base("DefaultConnection")
{
}
public DbSet<Feedback> Feedbacks { get; set; }
public DbSet<User> Users { get; set; }
public static ChatBotDbContext Create()
{
return new ChatBotDbContext();
}
public static void SetInitializer()
{
//TODO: make sure Entity Framework creates the database if it does not exists and migrates an existing database to the latest version
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ChatBotDbContext, Migrations.Configuration>());
}
}
Change it to be a scoped service. From the docs:
Warning: Transient instances are not tracked by the container. This means that Simple Injector will not dispose transient instances. Simple Injector will detect disposable instances that are registered as transient when calling container.Verify(). Please view Diagnostic Warning - Disposable Transient Components for more information.
You can read more on the error here: https://simpleinjector.readthedocs.io/en/latest/disposabletransientcomponent.html
I have a MVC 5 project (framework 4.6.1), where I would like to load a POCO from appsettings.json.
My MVC app does not have a Startup.cs, starting point seems to be Global.asax.
I tried adding Owin to have a Startup.cs, but contrary to most articles I have found, Configuration seems to be a void method called during startup and not an IConfiguration as in net core.
This article pretty much attempts to do what I want, but also assumes that Configuration is an IConfiguration interface.
Ok here is what I ended up doing:
I wanted to load an object of class ScrumBan from my appsettings.json.
I declared this class
public class ChartConfiguration: IChartConfiguration
{
public Scrumban Scrumban { get; }
public ChartConfiguration()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
Scrumban = new Scrumban();
configuration.GetSection("Scrumban").Bind(Scrumban);
}
}
The interface only exposes the ScrumBan object:
public interface IChartConfiguration
{
Scrumban Scrumban { get; }
}
Then i included Unity for Dependency Injection handling and registered my interface:
public static class IocExtensions
{
public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
}
}
public class UnityMvc5
{
public static void Start()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// Configuration object, one per request, ensure it is disposed
container.BindInRequestScope<IChartConfiguration, ChartConfiguration>();
return container;
}
}
Finally in Application_Start in Global.asax.cs I added the UnityMvc5.Start():
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
AreaRegistration.RegisterAllAreas();
UnityMvc5.Start();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
With Unity in place, I can now change my Controller constructors to include my IChartConfiguration interface and store it for future reference, exactly as is common practice with ASP.NET Core.
I am not quite sure about the instantiation model BindInRequestScope, I could have chosen the singleton, but as far as I can tell, the ChartConfiguration constructor is not called per request anyway. Similarly I am not sure of the value of reloadOnChange, but is not crucial to my app.
Hope this helps someone in a situation like mine.
This question already has an answer here:
How to inject webapi AccountController in WebApi
(1 answer)
Closed 5 years ago.
My controller is like :
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
private readonly ApplicationRoleManager _roleManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat,
ApplicationRoleManager roleManager)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
_roleManager = roleManager;
}
}
In UnityConfig.cs I try to configure like this way :
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();
container.RegisterType<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
}
In WebApiConfig.cs :
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
UnityConfig.RegisterTypes(container);
//Set the unity container as the default dependency resolver
config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
}
}
And in Global.asax.cs :
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register); // At the beginning, register with HttpConfiguration
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
But when i try to retrieve role using roleManager (var role = await _roleManager.FindByIdAsync(model.RoleId);) it says :
Object reference not set to an instance of an object.
I see there is a similar question here, but it can't solve my problem.
Based on how the code in the question looks I believe you are using Unity bootstrapper for ASP.NET Web API which should wire up a UnityDependencyResolver.
container.RegisterType<AccountController>(new InjectionConstructor());
This registers the AccountController and instructs Unity to use the paramterless constructor. This is why all of your dependencies are null. If you want to use the other constructor remove the AccountController registration and Unity will use the constructor with the most parameters. However if you do this then you will get a runtime error attempting to resolve the AccountController because ISecureDataFormat<> is not registered and Unity will not know how to map that interface to a concrete type.
If you register a mapping to SecureDataFormat<> then there are some additional dependencies that will need to be registered.
container.RegisterType(typeof(ISecureDataFormat<>), typeof(SecureDataFormat<>));
container.RegisterType<ITextEncoder, Base64UrlTextEncoder>()
container.RegisterType<IDataSerializer<AuthenticationTicket>, TicketSerializer>()
container.RegisterType<IDataProtector>(new ContainerControlledLifetimeManager(),
new InjectionFactory(c => new DpapiDataProtectionProvider().Create("App Name")));
Note that the above registrations are not tested. Not sure if you should configure OWIN with data protection (and perhaps get the protection provider from the OWIN config).
The following two registrations are not strictly required since Unity knows how to resolve a concrete type without a registration and no additional InjectionMembers are being provided (e.g. lifetime, parameters overrides etc.).
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();
I have a WebAPI controller that (should) looks like this:
public class MyController : ApiController
{
private IRepository repository;
public MyController(IRepository repository)
{
this.repository = repositor;
}
// REST implementations
}
WebApiConfig is configured like that:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Unity configuration
var container = new UnityContainer();
container
.RegisterType<IRepository , CustomRepository>();
config.DependencyResolver = new UnityResolver(container);
// Web API routes
// CORS
}
}
then in Global.asax.cs I have something like:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
// CORS
protected void Application_BeginRequest(object sender, EventArgs e)
{
// some CORS config
}
}
and finally I have a Startup.cs:
[assembly: OwinStartup(typeof(Path.To.Startup))]
namespace ZeroCode.ConfigurazioneServizio.Web.Api
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
new Mapping().Bootstrap();
}
}
}
To me everything looks ok, the code builds and I can launch the controller but as soon I make a request I get error cause parameterless constructor isn't present.
So I've added the default constructor but this will instantiate the controller so IRepository will never be injected.
I've searched for a possible solution. One of them tried to implement IHttpControllerActivator and so i've realized something like this:
public class UnityHttpControllerActivator : IHttpControllerActivator
{
private IUnityContainer _container;
public UnityHttpControllerActivator(IUnityContainer container)
{
_container = container;
}
public IHttpController Create(System.Net.Http.HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
return (IHttpController)_container.Resolve(controllerType);
}
}
At this point I've modified the WebApiConfig.cs inserting this line
config.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(container));
right after the config.DependencyResolver but this doesn't resolve the issue and exception is raised inside the Create method. I don't know what else I can do.
There's a nice little Nuget Package - Unity.Webapi. If you add that, you can simply plug in your container into your HttpConfiguration
public static void Register(HttpConfiguration config)
{
// Unity configuration
var container = new UnityContainer();
container.RegisterType<IRepository , CustomRepository>();
config.DependencyResolver = new UnityResolver(container);
//this
config.DependencyResolver = new UnityDependencyResolver(container);
// Web API routes
// CORS
}
Then you can bypass the extra class and web.config changes.
The first answer states to add Unity.WebApi. It is correct. After adding this package use it as is described in this link Using Unity.Mvc5 and Unity.WebApi together in a project. I did like this and my problem was solved.
With version 5 or higher for unity, you will have to add the Unity.AspNet.WebApi NuGet package. Then you can simply follow the instructions in the NuGet package to register your types and register your dependency resolver like the below:
using Unity.AspNet.WebApi;
config.DependencyResolver = new UnityDependencyResolver(container);
Link to NuGet package: https://github.com/unitycontainer/aspnet-webapi
You need to set up Unity as the dependency resolver for WebAPI.
Add the following NuGet package to your project: https://www.nuget.org/packages/Unity.WebAPI/
And then configure WebAPI to use the right resolver adding the following to your WebApiConfig.cs
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
This is 3 step process :
Register
Resolve
Link resolver to GlobalConfiguration
It appears you have not added resolving code and neither does above solutions.
Add this line before attaching DependencyResolver to GlobalConfiguration.
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
I had the same problem. For me the solution to this exact error was that all other controllers constructors also was loaded at request time.
And one of them had not a valid parameter in the constructor. It was not registered with Unity.
So I got the resolution fail from Unity.
But after fixing that other controller everything worked fin.
Following the answer from this other post I am trying to configure autofac for both an ASP .Net MVC 5 project and a Web Api 2 one.
For the Web Api project I used the Autofac.Integration.WebApi library that I referenced it manually to the project and modified the Global.asax file like so:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
ConfigureDiContainer();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
private static void ConfigureDiContainer()
{
var servicesAssembly = Assembly.GetExecutingAssembly();
var container = BuildContainer(servicesAssembly);
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private static IContainer BuildContainer(Assembly servicesAssembly)
{
var x = new ActivityBl();
var builder = new ContainerBuilder();
builder.RegisterApiControllers(servicesAssembly);
var appAssemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => a.ToString().StartsWith("SC."))
.ToArray();
builder.RegisterAssemblyTypes(appAssemblies).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(servicesAssembly).AsImplementedInterfaces();
return builder.Build();
}
}
And when I run the services this works as expected.
For the MVC 5 project I installed the Autofac.Integration.Mvc library from NuGet and modified the Global.asax code as well:
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
The controllers in both projects have no default constructor, only the ones with the dependencies:
MVC Controller:
private readonly IActivitiesService activitiesService;
public HomeController(IActivitiesService activitiesService)
{
this.activitiesService = activitiesService;
}
Web Api Controller:
public class ActivitiesController : ApiController, IActivitiesService
{
private readonly IActivities activitiesBl;
public ActivitiesController(IActivities activitiesBl)
{
if(activitiesBl == null) throw new ArgumentNullException("activitiesBl", "ActivitiesBl dependency was not properly created.");
this.activitiesBl = activitiesBl;
}
}
When I run the application I get the following error:
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'SC.Web.Controllers.HomeController' can be invoked with the available
services and parameters: Cannot resolve parameter
'SC.Services.ServiceContracts.IActivitiesService activitiesService' of
constructor 'Void
.ctor(SC.Services.ServiceContracts.IActivitiesService)'.
In a way I guess it makes sense since the IoC on the web project has no definitions for the services and it seems that it is trying to resolve the whole dependency tree which leads me to the following questions:
From the names of the libraries it seems that each one is specifically tailored for each kind of project, is that so or can I use the Mvc one also for the Web Api?
Have things changed in such a way that the recommendation I got from the previous post is no longer valid and now I must have all the definitions in the Composition Root for each client?
What would be now the best way of configuring the dependencies hierarchy in this kind of multi-layered setup?
Thank you.
I have many common dependencies coming from several projects, including Web Api (using the Web Api Autofac integration), Quartz Scheduling, unit tests, data migration console apps etc.
For this, I have been able to initiate the ContainerBuilder in the manner expected by the project and then I just pass it into some code that exists in a separate project to specify the shared dependencies.
You might have the following 3 projects
MyApp.WebApi
var builder = new ContainerBuilder();
builder.RegisterApiControllers(servicesAssembly);
CommonContainerConfig.RegisterDependencies(builder);
MyApp.Mvc5
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
CommonContainerConfig.RegisterDependencies(builder);
MyApp.Common
public static class CommonContainerConfig
{
public static void RegisterDependencies(ContainerBuilder builder)
{
builder.RegisterType<ActivitiesService>().As<IActivitiesService>();
//etc
}
}
This works for my scenario, although I'm not 100% sure it's what you're after...