top button
Flag Notify
    Connect to us
      Site Registration

Site Registration

Updated : Use Dependency Injection In ASP.NET Core 1.0

+1 vote
301 views

Dependency Injection (DI) is a technique to develop loosely coupled software systems. Although this article won't go into the details of DI as such, the basic idea is this:

Assume that there is a class Class1 that depends on Class2 and Class2 for its functioning. The normal practice is to instantiate the objects of Class2 and Class3 inside Class1 as shown below:

public class Class1
{
   private Class2 objClass2;
   private Class3 objClass3;

    public Class1()
    {
      objClass2 = new Class2();
      objClass3 = new Class3();
    }
   ....
   ....
}

Although this might work as expected it has a problem of its own - there is tight coupling between Class1 and its dependencies (Class2 and Class3). If you wish to replace Class2 and Class3 with some other implementations you need to change the code of Class1 since these objects are created inside the class.

To get away from this dependency you can do the following:

  • Base Class2 and Class3 on some interface.
  • Supply objects of classes implementing the interface (Class2 and Class3 in this case) from external world.

In other words you inject dependencies of a class from the external world. So, Class1 will look like this:

public class Class1
{
    public Class1(ISomeInterface objClass2, 
                  ISomeOtherInterface objClass3)
    {
      ....
    }
}

Ok. Now that you have some idea about DI, let's see how ASP.NET Core 1.0 allows you to work with it.

As far as ASP.NET Core 1.0 is concerned, a type to be injected is called a service. The ASP.NET Core dependency injection framework does two basic tasks for you:

  • It instantiates an object of the said service and supplies it to controllers. The dependencies can be injected through constructor injection or through property injection.
  • It handles the lifetime (when to create an object and when to dispose it) of the injected object.

There are three lifetime modes for a service being injected:

  • Singleton : An object of a service is created and supplied to all the requests to that service. So, basically all requests get the same object to work with.
  • Scoped : An object of a service is created for each and every request. So, each request gets its a new instance of a service to work with.
  • Transient : An object of a service is created every time an object is requested.

Let's see how each of these modes work.

Begin by creating a new ASP.NET Core 1.0 project as outlined. Then add an interface and a class to the Classes (or some other folder of you choice) folder:

public interface IMyServiceInterface
{
    string UniqueID { get; set; }
}

public class MyService:IMyServiceInterface
{
    public string UniqueID { get; set; }

    public MyService()
    {
        this.UniqueID = Guid.NewGuid().ToString();
    }
}

The MyServiceInterface class defines a single property - UniqueID. The MyService class implements IMyServiceInterface. The UniqueID property is set to a new GUID in the constructor of the MyService class. This way you can observe the value of UniqueID to understand the lifetime modes mentioned above.

Then add HomeController and Index view to the project.

Singleton

The DI services and their lifetime modes are registered in the Startup class. So, open the Startup class and modify the ConfigureServices() method as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IMyServiceInterface,MyService>();
}

Notice the line marked in bold letters. It uses the AddSingleton() method of the IServiceCollection to register MyService class as a service type. As the name suggests AddSingleton() method registers MyService with singleton mode.

Next, open the HomeController and write the following code to it:

public class HomeController : Controller
{
    private IMyServiceInterface obj;

    public HomeController(IMyServiceInterface obj)
    {
        this.obj = obj;
    }

    public IActionResult Index()
    {
        ViewBag.Obj = this.obj;
        return View();
    }
}

The HomeController constructor takes a parameter of IMyServiceInterface. Since a type that implements this interface is registered with the DI framework, an object of MyService is created and supplied to the constructor. The object reference is stored in a local obj variable for later use.

The Index() action, simply sets a ViewBag property to this injected object. The Index view outputs the value of UniqueID property as follows:

<h4>UniqueID of Obj : @ViewBag.Obj.UniqueID</h4>

If you run the application your browser should look something like this:

image

Now open another browser tab and issue another request to /home/index. You will find that both the tabs output the same UniqueID confirming that a singleton object is being created.

Scoped

To change the lifetime mode to Scoped, open Startup class again and change the call as shown below:

 services.AddScoped<IMyServiceInterface,MyService>();

This time the code uses AddScoped() method. After making this change run the application again. Simulate multiple requests as before. This time you will find that each tab displays different UniqueID. This conforms that each request is being supplied with a new object instance.

image

Transient

To test the transient mode you need to change the Startup class like this:

services.AddTransient<IMyServiceInterface,MyService>();

This time the code uses AddTransient() method to register MyService. Now, to simulate multiple object creation requests within a single request-response cycle modify HomeController as shown below:

public class HomeController : Controller
{
    private IMyServiceInterface obj1;
    private IMyServiceInterface obj2;

    public HomeController(IMyServiceInterface obj1, 
                   IMyServiceInterface obj2)
    {
        this.obj1 = obj1;
        this.obj2 = obj2;
    }

