ASP.NET Core: Using view injection
Besides all other dependency injection forms, ASP.NET Core supports also view injection. Yes, it is possible to inject instances directly to views and there’s no need to update view models to carry information that is already available through dependency injection. This blog post demonstrates how to use view injection.
In my last post about ASP.NET Core dependency injection I introduced custom request context class that carries application specific information. This post will use view injection to avoid using ViewBag to set page title.
Dependency injection in ASP.NET Core
On ASP.NET Core there is framework-level dependency injection. In Startup class there is method ConfigureService() and in this method all dependency injection stuff is set up and configured like shown in the following code example.
{
// Add Entity Framework services to the services container.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration[“Data:DefaultConnection:ConnectionString”])
);
// Add Identity services to the services container.
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add MVC services to the services container.
services.AddScoped<IFileClient, AzureFileClient>();
services.AddScoped<IMapperSession, MapperSession>();
services.AddScoped<IManufacturerDao, ManufacturerDao>();
services.AddScoped<IProductCategoryDao, ProductCategoryDao>()
}
The code above shows fragment of ConfigureServices() method of start-up class of ASP.NET Core application. AddScoped() method adds mapping that works on request level. It’s also possible define singletons and transient instances.
Application context class
Now let’s define application specific context class. To keep this class simple there is only the property for page title.
{
public string PageTitle { get; set; }
}
To make it available through dependency injection the class must be registered in ConfigureServices() method like shown below.
Every request gets new instance of our application context class now. As there is no interface for application context class and also there is no custom inheritance tree then it’s enough to just put concrete types to AddScoped() method.
Setting page title in controller actions
Controller actions know what is the title of current page. ASP.NET Core dependency injection uses constructor injection on controllers to get application context there. In controller actions we will set current page title.
{
private readonly ShopContext _shopContext;
public HomeController(ShopContext shopContext)
{
_shopContext = shopContext;
}
public IActionResult Index()
{
_shopContext.PageTitle = “Welcome to Crazy Shop!”;
return View();
}
}
When request comes in and controller is detected then new instance of this controller is created. If constructor has parameters then built-in dependency injection takes care of finding instances of given types and injects these to constructor, All controller actions can use these injected parameters if they are made available in controller scope.
Injecting application context to layout page
Now page titles are available in application context class. It’s possible to use HttpContext items collection to carry page title to layout page but it will be invisible dependency. It’s also possible to use ViewBag but it is not strongly typed and it will be overkill to add page title to all view models.
ASP.NET Core supports feature called view injection. It means it is possible to inject instances directly to views without messing any of things mentioned above. Here is the example of how custom application context is injected to layout page and how it is used to set page title for browser.
<!DOCTYPE html>
<!–[if IE 8]> <html lang=”en” class=”ie8 no-js”> <![endif]–>
<!–[if IE 9]> <html lang=”en” class=”ie9 no-js”> <![endif]–>
<!–[if !IE]><!–>
<html lang=“en”>
<!–<![endif]–>
<head>
<meta charset=“utf-8”>
<title>@_shopContext.PageTitle</title>
View injection is very easy to use but developers must be careful with it. Too much view injection may move too much code and logic to views and views are harder to test than controller actions.
Wrapping up
Framework level dependency injection in ASP.NET Core works very well also with views. View injection makes it very easy to get all injectable instances to views but don’t get it wrong – view must still deal only with representation of data and not carry any display logic.
what’s difference to directly use ViewData?
I don’t prefer to use ViewData and ViewBag as one is collection and the other one is dynamic. I prefer to use strongly typed models as compiler and view compiler can easily detect problems.
This is so ugly..
And msdn blog linked this..
Why not create ViewModel with necessary properties?
ViewModel can’t be provided to layout page. Its scope is view. It’s possible to use ViewBag that I don’t like and it’s possible to define section for title in view but I don’t like this approach either. Creating title property for all view models doesn’t seem good idea to me because some views doesn’t have view model. So, this approach here avoids all the bad things I don’t like :)
Pingback:Szumma #065 – 2016 45. hét | d/fuel
Thats exactly what I needed!!! Big thank you for sharing the idea.