Add Service in ASP.NET Core 2.1

min read

Cài đặt Service trong ASP.NET Core 2.1, Sử dụng một lớp Startup.cs để cài đặt các dịch vụ của ứng dụng, các dịch vụ được cài đặt trong hàm ConfigureService
Khi project chạy, thì các dịch vụ trong được đăng ký trong class Startup.cs sẽ được khởi động
Trong ứng dụng ta thường có rất nhiều dịch vụ, chính vì thế mà ta cần thêm các dịch vụ đó vào Startup class để khỏi động chạy cùng với ứng dụng
Bạn có thể tìm hiểu thêm các đối tượng dưới đây: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#service-lifetimes-and-registration-options

+ Transient : Đối tượng luôn khác nhau ,Mỗi lần ta gọi tới là nó luôn tạo mới đối tượng
+ Scoped : Được tạo một lần cho mỗi yêu , Các đối tượng có phạm vi giống nhau trong một yêu cầu và nó sử dụng cùng một thể hiện trong các cuộc gọi khác trong cùng một yêu cầu web.
+ Singleton : Các đối tượng Singleton giống nhau cho mọi đối tượng và mọi yêu cầu. Service được tạo chỉ một lần duy nhất.

Thật sự là khó hiểu mà, ta thử làm một ví dụ để thử nghiệm nó, bạn mới dễ hình dung ra nhé, còn không là khó có thể hiểu nổi, thật là quá khó hiểu mà! ::) cứ từ từ xem sau, cái gì cũng phải thử mới phiêu được

Bước 1: Trong Visual Studio 2019, Bạn chọn File->New, chọn Project
Bước 2: Chọn Create a new project
Bước 3: Chọn ASP.NET Core Web Application template
Bước 4: Đặt tên Project, chọn Create. 
Bước 5: Select .NET Core, ASP.NET Core 2.1, Chọn Web Application (Model-View-Controller), sau đó bấm Create

Tiếp theo, sau khi project đã được tạo, hãy vào thư mục Models, tạo class Product.cs 
+ Models/Product.cs

public class Product
    {
        public int idProduct { get; set; }
        public string Title { get; set; }
        public string UrlImage { get; set; }
        public decimal Price { get; set; }
        public string Detail { get; set; }

    }

Tạo thư mục chứa các Service(Scoped,Singleton,Transient)
Trong thư mục Services/Transient tạo 2 file:

Transient

+ Services/Transient/ITransient.cs : dùng cài đặt các phương thức interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Transient
{
    public interface ITransient
    {
		//return product
        Product getProduct();
		
		//return server count
        int countService();
    }
}

+ Services/Transient/ItemTransientService.cs : kế thừa từ ITransient.cs, để xây dựng các phương thức được định nghĩa ở file ITransient.cs

using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Transient
{
    public class ItemTransientService : ITransient
    {
        Product product;
        int count=0;
        public ItemTransientService()
        {
            product = new Product
            {
                idProduct = 1,
                Title = "Test Transient:" + Guid.NewGuid(),
                UrlImage = "Transient.jpg",
                Price = 79000,
                Detail = "Transient"
            };
           
        }
        public Product getProduct()
        {
            count++;
            return product;

        }
        public int countService()
        {
            return count;
        }
    }
}

Thiết lập xong Transient, ta cần phải add Transient đến Startup.cs, mở file Startup.cs 
Bước 1: using AddServiceASP_core21.Services.Transient;//trỏ đến thư mục chứa Services
Bước 2: đăng ký services.AddTransient<ITransient, ItemTransientService>(); trong ConfigureServices

Thư mục project Controllers->add new ProductController.cs

using AddServiceASP_core21.Services.Transient;
namespace AddServiceASP_core21.Controllers
{
    public class ProductController : Controller
    {
        /*Transient*/
        private readonly ITransient _transient1;
        private readonly ITransient _transient2;

        public ProductController(ITransient transient1, ITransient transient2)
        {
            _transient1 = transient1;
            _transient2 = transient2;

        }
        public IActionResult Index()
        {
            //Transient
            ViewBag.data01 = _transient1.getProduct();
            ViewBag.count01 = _transient1.countService();
            ViewBag.data02 = _transient2.getProduct();
            ViewBag.count02 = _transient2.countService();

            return View();
        }
    }
}

+ Views/Product/Index.cshtml:

@model IEnumerable<Product>
@{
    ViewData["Title"] = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";

    //Transient
    var data01 = ViewBag.data01;
    var data02 = ViewBag.data02;
}
<h2>Transient</h2>
<span>@data01.Title - [Price:@data01.Price] - CountServer:@ViewBag.count01</span>
<br />
<span>@data02.Title - [Price:@data02.Price] - CountServer:@ViewBag.count02</span>

