Should I inject services into my MVC views? - c#

We're working on some kind of Cloud CMS using ASP.NET MVC technology, and have found some obstacles on the way. There is a number of parameters user could change thru the control panel that we need to end up in Views. For example, Facebook application id to initialize the Facebook JS API. Or additional text to be shown on the page. Or background picture. For now we're not using DI to transfer this parameters, instead we're adding them to the ViewModel, but this ruin the ASP.NET MVC way of working with models (e.g. form validation, bindings etc.)
It looks like that using DI to inject services for providing parameters, texts and pictures could make my views less dependent on controllers specific, and there is even some Microsoft technique to do it http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-dependency-injection#Exercise2. However, there are a lot of answers on forums against injecting services into Views using DI.
So the question: what is a right way to inject some services into Views? Or I shouldn't do it at all and something is wrong in the application design?
UPDATE: some real code examples (now we're using Model to inject the services)
Injecting texts from database (they have to be user-editable, as it is CMS):
<div class="steps">#Html.Raw(Model.Texts["Main", "Step2"]</div>
Injecting translations from database (actually, it is localization):
<div class="gonfalon">#Model.Translations["Title_Winners"]</div>
Injecting parameters (from database, could be request-specific; for example, if the site has different domains, facebook application should be per-domain):
Facebook.Initialize(Model.Parameters["FbApplicationId"], Model.Parameters["FbApplicationSecret"]);
The problem of current approach is that this code has taken from contest mechanic. It is definitely out of contest business scope to deal with custom texts, translations or facebook application Id. Also it ruins the Model as model models not actual business domain but deals with a lot of things actually belongs to View (like translations and custom texts)
UPDATE 2: Have modified the snippet from the answer below to be a bit more generic:
public static class WebViewPageExtensions
{
public static I ResolveService<I>(this WebViewPage page)
{
return DependencyResolver.Current.GetService<I>();
}
}

No, you shouldn't inject services into Views, but...
For scenarios such as theming where you want to give the theme developer more power, just one model isn't enough. If your model contains the current post for example, how can a theme designer asks for a list of categories for the sidebar? Or for a widget?
In asp.net mvc you can use extension methods to offer that functionality.THe extension method will use the dependency resolver to get the service. This way, you can have the needed functionality in the view without actually injecting a service.
Note that calling the business layer to update the model is still a violation of Separation of Concerns. THe services made available to the view should contain only read model or general utility functionality.
An example
public static IMyViewServices MyServices(this WebViewPage view)
{
return DependencyResolver.Current.GetService<IMyViewServices>();
}
IMyViewServices lifetime configured in the DI Container should be per http (scope) request

No, end of story. Why? Here is why:
Your view only needs to know what the view model it's going to be working with to present that model. There are couple of reasons for this but the biggest one is the separation of concerns. Keep your view as stupid as possible. You will see that this seperation will give you a clean application structure throughout the way.
There is a number of parameters user could change through the control panel that we need to end up in Views.
I'm not sure what you exactly mean here but this is why there are view models. Your business layer will shape models up, your controller will simply map them to your view models and pass them into the view (presentation layer).

This really depends on how much or little you want your controllers to do and to what degree of separation you want to achieve.
In my world, the "controller" in an MVC app does as little as possible because I have a service layer handling all of the business logic and a data layer above that handling all of the database interaction.
On a GET, the controller will simply call a service method that will build the view model and hands it back to the controller and the controller passes it on to the view. On POST, the view posts data to the controller which sends it off to the service layer for validation, saving to DB, etc. The service is injected into the controller's constructor.
I'd be more than happy to post code examples if you'd like to see them.

Related

Interface between Controller and Service Layer

I am a newbie to .Net MVC and my question today is regarding the MVC pattern.
In our application we have a Service Layer which talks with the DB.
The Controller is Currently talking with the Service layer to get the values from the DB.
Our new Manager requires this service layer interaction from the Models and not from the Controller.
He does say that this architecture is to achieve a thin Controller. We are now starting to port the service layer interaction from controller to models.
And here comes my question. Apart from having a thin Controller, is there any other benefits from enforcing this pattern.
I would like to know the advantages and disadvantages of both pattern.
Some links would also be helpful
Why you shouldn't call services from your ViewModels:
ViewModels are supposed to be classes that contain some data that is interchanged between the View and the Controller. They should not perform any action or retrieve further data. They are dumb models, they don't do anything expect transport data.
What is a View Model
If you are having trouble understanding what a View Model is and what it isn't, think of it like a subset of your model. It only contains data that you need to display on a given view at a given time.
There are 3 types of Models - View Model, Domain Model and Data Model. Check here.
If you are talking about View Models then its a bad idea. There are ways to achieve a thin controller, but ViewModel never should interect with services. If its possible a Controller Action should only invoke a service and throw the result to View. Like this:
[HttpGet]
public ActionResult GetAnimals(int id)
{
var viewModel = new AnimalsService(id).GetViewModel();
return View(viewModel);
}
But in reality many times you can't do that for some obvious reasons. There are few things you can do though. Like don't validate models in controller, you can do that in service layer. Don't hesitate to create more services for different jobs, like pagination, context related logic or some third party api invocation. Create helper or utility classes for repititive codes. Also I think its ok to write fat services.

How can I refactor my database access code outside my MVC project but keep my viewmodels inside?

I have an asp.net-mvc website with the following folders:
Controllers
Scripts
Views
ViewModels
Models
DomainModel
I now want to access a lot of this business logic and database access code and data in another .net app (a windows console app so not web at all) so i am refactoring to remove as much stuff as possible outside of the MVC project and into other projects in the solution so that code could be shared with this other solutions.
I have 2 main issues;
My main issue is that I am struggling to find a place to put the code that generates the ViewModel because a lot of this code I would like to reuse in my console app as the console app sends email which requires the same data that is in the view.
Another main issue is that i am struggling to see how i can move my database access code out of the MVC project while still having the ViewModels inside when many of my functions that instantiate my viewmodels start with a bunch of database access code.
Here is a bit of the detail and my process so far:
Step 1 - Move DomainModel into another project - success
So moving the DomainModel project was simple (as that was a lot of raw objects with some business logic on top - nothing web about it).
Step 2 - Thin out controllers - success
I have thinned out as much of my controllers as possible and moved any business logic or complicated data access logic into the Models folder. When i tried to move the models folder outside the MVC project a few things broke:
Step 3 - Attempt to move Models folder outside MVC Project - struggle
In thinning out the controllers, I have a number of different controller actions that go to a model class and return my ViewModel that i pass back into the view. Something like this (in my controller class):
public ActionResult ApplicationDetail(int id)
{
AppDetailViewModel applicationViewModel = Model.GenerateAppDetailViewModel(id);
return View(applicationViewModel);
}
So files in my Model folder are dependency on the ViewModel classes. I do want to centralize the GenerateAppDetailViewModel() function as that is used in multiple different controllers. Also, in my console app (which sends out email, i often want to get all the data that happens to be on some view so my code "wants" to leverage the viewmodel as well .. if i move it out of the MVC project then I can reuse but i think have the dependency issue (clearly i don't need SelectListItem in my console app but in other cases where they are just container objects of different data needed to generate a view I do want to reuse)
or another thing that broke was the dependency on:
System.Web.Mvc
because I have a lot of code that:
queries a table in a database
Converts that into a collection of objects (i am using nhibernate)
Convert that into either some DTO object (which is sitting in ViewModels folder) or a List of SelectListItem objects (to be used to populate dropdowns in the view) which is part of System.web.mvc.
I wanted to look for suggestions on the best way to break out this dependency so i can move as much code out of the MVC project as possible for reuse.
The issue is that if i try to suck my ViewModel code into the Model folder and into another project then again i get stuck because the ViewModel classes have a lot of dependency on
System.Web.Mvc
due to things like SelectListItem.
Should i have 2 view models folders (one in the MVC project that has specific system.web.mvc references and another one that sits in a different project?). It seems like the dependency on SelectListItem is what keeps causing the contention
In most examples that i have seen ViewModels do have a dependency on System.Web.Mvc such as this tutorial
I have seen these questions:
Asp.Net MVC SelectList Refactoring Question?
Where should selectlist logic sit in ASP.NET MVC, view, model or controller?
which are sort of related but not sure they answer my specific overall refactoring question stated.
View models are specific to the particular application. I guess that the view models would differ between your web application and your console application. So have each application define its own view models and the corresponding mapping between the domain models and the view models. Don't have your domain models posses methods that convert them to view models because this way you are completely tying your domain layer to the UI layer which is the worst thing to happen. Use a mapping layer (which will be specific to each application type). AutoMapper is a great example of a mapping layer that you could have.
Don't even try to reuse ASP.NET MVC view models in a console application. As you have already found out they will contain references to System.Web.Mvc because for example a dropDownList in ASP.NET MVC is represented with the IEnumerable<SelectListItem> class whereas in a Console Application, god knows, maybe an IEnumerable<SomeItemViewModel>.
Conclusion: View models and mapping back and forth between the domain and view models belong to the UI layer (a.k.a ASP.NET MVC, Console, WPF, ...).
I understand what you want to achieve, and I must tell you: it's absolutely normal to reuse the same ViewModels for different UI layers. After all, VM is part of MVVM pattern, and that pattern is all about separating concerns. And, separation means the ability to replace lower-level layers with another implementations. That is the purpose of separate software layers (among others).
For the beginning, you must assume that your MVC web project is MVVM-based. That will mentally help you make correct decisions. I guess you already did this since you use ViewModel term.
Make ViewModels become platform independent. It's possible, and it has nothing to do with SelectListItem. After all, SelectListItem simply contains the option text/value pair, plus the flag whether it's selected or not. You obviously can express the same information in a different way. After passing this Generic kind of ViewModel to the MVC, you can convert the generic "SelectListItem" to the MVC SelectListItem. Yes, it is sort of mapping, and it does not matter whether it takes place in the MVC view or before passing it to the View. But it must happen on the UI layer (MVC web project), since it's a platform specific mapping concern.
You mentioned data access code: that's a separate software layer, usually abstractly injected into the ViewModels. I foresee no problems with this part.
Hence, you will end up having different software layers (most likely in different .NET libraries): Data Access Layer, ViewModel layer, MVC Web layer.
There is a possibility of having MVC ViewModels as well (one passed from Controller to View) defined in the MVC project, but those will be simply handling (probably accepting) the generic ViewModels and exposing things in the MVC View-specific terms (mapping, inheritance, your imagination?). And this is normal too - after all, MVC is a web-based UI and it definitely has platform-specific differences that must be handled on the platform level, not before. MVC specific ViewModel would be a good place to handle the mapping from generic to MVC SelectListItem.
Once this refactoring is done, there's nothing stopping you from implementing another UI layer - Console application that you are mentioning, by utilizing the same generic ViewModels as the other UI layer - MVC Web project. When using the generic ViewModels in the console application, if you face the Console platform-specific issues, you can come up with the platform-specific ViewModels in the same way as I explained above for the MVC-specific ViewModels.
You can create viewmodels in controller with extension methods:
Controller:
public ActionResult ApplicationDetail(int id)
{
var model = _serviceLayer.GetSomeModel(id);
var viewModel = model.CreateInstance(model);
return View(viewModel);
}
Create this SomeModelExtensions in your mvc project
public class SomeModelExtensions {
public AppDetailViewModel CreateInstance(this SomeModel model) {
var viewModel = new AppDetailViewModel();
// here you create viewmodel object from model with logic
return viewModel;
}
}
In general I use the following setup/architecture when laying out an MVC app where I may need to reuse the models:
MVC Project: everything web related. I define ViewModels here and map them to the domain models.
Models Project: class library with all your domain logic.
Repository project: This is a class library which access the DB and the Domain Models.
The way it works is that the MVC project will use the (hopefully injected) Repository library to get the Domain Model and map it to its own ViewModel.
If you want to separate the mapping as well, you can put the Mapping Layer, as others have suggested (using AutoMapper eventually), in a separate project. The mapping layer will reference the repositories (and the domain models), while the MVC app will only reference the Mapping layer.
The problem is that the mapping layer, in creating ViewModels, will need a reference to System.Web.Mvc as you found out and you cannot escape this. This is why others have said, and I agree, that you should have a mapping layer per project.
A nice way to get around this is to have a further generic mapping layer with mapping classes defined for the common cases (like the email). Then in the specific child classes you can define the mapping for specific cases (like the ones depending on System.Web.Mvc).
So the end stack would be something like the following, dependencies going down. Of course everything should be interface based.
MVC App Console App
| |
| |
MVC Specific Mapper Console Specific Mapper
\ /
\ /
\ /
GenericMapper <- EmailMapper and EmailViewModel can be implemented here
| |
| |
Repository |
| |
| |
DomainModels
The above is not struggle free and probably the effort of splitting the mapping apart is not worth the candle if there are only one or two common cases. That way, from the Generic Mapper down you are free from the System.Web.Mvc library, while above you are free to forget about DB access code (In a sense the Mapper will act as a Repository for the App).
I assume the MVC web will use the same data as the console app + extra fields, right?
so, what about inheritance your ViewModel from Model? That way you would be able to reuse the model and get custom fields on your ViewModel as needed.
public class AppDetailModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class AppDetailViewModel : AppDetailModel
{
public string ViewProperty { get; set; }
}

Understanding MVC4 Controllers

I'm fairly new to the .net Framework and the whole MVC programming philosophy. Could someone clarify and give me a basic explanation how controllers interact with sites using C#? I understand how to code in C#, and I understanding some aspects of the framework, but I don't see how they all tie together.
Model - Is a data structure that represents some kind of object (usually one). It's purpose is to read, write and manage the access to the underlying object with the aim to persist application state.
View - Is the components that are used to display a visual interface to the user, perhaps using a model. It might be a simple table or a complex combination into a full web page.
Controller - Is the user driven application logic layer the sits between views and models. It handlers user interaction, loads models, and sends views to the user. It determines what model is sent to the view depending on user requests.
The overall folder structure for an application might look like this.
>> Website
>> Controllers
>> Models
>> Views
In C# MVC each controller must have the suffix Controller in the name, they must extend Controller class and have a folder of the name prefix (without the Controller) in the views folder. This folder will then contain all the views related to particular actions on the controller.
Controllers can contain any number of actions defined as public functions. By default when returning a result from a controller action the name of the view must correspond with the name of the action. However you can also specify a view by name. When loading a view from a controller, it is possible to send an object as a model to the view and there by generate it's content.
Controllers can load any model and are not restricted in any way.
An Account controller defined as below with an action Login. The controller is placed in a AccountController.cs file in the /Controllers folder, and any views for this controller (Login in this instance with filename Login.cshtml) are placed in the /Views/Account folder.
Note: The naming convention has to be right as the names are used between the controllers and views to link the data.
public class AccountController : Controller
{
public ActionResult Login(string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index","Site");
}
return View("Login", new LogOnModel());
}
}
would be accessible via http://www.mysite.com/Account/Login. If the user is authenticated, the controller will redirect to the main site controller, if the user is not logged in then they are shown the Login view which loads data from the LogOnModel specified.
This is really just touching the surface of what is possible. Read some online information on some excellent articles by ScottGu which go into much more depth and talk you through how to use MVC.
ASP.NET MVC Framework Overview
ASP.NET MVC Framework How To - Part 1
// Part 2
// Part 3
// Part 4
Note : These articles are slightly outdated as they were written for MVC version 1 back in 2007, but the concepts of how the Models, Views and Controller interact still apply.
Controllers serve somewhat as an internal web service. They expose your server side code to your views and allow them to call the controllers. In terms of pattern, most people believe that controllers should be as thin as possible. If there is heavy lifting or other business logic, you should abstract it to another part of your application. In my eyes, controllers are there to provide the view with something to call, and then to return that data whether it be text/html, json, or xml.
Here's a great wealth of information, straight from the source: http://www.asp.net/mvc/mvc4
Specifically to the site, I'd highly recommend the tutorial. It will give you a much clearer picture of how Models, Views, and Controllers interact and depend on one another.
http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4
A controller is a class which has methods, those methods are called actions, you atach those actions to "views" (cshtml files).
//This is your controller
public class HomeController : Controller
{
// This is your action
public ActionResult Index()
{
return View();
}
}
You can right click the "Index" action and select "Add View..." this will create a new view atached to that action.
In order to access that view you will do something like: localhost/Controller/Action
In this case it should be: localhost/Home/Index where Home = Controller, Index = Action
You should read about the MVC pattern
Microsoft has some really good tutorials for beginers
Controller in ASP.NET MVC is an object that handel your app logic in response of requests. It will be created per request (e.g. a HTTP request) and will be available until response created by View layer. After that it will be an unusable object (and soon GC will free its allocated memory) and for another request a new controller object must be created and so on.
I think by this definition it will be obvious why it must be lightweight and how you must use it.

View Models and dependency injection

While working on a LOB desktop application with a lot of CRUD operations using PRISM and Enterprise Library, I have noticed a recurring pattern that seems annoying. For every domain model entity (eg. Contact) I find my self wrapping it with a view model (eg. ContactVM) then I introduce a new ContactsVM (notice the 's') where the latter class accepts a repository interface which is used to populate an ObservableCollection<ContactVM> and for every Contact entity that I read from the repository, I wrap it in a ContactVM which I pass the entity to via the constructor along with other enterprise library services needed by my ViewModel.
The problem is that all my view model constructors started taking this pattern like this:
ViewModel(EntityToWrap e, DependencyFromEntLib, OtherDependencies ...)
Now that is a problem because most tools and libraries require a default parameterless constructor (eg. some commercial data grids need that to provide filtering support), plus you can't use design data to visualize entities because they need parameterless constructors too. and finally the question: What is the right way to build view models and should Entlib services be provided via constructors or via the ServiceLocator ?
The following is one of many different ways to approach the problem.
I prefer view models which are much more lightweight. I then add a class whose responsibility is to compose the view model from one or more sources (e.g. a repository). This doesn't eliminate the problem of cascading dependencies, but it does free up your view model constructors.
It also keeps logic out of the controllers, and allows view models to be reused (when appropriate, of course).
Lightweight view models
Lightweight controller knows how to locate a composer which assembles the view model (you could use a DI framework to setup the composer with all of its dependencies). The controller may play a minor role in the setup process, but it should be kept simple.
Controller knows how the view model should be assembled, and shares that with the composer class. For example, the action might request a summary view which can still leverage the same view model with no children populated.
Composer assembles the necessary information to complete the view model. Composer may use other composers to gather information for which it is not directly responsible. Again, a DI framework can be used here so that these composers are also given the dependencies that they need.
Controller renders the view as usual with the completed view model.
In my opinion, this also provides a better level of abstraction. Just because a view model often looks like a particular domain model, that doesn't mean it will always be the case.
The end result:
Lots of classes (a downside, granted), but minimal repetition of code (i.e. DRY)
Thin view models which are testable (if needed...they may contain nothing to test)
Thin, testable controllers.
Testable composer objects which can be reused for different scenarios because they (presumably) know how to assemble view model(s) for various purposes.
Flexibility to mix and match view models, controllers, and composers to support different scenarios.

MVC3 - reference to a separate service project in which module?

Initial situation:
I would like to build an MVC3 application with a layered architecture. The layers would be the persistence
layer (repository pattern), service layer and the View layer. I also want to map entities to DTOs in the
persistence layer, and passing these DTOs to the View.
In the View I would like to apply the MVC pattern by using MVC3 weapp. Now my Question is, in which module, the Controller or the Model should i access (reference to) the service layer.
I always see references to the service layer in the controller, like this:
public class CustomerController
{
public ViewResult Details( int id )
{
CustomerDTO customerDto = MyService.GetCustomerById();
return View( customerDto );
}
}
Shouldn't I access the service layer in the Model module? If I access my service layer in the controllers, I don't need the Model module at all...?
I always work on the basis that any real work with the service layer is done in the controller.
If I access my service layer in the controllers, I don't need the Model module at all...?
Incorrect - it is highly unlikely that your service types either will have, or even should have the correct shape and metadata (for example [Display] or [DataType] attribution) or to make them work correctly with MVC views. You should have a Model type for all objects that get given to the view, even if they're one-for-one clones of your service types - because then you have a separation between the data that your view and controllers need and your service types.
If you try to bind your views directly to your service types, then you are creating either one of these two scenarios:
making it harder to change view & controller code because the data being sent to and fro has to conform to service types
making it harder to change service types because to do so would mean changing every view
The ViewModel (or Model, depending on your point of view) is your adapter between what's nice for viewing (displaying on a web page) and binding (receiving from a web page) - and it's simply the case that these two things will often drift apart from the actual service types used at the business logic level. Indeed they should, because they aim to solve different problems.
Depends on whether you want to hide MyService from controller.
In your example it's visible. If you had a method on Model of the same name that then delegated to MyService, it wouldn't be.
Advantage of hiding it is you could swap MyService for YourSevice without impacting the View and Controller layers.
As for no model. Where are you defining your DTOs then? Basically MyService would be your model.
You are also operating on the assumption that the DTO for model to controller to view is the same all the way through, even when adding at least one other layer.
I'd think through that assumption if I were you...

Categories

Resources