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;
}
}
Related
I'm trying to use a Generic Controller in my Web API. My goal, which I am currently failing at, is to pass in an object from my front end that will have say a typeId. Based on this typeId I was going to use a factory to inject the correct class implementation of a generic interface. I believe my Factory, Interface and Service is correct, but for some reason when I add a Generic to the API I am getting a 404. It works without a generic and just a test method. I am using autofac for my IoC registration.
API Controller:
public class ListItemsController<T> : ApiControllerBase
{
private readonly IListItemsService<T> _service;
public ListItemsController(int listItemTypeId)
{
_service = ListItemsFactory<T>.InitializeService(listItemTypeId);
}
[HttpGet]
[Route("{listItemTypeId: int}")]
public IEnumerable<T> GetAll()
{
return _service.GetAll();
}
[HttpGet]
[Route("test")]
public IHttpActionResult Test()
{
return Ok();
}
}
Factory:
public class ListItemsFactory<T>
{
public ListItemsFactory(IPrimaryContext context) : base()
{
}
public static IListItemsService<T> InitializeService(int listItemType)
{
switch (listItemType)
{
case 1: return (IListItemsService<T>)
new FloorTypeService(new PrimaryContext());
default: return null;
}
}
}
Interface:
public interface IListItemsService<T>
{
IEnumerable<T> GetAll();
void Save(T obj);
T GetById(int id);
void Delete(int id);
}
Error:
No HTTP resource was found that matches the request URI 'http://localhost:9000/api/v1/listitems/test'. No type was found that matches the controller named 'listitems'.
I'm not sure what piece I'm missing here. I'm using routing attributes but here is my API config:
private static void SetupRoutes(HttpConfiguration config)
{
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
config.Routes.MapHttpRoute("DefaultApi", "api/v{version}/{controller}/{id}",
new { id = RouteParameter.Optional });
}
Instead of resolving the type and trying to map to the right Controller, you also can create a Controller for each Type, which inherits from your GenericController. Then you don't have to copy the Code, but have a Controller for each Type, where you can route to by RouteAttribute.:
public class ListItemsController<T> : ApiControllerBase
{
//Properties/Fields should be protected to can be accessed from InstanceController.
protected readonly IListItemsService<T> _service;
// I think listItemTypeId is not necessary, if generic-type T is used?
public ListItemsController()
{
_service = ListItemsFactory<T>.InitializeService();
}
[HttpGet] // No need for RouteAttribute, because it will be in InstanceController.
public IEnumerable<T> GetAll()
{
return _service.GetAll();
}
[HttpGet]
[Route("test")] // This can rest here, because you want to use it.
public IHttpActionResult Test()
{
return Ok();
}
}
The implemented InstanceController can look like this:
[RoutePrefix("api/{controller}")]
public class FloorItemsController ListItemsController<Floor>
{
// delegate the Constructor-call to base()
public ListItemsController()
:base()
{
}
// No need to reimplement Methods.
}
The RouteConfiguration should be set back to default, because RouteAttributes are set for this.
Basically, what you'll need to do is to replace the controller activator, with a custom implementation.
First, createa class that implements the IHttpControllerSelector interface. Take a look at this link for some of the thing you should be aware before creating a custom activator. At the bottom there's a link to some code example of a custom implmentation.
Now, this depends on what your rules will actually be, but for perfomance reasons,you should try to build a solution that always map the same controller name to the same closed type of your generic controller type. A simple implementation for your case would look something like this:
public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
//get the generyc type of your controller
var genericControllerType = typeof(ListItemsController<>);
// Get the route value from which you'll get the type argument from your controller.
string typeParameterArgument = GetRouteVariable<string>(routeData, 'SomeKeyUsedToDecideTheClosedType');
Type typeArgument = //Somehow infer the generic type argument, form your route value based on your needs
Type[] typeArgs = { typeof(typeArgument) };
//obtain the closed generyc type
var t = genericControllerType.MakeGenericType(typeArgs);
//configuration must be an instance of HttpConfiguration, most likeley you would inject this on the activator constructor on the config phase
new HttpControllerDescriptor(_configuration, t.Name, t);
}
Finally, on your ApiConfig class you'll need to add this line:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
new MyOwnActivatior());
I can't test this code right now, so it might need some tweaking, but hopefully this will guide you on the right direction. Do take notice of the link i pasted above, since there are important considerations you'll need to take into account before implementing a custom activator. Also, check the code example linked on that post to see how to implement the GetControllerMapping method
My current class PropertyManager looks like this:
public class PropertyManager : IDisposable
{
private readonly IPropertyRepo _propertyRepo;
private readonly IUserTypeRepo _userTypeRepo;
public PropertyManager(IPropertyRepo propertyRepo, IUserTypeRepo userTypeRepo = null)
{
if (propertyRepo == null)
throw new ArgumentNullException("propertyRepo");
_propertyRepo = propertyRepo;
if (userTypeRepo != null)
_userTypeRepo = userTypeRepo;
}
}
My Property Manager will use the _userTypeRepo in some method to accomplish some task. I think I want to implment a rule that says "Each Manager(Service,Factory,etc) should be responsible for its own repository."
The idea:
The PropertyManager, because it needs to do something with the UserTypeRepo, I should be using the UserManager for such activities.
As such, this means that I will not provide a repo when creating an instance of the UserManager (i.e., var usrMgr = new UserManager(); // no repo). Instead, the UserManager will use the default constructor which will create a new instance of the IUserTypeRepo and provide a new instance of a UserManager and then it can do its work.
I think this accomplishes some design principle such as Separation of Concerns and the Single Responsibility, but then I may be getting away from my Dependency Injection design pattern as the new Managers would now have multiple constructors and look like this:
public class PropertyManager : IDisposable
{
private readonly IPropertyRepo _propertyRepo;
public PropertyManager(){
// use the default repo
_propertyRepo = new PropertyRepo();
}
// Used from Controller or Unit Testing
public PropertyManager(IPropertyRepo propertyRepo)
{
if (propertyRepo == null)
throw new ArgumentNullException("propertyRepo");
}
}
public class UserManager : IDisposable
{
private readonly IUserRepo _userRepo;
public UserManager(){
// use the default repo
_userRepo = new UserRepo();
}
// Used from Controller or Unit Testing
public UserManager(IUserRepo userRepo)
{
if (userRepo == null)
throw new ArgumentNullException("userRepo");
}
}
Would this be frowned upon? Or am I on the right track? In either case, why and thanks?
Update. After reading Yawar's post I decided to update my post and I think I have a relevant concern.
Let's think of a real world example of the above. I have a PropertyManager in real life named "Robert" one of the jobs he performs each morning at work is to Open() the Property (i.e., he unlocks the Property he is the Manager of). I also have a UserManger who manages people who visit the Property and her name is "Sarah" she has a function that she does called EnterProperty() (which is what she does in the morning when she physically walks into the building).
Rule: UserManager has a dependency on PropertyManager when using the EnterProperty()
This looks like this according to all accepted standards:
Property Manager
class PropertyManager : IPropertyManager
{
private readonly IPropertyRepo _propertyRepo;
public PropertyManager(IPropertyRepo propertyRepo)
{
if (propertyRepo == null)
throw new ArgumentNullException("propertyRepo");
this._propertyRepo = propertyRepo;
}
// this is when Robert opens the property in the morning
public void Open()
{
_propertyRepo.Open();
}
// this is when Robert closes the property in the evening
public void Close()
{
_propertyRepo.Close();
}
// this answers the question
public bool IsOpen()
{
return _propertyRepo.IsOpen();
}
}
User Manager
class UserManager : IUserManager
{
private readonly IPropertyRepo _propertyRepo;
private readonly IUserRepo _userRepo;
public UserManager(IUserRepo userRepo, IPropertyRepo propertyRepo = null)
{
if (userRepo == null)
throw new ArgumentNullException("userRepo");
this._userRepo = userRepo;
if (propertyRepo != null)
this._propertyRepo = propertyRepo;
}
// this allows Sarah to physically enter the building
public void EnterProperty()
{
if(_propertyRepo.IsOpen())
{
Console.WriteLine("I'm in the building.");
}else{
_propertyRepo.Open(); // here is my issue (explain below)
Console.WriteLine("Even though I had to execute the Open() operation, I'm in the building. Hmm...");
}
}
}
Web API Controller
{
public void OpenForBusiness(){
private const IPropertyRepo propertyRepo = new PropertyRepo();
private IPropertyManager propertyManager = new PropertyManager(propertyRepo);
private IUserManager userManager = new UserManager(new UserRepo(), propertyRepo);
// Robert, the `PropertyManager`, opens the `Property` in the morning
propertyManager.Open();
// Sarah, the `UserManager`, goes into `Property` after it is opened
userManager.EnterProperty();
}
}
Now, everything is cool and I can walk away and I now have a Repository Pattern which use Dependency Injection which supports TDD and not tightly coupled classes among other benefits.
However, is the truly realistic? (explain why I ask in second)
I think a more real-world (realistic) approach is one that does:
Web API Controller
public void Method1()
{
private IPropertyManager propMgr = new PropertyManager(new PropertyRepo());
private IUserManager userMgr = new UserManager(new UserRepo()); // no dependencies on any repository but my own
// 1. Robert, the `PropertyManager`, opens the `Property`
propMgr.Open();
// 2. Check to see if `Property` is open before entering
// choice a. try to open the door of the `Property`
// choice b. call or text Robert, the `PropertyManager`, and ask him if he opened the `Property` yet, so...
if(propMgr.IsOpen()){
// 3. Sarah, the `UserManager`, arrives at work and enters the `Property`
userMgr.EnterProperty();
}else{
// sol, that sucks, I can't enter the `Property` until the authorized person - Robert - the `PropertyManager` opens it
// right???
}
}
the EnterProperty() method on the UserManager now looks like this:
// this allows Sarah to physically enter the building
public void EnterProperty()
{
Console.WriteLine("I'm in the building.");
}
The promised explanation from above:
If we think in real-world terms we must agree that the later is preferred over the former. When thinking of a Repository lets say this is the definition of ones self (i.e., one's Person) (i.e., the UserRepo having all the data related to the User, is to the UserManager as the DNA, Heartbeat, Brain Wave Pattern, etc. is to a Human (the HumanRepo). As such, allowing the UserManager to know about the PropertyRepo and having access to its Open() method violates all Real-World security principles and Business Rules. In reality this says that through My Contructor() I can get an Interface Representation of a PropertyRepo that I can use any way I see fit. This is synonymous to the following logic of the HumanRepo:
I, Sarah - a UserManager - through a new instance of myself with the satisfaction of the PropertyRepo through my Constructor() create a Hologram Interface of Robert, the PropertyManager that I can use any way I see fit. Granted right now I only want to use the IsOpen() method of the PropertyRepo I actually use the Open() method to do it myself if Robert has not yet performed his duty. This is a security concern to me. In the real-world this says I don't have to wait for Robert to open the Property and use the Holocopy of him and implement his Open() method to get access.
That doesn't seem right.
I think with the last implementation I get SoC, SRP, DI, Repository Pattern, TDD, and Logical Security and as close to a real-world implementation as possible.
What do you all think?
I think I agree with your SoC and breaking the PropertyManager class into PropertyManager and UserManager classes. You are almost there.
I would just refactor as shown below:
public class PropertyManager : IDisposable, IPropertyManager
{
private readonly IPropertyRepo _propertyRepo;
// Used from Controller or Unit Testing
public PropertyManager(IPropertyRepo propertyRepo)
{
if (propertyRepo == null)
throw new ArgumentNullException("propertyRepo");
this._propertyRepo = propertyRepo;
}
}
public class UserManager : IDisposable, IUserManager
{
private readonly IUserRepo _userRepo;
// Used from Controller or Unit Testing
public UserManager(IUserRepo userRepo)
{
if (userRepo == null)
throw new ArgumentNullException("userRepo");
this._userRepo = userRepo;
}
}
Note: Just extract IPropertyManager & IUserManager so that the calling classes will depend upon the interfaces and provide the implementation.
Creating parameterless constructor is useless if you want to (you should) force the client to provide the concrete implementation of IPropertyRepo and IUserRepo interfaces.
public PropertyManager(){
// use the default repo
_propertyRepo = new PropertyRepo();
}
I dont think you would need
if (propertyRepo == null)
throw new ArgumentNullException("propertyRepo");
or
if (userRepo == null)
throw new ArgumentNullException("userRepo");
as IPropertyRepo and IUserRepo will be resolved via a IoC at the startup of your application (say its MVC then before calling the controller IoC will resolve them) so no need to check for null. I have never checked the dependencies for null in my code.
From what you have posted here thats pretty much it.
Unit of Work pattern is used for repository layer not in the manager layer. I would delete that from the title.
Hope this helps!
I think this accomplishes some OOP goal such as Separating Concerns
and the Single Responsibility Principle.
The result is opposite. Now, PropertyManager tightly couples to PropertyRepo; previously, they were loosely coupled.
First approach is better than the latter one. However, PropertyManager and UserManager should not create other objects on which they rely to do their work. The responsibility for creating and managing object should be offloaded to IoC container.
Interfaces describe what can be done, whereas classes describe how it is done. Only classes involve the implementation details—interfaces are completely unaware of how something is accomplished. Because only classes have constructors, it follows that constructors are an implementation detail. An
interesting corollary to this is that, aside from a few exceptions, you can consider an appearance of the new keyword to be a code smell. - Gary McLean Hall
Answer for Updated Question:
In your updated question, you combine Service/Manager and somewhat Domain into a single class - PropertyManager, UserManager. It becomes personal preference.
I personally like to keep them separate. In addition, I like to use Role based and Claim based authorization. Let me use my GitHub sample project as a reference. Please feel free to clone it.
User Domain
User class is also used by Entity Framework Code First Fluent API.
public partial class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
}
User Service
public class UserService : IUserService
{
private readonly IRepository<User> _repository;
public UserService(IRepository<User> repository)
{
_repository = repository;
}
public async Task<IPagedList<User>> GetUsersAsync(UserPagedDataRequest request)
{
...
}
}
Action Method
Notice that UI related Business Logic stays at UI layer.
public async Task<ActionResult> Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
bool result = _activeDirectoryService.ValidateCredentials(
model.Domain, model.UserName, model.Password);
if (result)
{
...
}
}
...
}
you can take quite a bit of a different approach.....( ignoring your repositories, but allowing for it to be injected )
In this system, the property is only readable, with an event system to handle the mutations, the event system also has rules system which controls what mutations are allowed. This means even if you have a property object you can't mutate it without going through its rules.
This code is more conceptual. The next logical step is to use a full actor model and something like (akka.net) and you may find your repository pattern just disappearing :)
public class Property
{
public string Name { get; private set; }
private IPropertyRules _rules;
private List<User> _occupants = new List<User>();
private IEventLog _eventLog;
public Property(IPropertyRules rules, IEventLog eventLog)
{
_rules = rules;
_eventLog = eventLog;
}
public ActionResult Do(IAction action, User user)
{
_eventLog.Add(action, user);
if (_rules.UserAllowedTo(action, user, this))
{
switch (action)
{
case Open o:
Open();
return new ActionResult(true, $"{user} opened {Name}");
case Enter e:
Enter(user);
return new ActionResult(true, $"{user} entered {Name}");
}
return new ActionResult(false, $"{Name} does not know how to {action} for {user}");
}
return new ActionResult(false, $"{user} is not allowed to {action} {Name}");
}
private void Enter(User user)
{
_occupants.Add(user);
}
private void Open()
{
IsOpen = true;
}
public bool IsOpen { get; set; }
}
public interface IEventLog
{
void Add(IAction action, User user);
}
public class Enter : IAction
{
}
public interface IPropertyRules
{
bool UserAllowedTo(IAction action, User user, Property property);
}
public class Open : IAction
{
}
public class ActionResult
{
public ActionResult(bool successful, string why)
{
Successful = successful;
WhatHappened = why;
}
public bool Successful { get; private set; }
public string WhatHappened { get; private set; }
}
public interface IAction
{
}
public class User
{
}
The way I am utilising the MVC pattern at the moment in my ASP.NET application (using Entity Framework) is as follows:
1) My Models folder contains all EF entities, as well as my ViewModels
2) I have a Helpers folders where I store classes created for the purposes of the particular application.
3) In my Helpers folder, I have a static class named MyHelper which contains methods that access the DB using EF.
namespace myApp.Helpers
{
public static class MyHelper
{
public static async Task<ProductVM> GetProductAsync(int productId)
{
using (var context = new myEntities())
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
}
4) My controllers then call these functions where necessary:
namespace myApp.Controllers
{
public class ProductController : Controller
{
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await MyHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
I usually encounter comments in SO of the type "don't use a static class, static classes are evil, etc". Would this apply in such a scenario? If yes, why? Is there a better 'structure' my app should follow for best practices and for avoiding such pitfalls?
You can't really use a static class for this. Your Entity Framework context should have one and only one instance per request. Your methods here instantiate a new context for each method, which is going to cause a ton of problems with Entity Framework.
The general concept is fine, but your MyHelper class should be a normal class. Add a constructor that takes an instance of your context, and then use a DI container to inject the context into the helper class and the helper class into your controller.
UPDATE
Helper
namespace myApp.Helpers
{
public class MyHelper
{
private readonly DbContext context;
public MyHelper(DbContext context)
{
this.context = context;
}
public async Task<ProductVM> GetProductAsync(int productId)
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
Controller
namespace myApp.Controllers
{
public class ProductController : Controller
{
private readonly MyHelper myHelper;
public ProductController(MyHelper myHelper)
{
this.myHelper = myHelper;
}
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await myHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
Then, you just need to set up a DI container to inject everything. The code for that is entirely dependent on which container you end up going with, so I can't really help you further. It's usually pretty straight-forward, though. Just read the docs for the container. You'll want to set the life-time scope of your objects to the request. Again, it's different for different containers, but they'll all have some sort of request-scope.
I was thinking to add comment to ChrisPratt's answer, but it ended being too long, so let me add separate answer.
Basically, this is not a life/death choice. Sure, static methods are not as flexible as classes for db access. But they are not bad per-se. One DbContext per request is a something to aim for. It is not an absolute must. It is kinda like dependency injection - you get more flexibility and in turn increase code complexity.
Look at these three questions and their answers, by taking into account everything they say, I'm sure you'll be able to answer your question yourself:
Why would I use static methods for database access
When to use static classes in C#
One DbContext per web request... why?
EDIT: Chris left good comment on my answer and I've changed answer a bit to take into account what he said.
Your idea is correct and I use it always. But the style is like this:
1) For each entity (i.e User) we have a static class inside Providers folder. In this class we can do general methods (i.e create, Get, GetAll , ..)
public static class Users
{
public static IEnumerable<kernel_Users> GetAll()
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users;
}
public static kernel_Users Get(int userId)
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users.Where(c => c.UserId == userId).FirstOrDefault();
}
...
}
2) We have another class that is not static.It is inside Models folder. This is the place that we can access to an instance of the entity :
public partial class kernel_Users
{
[Key]
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
[NotMapped]
public string FullName
{
get
{
return FirstName + " " + LastName;
}
}
public bool Delete(out string msg)
{
...
}
...
}
I use a static class that has the context injected into a static constructor for the purposes of loading a cache of data that rarely changes. And it (should) be thread safe. I hope this helps you, it's very handy in my experience:
public static class StaticCache<T> where T: class
{
private static List<T> dbSet;
public static Dictionary<string, List<T>> cache = new Dictionary<string, List<T>>();
private static readonly object Lock = new object();
public static void Load(DbContext db, string connStr, string tableName)
{
lock (Lock)
{
try
{
if (connStr != null)
{
using (db)
{
dbSet = db.Set<T>().ToList();
cache.Add(tableName, dbSet);
}
}
}
catch { }
}
}
}
void Testit()
{
var context = new YourContextSubClass(connStr);
StaticCache<TableEntity>.Load(context, connstr, "tableEntityNameString");
}
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
}
}
}
In a simple mvc 4 app I installed Ninject.MVC3 nuget package.
This is my controller, very basic, ISomeClass is being injected in the constructor by ninject.
public class HomeController : Controller
{
private readonly ISomeClass _someClass;
public HomeController(ISomeClass someclass)
{
_someClass = someclass;
}
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
public PartialViewResult MiniView()
{
return PartialView("miniview", _someClass.GetName());
}
}
This is SomeClass
public class SomeClass : ISomeClass
{
private readonly string _someName;
public SomeClass(string someName)
{
_someName = someName;
}
public string GetName()
{
return _someName;
}
}
In Index.cshtml view I have
#{ Html.RenderAction("MiniView","Home"); }
Now in NinjectWebCommon when I go to register the service I need to know if the request was a child action request or not. Like when I call Html.RenderAction. This is what I am trying but it is not working.
kernel.Bind<ISomeClass>().To<SomeClass>()
.WithConstructorArgument("someName", c => IsChildAction(c) ? "Child" : "Nope");
IsChildAction method - Always returns false.
private static bool IsChildAction(Ninject.Activation.IContext c)
{
var handler = HttpContext.Current.Handler;
/*Cant do this, ChildActionMvcHandler is internal*/
return handler is System.Web.Mvc.Html.ChildActionExtensions.ChildActionMvcHandler;
//OR
//This is how ControllerContext.IsChildAction gets its value in System.Web.Mvc but
//RouteData.DataTokens is empty for me
return ((MvcHandler)handler).RequestContext.RouteData.DataTokens
.ContainsKey("ParentActionViewContext");
}
Any ideas if this can be done?
ps: this is not actual code, just trying something. Is this something I should definately not do? Why?
I ended up checking if the current request has a previous handler. Seems like it is being set only on child actions.
HttpContext.Current.PreviousHandler != null &&
HttpContext.Current.PreviousHandler is MvcHandler;
If the IsChildAction is something only known at runtime and within the controller, I suggest you don't pass an instance of SomeClass. Pass a factory instead and build that instance when you need it using the factory. I think that approach would work best in your case.
For using the factory you can use Ninject.Extensions.Factory or implement one yourself:
public class SomeClassFactory
{
private readonly IKernel _kernel;
public SomeClassFactory(IKernel kernel)
{
_kernel = kernel;
}
public SomeClass Create(string name, bool isChild)
{
var childString = (isChild) ? "Child" : "Nope";
return _kernel.Get<SomeClass>(new ConstructorArgument("someName", childString));
}
}
UPDATE:
After you said a Factory wouldn't work, the only way I could figure out for you to have access to the RequestContext during controller creation would be with a custom controller factory. You won't be able to get it statically in your bindings, I'm afraid.
The code below performs resolution on your SomeClass at runtime depending on whether the RequestContext contains the information about child action. It uses a custom IControllerFactory which certainly could have a better implementation, but it is enough to show how it can be done.
internal class CustomControllerFactory : DefaultControllerFactory
{
internal const string ParentActionViewContextToken = "ParentActionViewContext";
private readonly IResolutionRoot _resolutionRoot;
public CustomControllerFactory(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
//You can improve this later if you want -> you'll need to figure out if your controller will fit into this case
//You can use marker interfaces, common supertype, etc... that's up to you
if (controllerName.Equals("home", StringComparison.InvariantCultureIgnoreCase))
{
var controllerType = typeof (HomeController);
var isChild = requestContext.RouteData.DataTokens.ContainsKey(ParentActionViewContextToken);
var constructorArgument = new ConstructorArgument("someName", (isChild) ? "Child" : "Nope");
var requestForDependency = _resolutionRoot.CreateRequest(typeof(IServiceClient), null, new Parameter[] { constructorArgument }, true, true);
var dependency = _resolutionRoot.Resolve(requestForDependency).SingleOrDefault();
return (IController)_resolutionRoot.Get(controllerType, new ConstructorArgument("service", dependency));
}
//Will go through the default pipeline (IDependencyResolver will be called, not affecting DI of other controllers)
return base.CreateController(requestContext, controllerName);
}
}
Make sure you bind it:
kernel.Bind<IControllerFactory>().To<CustomControllerFactory>();