You are on page 1of 33

Building Product Management

Application Using ASP.NET Core Web


API

Introduction
Your manager has asked you to develop an application for simple
employee management. The relationship between project and employee is
One-to-Many, one employee is belong to one project, one project will have
zero or many employee. The application has to support adding, viewing,
modifying, and removing employee - a standardized usage action verbs
better known as Create, Read, Update, Delete (CRUD).

This lab explores creating an application using ASP.NET Core Web API to
create RESTful API, and ASP.NET Core Web Application with Model-View-
Controller. A SQL Server Database will be created to persist the product
data that will be used for reading and managing employee data by Entity
Framework Core.

1|Page
Lab Objectives
In this lab, you will:
 Use the Visual Studio.NET to create ASP.NET Core Web Web API
Project.
 Develop Web application using MVC Pattern.
 Use Entity Framework to create a SQL Server database (Forward
Engineering Approach).
 Develop Entity classes, DBContext class, DAO class to perform
CRUD actions using Entity Framework Core.
 Apply Repository pattern to develop application.
 Run the project and test the application actions.

2|Page
Guidelines
Create a Blank Solution
Step 01. Create a Solution named Lab01_ASP.NETCoreWebAPI..

3|Page
Activity 01: Identify entities

4|Page
Diagram
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Entities.Exceptions.NotFoundException">
<Position X="4.5" Y="2.5" Width="1.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Exceptions\NotFoundException.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Entities.Exceptions.EmployeeNotFoundException">
<Position X="7" Y="3.5" Width="2.25" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Exceptions\EmployeeNotFoundException.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Entities.Exceptions.ProjectNotFoundException">
<Position X="7" Y="1.75" Width="2.25" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Exceptions\ProjectNotFoundException.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="System.Exception">
<Position X="2" Y="0.75" Width="2" />
<TypeIdentifier />
<Lollipop Position="0.2" />
</Class>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

Step 2 Employee Not found error


public sealed class EmployeeNotFoundException : NotFoundException
{
public EmployeeNotFoundException(Guid id)
: base($"The employee with {id} doesn't exists.")
{

}
}

Step 3- Project not found


public sealed class ProjectNotFoundException : NotFoundException
{
public ProjectNotFoundException(Guid projectId)
: base($"The project with {projectId} doesn't exists.")
{
}
}

Step 4 = Employee Model

5|Page
Step 5 = Project Model

6|Page
Activity 02: Contracts Project - Interface
Step 01. Create Class Library Project named Contracts Objects
Add dependence: Add Project reference Entity

Step 02. Create interface as


public interface IEmployeeRepository
{
IEnumerable<Employee> GetEmployeesByProjectId(Guid projectId, bool trackChanges);
Employee GetEmployeeByProjectId(Guid projectId, Guid id, bool trackChanges);

void CreateEmployeeForProject(Guid projectId, Employee employee);


void DeleteEmployee(Employee employee);
}

public interface ILoggerManager

7|Page
{
void LogInfo(string message);
void LogWarn(string message);
void LogDebug(string message);
void LogError(string message);
}

public interface IProjectRepository


{
IEnumerable<Project> GetAllProjects(bool trackChanges);
Project GetOneProjectById(Guid id, bool trackChanges);

void CreateProject(Project project);


void DeleteProject(Project project);
}

public interface IRepositoryBase<T> where T : class


{
IQueryable<T> FindAll(bool trackChanges);
IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression, bool trackChanges);
void Create(T entity);
void Update(T entity);
void Delete(T entity);
}

public interface IRepositoryManager


{
IProjectRepository Project { get; }
IEmployeeRepository Employee { get; }
void Save();
}

Activity 03: Logger class project


