ASP.NET Core 3.1 Web API and Swagger

Introduction

ASP.NET Web API and ASP.NET MVC previously had separate types and setups, but the Web API from ASP.NET Core is the same as the one from ASP.NET Core MVC. The Web API offers a simple communication way based on Representational State Transfer (REST). With REST, HTTP verbs such as GET, POST, PUT, and DELETE is used. GET is used to retrieve resources, POST is used to add new resources, PUT is used to update resources, and DELETE is used to delete resources.

Building Services

Using .NET Core, you need to start with an ASP.NET Core Web Application and select the Web API in the following dialog. This template adds folders and references needed with the Web API. The directory structure that is created with this template contains folders that are needed for creating the services. The Controllers directory contains the Web API controllers, Web API, and ASP.NET Core MVC makes use of the same infrastructure.

ASP.NET Core 3.1 Web API And Swagger

Section 1

Create a PlaceInfo datatable in MSSQL. Also, it creates a class PlaceInfo in the model folder.

PlaceInfo Table Structure

CREATE TABLE [dbo].[PlaceInfo](  
    [Id] [int] IDENTITY(1,1) NOT NULL,  
    [Place] [varchar](50) NOT NULL,  
    [About] [varchar](300) NOT NULL,  
    [City] [varchar](20) NOT NULL,  
    [State] [varchar](20) NOT NULL,  
    [Country] [varchar](20) NOT NULL,  
 CONSTRAINT [PK_PlaceInfo] PRIMARY KEY CLUSTERED   
(  
    [Id] ASC  
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,   
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  

PlaceInfo Class

public class PlaceInfo  
{  
    public int Id { get; set; }  
    [Required]  
    public string Place { get; set; }  
    [Required]  
    public string About { get; set; }  
    [Required]  
    public string City { get; set; }  
    [Required]  
    public string State { get; set; }  
    [Required]  
    public string Country { get; set; }  
}

Create a Services folder in project and add two classes, one is for interface IPlaceInfoService and add method in interface Add(),AddRange(),GetAll(),Find(),Remove() & Update(). Second create PlaceInfoService class is derived from IPlaceInfoService interface. This defines the body of all interface methods, Add(), AddRange(), GetAll(), Find(), Remove() & Update() in PlaceInfoService class. 

public interface IPlaceInfoService  
{  
    int Add(PlaceInfo placeInfo);  
    int AddRange(IEnumerable<PlaceInfo> places);  
    IEnumerable<PlaceInfo> GetAll();  
    PlaceInfo Find(int id);  
    int Remove(int id);  
    int Update(PlaceInfo placeInfo);  
}  
  
public class PlaceInfoService : IPlaceInfoService  
{  
    public int Add(PlaceInfo placeInfo)  
    {  
        string sQry = "INSERT INTO [PlaceInfo] ([Place],[About],[City],[State],[Country]) " +  
            "VALUES('" + placeInfo.Place + "','" + placeInfo.About + "','" + placeInfo.City + "','" +   
            placeInfo.State + "','" + placeInfo.Country + "')";  
        int retVal=ExecuteCRUDByQuery(sQry);  
        return retVal;  
    }  
  
    public int AddRange(IEnumerable<PlaceInfo> places)  
    {  
        string sQry = "INSERT INTO [PlaceInfo] ([Place],[About],[City],[State],[Country]) VALUES";  
        string sVal = "";  
        foreach(var place in places)              
          sVal+= "('" + place.Place + "','" + place.About + "','" + place.City + "','" + place.State + "','" + place.Country + "'),";  
        sVal = sVal.TrimEnd(',');  
        sQry = sQry + sVal;  
        int retVal=ExecuteCRUDByQuery(sQry);  
        return retVal;  
    }  
  
    public PlaceInfo Find(int id)  
    {  
        PlaceInfo placeInfo = null;  
        string sQry = "SELECT * FROM [PlaceInfo] WHERE [Id]="+id;  
        DataTable dtPlaceInfo = ExecuteQuery(sQry);  
        if (dtPlaceInfo != null)  
        {  
            DataRow dr = dtPlaceInfo.Rows[0];  
            placeInfo = GetPlaceInfoByRow(dr);  
        }  
        return placeInfo;  
    }  
  
    public IEnumerable<PlaceInfo> GetAll()  
    {  
        List<PlaceInfo> placeInfos = null;  
        string sQry = "SELECT * FROM [PlaceInfo]";  
        DataTable dtPlaceInfo = ExecuteQuery(sQry);             
        if (dtPlaceInfo != null)  
        {  
            placeInfos = new List<PlaceInfo>();  
            foreach (DataRow dr in dtPlaceInfo.Rows)  
              placeInfos.Add(GetPlaceInfoByRow(dr));  
        }  
        return placeInfos;  
    }  
  
    public int Remove(int id)  
    {  
        string sQry = "DELETE FROM [PlaceInfo] WHERE [Id]=" + id;  
        int retVal=ExecuteCRUDByQuery(sQry);  
        return retVal;  
    }  
  
    public int Update(PlaceInfo placeInfo)  
    {  
        string sQry = "UPDATE [PlaceInfo] SET [Place]='" + placeInfo.Place + "',[About]='" + placeInfo.About + "',[City]='" + placeInfo.City + "',[State]='" + placeInfo.State + "',[Country]='" + placeInfo.Country + "' WHERE [Id]=" + placeInfo.Id;  
        int retVal=ExecuteCRUDByQuery(sQry);  
        return retVal;              
    }  
   // code detail is below  
    private int ExecuteCRUDByQuery(string strSql){  }  
    private DataTable ExecuteQuery(string strSql){  }  
    private PlaceInfo GetPlaceInfoByRow(DataRow dr){  }  
  
}

Created three private functions which are named ExecuteCRUDByQuery,ExecuteQuery and GetPlaceInfoByRow. All three functions are used to communicate with theSQL database server. The first function ExecuteCRUDByQuery is used to insert, update and delete record in datatable by passing SQL query. The second function ExecuteQuery is used to get records from datatable by passing sql query. Function GetPlaceInfoByRow is used to get records from datarow to PlaceInfo model class.

private int ExecuteCRUDByQuery(string strSql)  
{  
    string sConStr = "Data Source=.\\SQLExpress;Initial Catalog=YourDB;Integrated Security=True";  
    SqlConnection conn = null;  
    int iR = 0;  
    try  
    {  
        conn = new SqlConnection(sConStr);  
        SqlCommand cmd = new SqlCommand(strSql, conn);  
        cmd.CommandType = CommandType.Text;  
        conn.Open();  
        //Execute the command  
        iR = cmd.ExecuteNonQuery();  
    }  
    catch { iR = 0; }  
    finally { if (conn.State != 0) conn.Close(); }  
    return iR;  
}  
  
private DataTable ExecuteQuery(string strSql)  
{  
    string sConStr = "Data Source=.\\SQLExpress;Initial Catalog=YourDB;Integrated Security=True";  
    SqlConnection conn = null;  
    DataTable dt = null;  
    try  
    {  
        conn = new SqlConnection(sConStr);                  
        SqlCommand cmd = new SqlCommand(strSql,conn);  
        cmd.CommandType = CommandType.Text;  
        SqlDataAdapter da = new SqlDataAdapter(cmd);  
        conn.Open();  
        dt = new DataTable();  
        //Fill the dataset  
        da.Fill(dt);  
        if (!(dt.Rows.Count > 0)) dt = null;  
    }  
    catch { dt = null;  }  
    finally { if (conn.State != 0) conn.Close(); }  
    return dt;  
}  
  
private PlaceInfo GetPlaceInfoByRow(DataRow dr)  
{  
    PlaceInfo placeInfo = new PlaceInfo();  
    placeInfo.Id = Convert.ToInt32(dr["Id"]);  
    placeInfo.Place = dr["Place"].ToString();  
    placeInfo.About = dr["About"].ToString();  
    placeInfo.City = dr["City"].ToString();  
    placeInfo.State = dr["State"].ToString();  
    placeInfo.Country = dr["Country"].ToString();  
    return placeInfo;  
}

Section 2

Section 2 is the controller code part. Add PlaceInfoController class in Controller folder. Add an attribute on top of class [ApiController], [Route("api/[controller]")]. Also, pass IPlaceInfoService in PlaceInfoController constructors. Create an API method GetPlaceInfos(), GetPlaceInfoById(), PostPlaceInfo(), PutPlaceInfo() & Delete() in PlaceInfoController.The API method returns a response as per the request called by user.

[ApiController]  
[Route("api/[controller]")]  
public class PlaceInfoController : ControllerBase  
{  
    private readonly IPlaceInfoService _placeInfoService;  
    public PlaceInfoController(IPlaceInfoService placeInfoService)  
    {  
        _placeInfoService = placeInfoService;  
    }  
    // GET api/placeinfo  
    [HttpGet]  
    public IEnumerable<PlaceInfo> GetPlaceInfos() =>_placeInfoService.GetAll();  
  
    // GET api/placeinfo/id  
    [HttpGet("{id}", Name = nameof(GetPlaceInfoById))]  
    public IActionResult GetPlaceInfoById(int id)  
    {  
        PlaceInfo placeInfo = _placeInfoService.Find(id);  
        if (placeInfo == null)   
            return NotFound();   
        else   
            return new ObjectResult(placeInfo);  
    }  
  
    // POST api/placeinfo  
    [HttpPost]  
    public IActionResult PostPlaceInfo([FromBody]PlaceInfo placeinfo)  
    {  
        if (placeinfo == null) return BadRequest();              
        int retVal=_placeInfoService.Add(placeinfo);              
        if (retVal > 0) return Ok(); else return NotFound();  
    }  
    // PUT api/placeinfo/guid  
    [HttpPut("{id}")]  
    public IActionResult PutPlaceInfo(int id,[FromBody] PlaceInfo placeinfo)  
    {  
        if (placeinfo == null || id != placeinfo.Id) return BadRequest();  
        if (_placeInfoService.Find(id) == null) return NotFound();  
        int retVal = _placeInfoService.Update(placeinfo);  
        if (retVal > 0) return Ok(); else return NotFound();              
    }  
  
    // DELETE api/placeinfo/5  
    [HttpDelete("{id}")]  
    public IActionResult Delete(int id)  
    {  
        int retVal=_placeInfoService.Remove(id);  
        if (retVal > 0) return Ok(); else return NotFound();  
    }  
}

Section 3

Section 3 is the Swagger part. For adding Swagger or OpenAPI to an ASP.NET Web API service, you can use Swashbuckle. The NuGet package Swashbuckle.AspNetCore is the library for ASP.NET Core. After you add the NuGet package, you need to add Swagger to the DI container. AddSwaggerGen is an extension method to add swagger services to the collection. To configure Swagger, you invoke the method SwaggerDoc. Passing an Info object, you can define the title, description, contact information, and more in code file Startup.cs.

ASP.NET Core 3.1 Web API And Swagger

Next open Startup.cs class and edit function ConfigureServices. Call AddSingleton from services object. Then pass interface IPlaceInfoService and class PlaceInfoService in the method. Next, Add Swagger info object to show small documentation for the API.

Next, edit the function Configure and add two method line for Swagger gui interface. These methods are app.UseSwagger() and app.UseSwaggerUi() pass SwaggerEndpoint(service_url,service_name) info. 

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddControllers();  
    services.AddSingleton<IPlaceInfoService, PlaceInfoService>();  
    services.AddSwaggerGen(options =>  
    {  
        options.SwaggerDoc("v2", new Microsoft.OpenApi.Models.OpenApiInfo  
        {  
            Title = "Place Info Service API",  
            Version = "v2",  
            Description = "Sample service for Learner",  
        });  
    });  
}  
  
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
    if (env.IsDevelopment()) app.UseDeveloperExceptionPage();  
    app.UseHttpsRedirection();  
    app.UseRouting();  
    app.UseAuthorization();  
    app.UseEndpoints(endpoints =>{endpoints.MapControllers();});  
    app.UseSwagger();  
    app.UseSwaggerUI(options =>options.SwaggerEndpoint("/swagger/v2/swagger.json", "PlaceInfo Services"));  
}

