Microservice using ASP.NET Core
This section will demonstrate how to create a Product microservice using ASP.NET Core step by step with the help of pictures. The service would be built using ASP.NET Core 2.1 and Visual Studio 2017. Asp.NET Core comes integrated with VS 2017. This service will have its own DBcontext and database with the isolated repository so that the service could be deployed independently.
Creating an ASP.NET Core Application Solution
- Choose the application as ASP.NET Core Web App and press to Next and give it a meaningful name.
- press Next and and select .net 5.0 as target framework make sure that “Enable Docker Support” option is selected with OS type as windows.
- The solution will look as shown below.
Adding Models
- Add a new folder named “Model” to the project.
- Add a few properties like Id, Name, Description, Price to the product class. The product should also be of some kind and for that, a category model is defined and a CategoryId property is added to the product model.
- Similarly, add Category model.
Enabling EF Core
Though .NET Core API project has inbuilt support for EF Core and all the related dependencies are downloaded at the time of project creation and compilation that could be found under SDK section in the project as shown below.
Microsoft.EntityFrameworkCore.SqlServer (2.1.1) should be the package inside the downloaded SDK’s. If it is not present, it could be explicitly added to the project via Nuget Packages.
Adding EF Core DbContext
A database context is needed so that the models could interact with the database.
2. Add a new class named ProductContext which includes the DbSet properties for Products and Categories. OnModelCreating is a method via which the master data could be seeded to the database. So, add the OnModelCreating method and add some sample categories that will be added to the database initially into the category table when the database is created.
3- ProductContext code
using Microsoft.EntityFrameworkCore;
using ProductMicroservice.Models;
namespace ProductMicroservice.DBContexts
{
public class ProductContext : DbContext
{
public ProductContext(DbContextOptions<ProductContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category
{
Id = 1,
Name = "Electronics",
Description = "Electronic Items",
},
new Category
{
Id = 2,
Name = "Clothes",
Description = "Dresses",
},
new Category
{
Id = 3,
Name = "Grocery",
Description = "Grocery Items",
}
);
}
}
}
Add a connection string in the appsettings.json file.
"ConnectionStrings": {
"ProductsDBConString": "Data Source=192.168.1.102,1433; Database=ProductsDB; User ID=sa; Password=Helpdesk1111; MultipleActiveResultSets=true;Persist Security Info=True"
}
Here “ProductsDBConString” is ConnectionString name and it shall be any name you can give.
Data Source value is address of your SQL Server.
ProductsDB is the Database name (you can give any name in the first time you creating it. and the rest is self explanatory.
Adding ConnectionString name to Startup.cs class
Open the Startup.cs file to add the SQL server db provider ConnectionsString name,which you have added to the appsetting.joson for EF Core as following:
services.AddDbContext<ProductContext>(o => o.UseSqlServer(Configuration.GetConnectionString("ProductsDBConString")));
Adding Repository
Repository works as a micro component of microservice that encapsulates the data access layer and helps in data persistence and testability as well.
- Add a new folder named Repository in the project and add an Interface name IProductRepository in that folder. Add the methods in the interface that performs CRUD operations for Product microservice.
- Add a new concrete class named ProductRepository in the same Repository folder that implements IProductRepository. All these methods need:
- Add the implementation for the methods via accessing context methods.ProductRepository.cs
using Microsoft.EntityFrameworkCore; using ProductMicroservice.DBContexts; using ProductMicroservice.Models; using System; using System.Collections.Generic; using System.Linq; namespace ProductMicroservice.Repository { public class ProductRepository : IProductRepository { private readonly ProductContext _dbContext; public ProductRepository(ProductContext dbContext) { _dbContext = dbContext; } public void DeleteProduct(int productId) { var product = _dbContext.Products.Find(productId); _dbContext.Products.Remove(product); Save(); } public Product GetProductByID(int productId) { return _dbContext.Products.Find(productId); } public IEnumerable<Product> GetProducts() { return _dbContext.Products.ToList(); } public void InsertProduct(Product product) { _dbContext.Add(product); Save(); } public void Save() { _dbContext.SaveChanges(); } public void UpdateProduct(Product product) { _dbContext.Entry(product).State = EntityState.Modified; Save(); } } }
- Open the Startup class in the project and add the code as services.AddTransient<IProductRepository, ProductRepository>(); inside ConfigureServices method so that the repository’s dependency is resolved at a run time.
Adding Controller
The microservice should have an endpoint for which a controller is needed which exposes the HTTP methods to the client as endpoints of the service methods.
- A ProductController class will be added in the Controllers folder with default read/write actions that will be replaced later with product read/write actions and HTTP methods are created acting as an endpoint of the service.
- ValuesController can be deleted as it is not needed.
- Add implementation to the methods by calling the repository methods as shown below. The basic implementation is shown here for the sake of understanding the concept. The methods could be attribute routed and could be decorated with more annotations as per need.ProductController.cs
using Microsoft.AspNetCore.Mvc; using ProductMicroservice.Models; using ProductMicroservice.Repository; using System; using System.Collections.Generic; using System.Transactions; namespace ProductMicroservice.Controllers { [Route("api/[controller]")] [ApiController] public class ProductController : ControllerBase { private readonly IProductRepository _productRepository; public ProductController(IProductRepository productRepository) { _productRepository = productRepository; } [HttpGet] public IActionResult Get() { var products = _productRepository.GetProducts(); return new OkObjectResult(products); } [HttpGet("{id}", Name = "Get")] public IActionResult Get(int id) { var product = _productRepository.GetProductByID(id); return new OkObjectResult(product); } [HttpPost] public IActionResult Post([FromBody] Product product) { using (var scope = new TransactionScope()) { _productRepository.InsertProduct(product); scope.Complete(); return CreatedAtAction(nameof(Get), new { id = product.Id }, product); } } [HttpPut] public IActionResult Put([FromBody] Product product) { if (product != null) { using (var scope = new TransactionScope()) { _productRepository.UpdateProduct(product); scope.Complete(); return new OkResult(); } } return new NoContentResult(); } [HttpDelete("{id}")] public IActionResult Delete(int id) { _productRepository.DeleteProduct(id); return new OkResult(); } } }
Entity Framework Core Migrations
Migrations allow us to provide code to Create/change the database from our Models classes (in our case Category and Product). To do this we do the followings:
- Open Package Manager Console
- To enable the migration, type the command, Add-Migration and give a parameter with a meaningful name for e.g. InitialCreate and press enter.
- Once the command is executed, we see there’s a new Migrations folder under current project (in our case ProductMicroservice), and it contains two files. One, a snapshot of our current context model and the other is creating Database tables from the our Modules.. The files are very much self- explanatory. These files shows creation of tables in the database with name of our modules in project (Category and Product).
- To ensure that migrations are applied to the database there’s another command for that. It’s called the update-database If executed, the migrations will be applied to the current database. ProductsDB is name of Database from appsetting.json in the ConnectionString.
- When data of the Categories table is viewed the default master data of three categories is shown.
Run the Product Microservice to test it.
The service could be run via IIS Express i.e. Visual Studio default or via Docker container as well.
Via IIS Express
Choose IIS Express in the Visual Studio as shown below and press F5 or click that IIS Express button itself.
The application will be up once the browser page is launched. Since it has nothing to show, it will be blank, but the service could be tested via any API testing client. Here Postman is used to testing the service endpoints. Keep it opened and application running.
Install Postman if it is not on the machine and launch it.
To test the POST method; i.e. create a new resource, select the method as POST in postman and provide the endpoint, i.e. https://localhost:44312/api/product and in the Body section, add a JSON similar to having properties of Product model as shown below and click on Send.
The response is returned with the Id of the product as well.
The “Post” method of the controller is responsible to create a resource in the database and send the response.
The line return CreatedAtAction(nameof(Get), new { id=product.Id }, product); returns the location of the created resource that could be checked in Location attribute in the response under Headers tab.
Perform a select query on the product table and an added row is shown for the newly created product.
Create one more product in a similar way.
Perform a GET request now with the same address and two records are shown as a JSON result response.
Perform the delete request by selecting DELETE as the verb and appending id as 1 (if the product with id 1 needs to be deleted) and press Send.
In the database, one record with Id 1, deleted.
PUT verb is responsible for updating the resource. Select PUT verb, provide the API address and in the Body section, provide details of which product needs to be updated in JSON format. For example, update the product with Id 2 and update its name, description, and price from Samsung to iPhone specific. Press Send.
Check the database to see the updated product.
I have updated this project to .NET 5.00 and you can find the code in my Github.
Conclusion
A microservice is a service built around a specific business capability, which can be independently deployed which is called bounded context. This article on microservices focused on what microservices are and their advantages over monolithic services architecture. The article in detail described to develop a microservice using ASP.NET Core and run it via IIS.
I have even showed how to create a Database from the Modules, DbContext and creating ConnectionString in appsetting.json, by using EF Core commands: Add-Migration and Update-Database in the Package Manager Console command line.
In my Next post I am going describe how to document your Microservice with Swagger.
This post is part of “Microservices-Step by step”.