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