I'm trying to use the Model-View-Controller-Pattern in my new project, a Windows Forms C# Application.
I have my project split into several sub-projects:
Core
UI (View)
Controller
Model
Services
Helper
Tests
The project dependecies are as follows:
My UI-Project contains 2 Forms, ListForm and AddForm (there are other forms, but these are not relevant for this question).
In the Controller-Project, I have interfaces for the different forms, which the Controller uses for updating the View.
In the Core-Project, I initialize a new ListForm, Controller and Model.
Now, if the User clicks the Add-Button inside the ListForm, I want the AddForm to Show.
But how can I create a new instance of AddForm inside the Controller if the Controller doesn't even know the UI-Project?
I tried to use a Service, but since the Service had to know the UI-Project to create instances, I would have had a circular dependency (according to Visual Studio).
How can I show the AddForm if the Users clicks the Add-Button inside the ListForm?
(There is always max. 1 AddForm shown at a Time).
One of possible approaches involves a controller factory. The factory is responsible for creating controllers and views and wiring both together.
The factory should be configurable so you could have different implementations for differnt set of views - a set of views that is used to build an actual ui has its own factory, another test set has another factory etc. All factories are accessed through the same api so that you only reconfigure the factory when necessary. One of the possible ways to implement such factory would be to use an IoC container, it could simplify the implementation but it is not necessary. With the IoC container you would just register different implementations of your views and could reuse the same implementation of the factory whereas without the IoC container you would need an extra implementation of the factory for each set of views.
Then your parent controller creates an instance of the child controller using the factory. The factory returns the child controller with the proper view injected into it. The parent controller calls the ShowView on the child controller which just makes the view visible or the child controller could even show the view automatically upon creation.
Edit: the example factory that creates controllers/views:
In the controller layer:
public interface IControllerFactory
{
TController CreateControllerAndView<TController>()
where TController : Controller;
}
public class ControllerFactory
{
// actual provider
private static IControllerFactory _provider;
// factory method
public static TController
CreateControllerAndView<TController>() where T : Controller
{
return _provider.CreateController<TController>();
}
public static void SetProvider( IControllerFactory provider )
{
_provider = provider;
}
}
Anytime you want to create a new controller, you refer to the factory:
var controller = ControllerFactory.CreateControllerAndView<UserController>();
Note that the factory doesn't depend on anything, it is merely defined, not yet implemented.
Then, somewhere in the most upper layer, in the startup project probably, you implement a concrete provider:
public class ConcreteControllerFactory : IControllerFactory
{
public TController CreateControllerAndView<TController>()
{
// since you are in the top most layer, you know all types from
// underlaying layers, including controllers and views
// IoC would help here a lot! But without it:
if ( typeof<TController> == typeof<UserController> )
{
IUserView view = new UIUserView();
UserController c = new UserController( view );
}
...
}
}
and then somewhere
ControllerFactory.SetProvider( new ConcreteControllerFactory() );
This way you can plug any specific provider to the factory, the test provider, the ui provider, whatever. The actual implementation could vary but you should get the idea.
Related
I create the web app include Home Page and Admin Page. I create a _sliderRepository.AllSliders to return of list of sliders in a database. How I reuse the repository code for 2 controllers
public class HomeController : Controller
{
private readonly ISliderRepository _sliderRepository;
public HomeController( ISliderRepository sliderRepository)
{
_sliderRepository = sliderRepository;
}
public IActionResult Index()
{
return View(_sliderRepository.AllSliders);
}
}
public class AdminController : Controller
{
private readonly ISliderRepository _sliderRepository;
public AdminController( ISliderRepository sliderRepository)
{
_sliderRepository = sliderRepository;
}
public IActionResult Slider()
{
return View( _sliderRepository.AllSliders);
}
}
Several options:
Use inheritance
Create a base controller class that inherits the Controller class and add there methods like CreateViewFrom. The main disadvantage here is if you use some service that needs to be injected in the base controller, then all inheriting controller would have to provide the service.
Use extension methods
Just create static class and define there extensions methods that again will create the responses you need. The main disadvantage here is you don't have access to functionality that exists in the Controller class.
Do nothing
You can do nothing, the cost is zero, just copy and paste code across controllers. The disadvantage is over time the maintenance cost increases. You need to find the best time when to decide to attack code duplication. In my experience do it as soon as possible.
General advice
Keep your controllers very light, they should not be services. In your particular example I can predict at some point you would want to save a slider in the database and the slider images in storage. Don't do this orchestration in the Controller classes. Extract an ISildersService abstraction and do the orchestration there. Keep 'em light.
In ASP.NET Core MVC all classes that implement Controller will be automatically resolved and added to the MVC pipeline. These controllers can also be injected into the DI container using services.AddMvc().AddControllersAsServices();
I also have a controller that also implements a specific interface, which I can also add to the DI container: services.AddSingleton<IMyInterface, MyImpl>();
public class MyImpl : Controller, IMyInterface { }
However, becase this controller also implements Controller it has already been added in AddControllersAsServices() so adding it to the DI container one more time causes there to be two instances of this class.
The reason for this design is that I will have multiple implementations of IMyInterface and later need to decide which one to use, but each implementation will also need to be a controller in order to provide certain API endpoints (each controller will provide different endpoints, so there will be no conflicts there).
How can I ensure that only one instance of my class is instantiated, and how can I then get all implementations of IMyInterface?
As much as Im concerned Controller class is instantiated on each request, so even if you specify something like this (Ninject style):
services.Bind<IMyInterface, MyController>().To<MyController>().InSingletonScope();
It will be very bad. I mean, Controller is statefull, and you just mix everything up and breaking it's internal context.
What you might do is decorate through controller, instead of managing its lifetime yourself:
public class MyImpl : IMyInterface
{
}
public class MyController : Controller
{
private readonly IMyInterface _inner; //delegate implementation to this one.
public MyController(IMyInterface inner)
{
_inner = inner;
}
}
And injection:
services.Bind<IMyInterface>().To<MyImpl>().InSingletonScope();//this is your logic.
sercices.Bind<MyController>().ToSomethingWhatever();//this line is managed by ASP .NET, mentioned this only to show the idea
You might need remove the MyImpl inheriting from Controller class. Also you need to consider MyImpl as sevice rather than Controller.
Another option is that this can be achieved with IoC container like Autofac or Ninject or Castle Windsor. When using with Autofac it will be something like the below
Add the Autofac, Autofac ASP.Net MVC4 Integration using NuGet Package
Open GLobal.asax.cs
Make following changes in the Application_Start().
3a. Comment out the below code as
//WebApiConfig.Register(GlobalConfiguration.Configuration);
3b. Create a new method RegisterAutofac(), call this as the first method call inside Application_Start()
3c. Below with the sample implementation for RegisterAutofac() method
private void RegisterAutofac()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterSource(new ViewRegistrationSource());
// The object to be injected in constructor etc.
builder.RegisterType<MyImpl>().As<IMyInterface>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.
I've been using a trick for a while to help with maintaining an audit trail. In or before the controller, I create a User which is bound in some way to the request. I can use DI to create most of my application as singletons and I can just inject a Func<User> wherever I think I need User information. I get the per-request User from the Func and can easily add audit information to everything.
This keeps my domain classes User agnostic and lets my DI container act as a User management system.
Now I'm using asp.net 5 and I'm having trouble doing the same thing. Honestly I've never been sure I should be able to do this, but I've gotten used to it.
I'm trying to do something like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<IUser, User>();
services.AddSingleton<IDependantOnUser, DependantOnUser>
services.AddScoped<Func<IUser>(c => c.GetRequiredService<IUser>);
}
Then in or before my controller I create and populate the user instance.
public class ValuesController : Controller
{
public ValuesController(Func<User> userFunc)
{
user = userFunc();
// hydrate user instance as needed
}
}
Then finally, I should have access to the user instance in my singleton object.
public class DependantOnUser : IDependantOnUser
{
public DependantOnUser(Func<User> userFunc)
{
user = userFunc();
// I want this to be the same instance as that generated by the controller
}
}
But I can't get this to work. Before asp.net 5, I've been using Autofac to achieve this, but haven't had any luck there. I've tried playing around with transient/scoped/singleton a bit with no luck. I've even tried resolving my own IServiceProvider and using it directly instead of just generating a user with c => c.GetRequiredService<IUser>
Everything I do seems to be working with the wrong IServiceProvider instance. Is there a way resolve an instance from a different ServiceProvider? Any other suggestions would also be helpful.
Before you suggest I just register everything using AddScoped(), some of the objects between my presentation and persistence layers work a lot better as singletons.
Also I would prefer not to just pass User information as a parameter to every method in my domain (we record it with nearly every CRUD operation and pass it with most external calls we make)
I believe that it is antipattern to inject scope depedency to singleton one, please refer to Captive Dependencies
Autofac Captive Dependencies
I am using Simple Injector with a ASP.NET MVC project. I added the SimpleInjector.Integration.Web.Mvc nuget package. This adds SimpleInjectorInitializer class in App_Start folder and initializes the DI. The code looks something like
public static void Initialize()
{
// Did you know the container can diagnose your configuration?
// Go to: https://simpleinjector.org/diagnostics
var container = new Container();
//Container configuration code
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
This configures the DI for the MVC controller correctly.
My question is, if I want to get the instance of the container in any of the controller\class to resolve some dependency manually how can I do it.
I have earlier worked on AutoFac and it has a dependency interface IComponentContext which can be injected into any class that needs to do any resolution manually.
Update:
Here is a scenario. My controller uses a service who initialization depends upon the input parameter passed in the controller method and hence the dependency cannot be instantiated during construction time.
I understand that this is somewhat an anti pattern for DI, but it is requirement at few places and hence injecting the DI container is next best thing. Simple Injector samples should use of static variable to share the container which i want to avoid and also it is not possible by the way SimpleInjectorInitializer works.
Except for any code that is part of the startup path of the application, no code should depend directly on the container (or a container abstraction, container facade, etc). This pattern is called Service Locator and Mark Seemann has a good explanation why this is a bad idea.
So components (such as Controllers) should not depend on the container directly, since this hides the used dependencies and makes classes harder to test. Furthermore your code starts to depend on an external framework (making it harder to change) or depending on an abstraction it doesn't need to know about.
My controller uses a service who initialization depends upon the input
parameter passed in the controller method and hence the dependency
cannot be instantiated during construction time
There's a general pattern for this problem: the abstract factory design pattern. The factory pattern allows you to delay the creation of types and allows you to pass in extra runtime parameters for the construction of a certain type. When you do this, your controller doesn't have to depend on Container and it prevents you from having to pass in a constructed container in your unit tests (DI frameworks should in general not be used in your unit test projects).
Do note however that letting your components require runtime data during creation is a code smell. Prevent doing that.
You might think that by doing this we are just moving the problem to the factory implementation. Although we are moving the dependency on the container into the factory implementation, we are in fact solving the problem because the factory implementation will be part of the application's Composition Root, which allows the application code itself oblivious to any DI framework.
So this is how I advice you to structure your code:
// Definition of the factory in the UI or BL layer
public interface ISomeServiceFactory
{
ISomeService Create(int inputParameter);
}
// Controller depending on that factory:
public class MyController : Controller
{
private readonly ISomeServiceFactory factory;
public MyController(ISomeServiceFactory factory)
{
this.factory = factory;
}
public ActionResult Index(int value)
{
// here we use that factory
var service = this.factory.Create(value);
}
}
In your composition root (the start up path) we define the factory implementation and the registration for it:
private class SomeServiceFactory : ISomeServiceFactory
{
private readonly Container container;
// Here we depend on Container, which is fine, since
// we're inside the composition root. The rest of the
// application knows nothing about a DI framework.
public SomeServiceFactory(Container container)
{
this.container = container;
}
public ISomeService Create(int inputParameter)
{
// Do what ever we need to do here. For instance:
if (inputParameter == 0)
return this.container.GetInstance<Service1>();
else
return this.container.GetInstance<Service2>();
}
}
public static void Initialize()
{
var container = new Container();
container.RegisterSingle<ISomeServiceFactory, SomeServiceFactory>();
}
Upon creation, the Container registers itself (using the call RegisterSingle<Container>(this)) so you can always inject the container into any component. That's similar to injecting the IComponentContext when working with Autofac. But the same holds for Autofac, Simple Injector, and any other container: you don't want to inject your container into components that are located outside the composition root (and there hardly ever is a reason for it).