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
}
}
}
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.
Working on web api using EF codefirst approach.
I want to use Dependency injection using Unity framework.
i downloaded--Unity.webapi, it addeds few unity files(unityconfig, unityresolver). my entities i registered as like attachment.
but my codefirst entities not implements any interfaces, all are plain code first classes. now i want to write code in my controllers. how to write ?
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<ApplicationDbContext,PolicyInfo>));
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<ApplicationDbContext, LossInformation>));
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<ApplicationDbContext, Manufacturer>));
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<ApplicationDbContext, ModelVariant>));
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
class
public class **PolicyInfo**
{
[Key]
public int PolicyId { get; set; }
[Required]
public string Manufacturer { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime PolicyIssuedDate { get; set; }
}
controller:
[RoutePrefix("api/PolicyInfo")]
public class PolicyInfoController : ApiController
{
GenericRepository<ApplicationDbContext, PolicyInfo> policycontext;
public PolicyInfoController()
{
this.policycontext = new GenericRepository<ApplicationDbContext, PolicyInfo>();
}
}
I hope this is not write way to create context object. because i written PolicyInfo object at constructor level. please suggest any one.
One of the key concepts behind Inversion of Control (IoC) and Dependency Injection (DI) is precisely not to have to manually instantiate the required dependencies inside the consumer class but those dependencies to get injected into the class.
So if you are using Unity or any other framework, the goal is to suppress the line where you are creating the object context by a parameter in this case in the constructor of your API Controller.
So you if your IoC container is properly configured you should be able to get a reference to the GenericRepository using e.g, constructor injection:
Try this:
[RoutePrefix("api/PolicyInfo")]
public class PolicyInfoController : ApiController
{
IGenericRepository<ApplicationDbContext, PolicyInfo> policycontext;
public PolicyInfoController(IGenericRepository<ApplicationContext,PolicyInfo> policyContext)
{
//use the context here... e.g.: Save the reference to the instance field.
this.policyContext = policyContext;
}
}
However, I would suggest a bit more of abstraction in your code in order to make it clearer and more efficient.
Take a look a this article, although a little old, still applies perfectly to your problem. Hope this helps.
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!
I'm writing a project in c# asp.net mvc3, and I have a helper-class that looks like this:
using System.Collections.Generic;
using System.Web;
namespace CoPrice.Helpers
{
public static class Messages
{
public static IList<Message> All
{
get
{
var list = ((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>();
HttpContext.Current.Session["_messages"] = new List<Message>();
return list;
}
}
public static bool Exists
{
get
{
return (((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>()).Count > 0;
}
}
public static void Add(MessageType type, string message)
{
Message m = new Message
{
Type = type,
Text = message
};
HttpContext.Current.Session["_messages"] = HttpContext.Current.Session["_messages"] as List<Message> ?? new List<Message>();
((IList<Message>)HttpContext.Current.Session["_messages"]).Add(m);
}
public enum MessageType
{
Info,
Success,
Error
}
public struct Message
{
public MessageType Type;
public string Text;
}
}
}
However, when I try to use these in a test, it crashes (cause of HttpContext.Current beeing null). How can I make this work both in tests and in the app itself? I don't mind having to change this class to use something else than HttpContext.Current to access the session, but I want it to have properties as it does, so it can't take the session-object as a parameter.
Any ideas on how to solve this problem?
You need to define an IMessagesProvider and use an DI container to inject the implementation of the IMessagesProvider. In real use you'll have an implementation that uses the ASP.Net session. In test use you'll mostly mock it. BTW, you probably shouldn't have a static Messages class. In fact, IMessagesProvider will probably replace your static Messages class.
Ex:
public class FooController : Controller
{
IMessagesProvider _messages;
public FooController(IMessagesProvider messages)
{
// Your DI container will inject the messages provider automatically.
_messages = messages;
}
public ActionResult Index()
{
ViewData["messages"] = _messages.GetMessages(Session.SessionId);
return View();
}
}
Mind you, this is a very simple example. In fact, you probably want one more class which is the model that drives the view. A quick intro:
public ActionResult Index()
{
var model = PrepareModel(_messages);
return View(model);
}
"PrepareModel" is your very own method that instantiates a new model class, fills it with the necessary data, and then you send it off to your view. It's typical to have one model class per view defined. E.g. you'd have model classes like "SignupFormModel", "DashboardModel", "ChatModel", etc., Doing so allows you to have strongly-typed views as well (a great thing).
You can also implement a mock session object that inherits from HttpSessionStateBase class
#xanadont is right that you need to turn Messages into a normal class. But (and I know this is heresy in some circles) there's no need for a one-off interface and a full-blown DI framework. Just make the methods on your Messages class virtual so you can mock them in your unit-tests, and use constructor injection:
public class FooController : Controller
{
Messages _messages;
// MVC will call this ctor
public FooController() : this(new Messages())
{
}
// call this ctor in your unit-tests with a mock object, testing subclass, etc.
public FooController(Messages messages)
{
_messages = messages;
}
}
public abstract class ConventionController : Controller
{
public const int PageSize = 5;
public IMappingService MappingService { get; set;}
}
How do I set up StructureMap to get the Instance of IMappingService?
Edit:
With the help of Joshua Flanagan I now have the following code:
EmployeeController
public class EmployeeController : ConventionController
{
private readonly ITeamEmployeeRepository _teamEmployeeRepository;
public EmployeeController(ITeamEmployeeRepository teamEmployeeRepository)
{
_teamEmployeeRepository = teamEmployeeRepository;
}
public ActionResult Index(int page = 1)
{
// The IMappingService dependency is hidden in the AutoMappedHybridView method that is a part of the ConventionController, easy use in the controller
return AutoMappedHybridView<TeamEmployee, TeamEmployeeForm>(_teamEmployeeRepository.GetPagedEmployees(page, PageSize));
// With constructor injection I had to write this ...
// return new HybridViewResult<TSourceElement, TDestinationElement>(_mappingService, _teamEmployeeRepository.GetPagedEmployees(page, PageSize));
}
}
ConventionController
public abstract class ConventionController : Controller
{
public const int PageSize = 5;
// This property is inject via StructureMap
public IMappingService MappingService { get; private set; }
public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
{
return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, pagedList, viewNameForAjaxRequest);
}
public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList)
{
return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, pagedList);
}
public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement, TDestinationElement>(TSourceElement sourceElement)
{
return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, sourceElement);
}
public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement, TDestinationElement>(TSourceElement sourceElement, string viewNameForAjaxRequest)
{
return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, sourceElement, viewNameForAjaxRequest);
}
}
HybridViewResult
public class HybridViewResult<TSourceElement, TDestinationElement> : BaseHybridViewResult
{
public HybridViewResult(IMappingService mappingService, PagedList<TSourceElement> pagedList)
{
ViewModel = mappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
}
public HybridViewResult(IMappingService mappingService, PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
{
ViewNameForAjaxRequest = viewNameForAjaxRequest;
ViewModel = mappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
}
public HybridViewResult(IMappingService mappingService, TSourceElement model)
{
ViewModel = mappingService.Map<TSourceElement, TDestinationElement>(model);
}
public HybridViewResult(IMappingService mappingService, TSourceElement model, string viewNameForAjaxRequest)
{
ViewNameForAjaxRequest = viewNameForAjaxRequest;
ViewModel = mappingService.Map<TSourceElement, TDestinationElement>(model);
}
}
As you can see the HybridViewResult needs the IMappingService dependency.
If I would use a constructur in the ConventionController I would "pollute" my EmployeeController (imho).
If EmployeeController would directly need the IMapping dependency I would use the constructor for injecting. But this would not be necessary, because there is already the IMapping property of the ConventionController. So as Darin Dimitrov said, this would violate the DI principle.
How do I refactor my code? Do I really have to use constructor injection?
Edit 2
How could I order StructureMap to create an instance of the HybridViewResult? If this would be possible the controllers would not need to know about a IMapping dependency. Is it at all possible to get an generic object (not boxed) from StructureMap?
Actually, no, SetAllProperties() does not work for abstract classes. This is a weakness in the Structuremap implementation. I'm sorry for you, as I am for myself, that Property Injection does not work for base abstract classes. For the base abstract classes, you will need to use constructor injection (which, contrary to all the hype around here, is not always the best way to go when satisfying dependencies).
I assume you are already getting your controllers out of StructureMap. If thats the case, you just need to add the SetAllProperties() call to your container configuration. SetAllProperties allows you to define the criteria for the properties that should be injected.