The extension method UseSwagger adds Swagger middleware and specifies that a JSON schema file should be generated. The default URI that you can configure with UseSwagger is /swagger/{version}/swagger.json. With the document configured in the previous code snippet, the URL is /swagger/v1/swagger.json. The method UseSwaggerUi enables the graphical user interface for Swagger and defines the URL in code file Startup.cs.

Finally, the update key launchUrl in launchsettings.json file. Key-value is "swagger", then build and run the Web API project.

{  
  "$schema": "http://json.schemastore.org/launchsettings.json",  
  "iisSettings": {  
    "windowsAuthentication": false,  
    "anonymousAuthentication": true,  
    "iisExpress": {  
      "applicationUrl": "http://localhost:60696",  
      "sslPort": 44320  
    }  
  },  
  "profiles": {  
    "IIS Express": {  
      "commandName": "IISExpress",  
      "launchBrowser": true,  
      "launchUrl": "swagger",  
      "environmentVariables": {  
        "ASPNETCORE_ENVIRONMENT": "Development"  
      }  
    },  
    "TestWebApi": {  
        "commandName": "Project",  
        "launchBrowser": true,  
        "launchUrl": "swagger",  
        "applicationUrl": "https://localhost:5001;http://localhost:5000",  
        "environmentVariables": {  
            "ASPNETCORE_ENVIRONMENT": "Development"  
        }  
    }  
  }  
}

Output

ASP.NET Core 3.1 Web API And Swagger

Conclusion

This article shows and explains to beginners how to create a Web API in ASP.NET Core and use Swagger. Swagger is a GUI interface to communicate with a Web API. Check a Youtube video of the tutorial to understand more about creating a Web API and using Swagger.