Add dependence: Add Project reference Contracts
namespace LoggerService
{
public class LoggerManager : ILoggerManager
{
private static ILogger logger = LogManager.GetCurrentClassLogger();
public LoggerManager()
{

public void LogDebug(string message) => logger.Debug(message);

public void LogError(string message) => logger.Error(message);

public void LogInfo(string message) => logger.Info(message);

public void LogWarn(string message) => logger.Warn(message);

}
}

8|Page
Activity 04: Class Library Repositories Project - create
an abstraction layer between the Data Access Layer
and the Business Logic Layer of the application
Step 01. Create Class Library Project named Repositories
Step 02. Add Project reference: Contracts, Entity
Step 03. Create config for entity
namespace Repository.Config
{
public class EmployeeConfig : IEntityTypeConfiguration<Employee>
{
public void Configure(EntityTypeBuilder<Employee> builder)
{
builder.HasData(
new Employee()
{
Id = new Guid("bc1ae16a-3572-40de-bd02-dab970697d20"),
ProjectId = new Guid("b67e3d43-23ef-444f-a022-5294810a5428"),
FirstName = "Ahmet",
LastName = "Yıldırım",
Age = 30,
Position = "Senior Developer"
}
);
}
}
}

namespace Repository.Config
{
public class ProjectConfig : IEntityTypeConfiguration<Project>
{
public void Configure(EntityTypeBuilder<Project> builder)
{
builder.HasData(
new Project
{
Id = new Guid("b67e3d43-23ef-444f-a022-5294810a5428"),
Name = "ASP.NET Core Web API Project",
Description = "Web Application Programming Interface",
Field = "Computer Science"
});
}
}
}

Step 04: Create RepositoryBase


public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected RepositoryContext _repositoryContext;

9|Page
protected RepositoryBase(RepositoryContext repositoryContext)
{
_repositoryContext = repositoryContext;
}

public void Create(T entity) => _repositoryContext.Set<T>().Add(entity);


public void Delete(T entity) => _repositoryContext.Set<T>().Remove(entity);

public IQueryable<T> FindAll(bool trackChanges) =>


!trackChanges ?
_repositoryContext.Set<T>().AsNoTracking() :
_repositoryContext.Set<T>();

public IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression, bool trackChanges) =>


!trackChanges ?
_repositoryContext.Set<T>().Where(expression).AsNoTracking() :
_repositoryContext.Set<T>();

public void Update(T entity) => _repositoryContext.Set<T>().Update(entity);

Step 05: Create Repository Context


