Web API in Asp.net Core 3.1

This is Web API tutorial using Asp.net Core 3.1 for beginners and professionals with some real-time examples.

If you are very new to asp.net core web API, please take a look at how to create basic asp.net code web API [Part-1]

What do I learn from this tutorial?

  • how to create web api using asp.net core 3.1 framework.
  • Creating different get methods, custom get methods other than default one.
  • how to create api controller methods and use route attribute.
  • creating database connection and reading, writing data to database.
  • creating dynamic object from database using drapper class.

Note: In this post I will explain the life cycle of web api call with get methods, so you know how to create an api using asp.net core 3.1 framework. (not covering other post, put and delete methods). you can check those examples here.

asp.net core web api

In this tutorial you learn how to create asp.net core Web API using asp.net core 3.1, like earlier version of Web API you will see many similarities and also learn many new things from asp.Net Core framework

In this example, we focus on Asp.net Core 3.1 framework and some new changes compare to earlier version

Asp.Net Core 3.1 Web API Controller

Here in example below I have created an API controller with two methods “Get” and “GetOrders”

Things to learn:

  • How to create new instance of ILogger and IQueryService using constructor dependency injection
    private readonly ILogger<OrderController> _logger;
    private readonly IQueryService _queryService;
    
    public OrderController(ILogger<OrderController> logger, IQueryService query)
    {
    _logger = logger;
    _queryService = query;
    }    
    
  • How default route is defined! you can have only one in each controller.
    [Route("")]
    [HttpGet]
    public IEnumerable<OrderItem> Get()
    {
    
    }
    
  • How to define a custom get method names (in Asp.net Core Web API) without any parameter like default get method.
    [Route("GetOrders")]
    [HttpGet]
    [ProducesResponseType(typeof(IEnumerable<Order>),(int)HttpStatusCode.OK)]
    public async Task<IActionResult> GetOrders()
    {
       return Ok(results);
    }
    

Here is the complete ApiController code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Net;

[ApiController]
[Route("[controller]")]    
public class OrderController : ControllerBase
{
        
    private readonly ILogger<OrderController> _logger;
    private readonly IQueryService _queryService;
    public OrderController(ILogger<OrderController> logger, IQueryService query)
    {
        _logger = logger;
        _queryService = query;
    }
    

    [Route("")]
    [HttpGet]
    public IEnumerable<OrderItem> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index =< new OrderItem
        {
            OrderDate = DateTime.Now.AddDays(index),
            ProductId = rng.Next(-20, 55),
                
        })
        .ToArray();
    }


    [Route("GetOrders")]
    [HttpGet]
    [ProducesResponseType(typeof(IEnumerable<Order>),(int)HttpStatusCode.OK)]
    public async Task<IActionResult> GetOrders()
    {               
        var orders = await _queryService.GetNewOrdersAsync();
              
        return Ok(orders);
    }	
	


	[HttpPost]
	public void Post([FromBody]string value)
	{

	}



	[HttpPut("{id}")]
	public void Put(int id, [FromBody]string value)
	{
	}



	[HttpDelete("{id}")]
	public void Delete(int id)
	{

	}	
}

Notice, in above controller I am calling the function from a service instance called _queryService , so now let's look at the "QueryService" class design

Service class design

We can create any number of services that we want to consume in Web API, as an example here we have created IQueryService interface and QueryService class.

You will also learn how to return strongly typed class object and dynamic object from database query.

Look at the code below, how to create DbConnection object using constructor dependency injection (DI).

private readonly DbConnection dbconfig;

public QueryService(IOptions<DbConnection> dbcon)
    {
        dbconfig = dbcon.Value;
    }

You need to install Dapper from Nuget package, Dapper provides many ready to use extension method, In this example "Dapper" will be used for creating dynamic object from database query, and the advantage of creating dynamic object is that you don’t have to make changes in your business object every time you make changes in database table or view. It will directly create object from SQL query

    connection.QueryAsync<dynamic>(@"SELECT * from tbProducts");

Here is the example of how your service class will look like!