    public IActionResult Index()
    {
        ViewBag.Obj1 = this.obj1;
        ViewBag.Obj2 = this.obj2;
        return View();
    }
}

This time the HomeController declares two variables of IMyServiceInterface. The constructor accepts two parameters of IMyServiceInterface - obj1 and obj2. This is just to simulate multiple object creation requests. The obj1 and obj2 are stored in ViewBag as before.

The Index view outputs the UniqueID from both the objects like this:

<h4>UniqueID of Obj : @ViewBag.Obj1.UniqueID</h4>
<h4>UniqueID of Obj2 : @ViewBag.Obj2.UniqueID</h4>

To test the transient mode, run the application. You will find that the two UniqueID values are different even for a single HTTP request.

image

Special case of Singleton - instance

You can register a singleton service by creating its instance yourself. In this case you are responsible for creating an object of a service. The DI framework then uses that instance in singleton mode mentioned earlier. For example, you can create an instance of MyService and register it with the DI framework. You can do so in ConfigureServices() as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    MyService obj = new MyService();
    services.AddSingleton<IMyServiceInterface>(obj);
}

As you can see, the code creates an object of MyService instead of relying on DI framework. This manually created object instance is then registered with the DI framework using an overload of AddSingleton() method. Notice that this overload accepts an object instance that is then registered as a singleton instance with the system.

You can run the application as before. You will observe that instance mode works like singleton lifetime mode - the same object instance is supplied to all the requests.

posted Jan 9, 2017 by Shivaranjini

  Promote This Article
Facebook Share Button Twitter Share Button LinkedIn Share Button


Related Articles

ASP.NET Core is a modern web development framework. Features such as model binding make your life easy by mapping form field values with model properties. So, accessing form and query string values manually might not be needed so often. However, at times you may need to read the form collection and query string values manually. The same can be said about Items collection of HttpContent. This article discusses how the form collection, query string values and Items collection can be accessed in ASP.NET Core. You will also learn how HttpContext can be accessed inside classes other than the controller.

To illustrate what we just mentioned you will develop a simple web application as shown below:

image

As you can see the page consists of a simple form that allows you to enter first name and last name. Upon click the Submit button a welcome message is displayed below.

Reading Form collection

To understand how the form collection can be accessed let's POST the above form to an action :

<h1>Enter your name :</h1>

<form asp-action="ProcessForm"
      asp-controller="Home" method="post">
    <label for="firstName">First Name :</label>
    <input type="text" name="firstname" />
    <label for="lastName">Last Name :</label>
    <input type="text" name="lastname" />
    <input type="submit" value="Submit" />
</form>

<h4>@ViewBag.Message</h4>

The above form consists of two text input fields and a submit button. The form is POSTed to the ProcessForm() action of the HomeController. The ProcessForm() action is shown below:

public IActionResult GetForm()
{
 string firstName = HttpContext.Request.Form["firstname"];
 string lastName = HttpContext.Request.Form["lastname"];
 ViewBag.Message = $"Welcome {firstName} {lastName}!";
 return View("Index");
}

Since the form is submitted to the server using a POST request, its values need to be accessed using the Form collection of the Request object. This is quite similar to ASP.NET Web Forms or ASP.NET MVC. The form collection is a dictionary that can be accessed using a key-value notation. The above code uses firstname and lastname keys to read the respective values. Notice that these keys are same as the name attributes of the text input fields. The code then forms a welcome message and stores it in ViewBag's Message property.

If you run the application you will get results as shown earlier.

Reading query string values

Now, change the method of the <form> element to GET and change the asp-action to ProcessQueryString.

<form asp-action="ProcessQueryString"
      asp-controller="Home" method="get">
...
</form>

Since the form is now being submitted through GET request, the values will be sent through query string. To access these values on the server you need to write ProcessQueryString() action as follows :

public IActionResult ProcessQueryString()
{
 string firstName = HttpContext.Request.Query["firstname"];
 string lastName = HttpContext.Request.Query["lastname"];
 ViewBag.Message = $"Welcome {firstName} {lastName}!";
 return View("Index");
}

In this case you use Query collection (not QueryString ptoperty!). As before Query collection is accessed by specifying a key. A welcome message is formed as before. You can access y string values sent via plain hyperlinks (rather than form submission) in the same manner.

Storing and retrieving items in the Items collection of HttpContext

The Items collection of the HttpContext is used to store data that is accessible within the current request. Once the current request ends the Items collection is emptied. Let's say you wish to store arbitrary number of key-value pairs in Items collection so that they can be accessed in other classes. You can store data in Items collection like this :

 public IActionResult ProcessForm()
{
    HttpContext.Items["firstname"] = 
              HttpContext.Request.Form["firstname"];
    HttpContext.Items["lastname"] = 
              HttpContext.Request.Form["lastname"];
    ViewBag.Message = helper.DoWork();
    return View("Index");
}