public class RepositoryContext : DbContext
{
public RepositoryContext(DbContextOptions options) : base(options)
{

protected override void OnModelCreating(ModelBuilder modelBuilder)


{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}

public DbSet<Project> Projects { get; set; }


public DbSet<Employee> Employees { get; set; }
}

Step 05: Create Repository Manager


public class RepositoryManager : IRepositoryManager
{
private readonly RepositoryContext _context;
private Lazy<IProjectRepository> _projectRepository;
private Lazy<IEmployeeRepository> _employeeRepository;

public RepositoryManager(RepositoryContext context)


{
_context = context;

_projectRepository =
new Lazy<IProjectRepository>(() => new ProjectRepository(_context));

10 | P a g e
_employeeRepository =
new Lazy<IEmployeeRepository>(() => new EmployeeRepository(_context));
}

public IProjectRepository Project => _projectRepository.Value;


public IEmployeeRepository Employee => _employeeRepository.Value;

public void Save()


{
_context.SaveChanges();
}
}

Step 06: Create EmployeeRepository & ProjectRepository

public class EmployeeRepository : RepositoryBase<Employee>, IEmployeeRepository


{
public EmployeeRepository(RepositoryContext repositoryContext) : base(repositoryContext)
{
}

public void CreateEmployeeForProject(Guid projectId, Employee employee)


{
employee.ProjectId = projectId;
Create(employee);
}

public void DeleteEmployee(Employee employee)


{
Delete(employee);
}

public Employee GetEmployeeByProjectId(Guid projectId, Guid id, bool trackChanges) =>


FindByCondition(e => e.ProjectId.Equals(projectId) && e.Id.Equals(id), trackChanges)
.SingleOrDefault();

public IEnumerable<Employee> GetEmployeesByProjectId(Guid projectId, bool trackChanges) =>


FindByCondition(e => e.ProjectId.Equals(projectId), trackChanges)
.OrderBy(e => e.FirstName)
.ToList();

///
public class ProjectRepository : RepositoryBase<Project>, IProjectRepository
{
public ProjectRepository(RepositoryContext repositoryContext) : base(repositoryContext)
{
}

public void CreateProject(Project project) => Create(project);

public void DeleteProject(Project project) => Delete(project);

11 | P a g e
public IEnumerable<Project> GetAllProjects(bool trackChanges) =>
FindAll(trackChanges)
.OrderBy(p => p.Name)
.ToList();

public Project GetOneProjectById(Guid id, bool trackChanges) =>


FindByCondition(p => p.Id.Equals(id), trackChanges)
.SingleOrDefault();

Activity 05: Create Share library Project


Create EmployeeDto
public record EmployeeDto(Guid Id, string FirstName, string LastName, int Age, string Position);

DTO for create

namespace Shared.DataTransferObjects
{
public record EmployeeDtoForCreation(string FirstName, string LastName, int Age, string Position);

Project DOT

namespace Shared.DataTransferObjects
{
public record ProjectDto
{
public Guid Id { get; init; }
public string Name { get; init; }
public string Description { get; init; }
public string Field { get; init; }
};

DTO for create

namespace Shared.DataTransferObjects
{
public record ProjectDtoForCreation(string Name, string Description, string Field);

Activity 06: Create Service.Contracts library Project


Step 01. Add Project reference: Shared, Entity
Step 02. Add Interface
public interface IEmployeeService
{

12 | P a g e
IEnumerable<EmployeeDto> GetAllEmployeesByProjectId(Guid projectId, bool trackChanges);
EmployeeDto GetOneEmployeeByProjectId(Guid projectId, Guid employeeId, bool trackChanges);
EmployeeDto CreateOneEmployeeByProjectId(Guid projectId, EmployeeDtoForCreation employeeDto, bool
trackChanges);
}

Step 03. Add Interface


public interface IProjectService
{
IEnumerable<ProjectDto> GetAllProjects(bool trackChanges);
ProjectDto GetOneProjectById(Guid id, bool trackChanges);
ProjectDto CreateOneProject(ProjectDtoForCreation projectDto);
}
Step 04. Add Interface
namespace Service.Contracts
{
public interface IServiceManager
{
IProjectService ProjectService { get; }
IEmployeeService EmployeeService { get; }
}
}

Activity 07: Create Service library Project


Step 01. Add Project reference: Contracts, Service.Contracts
Step 02. Add nurget packet & rebuild project

Step 03. Add EmployeeService class


public class EmployeeService : IEmployeeService
{
private readonly IRepositoryManager _repository;
private readonly ILoggerManager _logger;
private readonly IMapper _mapper;

public EmployeeService(IRepositoryManager repository,


ILoggerManager logger,
IMapper mapper)
{
_repository = repository;
_logger = logger;
_mapper = mapper;
}

public EmployeeDto CreateOneEmployeeByProjectId(Guid projectId,


EmployeeDtoForCreation employeeDto,
bool trackChanges)
{
// Project exists? | ProjectService (!)
var project = _repository.Project.GetOneProjectById(projectId, false);

13 | P a g e
if(project is null)
throw new ProjectNotFoundException(projectId);

// Dto -> Entity


var entity = _mapper.Map<Employee>(employeeDto);
entity.ProjectId = projectId;

// Save (EF)
_repository.Employee.CreateEmployeeForProject(projectId,entity);
_repository.Save();

return _mapper.Map<EmployeeDto>(entity);
}

public IEnumerable<EmployeeDto> GetAllEmployeesByProjectId(Guid projectId, bool trackChanges)


{
CheckProjectExists(projectId);

var employeeList = _repository.Employee


.GetEmployeesByProjectId(projectId, trackChanges);

var employeeDtos = _mapper.Map<IEnumerable<EmployeeDto>>(employeeList);


return employeeDtos;
}

public EmployeeDto GetOneEmployeeByProjectId(Guid projectId, Guid employeeId, bool trackChanges)


{
CheckProjectExists(projectId);

var employee = _repository.Employee.GetEmployeeByProjectId(projectId, employeeId, trackChanges);

if (employee is null)
throw new EmployeeNotFoundException(employeeId);

var employeeDto = _mapper.Map<EmployeeDto>(employee);

return employeeDto;
}

private void CheckProjectExists(Guid projectId)


{
var project = _repository.Project.GetOneProjectById(projectId, trackChanges: false);
if (project is null)
throw new ProjectNotFoundException(projectId);
}
}

Step 04. Add ProjectService class


public class ProjectService : IProjectService
{
private readonly IRepositoryManager _repository;
private readonly ILoggerManager _logger;
private readonly IMapper _mapper;

public ProjectService(IRepositoryManager repository,


ILoggerManager logger,
IMapper mapper)
{

14 | P a g e
_repository = repository;
_logger = logger;
_mapper = mapper;
}

public ProjectDto CreateOneProject(ProjectDtoForCreation projectDto)


{
// Dto -> Entity
var entity = _mapper.Map<Project>(projectDto);

// Repo -> Save


_repository.Project.CreateProject(entity);
_repository.Save();

// Entity -> Dto


return _mapper.Map<ProjectDto>(entity);
}

public IEnumerable<ProjectDto> GetAllProjects(bool trackChanges)


{
var projects = _repository.Project.GetAllProjects(trackChanges);
var projectDtos = _mapper.Map<IEnumerable<ProjectDto>>(projects);
return projectDtos;
}

public ProjectDto GetOneProjectById(Guid id, bool trackChanges)


{
var project = _repository.Project.GetOneProjectById(id, trackChanges);
if (project is null)
throw new ProjectNotFoundException(id);
var projectDto = _mapper.Map<ProjectDto>(project);
return projectDto;
}
}
Step 05. Add ServiceManager class
public class ServiceManager : IServiceManager
{
private readonly Lazy<IProjectService> _projectService;
private readonly Lazy<IEmployeeService> _employeeService;

public ServiceManager(IRepositoryManager repository,


ILoggerManager logger,
IMapper mapper)
{
_projectService =
new Lazy<IProjectService>(() => new ProjectService(repository, logger, mapper));

_employeeService =
new Lazy<IEmployeeService>(() => new EmployeeService(repository, logger, mapper));

public IProjectService ProjectService => _projectService.Value;


public IEmployeeService EmployeeService => _employeeService.Value;
}

15 | P a g e
Activity 08: Create ProjectManagement.Presentation
library Project
Step 01. Install the following packages from NuGet:

Add Project reference: Service.Contracts


Step 2: Add Controller for employee
amespace ProjectManagement.Presentation.Controllers
{
[ApiController]
[Route("api/projects/{projectId}/employees")]
public class EmployeesController : ControllerBase
{
private readonly IServiceManager _service;
public EmployeesController(IServiceManager service)
{
_service = service;
}

[HttpGet]
public IActionResult GetAllEmployeeByProjectId(Guid projectId)
{
var employeeList = _service
.EmployeeService
.GetAllEmployeesByProjectId(projectId, false);

return Ok(employeeList);
}

[HttpGet("{id:guid}", Name ="GetOneEmployeeByProjectIdAndId")]


public IActionResult GetOneEmployeeByProjectId(Guid projectId, Guid id)
{
var employee = _service
.EmployeeService
.GetOneEmployeeByProjectId(projectId, id, false);

return Ok(employee);
}

[HttpPost]
public IActionResult CreateOneEmployeeByProjectId(Guid projectId,
[FromBody] EmployeeDtoForCreation employeeDto)
{
EmployeeDto employee = _service
.EmployeeService
.CreateOneEmployeeByProjectId(projectId, employeeDto, true);

return CreatedAtRoute("GetOneEmployeeByProjectIdAndId",
new { projectId, id = employee.Id },
employee);

16 | P a g e
}

}
}

Step 03: Add Controller for Project entity


[ApiController]
[Route("api/projects")]
public class ProjectsController : ControllerBase
{
private readonly IServiceManager _service;

public ProjectsController(IServiceManager service)


{
_service = service;
}

[HttpGet]
public IActionResult GetAllProjects()
{
var projects = _service.ProjectService.GetAllProjects(false);
return Ok(projects);
}

[HttpGet("{id:guid}", Name ="ProjectById")]


public IActionResult GetOneProjectById(Guid id)
{
var project = _service.ProjectService.GetOneProjectById(id, false);
return Ok(project);
}

[HttpPost] // 201 : CREATED


public IActionResult CreateOneProject([FromBody] ProjectDtoForCreation projectDto)
{
var project = _service.ProjectService.CreateOneProject(projectDto);
return CreatedAtRoute("ProjectById", new { id = project.Id }, project);
}
}

Activity 09: ProjectManagement


Create ASP Core Web API
Step 01. Install the following packages from NuGet:

Add Project reference: Contracts, Entity, LoggerService,


ProjectManagement. Presentation,Respository, Service,Service.Contracts

17 | P a g e
Step 02: rebuild project
Step 03. Add Connection string (also add JSON appsettings.json file)
{"ConnectionStrings": {
"sqlConnection": "server =(local); database =
MSSQLLocalDB;uid=sa;pwd=123456;Trusted_Connection=True;Encrypt=False"
},

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

Step 04. Add Migration forder to create database code first


Class 20220422151923_CreateDb.cs
public partial class CreateDb : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Projects",
columns: table => new
{
ProjecId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(60)", maxLength: 60, nullable: false),
Description = table.Column<string>(type: "nvarchar(max)", nullable: true),
Field = table.Column<string>(type: "nvarchar(max)", nullable: true),
ImageUrl = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Projects", x => x.ProjecId);
});

migrationBuilder.CreateTable(
name: "Employees",
columns: table => new
{
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: false),
LastName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Age = table.Column<int>(type: "int", nullable: true),
Position = table.Column<string>(type: "nvarchar(max)", nullable: true),
ProjectId = table.Column<Guid>(type: "uniqueidentifier", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Employees", x => x.EmployeeId);
table.ForeignKey(
name: "FK_Employees_Projects_ProjectId",
column: x => x.ProjectId,
principalTable: "Projects",
principalColumn: "ProjecId",

18 | P a g e
onDelete: ReferentialAction.Cascade);
});

migrationBuilder.InsertData(
table: "Projects",
columns: new[] { "ProjecId", "Description", "Field", "ImageUrl", "Name" },
values: new object[] { new Guid("b67e3d43-23ef-444f-a022-5294810a5428"), "Web Application Programming
Interface", "Computer Science", null, "ASP.NET Core Web API Project" });

migrationBuilder.InsertData(
table: "Employees",
columns: new[] { "EmployeeId", "Age", "FirstName", "LastName", "Position", "ProjectId" },
values: new object[] { new Guid("bc1ae16a-3572-40de-bd02-dab970697d20"), 30, "Ahmet", "Yıldırım", "Senior
Developer", new Guid("b67e3d43-23ef-444f-a022-5294810a5428") });

migrationBuilder.CreateIndex(
name: "IX_Employees_ProjectId",
table: "Employees",
column: "ProjectId");
}

protected override void Down(MigrationBuilder migrationBuilder)


{
migrationBuilder.DropTable(
name: "Employees");

migrationBuilder.DropTable(
name: "Projects");
}
}

Class Initial Database: InitialDB


public partial class InitialDB : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{

protected override void Down(MigrationBuilder migrationBuilder)


{

}
}

Class RepositoryContextModelSnapshot
namespace ProjectManagement.Migrations
{
[DbContext(typeof(RepositoryContext))]
partial class RepositoryContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.0")

19 | P a g e
.HasAnnotation("Relational:MaxIdentifierLength", 128);

SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);

modelBuilder.Entity("Entities.Models.Employee", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("EmployeeId");

b.Property<int?>("Age")
.HasColumnType("int");

b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");

b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");

b.Property<string>("Position")
.HasColumnType("nvarchar(max)");

b.Property<Guid?>("ProjectId")
.IsRequired()
.HasColumnType("uniqueidentifier");

b.HasKey("Id");

b.HasIndex("ProjectId");

b.ToTable("Employees");

b.HasData(
new
{
Id = new Guid("bc1ae16a-3572-40de-bd02-dab970697d20"),
Age = 30,
FirstName = "Ahmet",
LastName = "Yıldırım",
Position = "Senior Developer",
ProjectId = new Guid("b67e3d43-23ef-444f-a022-5294810a5428")
});
});

modelBuilder.Entity("Entities.Models.Project", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("ProjecId");

b.Property<string>("Description")
.HasColumnType("nvarchar(max)");

b.Property<string>("Field")
.HasColumnType("nvarchar(max)");

20 | P a g e
b.Property<string>("ImageUrl")
.HasColumnType("nvarchar(max)");

b.Property<string>("Name")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("nvarchar(60)");

b.HasKey("Id");

b.ToTable("Projects");

b.HasData(
new
{
Id = new Guid("b67e3d43-23ef-444f-a022-5294810a5428"),
Description = "Web Application Programming Interface",
Field = "Computer Science",
Name = "ASP.NET Core Web API Project"
});
});

modelBuilder.Entity("Entities.Models.Employee", b =>
{
b.HasOne("Entities.Models.Project", "Project")
.WithMany("Employees")
.HasForeignKey("ProjectId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();

b.Navigation("Project");
});

modelBuilder.Entity("Entities.Models.Project", b =>
{
b.Navigation("Employees");
});
#pragma warning restore 612, 618
}
}

Step 05. Add-Migration and Update-Database


dotnet ef migrations add “InitialDB”
dotnet ef database update

Step 05. Create Folder Extensions


Create Class ExceptionMiddlewareExtensions
public static class ExceptionMiddlewareExtensions

21 | P a g e
{
public static void ConfigureExceptionHandler(this WebApplication app,
ILoggerManager logger)
{
app.UseExceptionHandler(appError =>
{
appError.Run(async context =>
{
context.Response.ContentType = "application/json";

var contextFeature = context.Features.Get<IExceptionHandlerFeature>();


if (contextFeature != null)
{
context.Response.StatusCode = contextFeature.Error switch
{
NotFoundException => StatusCodes.Status404NotFound,
_ => StatusCodes.Status500InternalServerError
};

logger.LogError("There is a problem : " + contextFeature.Error);

await context.Response.WriteAsync(new ErrorDetails


{
StatusCode = context.Response.StatusCode,
Message = contextFeature.Error.Message
}.ToString());
}
});
});
}
}

Create Class ServiceExtensions


public static class ServiceExtensions
{
public static void ConfigureCors(this IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
});
}

public static void ConfigureLoggerManager(this IServiceCollection services)


{
services.AddSingleton<ILoggerManager, LoggerManager>();
}

public static void ConfigureSqlContext(this IServiceCollection services,


IConfiguration configuration)
{
services.AddDbContext<RepositoryContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("sqlConnection"),
project => project.MigrationsAssembly("ProjectManagement"))

22 | P a g e
);
}

public static void ConfigureRepositoryManager(this IServiceCollection services) =>


services.AddScoped<IRepositoryManager, RepositoryManager>();

public static void ConfigureServiceManager(this IServiceCollection services) =>


services.AddScoped<IServiceManager, ServiceManager>();

public static IMvcBuilder AddCustomCSVFormatter(this IMvcBuilder builder) =>


builder.AddMvcOptions(config => config.OutputFormatters.Add(new CsvOutputFormatter()));

Step 06. Create internal_logs Folder & file internallog.txt in this


Step 07. Create Utilities Folder
Create class MappingProfile
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Project, ProjectDto>().ReverseMap();
CreateMap<ProjectDtoForCreation, Project>();

CreateMap<Employee, EmployeeDto>().ReverseMap();
CreateMap<EmployeeDtoForCreation, Employee>();
}
}

Create class CsvOutputFormatter

23 | P a g e
Step 07. Update Class Program.CS
var builder = WebApplication.CreateBuilder(args);

LogManager.LoadConfiguration(String.Concat(Directory.GetCurrentDirectory(), "/nlog.config"));

// Add services to the container.

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.ConfigureCors();
builder.Services.ConfigureLoggerManager();
builder.Services.ConfigureSqlContext(builder.Configuration);
builder.Services.ConfigureRepositoryManager();
builder.Services.ConfigureServiceManager();

builder.Services.AddAutoMapper(typeof(Program));

builder.Services.AddControllers(config =>
{
config.RespectBrowserAcceptHeader = true;
config.ReturnHttpNotAcceptable = true; // 406
})
.AddXmlDataContractSerializerFormatters()
.AddCustomCSVFormatter()

24 | P a g e
.AddApplicationPart(typeof(ProjectManagement.Presentation
.AssemblyReference).Assembly);

var app = builder.Build();

var logger = app.Services.GetRequiredService<ILoggerManager>();


app.ConfigureExceptionHandler(logger);

if (app.Environment.IsProduction())
app.UseHsts();

// Configure the HTTP request pipeline.


if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.UseCors("CorsPolicy");

app.Run();

25 | P a g e
26 | P a g e
Activity 05: Create ProductManagementAPI Project
(Work with ASP.NET Core Web API template)
Step 01. Create ASP.NET Core Web API Project named
ProductManagementAPI
Step 02. Add Project reference: Repository Project
Step 03. Add ApiController named ProductsControllers.cs

The detail of functions in ProductControllers (Web API).

27 | P a g e
Step 04. Test API project with OpenAPI or Postman

28 | P a g e
Activity 06: ASP.NET Core Web Application with
Model-View-Controller Project
Step 01. Create ASP.NET Core Web App (Model-View-Controller) named
ProductManagementWebClient
Step 02. Add Project reference: BusinessObjects Project (or create new
DTO classes)
Step 03. Create Controller to connect to ProductManagementAPI

29 | P a g e
The detail of functions in ProductController (Web App MVC).

30 | P a g e
Step 04. Create View

31 | P a g e
Step 05. Test the function of Web Client

32 | P a g e
Activity 07: Build and run Project. Test all CRUD
actions
Note: Choose the option for multiple startup projects.

33 | P a g e

You might also like