Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / .NET / .NET-Core

Web API in .NET Core

4.33/5 (4 votes)
19 Apr 2018CPOL4 min read 13.3K  
Web API using .NET-Core

Introduction

The .NET Core 2.0 is the latest framework provided by Microsoft. Today, we will learn how to create a simple web API using .NET Core.

Note: To understand this article, you must have knowledge of MVC architecture, old web API and entity framework. If you know all, just go for it.

Using the Code

The WEB API basic architecture is the same as that of the existing one. We are using same MVC framework for creating the web API. The things here are we will be seeing what new thing we need to perform to make WEB API work in .NET Core framework as well.

Initial Setup

We don't need any library to install to run the web API because .NET Core includes all the libraries by default. However, if you want to use any extra functionality, then we need to download the third party libraries from nuget package manager. In our application, we are using the below libraries. You can also include all into your project.

  1. Auto Mapper: for mapping the database entities into model classes
  2. Nlog: for logging into file

Dependencies

Startup.cs

The startup.cs is the starting point for the .NET Core application. Here, you will see two functions:

  1. ConfigureServices
  2. Configure

1. ConfigureServices

The configureServices method used to set the dependencies or services that are going to be used in our application. It uses IServiceCollection interface to define services inside our application.

In the below code, you will see that I have configured session using services.AddSession();. Apart from that, we are using AddMVC for the MVC architecture. Inside that, you will see AddJsonOption method. This method uses to set the default formatting and naming convention for your json members.

Example:

a. In the below code, I have set the NamingStrategy to null - that means whatever casing you are using for your model json member, the result will display in that format only. Like you named "id" in your model as "ID", then it will render the data as "ID". If you will remove this line, then result will choose default formatting that is camel case and result will render as "id" only.

C#
.AddJsonOptions(o =>
                   {
                       if (o.SerializerSettings.ContractResolver != null)
                       {
                           var resolver =
                                 o.SerializerSettings.ContractResolver as DefaultContractResolver;
                           resolver.NamingStrategy = null;
                       }
                   })
               .AddMvcOptions(o =>
               {
                   o.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
               });

b. We are using Addcors, which I'm using for cross origin resource sharing. If we are on two different domains, JavaScript or browser doesn't allow to hit the service because of security issues. So here, we are telling our application what it will allow cors. For more information on cors, please visit this link.

C#
services.AddCors();

2. Configure

The purpose of configure method is to configure the behaviour of the application. Here, we are configuring the exception behaviour, Session and routing in the application. In my application, I'm using attribute routing only.

Code

C#
public class Startup
   {
       // 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 https://go.microsoft.com/fwlink/?LinkID=398940
       public void ConfigureServices(IServiceCollection services)
       {
           //set default json formatter and output media type

           services.AddSession();
           services.AddMvc()
               .AddJsonOptions(o =>
                   {
                       if (o.SerializerSettings.ContractResolver != null)
                       {
                           var resolver = o.SerializerSettings.ContractResolver
                                                       as DefaultContractResolver;
                           resolver.NamingStrategy = null;
                       }
                   })
               .AddMvcOptions(o =>
               {
                   o.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
               });

           services.AddCors();
           //Services Injection DI
           services.AddScoped<IRepositoryDB, RepositoryDBContextAccess.RepositoryDB>();
           services.AddScoped<IErrorLog, ErrorLogDB>();

       }

       // This method gets called by the runtime. Use this method to configure
       // the HTTP request pipeline.
       public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
       {
           //Setting of project
           if (env.IsDevelopment())
           {
               app.UseDeveloperExceptionPage();
           }
           else
           {
               app.UseExceptionHandler(appBuilder =>
               {
                   appBuilder.Run(async context =>
                   {
                       context.Response.StatusCode = 500;
                       await context.Response.WriteAsync("Server is down, Try again later");
                   });

               });
           }

           //Status shown on UI
           app.UseStatusCodePages();
           app.UseSession();
           //Logging in debug mode and File
           log.AddDebug();
           log.AddNLog();

           app.UseCors(builder => {

               builder.AllowAnyOrigin();
               builder.AllowAnyHeader();
               builder.AllowAnyMethod();

           });

           //Automapper to map from entity to model
           AutoMapper.Mapper.Initialize(cfg =>
           {
               cfg.CreateMap<StudentEntity, StudentsModel>().ForMember
                (model => model.CourseCount, opt =>
                 opt.MapFrom(entity => entity.StudentCourses.Count()));

               cfg.CreateMap<CourseEntity, CourseModel>();

           });

           //Convention based routing
           app.UseMvc(routes =>
           {
               routes.MapRoute(
                   name: "default",
                   template: "{controller=student}/{action=GetAllStudents}/{id?}");
           });

       }
   }

Student Controller

We are creating the simple controller here named student controller. Check out the difference in the web API controller. I'm inheriting my controller from Controller instead of API controller. This is how .NET Core mix MVC and WebApi together. Interesting?

Constructor

The dependency injection is now inbuilt handle by .NET Core. Please check we are just passing the depend component inside the controller constructor and will use that in the application.

Note: To make your application better or unit testable, always use abstraction instead of concrete. Use interface instead of class to pass as dependency injection.

C#
//Constructor to inject services(DI)
     public StudentController(IRepositoryDB repository, ILogger<StudentController> log,
         IErrorLog logErrorDb)
     {
         repositoryObject = repository;
         logger = log;
         errorLogDB = logErrorDb;
     }

Methods

We are declaring two methods in our controller to get all the students and to get the courses of the student based on student id.

