I have the following constructor (only one for the controller):
[Authorize]
public class AccountController : Controller
{
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager,
IAccountService accountSrv)
{
UserManager = userManager;
SignInManager = signInManager;
AccountService = accountSrv;
}
private IAccountService AccountService { get; }
private ApplicationSignInManager SignInManager { get; }
private ApplicationUserManager UserManager { get; }
And I'd like MVC to call it with proper parameters, so I tried this:
Global.asax.cs
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DALMapper.Mapping();
LabMapper.Mapping();
var container = new UnityContainer();
container
.RegisterType<IDALContext, DALContext>()
.RegisterType<IConsultantService, ConsultantService>()
.RegisterType<IProjectService, ProjectService>()
.RegisterType<IAccountService, AccountService>()
.RegisterType<AccountController, AccountController>()
.RegisterType<ApplicationUserManager, ApplicationUserManager>()
.RegisterType<ApplicationSignInManager, ApplicationSignInManager>()
.RegisterInstance<IAccountService>(new AccountService(new DALContext()), new ContainerControlledLifetimeManager())
;
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
(UnityDependencyResolver being:)
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
}
Where I register every types needed (the result feel weird though when in/from types are the same (I'm that new to Unity)).
But it doesn't work. (As far as I know, since MV3, the default controller factory will use the service locator, so one doesn't need to implement it's own factory).
What's wrong?
Current result:
Server Error in '/' Application.
No parameterless constructor defined for this object.
If I understand your problem correctly, there's a problem resolving the dependencies for ApplicationUserManager and ApplicationSignInManager.
This is the code that solved the problem for me:
//for accountcontroller
container.RegisterType<DbContext, ApplicationDBContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IAuthenticationManager>(new InjectionFactory(o => HttpContext.Current.GetOwinContext().Authentication));
After digging it up more (downloaded the Unity source code, built it, added a reference to the dll, added the pdb to the symbols locations (debug))*, I could see the error was coming from another constructor which requirs parameters.
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
(I've yet to solve this, but that should be easy).
*is there an easier way to step into a third party library's code? Let me know in the comment.
Related
I have the following asp.net c# code
{
public class Test
{
ISomeService _someService;
public Test()
{
}
public void DoSomething()
{
_someService.Do();
}
}
I need to provide ISomeService to Test class, and I dont know how to do it. I am not allowed to add additional construction which would make entire problem go away, for example
public Test(ISomeService someService)
{
_someService = someService;
}
I tried using setter injection or method injection but that didnt do the trick.
Implementation of ISomeService in SomeService class also uses constructor injection, such as
public SomeService(IService1 service1, Iservice2 service2)
Not sure what to do here.
HERE IS A COMPLETE CODE
public class Startup
{
private IService _service;
public Startup()
{
}
public Startup(IService service)
{
_service = service;
}
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var container = new UnityContainer();
container.RegisterType<IService, Service>();
config.DependencyResolver = new UnityDependencyResolver(container);
app.UseWebApi(config);
_service.DoSomething());
}
}
_service is null
I would suggest you use a factory to create your object. That would have an instance of ISomeService injected on the constructor.
Then in a CreateTest() method on your factory set the ISomeService property directly.
public class Factory
{
private readonly ISomeService someService;
public Factory(ISomeService someService)
{
this.someService = someService ?? throw new ArgumentNullException(nameof(someService));
}
public TestClass CreateTestClass()
{
var instance = new TestClass();
instance.SomeService = this.someService;
return instance;
}
}
You should note that most DI providers have built in functionality to allow factory semantics without the need to create your own factories.
What I ended up doing is this
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IService, Service>();
// create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
_service = ActivatorUtilities.CreateInstance<Service>(serviceProvider);
_service.DoSomething();
Thanks to this answer Dependency Injection with classes other than a Controller class
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
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 2 tier architecture application(Web and Service) in MVC. I have registered my service classes in the startup method in web project like below,
protected void Application_Start()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterControllers(typeof(MvcApplication).Assembly);
containerBuilder.RegisterModelBinders(Assembly.GetExecutingAssembly());
containerBuilder.RegisterModelBinderProvider();
containerBuilder.RegisterType<SearchService>().As<ISearchService>();
var container = containerBuilder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I have created a DbContext with interface, like below
public interface IApplicationDbContext
{
DbSet<Customer> Customers { get; set; }
}
and I have a DbContextClass like this,
public class ApplicationDbContext :
IdentityDbContext<User, Role, Guid, UserLogin, UserRole, UserClaim>,
IApplicationDbContext
{
public ApplicationDbContext() : base("DefaultConnection")
{
Database.SetInitializer(new CreateDatabaseIfNotExists<ApplicationDbContext>());
}
}
Here my question is, I want to pass DbContext object as parameter to below service class, like this
public class SearchService : ISearchService
{
IApplicationDbContext _dbContext;
public QueueService(IApplicationDbContext context)
{
_dbContext = context;
}
}
I think you use SearchService in your MVC Controller, so u have to create ISearchService instance there. In this case Autofac can make constructor injection in you controller.
public class ExampleController : Controller
{
ISearchService _svc;
public B2BHealthApiController(ISearchService s)
{
_svc = s;
}
}
When Autofac creates instance of ISearchService, engine defines that ISearchService require instance of IApplicationDbContext and creates it automaticly (the same constructor injection).
So you just have to say Autofac where take IApplicationDbContext and ISearchService instances. Add to your Application_Start
builder.RegisterType<ApplicationDbContext>()
.As<IApplicationDbContext>()
.InstancePerDependency();
builder.RegisterType<SearchService>()
.As<ISearchService>()
.InstancePerRequest();
I am using Castle Windsor 3.0 and it worked perfectly for me until I tried to register controllers (I used WCF facility and IoC for repository/service layer). Here is my controllers installer class:
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
RegisterAllBasedOnWithCustomComponentRegistration(container, typeof(IController),
typeof(HomeController).Assembly,
cr => cr.LifeStyle.Transient);
}
private void RegisterAllBasedOnWithCustomComponentRegistration(IWindsorContainer container, Type baseType,
Assembly assemblyWithImplementations, Func<ComponentRegistration, ComponentRegistration<object>> customComponentRegistrationCb)
{
container.Register(
AllTypes.FromAssembly(assemblyWithImplementations)
.BasedOn(baseType)
.If(t => t.Name.EndsWith("Controller"))
.Configure(c => customComponentRegistrationCb(c)));
}
}
And here is my controller factory:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controllerComponentName = controllerName + "Controller";
return _kernel.Resolve<IController>(controllerComponentName);
}
}
From my global.asax I call the next method:
InversionOfControl.InstallControllers(FromAssembly.This());
which lies in an another project. And in there I do call the installation code:
public static void InstallControllers(IWindsorInstaller install)
{
_container.Install(install);
}
it seems like I am doing something wrong and I hope I am because it could be a "never use awny beta again" moment for me.
I get the next exception : No component for supporting the service System.Web.Mvc.IController was found altough I can see the controller in the debug mode being registered in the container
In your ControllerFactory, you don't shouldn't Resolve IController but rather the concrete controller type. Here's a typical Windsor-base ControllerFactory I always use:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (IController)_container.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
_container.Release(controller);
}
}
In this case add .WithServices(typeof(IController)) and name all components.
cr => cr.LifeStyle.Transient.Named(cr.Implementation.Name)
and your registration should look like:
.Register(
AllTypes.FromAssembly(assemblyWithImplementations)
.BasedOn(baseType)
.WithServices(typeof(IController))
.If(t => t.Name.EndsWith("Controller"))...)