Introduction to ASP.NET Core part 19: dependency injection into views

Introduction

In the previous post we saw some other examples of creating custom views in .NET Core MVC. We first discussed how to set the HTML content before and after some text using the “spandec” custom attribute. It enclosed a piece of text within a span element and added a class attribute to the span element as well. We then saw how easy it was to provide the custom tag with an object from the HTML markup using an attribute. Therefore we’re not confined to supplying primitive types to custom tags as arguments. Lastly we saw how to create a conditional tag helper to filter out specific Book records based on an if-condition.

In this post we’ll briefly look at dependency injection into views.

Dependency injection in views

Before in this series we looked at handling dependency injection in Controllers and other parts of the system in Startup.cs. Here’s a short example on how we did it:

public void ConfigureServices(IServiceCollection services)
{
//rest of demo code ignored
     services.AddSingleton<IStringFormatter, JsonStringFormatter>();
}

In our IndexController we use an injected IBookService to get all the books from an IBookRepository which in turn was also injected into the implementation of IBookService. It is really smooth to wire up dependencies this way.

However, what if a view file also needs some dependency injected into it? Normally the controller should provide the view with all the details it needs in order to build a piece of HTML. The view should not go out and fetch data from a service or a repository. In this new version of MVC it’s possible to declare and inject dependencies in views. However, this is a good case of “just because you can, it doesn’t mean you should”. So you should have a very good reason to using the following technique.

We use the @inject directive in a view to declare the object type to be injected. Recall our previous IStringFormatter interface:

namespace DotNetCoreBookstore.Dependencies
{
    public interface IStringFormatter
    {
		string FormatMe(object input);
    }
}

…and its implementation, the JsonStringFormatter class:

using DotNetCoreBookstore.ProjectDependencies;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;

namespace DotNetCoreBookstore.Dependencies
{
	public class JsonStringFormatter : IStringFormatter
	{
		private readonly IGreeter _greeter;
		private readonly IConfiguration _configuration;
		private readonly ProductMeasures _productMeasures;
		private readonly FavOptions _favOptions;

		public JsonStringFormatter(IGreeter greeter, IConfiguration configuration, ProductMeasures productMeasures
			, IOptions<FavOptions> favourites)
		{
			if (greeter == null) throw new ArgumentNullException("Greeter");
			if (configuration == null) throw new ArgumentNullException("Configuration");
			if (productMeasures == null) throw new ArgumentNullException("Measures");
			if (favourites == null || favourites.Value == null) throw new ArgumentNullException("Favourites");
			_greeter = greeter;
			_configuration = configuration;
			_productMeasures = productMeasures;
			_favOptions = favourites.Value;
		}

		public string FormatMe(object input)
		{
			return JsonConvert.SerializeObject(new { Greeting = _greeter.SendGreeting(), Content = input,
				Mood = _configuration["Mood"], Measures = _productMeasures, Favourites = _favOptions });
		}
	}
}

We’ve wired up all the dependencies in the ConfigureServices function of Startup.cs for the JsonStringFormatter class to be injected anywhere it’s needed. Here’s an example of injecting an IStringFormatter into the _Layout.cshtml view:

@using DotNetCoreBookstore.Dependencies
@inject IStringFormatter StringFormatter
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <div>
        @RenderBody()
    </div>
    <div>
        @RenderSection("FunnyMessage", false)
    </div>
    <div>
        <p>@StringFormatter.FormatMe(new { Message = "Hello from the Layout view using dependency injection", Warning = "Use this technique sparingly"})</p>
    </div>
</body>
</html>

The inject directive requires a type and a name. The type can be an abstraction or a concrete type. If it’s an abstraction then its concrete type should be declared in the ConfigureServices function:

services.AddSingleton<IStringFormatter, JsonStringFormatter>();

…otherwise code execution will fail with the following message:

An error occurred while starting the application.

InvalidOperationException: No service for type ‘DotNetCoreBookstore.Dependencies.IStringFormatter’ has been registered.

The name property declares the name of the variable which invokes the dependency in the C# code of the view. This can be any string like “ElvisPresley” or “BarbraStreisand”. See how “StringFormatter” is invoked in the final paragraph.

If you test the above code then you’ll see that JsonStringFormatter was correctly invoked and all views using the layout view will have an extra paragraph:

{"Greeting":"Good morning","Content":{"Message":"Hello from the Layout view using dependency injection","Warning":"Use this technique sparingly"},"Mood":"HiHi","Measures":{"Width":123,"Height":867,"Length":456,"Type":"3D"},"Favourites":{"Music":"Rock","Food":"TomatoSoup","Technology":".NET"}}

We’ll look at partial views in the next post.

View the list of MVC and Web API related posts here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: