In an MVC3 application, I need to construct a domain object from values contained in the incoming Http Request. The logic is sufficiently complex that I have created a factory class with the responsibility of creating my domain object.
My question is whether to pass into this factory class the value of the Controller's Request property, or should I reference the value of the static HttpContext.Request property from inside the factory class?
My intention is to unit test both the controller and the factory class so I will have perform the necessary overhead of setting up the HttpContext somewhere. I just wondered if there are any general rules to stick to?
Simply pass a NameValueCollection to your factory class:
public SomeDomainObject ConstructDomainObject(NameValueCollection data)
{
...
}
and then in your controller simply:
var domainModel = factory.ConstructDomainObject(Request.Params);
Now you can unit test the ConstructDomainObject method as much as you like.
If you want to test your controller in isolation then make have this factory object implement an interface:
public interface IMyFactory
{
SomeDomainObject ConstructDomainObject(NameValueCollection data);
}
that your controller will work with:
public class SomeController: Controller
{
private readonly IMyFactory factory;
public SomeController(IMyFactory factory)
{
this.factory = factory;
}
public ActionResult SomeAction()
{
var domainModel = this.factory.ConstructDomainObject(Request.Params);
...
}
}
All this being said, have you considered writing a custom model binder? In ASP.NET MVC the responsibility of the model binder is exactly that: instantiate some model from the request. This way you don't need to be reinventing some wheels but you will be using what's natively built into the framework for this purpose.
Related
I know how to inject into controller actions and the controller directly, by adding the service to the IServiceprovider and then the framework just handles it for me and in the case of controller actions I could add [Microsoft.AspNetCore.Mvc.FromServices] and it would inject the service to the specific action.
But that requires my controller to know specifically what the underlying parameter would need, which is a coupling I find unnecessary and potentially harmful.
I would like to know if it is possible to have something close to the following:
[HttpPost]
public async Task<ActionResult> PostThings([FromBody]ParameterClassWithInjection parameter) {
parameter.DoStuff();
...}
public class ParameterClassWithInjection{
public readonly MyService _myService;
public ParameterClassWithInjection(IMyService service){ _myService = service;}
public void DoStuff(){ _myService.DoStuff(); }
}
I have only found something about a custom model binder in the docs.
https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1#custom-model-binder-sample
This shows how you can create a custom binder and have a custom provider supply the injection.
It just seems I need to implement a lot of boilerplate code from the automatic binding (which works absolutely fine for me in every case) in order to get some dependency injection.
I would hope you could point me in a better direction or put my quest to a rest if this is the only option.
I later chose to do the following.
[HttpPost]
public async Task<ActionResult> PostThings([FromBody]ParameterClassWithInjection parameter, [FromServices] MyService) {
await MyService.DoStuff(parameter);
...}
Where the service is injected into the api action.
I then opted for having very small services, one per request to keep it very split up.
If these services then needed some shared code, let's say from a repository then I simply injected that into these smaller services.
Upsides includes; it is very easy to mock and test in unit tests, and keeps changes simple without affecting other actions because it is very explicitly stated that this "service"/request is only used once.
Downside is that you have to create a lot of classes.
With nice folder structuring you can mitigate some of the overview burden.
- MyControllerFolder
-Controller
-Requests
- MyFirstRequsetFolder
- Parameter.cs
- RequestService.cs
```
Shotcut
If the content type is JSON and you are using Newtonsoft.Json, you could deserialize your model with dependency injection using a custom contract resolver.
Model binding
Otherwise, if you need to support other content types etc, you need to go a complex way.
For specific model, or models only FromBody:
Use a model binder and do property injection. See my answer couple weeks ago.
For generic model or models from other sources:
You need a custom model binder provider. In the model binder provider, you could iterate through existing model binder providers, find the model binder for the current model binding context, then decorate it with your own model binder decorator which can do DI for models.
For example:
public class DependencyInjectionModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
// Get MVC options.
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>();
// Find model binder provider for the current context.
IModelBinder binder = null;
foreach (var modelBinderProvider in mvcOptions.Value.ModelBinderProviders)
{
if (modelBinderProvider == this)
{
continue;
}
binder = modelBinderProvider.GetBinder(context);
if (binder != null)
{
break;
}
}
return binder == null
? null
: new DependencyInjectionModelBinder(binder);
}
}
// Model binder decorator.
public class DependencyInjectionModelBinder : IModelBinder
{
private readonly IModelBinder _innerBinder;
public DependencyInjectionModelBinder(IModelBinder innerBinder)
{
_innerBinder = innerBinder;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
await _innerBinder.BindModelAsync(bindingContext);
if (bindingContext.Result.IsModelSet)
{
var serviceProvider = bindingContext.HttpContext.RequestServices;
// Do DI stuff.
}
}
}
// Register your model binder provider
services.AddControllers(opt =>
{
opt.ModelBinderProviders.Insert(
0, new DependencyInjectionModelBinderProvider());
});
This works for property injection.
For constructor injection, because creation of model still happens in the inner model binder, you definitely need more code than this example, and I haven't tried to get constructor injection working in this case.
So I have created the simplest of the applications using ASP.NET MVC (in .NET Framework) and I want to demo dependency injection to a junior using this. it is very simple code, even a newbie can understand it.
public interface IMovieRepository
{
MyViewModel GetDetails(string movie);
}
public class MoviesController : Controller
{
[HttpPost]
public async Task<ActionResult> Search(string movie)
{
// Confusion here! Is the below line a good place to inject dependency
IMovieRepository repository = new DBMovieRepository(); // <-- it can be DBMovieRepository or WebServiceMovieRepository or MockMovieRepository
MovieFinder finder = new MovieFinder(repository);
MyViewModel model = await finder.Find(movie);
return View(model);
}
}
public class MovieFinder
{
private IMovieRepository _repository;
public MovieFinder(IMovieRepository repository)
{
_repository = repository;
}
public async Task<MyViewModel> Find(string movie)
{
// Connect to database and return a detailed object
var myViewModelObj = _repository.GetDetails(movie);
return myViewModelObj;
}
}
public class DBMovieRepository : IMovieRepository
{
public MyViewModel GetDetails()
{
// Code for fetching data from a database
}
}
public class WebServiceMovieRepository : IMovieRepository
{
public MyViewModel GetDetails()
{
// Code for fetching data from a IMDB webservice
}
}
public class MockMovieRepository : IMovieRepository
{
public MyViewModel GetDetails()
{
// Code for returning a mock object here
}
}
There is an inline comment in the code where I asked that my confusion is here. Is that a good place to inject dependencies or do I have to inject it in the MoviesController constructor. If yes, then how will I pass it to the constructor? This is a .NET Framework 4.5 application and I don't want to complicate the lesson by introducing a DI Container and just want to use Pure DI to clarify the concept to my junior.
This is a .NET Framework 4.5 application and I don't want to complicate the lesson by introducing a DI Container and just want to use Pure DI to clarify the concept to my junior.
That literally doesn't make sense.
Pure DI
Or Dependency Injection simply means using IOC to provide an Instance of a Dependency to the object (via Constructor or Property).
Inversion of Control simply means that instead of the dependent object creating the Dependency, you invert control to something else to provide the instance.
You can Architect your Controller to use IOC. You can't DI without something providing the instance. The most lightweight/semi-hacky way to write your DI with minimum effort using your stack is to write your own Controller Factory to inspect your constructor for its dependencies and inject whatever those dependencies are (or just assume what it needs, pass it... yikes).
Relevant SO Question of Mine: My MVC Custom ControllerFactory works but could it be better?
There is a question I always ask myself when I'm using a Factory pattern inside my code (C#, but it applies to any language I suppose).
I have a "Service" that takes care of interacting with my database, do stuff with objects and interacts with my object model.
This Service uses a Factory sometimes to delegate the instanciation of an object.
But this factory obviously needs to interact by itself with the database to instanciate my object properly.
Is it a good/bad practice to pass the Database context to the Create method for example?
Like this :
var myNewObject = MyFactory.Create(myDatabaseContext);
the other way would be to let the Service always be the only one to talk with the database.
var myNewObject = MyFactory.Create();
var extraProperty = myDatabaseContext.Get(something);
myNewObject.extraProp = extraProperty;
Any advices?
The idea of passing the database context into the factory create method is called method injection. This is a form of dependency injection, so you are on the right track.
You can use dependency injection to manage your database context inside of your factory via the constructor. The factory could look something like this:
public class MyFactory
{
private readonly IMyDbContext dbContext;
public MyFactory(IMyDbContext dbContext)
{
this.dbContext = dbContext;
}
public object Create()
{
// Use the dbContext, etc
}
}
Constructor injection is usually favored because it leaves method signatures less cluttered. We will also most likely have one type of database context so there will be no need to take advantage of polymorphism based on some other runtime information.
You can choose to use a Dependency Injection Container like Ninject or, my favorite, SimpleInjector to manage the dependencies for you.
It is OK to have the DbContext only used by the factory. One thing you may want to watch out for is that a user of your factory may not realize that the factory is calling to the database. This could be a bad thing and have negative performance implications. Typically, construction information is passed into the factory method, not initialized into the factory method from the DB. You could even take it a step further and use the Repository Pattern to abstract away some more of the data access logic if you think it is necessary and you don't have that already.
To learn more about Dependency Injection, in case you are unfamiliar, you can start here.
My ideal structure may look like this:
public class MyFactory : IFactory
{
public object Create(object someProperty)
{
// build object
}
}
public class MyService
{
private readonly IMyDbContext dbContext;
private readonly IFactory factory;
public MyService(IMyDbContext dbContext, IFactory factory)
{
this.dbContext = dbContext;
this.factory = factory;
}
public void DoWork()
{
var property = dbContext.Get(something);
var newObj = factory.Create(property);
// Use stuff
}
}
In the project I am working on, we try to keep all database access inside the Service. If the Factory needs objects that must be loaded from the DB, the Service should load them and pass them to the Factory. If the object returned by the Factory shall be persisted, the Service should add it to the DbContext.
This corresponds to the second way you have shown. The advantage is that the Factory can be unit tested without any need to mock the DbContext.
If you want to keep the DB access inside the Factory anyways, I would inject the DbContext into the constructor of the Factory, instead of passing it to the Create() method.
The Service gets an instance of the Factory injected in turn (instead of accessing static methods of the Factory). Again, this will make mocking much easier.
public class Service {
private readonly IMyDbContext _myDatabaseContext;
private readonly IMyFactory _myfactory;
public Service (IMyDbContext myDbContext, IMyFactory myfactory) {
_myDatabaseContext = myDbContext;
_myfactory = myfactory
}
public void Create() {
var extraProperty = myDatabaseContext.Get(something);
var myNewObject = _myFactory.Create(extraProperty);
_myDatabaseContext.Add(myNewObject);
_myDatabaseContext.SaveChanges();
}
}
Below is the piece of the code of my action :-
public ActionResult Edit(int id)
{
ProductViewModel viewmodel = GetProduct(id);
if (viewmodel != null)
{
....................
}
}
In above code the if condition is based on the viewmodel.Which is returning from the GetProduct() method.Where GetProduct() method is the private method of the controller.
And i want to mock the ProductViewModel in my unit test method with MOQ.Can anyone suggest me what is the best way to do that ?
Ideally your viewModel should only have public properties that your view will be bound to. So there should not be a scenario where you would need to mock the viewModel class.
If it is possible to, mock the GetProduct method to return an instance of ProductViewModel where the public properties have already been set. That way your viewModel will return exactly the values you want it to return for your test case.
Usually using the MVVM pattern will look like :
public class MainViewModel : MyViewModelBase
{
private readonly IDataService _dataService;
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
// ...
}
//..
}
And you'll have a locator that looks like:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
}
// Here you'll register your view models
SimpleIoc.Default.Register<MainViewModel>();
}
//..
}
So, mocking this is fairly easy, just use the DI to pass in whatever you want to pass, and hook your methods either to static data (usually done to have nice output in design mode), or dummy methods that will return whatever it is you need.
The correct approach is to test indirectly the GetProduct method. Based on the name you are getting info from some kind of storage and you can mock that storage and return an object which is mapped by GetProduct in the ViewModel you want. You shouldn't mock method of the same class you are testing.
Your controller is very strongly coupled with the business logic, in this case the GetProduct method. I would suggest to restructure your code to have an interface for your "Product" specific business logic. The product controller should depend on an abstraction i.e. the interface and not anything that is concrete.
Use any dependency injection framework like sring.net, MS unity etc to inject concrete implementations (dependencies) into your controller.
Now use MOQ to mock the business logic so that controller can be tested in isolation.
Lastly, this is just another wonderful example demonstrating how if it becomes difficult to unit test a particular code component, it more than often points towards a design flaw than a unit testing/mocking framework incapability.
I want to use EF 5 model validation to avoid duplicate values in the database, so I'm using a model class like this:
[Table("MeasureUnits")]
public class MeasureUnit : IValidatableObject
{
public int MeasureUnitId { get; set; }
public string Symbol { get; set; }
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
using (MeasureUnitRepository rep = new MeasureUnitRepository())
{
MeasureUnit measureUnit = rep.FindDuplicateBySymbol(this);
if (measureUnit != null)
yield return new ValidationResult(
"There is another unit with this symbol, you can't duplicate it",
new[] { "Symbol" });
}
}
The repository class creates the DbContext, implements IDisposable, has the logic to find the duplicate and it all works just as intended.
However, using the debugger I realized the validation is performed twice for every insert or update, so the repository (and DbContext) gets instantiated and disposed twice also.
Besides that, there is another DbContext living in the controller but just don't find the way to use it inside the model class, other than including the DbContext in the model's constructor, but I feel it's not the right solution.
Is there a better o "right" way to achieve this validation?
Thanks in advance.
When you have to go to the database then you need to use DbContext and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
Also, instantiating a context inside your repository is likely to cause you grief. The repositories will need to share a context. You could treat the context as your unit of work and pass it into the repository in the constructor, or you could wrap the context in your own unit of work and pass that in.
You can use any IOC container available out there like Unity, Ninject, Autofac or StructureMap to inject your repository as a dependency.
This way you would be able to access the same object in the controller, your Validate method or wherever you need to use it.
Some of these IOC(Ninject for sure - look for 'request scope') containers are capable of integrating with ASP.NET MVC so that the dependency(your repository in that case) is created once per request and disposed when the request ends.
Example using Ninject:
You create a globally accessible(the design is up to you) ninject kernel
public static class NinjectKernel
{
public static IKernel Kernel = new StandardKernel();
static NinjectKernel()
{
Kernel.Bind<IMyRepository>().To<MyRepositoryImpl>().InRequestScope();
}
}
and a controller factory for MVC controllers
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null ? null : (IController)NinjectKernel.Kernel.Get(controllerType);
}
}
You can then set your controller factory in Global.asax like this
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
and get the repository in your Validate method in a similar way it's done in the Controller factory.