You have an old version of the software. The website may not work properly. Please update your system to view the page with all available features.
light
dark
03 July 2020 | Stanisław Suchodolski

ASP.NET CORE Introduction — Part 3

In this days in­ver­sion of con­trol in every­where. That is a fact. We also face this pat­tern when cre­at­ing ASP.​NET Core ap­pli­ca­tions. So let’s ask our self the ques­tion if our cur­rent so­lu­tion in using this de­sign pat­tern. There can only be one an­swer “No”. And that is a shame. Be­cause the an­swer should be “Yes”. So let’s try to change this sit­u­a­tion.

First let’s wind a place when the in­ver­sion of con­trol ap­proach can be use­ful. The an­swer is sim­ple. In­ver­sion of con­trol pat­tern should to use while get­ting hello mes­sage. So let’s to that. We need to start by cre­at­ing an in­ter­face and a class. That will be used to get hello mes­sage.

In­ter­face

namespace CoreDemo
{
    public interface IHelloService
    {
        string GetHelloMessage();
    }
}

Class

namespace CoreDemo
{
    public class HelloService: IHelloService
    {
        public string GetHelloMessage()
        {
            return "Example Hello";
        }
    }
}

As we can see, IHel­loSer­vice and Hel­loSer­vice ale very sim­ple. Get just re­turn string. We will change it soon, don’t worry. At this mo­ment we need to con­cen­trate at the In­ver­sion of con­trol. So let’s try to use this new ser­vice ac­cord­ing to this pat­tern.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace CoreDemo
{
    public class Startup
    {
        public Startup(IHostingEnvironment hostingEnvironment)
        {
            var configurationBuilder = new ConfigurationBuilder()
                .SetBasePath(hostingEnvironment.ContentRootPath)
                .AddJsonFile("appsettings.json");
 
            this.Configuration = configurationBuilder.Build();
        }
 
        public IConfiguration Configuration { get; set; }
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IHelloService helloService)
        {
            loggerFactory.AddConsole();
 
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync(helloService.GetHelloMessage());
            });
        }
    }
}

That look fine. Does not it? Con­fig­ure method pa­ra­me­ter got ex­tended for a needed ser­vice. We used it just like, for ex­am­ple Log­ger­Fac­tory. So let’s see if it all works.

I doesn’t. Get ques­tion is why. It looks all ok. We cre­ated an in­ter­face and a class, and added it just like other pa­ra­me­ters it Con­fig­ure method. It all should be right. Right? Wrong!!!!

El­e­ments like Log­ger­Fac­tory get reg­is­tered by de­fault. In case of cus­tom ser­vices we un­for­tu­nately need to reg­is­ter them by our self. So let’s do that.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace CoreDemo
{
    public class Startup
    {
        public Startup(IHostingEnvironment hostingEnvironment)
        {
            var configurationBuilder = new ConfigurationBuilder()
                .SetBasePath(hostingEnvironment.ContentRootPath)
                .AddJsonFile("appsettings.json");
 
            this.Configuration = configurationBuilder.Build();
        }
 
        public IConfiguration Configuration { get; set; }
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IHelloService, HelloService>();
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IHelloService helloService)
        {
            loggerFactory.AddConsole();
 
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync(helloService.GetHelloMessage());
            });
        }
    }
}

It is not hard. All we need to do is to use ser­vice method. In this case it is method to add sin­gle­ton.

Final touch

Now that all the el­e­ments are in place there is only one more thing to do. We need to make Hel­loSer­vice ac­tu­ally work­ing. So it needs to get data from the set­tings file and use IOC pat­tern.

using Microsoft.Extensions.Configuration;
 
namespace CoreDemo
{
    public class HelloService: IHelloService
    {
        private string _hello;
        public HelloService(IConfiguration configuration)
        {
            _hello = configuration["HelloMessage"];
        }
        public string GetHelloMessage()
        {
            return _hello;
        }
    }
}

This is how ser­vice looks now. The in­ter­est­ing thing is that it uses ICon­fig­u­ra­tion via the IOC pat­tern. So it needs to be reg­is­tered, be­fore it can be used. Just like in pre­vi­ous case. Let’s see how it is done now.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace CoreDemo
{
    public class Startup
    {
        public Startup(IHostingEnvironment hostingEnvironment)
        {
            var configurationBuilder = new ConfigurationBuilder()
                .SetBasePath(hostingEnvironment.ContentRootPath)
                .AddJsonFile("appsettings.json");
 
            this.Configuration = configurationBuilder.Build();
        }
 
        public IConfiguration Configuration { get; set; }
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(Configuration);
            services.AddSingleton<IHelloService, HelloService>();
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IHelloService helloService)
        {
            loggerFactory.AddConsole();
 
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync(helloService.GetHelloMessage());
            });
        }
    }
}

It is dif­fered ap­proach. In this case we add con­fig­u­ra­tion ob­ject as via the sin­gle­ton method. We can do that when we want to pre­pare ob­ject be­fore pass­ing it to IOC con­tainer. In can come very handy in some sit­u­a­tions.


Karol Rogowski