Demo Transient:

Trong demo Transient trên ta thấy ID luôn thay đổi, server luôn tạo mới, vì thể ta mới thấy biến count luôn là bằng 1, vì mỗi lần tạo mới count=0, sao đó ta gọi hàm getProduct() nó thì count++;

Singleton

+ Services/Singleton/ISingleton.cs

using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Singleton
{
    public interface ISingleton
    {
        Product getProduct();
        int countService();
    }
}

+ Services/Singleton/ItemSingletonService.cs

using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Singleton
{
    public class ItemSingletonService : ISingleton
    {
        Product product;
        int count = 0;
       
        public ItemSingletonService()
        {
            product = new Product
            {
                idProduct = 1,
                Title = "Test Singleto:" + Guid.NewGuid(),
                UrlImage = "Singleto.jpg",
                Price = 79000,
                Detail = "Singleto"
            };
           
        }
        public Product getProduct()
        {
            count++;
            return product;

        }
        public int countService()
        {
            return count;
        }
       
    }
}

Đăng ký Service trong ConfigureServices
services.AddSingleton<ISingleton, ItemSingletonService>();

+ Controllers/ProductController.cs chỉnh sửa lại như sau:

using AddServiceASP_core21.Services.Transient;
using AddServiceASP_core21.Services.Singleton;
namespace AddServiceASP_core21.Controllers
{
    public class ProductController : Controller
    {
        /*Transient*/
        private readonly ITransient _transient1;
        private readonly ITransient _transient2;

        /*SingletoService*/
        private readonly ISingleton _singleton1;
        private readonly ISingleton _singleton2;

        public ProductController(ITransient transient1, ITransient transient2,ISingleton singleton1, ISingleton singleton2)
        {
            _transient1 = transient1;
            _transient2 = transient2;

            _singleton1 = singleton1;
            _singleton2 = singleton2;

            _scoped1 = scoped1;
            _scoped2 = scoped2;

        }
         
        public IActionResult Index()
        {
            //Transient
            ViewBag.data01 = _transient1.getProduct();
            ViewBag.count01 = _transient1.countService();
            ViewBag.data02 = _transient2.getProduct();
            ViewBag.count02 = _transient2.countService();

            //Singleto
            ViewBag.data03 = _singleton1.getProduct();
            ViewBag.count03 = _singleton1.countService();
            ViewBag.data04 = _singleton2.getProduct();
            ViewBag.count04 = _singleton2.countService();

            return View();
        }
    }
}

+ Views/Product/Index.cs chỉnh sửa lại khung nhìn

@model IEnumerable<Product>

@{
    ViewData["Title"] = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";

    //Transient
    var data01 = ViewBag.data01;
    var data02 = ViewBag.data02;


    //Singleto
    var data03 = ViewBag.data03;
    var data04 = ViewBag.data04;


}

<h2>Transient</h2>
<span>@data01.Title - [Price:@data01.Price] - CountServer:@ViewBag.count01</span>
<br />
<span>@data02.Title - [Price:@data02.Price] - CountServer:@ViewBag.count02</span>

<p>----------------------------------------------</p>

<h2>Singleto</h2>
<span>@data03.Title - [Price:@data03.Price] - CountServer:@ViewBag.count03</span>
<br />
<span>@data04.Title - [Price:@data04.Price] - CountServer:@ViewBag.count04</span>

Demo Transient & Scoped:

Các bạn nhìn trong hình xem, đối tượng Product không thay đổi ID dù bạn refresh nhiều lần, nhưng Count nó tăng lên, có nghĩa là, Server chỉ chạy một lần duy nhất, nó lưu lại đối tượng và dùng tiếp
Lần 1: count=1;
Lần 2: count=2:// nó tăng lên bạn có thể thử refresh trình duyệt, bạn sẽ thấy nó tăng lên
Nó tạo ra thể hiện lần đầu tiên và sử dụng lại cùng một đối tượng trong tất cả các cuộc gọi.

Scoped

+ Services/Scoped/IScoped.cs

using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Scoped
{
    public interface IScoped
    {
        Product getProduct();
        int countService();
    }

}

+ Services/Scoped/ItemScopedService.cs

using AddServiceASP_core21.Models;
namespace AddServiceASP_core21.Services.Scoped
{
    public class ItemScopedService : IScoped
    {
        Product product;
        int count = 0;
        public ItemScopedService()
        {
            product = new Product
            {
                idProduct = 1,
                Title = "Test Scoped:" + Guid.NewGuid(),
                UrlImage = "Scoped.jpg",
                Price = 79000,
                Detail = "Singleto"
            };
        }
        public Product getProduct()
        {
            count++;
            return product;

        }
        public int countService()
        {
            return count;
        }
    }
}