We are decorating our method using HttpGet verb. As we know, web APIs work on Http protocol. We have freedom to use all http verbs in our application like get, post, put, patch, delete, etc.

Inside HttpGet, I'm writing the attribute routing and it will tell the client where they need to visit to get the resources. So we will get all the students when we will hit our "www.domain.com/api/getStudents". Similar for the other method.

Inside our methods, we are using Automapper to map the DBResult with our MVC model classes. You already saw the mapping in startup.cs class above in this article. Please check again if you are not sure where it was.

Methods Code

C#
[HttpGet("api/getStudents")]
public IActionResult GetAllStudent()
{
    try
    {
        logger.LogInformation("Controller has been started");
        List<StudentsModel> list = new List<StudentsModel>();
        var result = repositoryObject.GetAllStudent();
        list = Mapper.Map<List<StudentsModel>>(result);
        HttpContext.Session.Set<List<StudentsModel>>("studentObject", list);
        return new JsonResult(list);
    }
    catch (Exception ex)
    {
        errorLogDB.InfoLog(ex.Message, (int)ErrorLogEnum.Error, ex.StackTrace.ToString());

        return null;
    }
    finally
    {
        logger.LogInformation("exception");
    }
}

[HttpGet("api/getStudents/{id}/getCourses")]
public IActionResult GetStudentCourses(int id)
{
    List<StudentsModel> sessionGet =
    HttpContext.Session.Get<List<StudentsModel>>("studentObject");
    List<CourseModel> list = new List<CourseModel>();
    var result = repositoryObject.GetStudentCourses(id);
    list = Mapper.Map<List<CourseModel>>(result);
    return new JsonResult(list);
}

I have created a session management class to handle the session by my own type. With the help of Isession interface, we can extend the functionality of session default behaviour. Please check the code below.

Session Management

To enhance the functionality of the session default behaviour.

C#
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FirstApplication
{
    public static class SessionManagement
    {

        public static void Set<T>(this ISession session, string key, T value)
        {
            session.SetString(key, JsonConvert.SerializeObject(value));
        }

        public static T Get<T>(this ISession session, string key)
        {
            var value = session.GetString(key);
            return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
        }

    }
}

In the exception, it is logging the exception inside the database. You can log in file and debug window. The choice is yours.

Code

C#
using AutoMapper;
using FirstApplication.DataSource;
using FirstApplication.Entities;
using FirstApplication.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FirstApplication.Controllers
{
    public class StudentController : Controller
    {
       
        private IRepositoryDB repositoryObject;
        private ILogger<StudentController> logger;
        private IErrorLog errorLogDB;        

        //Constructor to inject services(DI)
        public StudentController(IRepositoryDB repository, ILogger<StudentController> log,
            IErrorLog logErrorDb)
        {
            repositoryObject = repository;
            logger = log;
            errorLogDB = logErrorDb;
        }
        
        [HttpGet("api/getStudents")]
        public IActionResult GetAllStudent()
        {
            try
            {
                logger.LogInformation("Controller has been started");
                List<StudentsModel> list = new List<StudentsModel>();
                var result = repositoryObject.GetAllStudent();
                list = Mapper.Map<List<StudentsModel>>(result);
                HttpContext.Session.Set<List<StudentsModel>>("studentObject", list);
                return new JsonResult(list);
            }
            catch (Exception ex)
            {
                errorLogDB.InfoLog(ex.Message, (int)ErrorLogEnum.Error, ex.StackTrace.ToString());

                return null;
            }
            finally
            {
                logger.LogInformation("exception");
            }
        }
        
        [HttpGet("api/getStudents/{id}/getCourses")]
        public IActionResult GetStudentCourses(int id)
        {
            List<StudentsModel> sessionGet = 
            HttpContext.Session.Get<List<StudentsModel>>("studentObject");
            List<CourseModel> list = new List<CourseModel>();
            var result = repositoryObject.GetStudentCourses(id);
            list = Mapper.Map<List<CourseModel>>(result);
            return new JsonResult(list);
        }
    }
}

Model

We are having different models for the student and for the course entity as follows:

Student Model

C#
public class StudentsModel
  {
      public int Id { get; set; }
      public string Name { get; set; }
      public int CourseCount { get; set; }
      public string Address { get; set; }
      public List<CourseModel> StudentCourses { get; set; } = new List<CourseModel>();
  }

Course Model

C#
public class CourseModel
   {
       public int ID { get; set; }
       public string CourseName { get; set; }
       public string CourseDescription { get; set; }
   }

Database

Here, I'm using the entity framework code first approach. You can see the database entities that have created and Dbcontext as below:

To know more about the code first entity framework approach, visit this link.

Entities

StudentEntity

C#
public class StudentEntity
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public ICollection<CourseEntity> StudentCourses { get; set; }
    }

CourseEntity

C#
public class CourseEntity
   {
       [Key]
       public int ID { get; set; }
       public string CourseName { get; set; }
       public string CourseDescription { get; set; }
       StudentEntity student { get; set; }
       [JsonIgnore]
       public int StudentEntityId { get; set; }
   }

DBContext

DB context used to interact with database.

C#
public class StudentDBContext: DbContext
  {
      public StudentDBContext()
      {

      }

      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
          optionsBuilder.UseSqlServer(@"Connection string here like server name,db ");
      }
      public DbSet<StudentEntity> Students{get;set;}

      public DbSet<CourseEntity> Courses { get; set; }

      public DbSet<ErrorLogEntity> ErrorsLog { get; set; }
  }

Working Scenario

Get All Students

All Student Data

Get Student Courses

Image 3Courses

I hope you will like the article. Please let me know if you face any issues or need further help in creating web API.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)