The above code shows the modified version of ProcessForm(). The modified ProcessForm() retrieves firstname and lastname from Form collection and stores them in the Items collection of HttpContext. The code then invokes DoWork() method on a helper object. The helper object (discussed later) is supposed to read the Items collection and return the welcome message.

This means inside the helper object you need to access the HttpContext. The HttpContext is available readily in the controller classes but if you wish to access it inside a class (let's call it a helper class for simplicity) you need to do a few things. Firstly, you need to register the HttpContextAccessor (Microsoft.AspNetCore.Http namespace) and your helper class as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton
        <IHttpContextAccessor,HttpContextAccessor>();
    services.AddScoped<MyHelperClass>();
}

 Here, you registered HttpContextAccessor as a singleton service. You also registered MyHelperClass as a scoped service. Once registered you can inject the HttpContextAccessor in the MyHelperClass. As the name implies the HttpContextAccessor allows you to access the web application's HttpContext object. The MyHelperClass is shown below:

public class MyHelperClass
{
    IHttpContextAccessor contextAccessor;

    public MyHelperClass(IHttpContextAccessor 
                          contextAccessor)
    {
        this.contextAccessor = contextAccessor;
    }

    public string DoWork()
    {
        string firstName = contextAccessor.
                  HttpContext.Items["firstname"].ToString();
        string lastName = contextAccessor.
                  HttpContext.Items["lastname"].ToString();
        return $"Welcome {firstName} {lastName}!";
    }
}

Notice the MyHelperClass class carefully. It declares a private variable of type IHttpContextAccessor. The IHttpContextAccessor object is injected in the constructor and is stored in the variable. The DoWork() method then retrieves the firstname and lastname items using the HttpContext property of IHttpContextAccessor. This way the web application's HttpContext can be accessed inside any class.

If you run the application you should see the welcome message displayed as expected.

That's it for now! Keep coding!!

READ MORE

Storing and retrieving small pieces of information in cookies a common requirement in many web applications. This article explains with an example how ASP.NET Core 1.0 deals with cookies. You will learn to read and write cookies using ASP.NET Core. You will also learn to configure the cookie properties such as expiration time.

The application you develop in this article looks like this:

image

As you can see the page allows you to specify certain preferences such as font name, font size and color. You can select a preference from the dropdown list and specify its value in the textbox. Clicking on the Write Cookie button saves that preference in a cookie. The Is Persistent checkbox controls whether the cookies are to be stored on the local disk so that they are be read during a different browser session. The read cookies link takes you to another page where the preferences are read and applied to a sample HTML markup.

Begin by creating a new ASP.NET Core Web Application using Visual Studio 2015. Then open the HomeController and add three actions to it - Index(), WriteCookies() and ReadCookies().

The Index() action is quite straightforward and simply returns the Index view to the browser.

public IActionResult Index()
{
    return View();
}

The WriteCookies() action does the job of writing cookies and is shown below:

public IActionResult WriteCookies(string setting,
              string settingValue,bool isPersistent)
{
    if (isPersistent)
    {
        CookieOptions options = new CookieOptions();
        options.Expires = DateTime.Now.AddDays(1);
        Response.Cookies.Append(setting, settingValue,options);
    }
    else
    {
        Response.Cookies.Append(setting, settingValue);
    }
    ViewBag.Message = "Cookie written successfully!";
    return View("Index");
}

The WriteCookies() method receives three parameters namely setting, settingValue and isPersistent through model binding. The setting paremeter will be the value selected in the dropdown list. The settingValue parameter will be the value entered in the textbox and isPersistent will indicate whether isPersistent checkbox is checked or not.