+ Controllers/ProductController.cs chỉnh sửa lại như sau:

using AddServiceASP_core21.Models;
using AddServiceASP_core21.Services.Transient;
using AddServiceASP_core21.Services.Singleton;
using AddServiceASP_core21.Services.Scoped;
namespace AddServiceASP_core21.Controllers
{
    public class ProductController : Controller
    {
        /*Transient*/
        private readonly ITransient _transient1;
        private readonly ITransient _transient2;

        /*SingletoService*/
        private readonly ISingleton _singleton1;
        private readonly ISingleton _singleton2;

        /*ScopedService*/
        private readonly IScoped _scoped1;
        private readonly IScoped _scoped2;
        public ProductController(ITransient transient1, ITransient transient2,ISingleton singleton1, ISingleton singleton2, IScoped scoped1,IScoped scoped2)
        {
            _transient1 = transient1;
            _transient2 = transient2;

            _singleton1 = singleton1;
            _singleton2 = singleton2;

            _scoped1 = scoped1;
            _scoped2 = scoped2;

        }
         
        public IActionResult Index()
        {
            //Transient
            ViewBag.data01 = _transient1.getProduct();
            ViewBag.count01 = _transient1.countService();
            ViewBag.data02 = _transient2.getProduct();
            ViewBag.count02 = _transient2.countService();

            //Singleto
            ViewBag.data03 = _singleton1.getProduct();
            ViewBag.count03 = _singleton1.countService();
            ViewBag.data04 = _singleton2.getProduct();
            ViewBag.count04 = _singleton2.countService();


            //Scoped
            ViewBag.data05 = _scoped1.getProduct();
            ViewBag.count05 = _scoped1.countService();
            ViewBag.data06 = _scoped2.getProduct();
            ViewBag.count06 = _scoped2.countService();


            return View();
        }
    }
}

Đăng ký Scoped trong ConfigureService
services.AddScoped<IScoped, ItemScopedService>();

+ Startup.cs (full code)

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AddServiceASP_core21.Services.Transient;
using AddServiceASP_core21.Services.Singleton;
using AddServiceASP_core21.Services.Scoped;
namespace AddServiceASP_core21
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //Transient
            services.AddTransient<ITransient, ItemTransientService>();
            //Singleto
            services.AddSingleton<ISingleton, ItemSingletonService>();
            //Scoped
            services.AddScoped<IScoped, ItemScopedService>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Product}/{action=Index}/{id?}");
            });
        }
    }
}

+ Views/Product/Index.cshtml chỉnh sửa lại

@model IEnumerable<Product>

@{
    ViewData["Title"] = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";

    //Transient
    var data01 = ViewBag.data01;
    var data02 = ViewBag.data02;


    //Singleto
    var data03 = ViewBag.data03;
    var data04 = ViewBag.data04;

    //Scoped
    var data05 = ViewBag.data05;
    var data06 = ViewBag.data06;

}

<h2>Transient</h2>
<span>@data01.Title - [Price:@data01.Price] - CountServer:@ViewBag.count01</span>
<br />
<span>@data02.Title - [Price:@data02.Price] - CountServer:@ViewBag.count02</span>

<p>----------------------------------------------</p>

<h2>Singleto</h2>
<span>@data03.Title - [Price:@data03.Price] - CountServer:@ViewBag.count03</span>
<br />
<span>@data04.Title - [Price:@data04.Price] - CountServer:@ViewBag.count04</span>

<p>----------------------------------------------</p>

<h2>Scoped</h2>
<span>@data05.Title - [Price:@data05.Price] - CountServer:@ViewBag.count05</span>
<br />
<span>@data06.Title - [Price:@data06.Price] - CountServer:@ViewBag.count06</span>

Demo Transient & Singleto & Scoped

Ta nhìn Scoped trên hình trên, ID không thay đổi, nó chỉ thay đổi khi refresh lại trang, còn Count thì nó luôn thay đổi
Nó chỉ tạo một đối tượng request mới một lần, vì thể ID không thay đổi, và chính vì thể mà Count nó tăng lên bằng 2
Mỗi lần request lại trang là nó sẽ tạo một đối tượng mới

Tôi nghĩ mọi người nên chạy Demo thử nghiệm nó xem , để dễ hình dùng ra!

Github:ADD SERVICE IN ASP CORE 2.1