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>();
}
}
View injection can be useful for populating UI elements, like selection list, radio buttons etc. This will increase code re-usability and keep your Controller clean by minimizing the amount of code required on Controllers. Reference. http://aspnetmvc.readthedocs.io/projects/mvc/en/latest/views/dependency-injection.html.
From the docs, "Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views." If your ASP.NET MVC app makes heavy use of views, you may want to consider migrating from actions and views to Razor Pages.
The Dependency Injection (DI) Design PatternThe Dependency Resolver in ASP.NET MVC can allow you to register your dependency logic somewhere else (e.g. a container or a bag of clubs). The advantages of using Dependency Injection pattern and Inversion of Control are the following: Reduces class coupling.
You can think of @inject as adding a property to the view, and populating the property using DI. CSHTML Copy.
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).
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With