Inside, the code checks the value of isPersistent boolean parameter. If it is true an object of CookieOptions class (Microsoft.AspNetCore.Http namespace) is created. The CookieOptions class allows you to specify the properties of the cookie such as the following:

  • Domain (domain associated with the cookie)
  • Expires (when the cookie should expire)
  • Path (specify path where cookie is applicable)
  • Secure (cookie is sent only on https channel)
  • HttpOnly (client side script can't access the cookie)

In the above example, you set the Expires property of the cookie to one day from now. This way the cookie will be persisted on the client machine for one day. Then a cookie is written to the response using the Append() method of the Cookies collection. The Append() method accepts key, value and CookieOptions object.

The else block of the code simply appends a cookie by setting its key and value (no CookieOptions object is passed).

A ViewBag message indicates to the user that the preference is stored successfully.

Then add Index view and write the following markup into it:

<h1>Specify your preferences :</h1>
<form asp-action="WriteCookies" asp-controller="Home">
    <select name="setting">
        <option value="fontName">Font Name</option>
        <option value="fontSize">Font Size</option>
        <option value="color">Color</option>
    </select>
    <input type="text" name="settingValue" />
    <input type="checkbox" name="isPersistent" 
           value="true" /> Is Persistent?
    <input type="submit" value="Write Cookie" />
</form>

<h4>@ViewBag.Message</h4>

<h4>
    <a asp-action="ReadCookies" asp-controller="Home">
       Read Cookies
    </a>
</h4>

The Index view renders a <form> shown earlier using ASP.NET Core tag helpers and input elements. It also outputs the Message property from ViewBag. A Read Cookies link takes the user to a test page where  preferences are applied.

Now, add ReadCookies() action to the HomeController and write the following code to it :

public IActionResult ReadCookies()
{
    ViewBag.FontName = Request.Cookies["fontName"];
    ViewBag.FontSize = Request.Cookies["fontSize"];
    ViewBag.Color = Request.Cookies["color"];

    if(string.IsNullOrEmpty(ViewBag.FontName))
    {
        ViewBag.FontName = "Arial";
    }
    if (string.IsNullOrEmpty(ViewBag.FontSize))
    {
        ViewBag.FontSize = "22px";
    }
    if (string.IsNullOrEmpty(ViewBag.Color))
    {
        ViewBag.Color = "Blue";
    }
    return View();
}

The ReadCookies() action reads three cookies with the help of their respective keys. This is done using Cookies collection of the Request object. The cookie values are stored in ViewBag properties. A series of if statements check whether a particular preference is empty and if so assign a default value to it.

The ReadCookies view where these preferences are used is shown below:

<div style="font-family:'@ViewBag.FontName';
     font-size:@ViewBag.FontSize;color:
     @ViewBag.Color">
    Hello World! 
</div>

 The ReadCookies view consists of a <div> element whose style attribute makes use of font name, font size and color specified in the respective ViewBag properties.

This completes the application. Run it and specify values to the three preferences. Don't check the Is Persistent checkbox while saving the values. Then click on the Read Cookies link. You should something similar to this:

image

Then run the application again and repeat the process by checking the Is Persistent checkbox. If you observe the browser's cookie cache you will find the three cookies there:

image

That's it for now! Keep coding!!

READ MORE

Recently one of the readers, who was quite new to ASP.NET Core, asked this question -

"I am following your instructions to create a working example based on your article. After creating the project my solution explorer looks different than your screen shots. Why is so? Am I missing something?"

Well. That's actually because of a simple setting. But it is always good to know why things are happening in the way they are. So, in this short post I am explaining why you see two different solution structures in Visual Studio 2015.

Solution Structure - ASP.NET MVC 5 Style

Let's create a new ASP.NET MVC 5 project using Visual Studio 2015.

Open Visual Studio 2015 and select File > New > Project. This will open a new project dialog as shown below:

image

Observe this dialog carefully. Specifically note the following:

  • Project name is Project1
  • Solution name is Solution1
  • Create directory for solution checkbox is checked

When you complete the project creation your Solution Explorer will resemble this:

image

If you glance over the folder structure using Windows explorer, you will have this:

image

Notice that under the Demos folder you have Solution1 folder because you selected the "Create directory for solution" checkbox. Inside, you have Project1 folder that contains all the project specific files and folders.

Now, create a new project again but this time uncheck the "Create directory for solution" checkbox.

image

This time Project2 folder (the folder containing project's files and folders) gets created directly inside Demos folder. There is no separate folder for solution since you unchecked the "Create directory for solution" checkbox.

Solution Structure - ASP.NET Core Style

So far so good. Now create a new ASP.NET Core project by checking the "Create directory for solution" checkbox.

image

This time project name is Project3 and solution name is Solution3. This time your solution explorer would look like this:

image

That's bit different! Observe the following differences:

  • There are two top level folders - Solution Items and src.
  • Solution Items contains global.json file.
  • Src folder contains the project - Project3.

Now try adding another project to the same solution by right clicking on Solution3 (this process remains the same as before). After adding the new project your Solution Explorer will resemble this:

image

Thus all the projects belonging to a solution are located inside the Src folder. The physical folder structure will look like this:

image

You may ask - Why this structure?

That's because this structure closely resembles the GitHub project layout. Since ASP.NET Core heavily uses OSS, the new solution structure mimics what people using repositories such as GitHub are familiar with.

You are not limited to these two folders. You can, for example, create Tests folder to store unit testing related things and Documentation folder to store documentation files.

Now you may ask - Can I continue using the older solution structure in ASP.NET Core also?

Yes. You can do that. Simply uncheck the "Create directory for solution" checkbox while creating a project and you will have a solution with older and familiar structure. Here is an example:

image

And  the result is as follows:

image

That's it for now! Keep coding !! 

READ MORE
...