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.
- Auto Mapper: for mapping the database entities into model classes
- Nlog: for logging into file
Startup.cs
The startup.cs is the starting point for the .NET Core application. Here, you will see two functions:
ConfigureServices
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.
.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.
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
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
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.AddScoped<IRepositoryDB, RepositoryDBContextAccess.RepositoryDB>();
services.AddScoped<IErrorLog, ErrorLogDB>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
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");
});
});
}
app.UseStatusCodePages();
app.UseSession();
log.AddDebug();
log.AddNLog();
app.UseCors(builder => {
builder.AllowAnyOrigin();
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<StudentEntity, StudentsModel>().ForMember
(model => model.CourseCount, opt =>
opt.MapFrom(entity => entity.StudentCourses.Count()));
cfg.CreateMap<CourseEntity, CourseModel>();
});
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.
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
[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.
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
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;
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
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
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
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
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.
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
Get Student Courses
I hope you will like the article. Please let me know if you face any issues or need further help in creating web API.