I have a class LkCredentials, which is used to store data from SQL table.
[Table(Name = "Credentials")]
public class LkCredentials : LkTable
{
// Database fields
[Column(Name = "id", IsPrimaryKey = true)]
public Binary Uid { get; set; }
...
// Used for dependency injection through Ninject
public ICustomer Customer { get; set; }
public LkCredentials(ICustomer Customer)
{
this.Customer = Customer;
}
// Data loader from database
public void Load(string login)
{
var user = (new SqlTRepository<LkCredentials>()).DBObject.Where(x => x.Login == login).Single();
... // copying data from user to this
}
I'm using Ninject to inject proper ICustomer class this way:
// Create new instance for correct constructor to run and Ninject to resolve
var cred = new LkCredentials((ICustomer)null);
// Load data from database
cred.Load(model.UserName);
But in the process of loading data (void Load), in the variable user new instance of LkCredentials is created, and compiler demands parameterless constructor to be defined. If I create parameterless constructor, then it will be used to create new instance of LkCredentials, but Ninject will not bind correct class - cause constructor incorrect :( And NullReference exception will be raised.
I tried to create constructors chain:
public LkCredentials() : this((ICustomer)null)
{ }
But it didn't work.
What I can do for Ninject to work properly? Any ideas?
P.S.:
Ninject installed as MVC Extension.
Ninject injection in controllers works great, with the same bindings.
Ninject bindings from NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICustomer>().ToProvider<ObjectProvider<ICustomer, Customer, Customer82>>();
kernel.Bind<IAddress>().ToProvider<ObjectProvider<IAddress, Address, ContactInfo>>();
}
public class ObjectProvider<T1,T2,T3> : IProvider
{
public Type Type { get { return typeof(T1); } }
public object Create(IContext context)
{
var securityInfo = context.Kernel.Get<SecurityInformation>();
if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "81")
return context.Kernel.Get<T2>();
else if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "82")
return context.Kernel.Get<T3>();
else
return context.Kernel.Get<T2>();
}
}
I am a student of Ninject and like it a lot. I think the issue is you need to bind LkCredentials to an ILkCredentials and bind it with a parameter. Something like this:
Bind<ILkCredentials>().To<LkCredentials>().WithConstructorArgument("Customer", "Customer");
In the WithConstructorArgument(, ). It's a little confusing because your parameter name is also the name of the object you want to inject.
Here's another example where the parameter name is "name" and the constructor argument is "Fender":
Bind<IGuitar>().To<Guitar>().WithConstructorArgument("name", "Fender");
Hope that helps.
I left parameterless constructor as is, but at the first point, where a need a Customer, I added:
if (this.Customer == null)
this.Customer = (ICustomer)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(ICustomer));
It was enough.
Great thanks to Stephen Byrne, he gives me great advice!
Related
I am using Ninject for Dependency Injection. I have to call two identical classes in the constructor.
public EsyonluAntennaManager(
IModbusActuatorService dksEkbService1, IModbusActuatorService dksEkbService2)
{
_dksEkbService1 = dksEkbService1;
_dksEkbService2 = dksEkbService2;
}
IModbusActuatorService and ModbusActuatorManager are connected to each other.
public ModbusActuatorManager(
ISocketDeviceDal socketDeviceDal,
IDataBaseErrorService dataBaseError,
IDataBaseService dataBase,
Code code)
{
_socketDeviceDal = socketDeviceDal;
_dataBaseError = dataBaseError;
_dataBase = dataBase;
_code = code;
}
The ISocketDeviceDal's constructor does not take any arguments. IDataBaseErrorService and IDataBaseService have only one argument in constructor.
Bind<IDataBaseService>().To<DataBaseManager>()
.WithConstructorArgument("path", _pathDbLog);
Bind<IDataBaseErrorService>().To<DataBaseErrorManager>()
.WithConstructorArgument("path", _pathDbError);
Bind<ISocketDeviceDal>().To<SocketDeviceDal>();
Bind<IModbusActuatorService>().To<ModbusActuatorManager>()
.WithConstructorArgument("code", _code);
Bind<IKamciAntennaService>().To<KamciAntennaManager>();
I observed Injection Ensure that you have not accidentally loaded the same module twice this error. How can I do that? How can Inject IKamciAntennaService and KamciAntennaManager
public static T GetService<T>(
string pathDbError, string pathDbLog, Code _code,Code _code1)
{
var kernel = new StandardKernel(
new DependecyInjection(pathDbError, pathDbLog, _code),
new DependecyInjection(pathDbError, pathDbLog, _code1));
return kernel.Get<T>();
}
UPDATED
I fixed the problem.
public EsyonluAntennaManager(
[Named("Local")]IModbusActuatorService dksEkbService1,
[Named("Remote")] IModbusActuatorService dksEkbService2)
{
_dksEkbService1 = dksEkbService1;
_dksEkbService2 = dksEkbService2;
}
Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope()
.Named("Remote").WithConstructorArgument("code", _codeRemote);
Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope()
.Named("Local").WithConstructorArgument("code", _codeLocal);
The common solution to this issue is to employ the factory pattern.
You create a factory, that based on some paramter set, during runtime, decide which of the classes to use, and then you merely dependency inject that factory.
public interface IDksServiceFactory
{
IDkservice ResolveDksService()//add some input paraameters?
}
public DksServiceFactory : IDksServiceFactory
{
public IDkservice ResolveDksService()
{
if()//something?
{
return new DksEkbService1();
}
else
{
return new DksEkbService2();
}
}
}
public interface IDksService() // implement the interface for your "identical" services.
{
}
public class DksEkbService1 : IDksService
{
}
public class DksEkbService2 : IDksService
{
}
and then in your services, you just add the factory, and use the "resolve method" on the object from your constructor to find the class you need.
I have a base controller and before every page load I want to get the current user. I originally had a constructor in my BaseController that looked like this
public BaseController(ISystemUserCommand command)
{
_systemUserCommand = command
}
The problem with this then is that every controller that inherits from the BaseController would have to contain the ISystemUserCommand in its constructor, which I don't think would be good.
Instead I tried to create just an instance of the service class (shown below - it's the commented line under var sid...) but I need to pass in user service. How would I pass in the user service here or is this a bad way of doing it?
public abstract class BaseController : Controller
{
public SystemUserViewModel CurrentUser { get; set; }
private readonly ISystemUserCommand _systemUserCommand;
public SystemUserViewModel GetCurrentUser()
{
if (HttpContext == null || HttpContext.User == null) return null;
if (CurrentUser != null) return CurrentUser;
var sid = System.Web.HttpContext.Current.Request.LogonUserIdentity.User.ToString();
//var command = new SystemUserCommand();
CurrentUser = _systemUserCommand.GetUser(sid);
return CurrentUser;
}
public void SetUserInformation(SystemUserViewModel currentUser)
{
ViewBag.UserId = currentUser.SystemUserId;
ViewBag.FullName = string.Format("{0} {1}", currentUser.FirstName, currentUser.LastName);
ViewBag.FirstName = currentUser.FirstName;
ViewBag.LastName = currentUser.LastName;
ViewBag.CurrentUser = currentUser;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var currentUser = GetCurrentUser();
if (currentUser != null)
{
if (currentUser.IsActive)
{
SetUserInformation(currentUser);
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
base.OnActionExecuting(filterContext);
}
}
public class SystemUserCommand : ISystemUserCommand
{
private readonly ISystemUserBusiness _systemUserBusiness;
public SystemUserCommand(ISystemUserBusiness systemUserBusiness)
{
_systemUserBusiness = systemUserBusiness;
}
...
}
You could use property injection instead of constructor injection, via the base class, eg using unity:
public abstract class BaseController : Controller
{
[Dependency]
public ISystemUserCommand SystemUserCommand { get; set; }
}
This would mean the interface reference is only on the base class.
See here for the full examples.
EDIT, Autofac example:
You don't need property attributes on the dependency,
public abstract class BaseController : Controller
{
public ISystemUserCommand SystemUserCommand { get; set; }
}
Just to register the properites to auto resolve on the autofac builder:
builder.RegisterControllers(typeof(MvcApplication).Assembly).Where(t => t.IsAssignableFrom(typeof(BaseController))).PropertiesAutowired();
See autofac property injection here.
First of all, it does not seem a good idea to have OnActionExecuting override in the controller. You can use filters, that are specially designed for this purpose. And it seems that is the main reason you created the BaseController at all.
Regarding the problem with injecting the system command in all the required service, I would do so, but without inheriting from a base class, since I generally prefer aggregation to inheritance. That would mean that each controller that needs to work with the service will get it.
Another option that I have used few times to abstract some operations is to create a UserSerivce that will provide the required operations to the controllers. It will have ISystemUserCommand and HttpContext injected inside so that all of your controllers won't have to do the job. You can either use HttpContext.Current as static or abstract it away if you need testability.
Moreover I would not recommend property injection since it is more obscure than constructor injection that should be preferred if possible.
You can read more about filters here. Unfortunately if you use filters it's not that easy to inject in filters themselves and mostly done with property injection or ServiceLocator pattern (which is not good usually). It's possible to do better with some amount of voodoo though. I think that SimpleInjector has a lot of examples and tutorials on how to apply DI to filters in MVC, maybe they even have a nuget package now to ahieve that.
I have a class similar to the following:
public class CarAttributes
{
private readonly ICarRepository _carRepository;
private readonly int _carId;
public CarAttributes(ICarRepository carRepository, int carId)
{
_carRepository = carRepository;
_carId = carId;
}
public bool IsRegistered
{
get
{
return _carRepository.IsRegistered(_carId);
}
}
public bool IsStolen
{
get
{
return _carRepository.IsStolen(_carId);
}
}
}
I also have the following method (which is syntactically incorrect)
public CarAttributes GetCarAttributes(int carId)
{
return new CarAttributes(carId);
}
I am using Unity to inject the ICarRepository at runtime
container.RegisterType<ICarRepository, CarRepository>();
How do I inject CarAttributes with the CarRepository via Unity but allow the program to supply the carId?
Am I correct in thinking that i need a factory to do this?
Something perhaps like the following
public class CarAttributesFactory()
{
private readonly ICarRepository _carRepository;
public CarAttributesFactory(ICarRepository carRepository)
{
_carRepository = carRepository;
}
public CarAttributes GetCarAttributes(int carId)
{
return new CarAttributes(_carRepository, carId);
}
}
This allows unity to inject the factory with the dependency, but will also allow the program to specify the carId when the GetCarAttributes method is invoked.
However is this not going against the DI principles, as I am creating a dependency here between the CarAttributesFactory and the CarAttributes classes.
Is this the correct usage for using factories?
Also I have read about other DI frameworks having things such as TypedFactories for this kind of thing, although I would like to do it manually first to understand the concepts.
Here for example
Unity - Constructor Injection with other parameter
Hope this makes sense.
EDIT: Example usage
From my MVC controller I need to be able to retrieve back a CarAttributes object for a specific carId which will be passed in via a view model. The CarAttributes class requires the use of one or more repositories (only one shown in this example), as well as a run time parameter passed in which is carId depending on what comes though the view model.
(I would also have to create an ICarAttributesFactory interface as well in order to inject the factory into the controller in the below example)
public SomeController : Controller
{
private readonly ICarAttributesFactory _carAttributesFactory;
public SomeController(ICarAttributesFactory carAttributesFactory)
{
_carAttributesFactory = carAttributesFactory;
}
public ActionResult Submit(DataViewModel model)
{
// model will contain a carId property
var carAttribs = _carAttributesFactory.GetCarAttributes(model.carId);
if(carAttribs.IsStolen)
{
// do something
}
}
}
I try to access my repository from a class for RSS service. So I used dependency injection for that.
Here is what I do in the NinjectControllerFactory:
ninjectKernel.Bind<IPostRepositoryFactory>().To<NinjectPostRepositoryFactory>().InSingletonScope();
Here is my IPostRepositoryFactory class:
public interface IPostRepositoryFactory
{
IPostRepository GetRepository();
}
public class NinjectPostRepositoryFactory : IPostRepositoryFactory
{
private readonly IKernel kernel;
public NinjectPostRepositoryFactory(IKernel kernel)
{
if (kernel == null)
throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
public IPostRepository GetRepository()
{
return kernel.Get<IPostRepository>();
}
}
Here is the call from my controller:
public ActionResult Feed(int? page = 1)
{
var mgr = new SyndicationManager();
return mgr.GetFeedResult(page);
}
Here is the SyndicationManager class:
public class SyndicationManager
{
[Inject]
public IPostRepositoryFactory m_PostRepositoryFactory { get; set; }
private SiteConfiguration m_SiteConfiguration;
public SyndicationManager()
{
m_SiteConfiguration = SiteManager.CurrentConfiguration;
}
public ActionResult GetFeedResult(int? page = 1)
{
IPostRepository repository = m_PostRepositoryFactory.GetRepository();
var feed = new SyndicationFeed(m_SiteConfiguration.Name,
m_SiteConfiguration.Description,
new Uri(SiteManager.GetBaseUrl()));
So I started debugging from my Feed action controller. Then accessing GetFeedResult and there is the problem: error is that my m_PostRepositoryFactory is always null.
Any help is greatly appreciated.
Why aren't you using constructor injection? It makes it easier to find dependencies of your classes and all resolves will fail directly if any of the dependencies are missing.
Just use the ninject.mvc3 nuget package to configure ASP.NET MVC to use dependency injection for the controllers.
And I don't see the use of a singleton factory to find the repository? Why can't you resolve the repository interface directly?
#Jehof is correct. ninject will not resolve any dependencies when you create objects yourself. But as I said: Don't use the kernel directly, configure MVC3+NInject correctly instead.
http://nuget.org/packages/Ninject.MVC3/2.2.2.0
I´m not an expert on Ninject, but i use Unity as DependencyInjection-Framework. I think the problem is that you instantiate SyndicationManager using its default constructor.
You need to get a reference to the SyndicationManager by resolving it from the Ninject-Kernel, otherwise the dependencies won´t be injected.
public ActionResult Feed(int? page = 1)
{
IKernel kernel = // get the kernel from somewhere
var mgr = kernel.Get<SyndicationManager>();
return mgr.GetFeedResult(page);
}
In short: I am trying to create a custom model binder that will take in the type of user and get their id, then use a service class to retrieve the strongly typed object.
If there is a better way to do this, please let me know.
Elabaration:
I have ninject setup with all my bindings within my DomainService layer, 3 web ui's are hooked up to the domain service layer. Each asp.net mvc app loads the bindings into the kernal.
//my custom model binder
public class UserModelBinder : IModelBinder
{
private IAuthenticationService auth;
public UserModelBinder(IAuthenticationService _auth, EntityName type,
string loggedonuserid)
{
this.auth = _auth;
CurrentUserType = type;
CurrentUserId = loggedonuserid;
}
public EntityName CurrentUserType { get; private set; }
private string CurrentUserId { get; set; }
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
object loggedonuser = null;
if (CurrentUserType == EntityName.Client)
loggedonuser = GetLoggedOnClientUser(CurrentUserId);
else if (CurrentUserType == EntityName.Shop)
loggedonuser = GetLoggedOnShopUser(CurrentUserId);
else
throw new NotImplementedException();
return loggedonuser;
}
public ClientUser GetLoggedOnClientUser(string loggedonuserid)
{
var user = _auth.GetLoggedOnClientUser(loggedonuserid);
if (user == null)
throw new NoAccessException();
return user;
}
public ShopUser GetLoggedOnShopUser(string loggedonuserid)
{
var user = _auth.GetLoggedOnShopUser(loggedonuserid);
if (user == null)
throw new NoAccessException();
return user;
}
}
my Global.aspx.cs
// using NInject to override application started
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
// hand over control to NInject to register all controllers
RegisterRoutes(RouteTable.Routes);
//how do I instantiate?
ModelBinders.Binders.Add(typeof(object), new
UserModelBinder(null,EntityName.Client, User.Identity.Name));
}
My problem is IAuthentication is a service, it is connected to other things like a repository, how do I actually instantiate this properly? Should I create a new NinjectModule? I am really confused with this so any help is greatly appreciated. I have tried to pass in Container.Get(); - but it is null...
NOTE: the reason why I am creating a modelbinder- all controllers will require the type of user as I my service layer requires which type of user is making a request, most methods in my service layer will have overloads where it will do one thing for a ShopUser or ClientUser or any other user in the system...
EDIT:
I could very easiy within my controller call upon the IAuthenticationService and get the type of user and pass into my domainservice layer to process the relevant tasks but I just want to know how it is possible with the ModelBindings (and if it makes sense to do it that way).
Edit2: Is there a working sample of using a custom Attribute with AOP with the custom attribute calling/binding/getting an instance of ISomethingService?
You can use the Service Locator pattern here. Pass the Ninject Container (IKernel?) to the constructor and resolve the AuthenticationService each time you need to bind something.
A refinement of this could be to have a constructor argument Func where you pass the function to resolve the service. This would be more explicit and removes the dependency on Ninject. Something like this:
public class MyModelBinder : IModelBinder
{
Func<IAuthenticationService> _resolveAuthService;
public MyModelBinder(Func<IAuthenticationService> resolveAuthService)
{
_resolveAuthService = resolveAuthService;
}
public override object Bind(Context c)
{
var authService = _resolveAuthService();
authService.GetSomething();
// etc...
}
}