When adding a controller in ASP.Net MVC 3 using "Controller with Read/Write actions and views, using EntityFramework" as template, it generates a class as follows:
namespace Project.Controllers
{
public class Default1Controller : Controller
{
private ProjectEntities db = new ProjectEntities();
...
}
}
Now, I would like to know if it would be a good practice to change this so that my Controller would inherit a custom base controller that would instantiate ProjectEntities. It would look as follows:
BaseController:
namespace MatchesHorsConcours.Controllers
{
public class BaseController : Controller
{
protected MatchesEntities db = new MatchesEntities();
...
}
}
Other controllers:
namespace Project.Controllers
{
public class Default1Controller : BaseController
{
...
}
}
This technique is useful when you need logic in your master page (for example, to dynamically render menu options). Read about this here: http://www.asp.net/mvc/tutorials/passing-data-to-view-master-pages-cs
However, in general this is not a good technique. I would recommend using dependency injection (Ninject works well with MVC and is easy to implement)
No absolutely not. It makes totally untestable. Please use repository pattern and constructor injection if possible: Repository Pattern vs DAL
Related
I have a solution like this:
MVC Core 2.0 application <-> Business Class library <-> Domain class library
(ViewModel) <- P1 -> (Dto) <-P2-> (Domain entity)
I created Automapper profiles in each MVC and Business projects for mapping ViewModel<->Dto (P1) and Dto<->Domain entity (P2). P1 profile&map is in MVC project, P2 profile&map is in Business library.
I then made a xUnit test project which creates a Dto object and sends it to a Business Service, inside the unit test on init I call:
Business.App.AutoMapperConfiguration.Configure();
And this unit test works exactly as expected.
I then do the same (I even copy/pasted code from Unit test) in the MVC controller and I get an error in mapping Dto to Domain entity:
Unmapped members were found. Review the types and members below...
I configured Automapper maps in startup.cs like this:
services.AddAutoMapper();
If I understand correctly this is supposed to traverse all assemblies for classes inheriting Profile and adding them to configuration.
Example map:
public class StrankaMap : Profile
{
public override string ProfileName => nameof(StrankaMap);
public StrankaMap()
{
CreateMap<SomeDto, SomeDomainEntity>().ReverseMap()
CreateMap<AnotherDto, AnotherDomainEntity>().ReverseMap()
}
}
I don't know what is the cause of this error if my unit test works but not from MVC app - I even copied the code from unit test to MVC controller and ran that. I'm suspecting an error in configuration. Do I assume correctly that inside Startup.cs adding services.AddAutoMapper(); is enough for this to work?
Solution (edit)
Apparently I misunderstood that the service.AddAutoMapper() will traverse all assemblies and search for Profile inherited classes. There might be a better solution but I used the one below, with the help of a hint from the comment #LucianBargaoanu.
I solved it like this:
// Startup.cs
services.AddAutoMapper(
typeof(Business.App.AutoMapperConfiguration),
typeof(MvcApp.Infrastructure.Configuration.AutoMapperConfiguration));
//And the AutoMapperConfiguration class:
namespace MvcApp.Infrastructure.Configuration
{
using AutoMapper;
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<Models.Mapping.StrankaMap>();
});
}
}
}
Apparently I misunderstood that the service.AddAutoMapper() will traverse all assemblies and search for Profile inherited classes. There might be a better solution but I used the one below, with the help of a hint from the comment #LucianBargaoanu.
I solved it like this:
// Startup.cs
services.AddAutoMapper(
typeof(Business.App.AutoMapperConfiguration),
typeof(MvcApp.Infrastructure.Configuration.AutoMapperConfiguration));
//And the AutoMapperConfiguration class:
namespace MvcApp.Infrastructure.Configuration
{
using AutoMapper;
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<Models.Mapping.StrankaMap>();
});
}
}
}
Let's say I have a class called MySiteConfiguration in which I have a bunch of, you guessed it, configuration data. This data will not change over the course of the application's runtime after it has been loaded.
My goal would be to construct an instance of this class at startup and access it from my controller actions. I do not want to construct the class more than once, as this should not be needed.
To do this in WebApi 2 for instance, I would:
Instantiate the class in my application start method.
Store the instance on the HttpConfiguration.Properties
Create a ControllerBase class which inherits from ApiController.
Override the Initialize(HttpControllerContext) method in my ControllerBase class. This override would read the configuration instance from HttpControllerContext.Configuration.Properties and assign it to a property / field in ControllerBase.
Any controller needing access to the configuration instance would inherit ControllerBase and reference the base property. Not so bad...
With that said, this pattern does not work in the new framework from what I can tell. There is no initialize method to override on MVC 6's new Controller class. I'm also not familiar enough with the new Startup.cs patterns and middleware available to know where to start with this problem.
Thanks.
Use dependency injection. Register a singleton service that has your data, and then use constructor injection on your controllers to acquire the service instance.
First, define a service. A service can really be any class or interface.
public class MyConfigService {
// declare some properties/methods/whatever on here
}
In your Startup.cs do something like this:
services.AddSingleton<MyConfigService>();
(Note that there are other overloads of AddSingleton depending on your scenario.)
And then consume it in each controller:
public MyController : Controller {
public MyController(MyConfigService myService) {
// do something with the service (read some data from it, store it in a private field/property, etc.
}
}
How about using the application state to store your configuration data?
protected void Application_Start()
{
Application["MySiteConfiguration"] = new MySiteConfiguration();
}
You can then access your configuration data from inside your controllers.
public ActionResult Index()
{
var config = HttpContext.Application["MySiteConfiguration"] as MySiteConfiguration;
}
Im using Spring mvc 3.1 version and Apache Tiles 2.2.2 version i'd like to define some common modules in my applications pages.
For example i want to define a menu in the top, a left side and right side,.. all my page will display these block.
Im using Tiles to define the differents blocks, some part of tiles implements ViewPreparer because i need to get information from database, know if the user is logged,... each tile is responsable of its own module(get data, set attribute for the jsp...).
Is it a good way to create some modules ? Or should i define a controller who will define the data, the business...to all page modules ? (left side, right side, menu...)
If your common module only consists of HTML then it doesn't matter how you do it. Tiles template is sufficient.
The problem is if the common module need models to be populated on the controller. You don't want to duplicate the code on every single of your controller which view includes the common module.
One approach you can take is subclass your controller with a class that populates common module model, eg:
public class CommonHandler {
#ModelAttribute("loggedInUser")
public UserInfo getLoggedInUser() {
// check and return logged in user if any here..
}
}
#Controller
public class MyController extends CommonHandler (
#RequestMapping(..)
public String myHandler() {
// ...
}
}
In above example if myHandler is requested, getLoggedInUser from CommonHandler class will automatically be called to populate loggedInUser model. In your view you just obtain it using ${loggedInUser}
When using ViewPreparerSupport which implements ViewPreparer, it works very well :
#Component
public class MyPreparer extends ViewPreparerSupport {
#Autowired
private UtilisateurService utilisateurService;
#Override
public void execute(TilesRequestContext tilesContext,
AttributeContext attributeContext) {
//information to set for the jsp tile
}
}
I'm trying to inject a second repository into my asp.net mvc 3 controller. And I cant get it to work, not sure where to "add another" using Ninject.
I have a void function in global.asa.cs
kernel.Bind<INewsRepository>().To<NewsRepository>();
And in my controller I have:
private INewsRepository _newsRepository;
private IContentRepository _contentRepository;
public NewsController(INewsRepository newsRepository, IContentRepository contentRepository)
{
this._newsRepository = newsRepository;
this._contentRepository = contentRepository;
}
How can I register IContentRepository for the NewsController as well?
I use autofac instead of Ninject but the basics stay the same.
If you got your first dependency injection working then you should be able to bind others as well. You just have to add a new binding in Application_Start() in your Global.asax.
So under your first binding do this as well:
kernel.Bind<IContentRepository>().To<ContentRepository>();
You can have as many bindings as you like.
First off it's a good practice to move the bootstrapping of your application into a separate location. This keeps your Global.asax clean.
You should also be using convention based registration. It will end up saving you lots of time for the bindings you don't need to customize.
So for you I'd probably suggest the following
public static class Bootstrapper()
{
public static void Bootstrap()
{
kernel.Scan( k =>
{
k.FromAssemblyContaining<INewsRepository>();
k.BindWithDefaultConventions();
});
}
}
And in your Global.asax you add this..
Bootstrapper.Bootstrap();
Then I would suggest you spend some time on Google reading about ninject conventions.
I have the following code:
public abstract class BaseController : Controller
{
public IUserService UserService { get; set; }
}
All my controllers inherit from this base controller. I started out by configuring it in Ninject using the following code:
kernel.Bind<BaseController>()
.ToSelf()
.WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));
This did not work. I assume it is because of the fact that the BaseController is an abstract class (please confirm my assumption). So I moved on to modify the configuration to:
kernel.Bind<HomeController>()
.ToSelf()
.WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));
This does work. The minor downside is that I now have to configure every controller the same way.
Since I also have DependencyResolver setup in my ASP.NET MVC 3 project I could also remove the above Ninject configuration and modify my base controller to look like:
public IUserService UserService
{
get
{
return DependencyResolver.Current.GetService<IUserService>();
}
}
Is there any benefit to using the fluent configuration as opposed to using the DependencyResolver approach? Is one better than the other? Which approach would be considered a better practice?
It is worth mentioning that I did not want to do constructor injection in my base controller.
A better practice in MVC it is to use constructor injection over property injection. Why did you make your choice like this ?
Using Constructor Injection you states that all dependencies in constructor are necessary for the class to do its job.
Property injection means that the dependencies are optional or that there are the local defaults implementations, so all will work even if you don't provide necessary implementations yourself.
You should really know what you're doing using Property injection or you have no other choice, so the safer approach is to rely on constructor injection.
Now I'll give you my point of view. Other may have other opinions.
DependencyResolver was introduced in MVC 3 for "convenient" service location but for me it's a regular Service locator which for me is also an anti-pattern http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. I don't use it because I don't like it and there is no benefit in using it.
I prefer to user my controller factory like before and pass the dependencies through constructor.
More the IDependencyResolver has somme issues with some IoC containers (I don't know if it's the case with Ninject). You can read more here : http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html
If you need the same dependency in each controller then there seems to be something wrong in your design. Most likely you are handling some kind of cross cutting concern in your base controller. In this case Doing property injection is just treating sympthoms instead of cureing the disease. This should rather be handled by an aspect (e.g. a filter or an interceptor) so that you do not have to pollute your controller with something that does not belong there.
There are many ways to skin the cat they say. You could use conventions-based bindings with .WithPropertyValue() or with .OnActivaction() (as described here).
public class ControllerModule : NinjectModule
{
public override void Load()
{
// Get all controller types derived from the base controller.
IEnumerable<Type> controllerTypes = // ...
foreach (var controllerType in controllerTypes)
{
Bind(controllerType).ToSelf().InRequestScope()
.WithPropertyValue(...);
}
}
}
You could create your own custom implementation of the IInjectionHeuristic interface as described here or your own custom implementation of the IControllerActivator interface.
public class CustomNinjectControllerActivator : IControllerActivator
{
private readonly IKernel kernel;
public CustomNinjectControllerActivator(IKernel kernel)
{
this.kernel = kernel;
}
public IController Create(RequestContext context, Type controllerType)
{
var baseController = kernel.TryGet(controllerType) as BaseController;
if (baseController == null)
{
return null;
}
baseController.UserService = kernel.Get<IUserService>();
return baseController;
}
}
Heck, you could even use the service locator pattern if you are comfortable using it.
public IUserService UserService
{
get { return DependencyResolver.Current.GetService<IUserService>(); }
}
You should choose whichever solution is easiest to implement, test and maintain, and of course provides the desired behavior.