using Dapper;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;
public interface IQueryService
{
Task GetNewOrders();
Task<IEnumerable<dynamic>> GetNewOrdersAsync(); }
public class QueryService : IQueryService
{
private readonly DbConnection dbconfig;
public QueryService(IOptions<DbConnection> dbcon)
{
dbconfig = dbcon.Value;
}
public Task GetNewOrders()
{ using (var connection = new SqlConnection(dbconfig.ConnectionString))
{
connection.Open();
// do whatever
connection.Close();
}
throw new NotImplementedException();
}
public async Task<IEnumerable<dynamic>> GetNewOrdersAsync()
{
using (var connection = new SqlConnection(dbconfig.ConnectionString))
{
connection.Open(); return await connection.QueryAsync<dynamic>(@"SELECT * from tbProducts");
 }
    }
}
api database connection information

Now create a class for loading database connection string related information from appsettings.json, we need to register this class in startup service class like example below.

services.Configure<DbConnection>(Configuration.GetSection("DbConnectionConfig"));

Notice, how the connection string (read only) property has been formed

public string ConnectionString
{
    get
    {
        return string.Format("Server={0};Database={1};User ID={2};Password={3};" +
        "Trusted_Connection=False;MultipleActiveResultSets=true;", ServerName, DatabaseName, UserName, Password);
    }
}

Here is the code for DbConnection class

public class DbConnection
{
    public string DatabaseName { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public string ServerName { get; set; }

    public string ConnectionString
    {
        get
        {
            return string.Format("Server={0};Database={1};User ID={2};Password={3};" +
            "Trusted_Connection=False;MultipleActiveResultSets=true;", ServerName, DatabaseName, UserName, Password);
        }
    }
}
Configure appSettings.json file

Now we add a new section in appsettings file, as you can see at the file below, we have added a new section called “DbConnectionConfig” with all database related information

    "DbConnectionConfig": {
    "DatabaseName": "FoodServiceDB",
    "UserName": "dbusername",
    "Password": "dbpassword",
    "ServerName": "ACMachine1\\SQLEXPRESS"
  },

We can create different section to classify configuration related information.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "DbConnectionConfig": {
    "DatabaseName": "FoodServiceDB",
    "UserName": "dbusername",
    "Password": "dbpassword",
    "ServerName": "ACMachine1\\SQLEXPRESS"
  },
  "AllowedHosts": "*"
}

If you are very new to appsettings.json, then you may be interested to know how to read information from appsettings.json

Create DbContext Class

Now we create a custom DbContext class inherited from DbContext AppContext:DbContext

Notice, how DbConnection object is created using constructor dependency injection.

private readonly DbConnection dbconfig;      
public AppContext(IOptions<DbConnection> dbcon)
{
    dbconfig = dbcon.Value;
}

You may need to install Microsoft.EntityFrameworkCore.SqlServer from Nuget package for using UseSqlServer function, UseSqlServer is the extension method

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
    {
        optionsBuilder.UseSqlServer(ConnectionString);
    }
    base.OnConfiguring(optionsBuilder);
}

Here is the code for your AppContext class

public class AppContext:DbContext
    {
        private readonly DbConnection dbconfig;
        public AppContext() : base()
        {
        }
       
        public AppContext(IOptions<DbConnection> dbcon)
        {
            dbconfig = dbcon.Value;
        }
 
       public  string ConnectionString
        {
            get
            {
                return dbconfig.ConnectionString;
            }
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer(ConnectionString);
            }
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //modelBuilder.Entity<Student>().HasKey(s => s.StuId);
            base.OnModelCreating(modelBuilder);
        }
        //public DbSet<Student> Orders { get; set; }
}
Add service in ConfigureServices method of Startup.cs

Now, we need make some changes in Startup.cs file; Configure DbConnection class and QueryService class in ConfigureServices method

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.Configure<DbConnection>(Configuration.GetSection("DbConnectionConfig"));
    services.AddScoped<IQueryService, QueryService>();
}
public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }


    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.Configure<DbConnection>(Configuration.GetSection("DbConnectionConfig"));
        services.AddScoped<IQueryService, QueryService>();
    }
}

This was a basic example of creating asp.net core web API on localhost, now we create an asp.net core web api with database methods including security and different serialization settings, exception handing etc.


 
Asp.Net Core 3.1 Web API Example
Learn Web API: creating API using C# .Net, post, update, delete, read using .net API, set security, check authentication, testing.

C# web service interview questions

Learn API development
Asp.Net C# Web API Examples | Join Asp.Net MVC Course