Building Soccer microservice on .Net Core, Entity Framework, Mysql, Insomnia, with Swagger, Auto-mapper, OData, etc.
Introduction
In this article we will show you how to create a webApi and build a CRUD with a mysql database, from inserting data, handling files and using VSC with some extensions. I hope I can help.
Requirements before starting · Download sdk .net core 3.1 https://dotnet.microsoft.com/download/dotnet/3.1. · Visual Studio Code https://code.visualstudio.com/download · Mysql https://www.mysql.com/ · Workbench or DBeaver (databases administrator). · Postman or Insomnia (I always use Insomnia). · Database:
CREATE DATABASE `soccernetcore`;
CREATE TABLE `player` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(100) DEFAULT NULL,
`LastName` varchar(100) DEFAULT NULL,
`Country` varchar(100) DEFAULT NULL,
`Logo` varchar(200) DEFAULT NULL,
`LogoNameUniq` varchar(200) DEFAULT NULL,
`TeamId` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`),
KEY `player_FK` (`TeamId`),
CONSTRAINT `player_FK`
FOREIGN KEY (`TeamId`)
REFERENCES `team` (`Id`)
)
ENGINE=InnoDB AUTO_INCREMENT=57 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `team` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(100) DEFAULT NULL,
`Country` varchar(50) DEFAULT NULL,
`Logo` varchar(100) DEFAULT NULL,
PRIMARY KEY (`Id`)
)
ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
The main thing in this service is the loading of players with their photos.
Detail of the services in which we will be working on:
Project Folder Structure
Let´s go.
We write by console:
dotnet new webapi -o SoccerApi
We validate if everything went well with dotnet run or dotnet build (to compile).
dotnet run
The host is https://localhost:5001/WeatherForecast method Get. It has a WeatherForecastController by default.
Create folder Models
→Player.cs
public class Player
{
public int Id {get;set;}
public string Name {get;set;}
public string LastName {get;set;}
public string Logo {get;set;}
public string LogoNameUniq {get;set;}
public string Country {get;set;}
[ForeignKey("TeamId")]
public int TeamId {get;set;}
public virtual Team Team { get; set; }
}
→Team.cs
public class Team
{
public Team()
{
Players = new HashSet<Player>();
}
public int Id {get;set;}
public string Name {get;set;}
public string Country {get;set;}
public virtual ICollection<Player> Players { get; set; }
}
Create folder Repositories
→DependencyInjection.cs
public static class DependencyInjection
{
public static IServiceCollection AddRepository(this IServiceCollection services, IConfiguration configuration)
{
if (configuration.GetValue<bool>("UseInMemoryDatabase"))
{
services.AddDbContext<SoccerNetCoreDbContext>(options =>options.UseInMemoryDatabase("Test db"));
}else{
services.AddDbContext<SoccerNetCoreDbContext>(options => options.UseMySQL(Environment.GetEnvironmentVariable("ConnectionString") ?? configuration.GetConnectionString("DefaultConnection")));
}
services.AddScoped<ISoccerNetCoreDbContext>(provider => provider.GetService<ISoccerNetCoreDbContext>());
services.AddRepositories();
return services;
}
private static IServiceCollection AddRepositories(this IServiceCollection services)
{
services.AddTransient<IPlayerRepository, PlayerRepository>();
services.AddTransient<ITeamRepository, TeamRepository>();
return services;
}
}
→Create PlayerRepository.cs
namespace SoccerNetCore.Repository
{
public class PlayerRepository : IPlayerRepository
{
private readonly SoccerNetCoreDbContext _dbContext = null;
public PlayerRepository(SoccerNetCoreDbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(Player player)
{
_dbContext.Add(player);
_dbContext.SaveChanges();
}
public void Remove(Player player)
{
_dbContext.Remove(player);
_dbContext.SaveChanges();
}
public IEnumerable<Player> ListAll()
{
var players = _dbContext.Player.Include(c => c.Team).ToList();
return players.AsEnumerable();
}
public Player GetById(int id) => _dbContext.Player.Find(id);
public void Update(Player player, int playerId)
{
var players = _dbContext.Player.Find(playerId);
players.LastName = player.LastName;
players.Name = player.Name;
players.Country = player.Country;
player.TeamId = player.TeamId;
_dbContext.SaveChanges();
}
}
}
→Create IPlayerRepository.cs
namespace SoccerNetCore.Repository
{
public interface IPlayerRepository
{
void Add(Player player);
void Remove(Player player);
IEnumerable<Player> ListAll();
Player GetById(int id);
void Update(Player player, int playerId);
}
}
→Create TeamRepository.cs
public class TeamRepository : ITeamRepository
{
private readonly SoccerNetCoreDbContext _dbContext = null;
public TeamRepository(SoccerNetCoreDbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(Team team)
{
_dbContext.Add(team);
_dbContext.SaveChanges();
}
public IEnumerable<Team> ListAll() => _dbContext.Team.ToList();
public Team GetById(int id) => _dbContext.Team.Find(id);
}
→Create ITeamRepository.cs
public interface ITeamRepository
{
void Add(Team team);
IEnumerable<Team> ListAll();
Team GetById(int id);
}
Create folder Services
→DependencyInjection.cs
public static class DependencyInjection
{
public static IServiceCollection AddService(this IServiceCollection services)
{
services.AddTransient<IPlayerService, PlayerService>();
services.AddTransient<ITeamService, TeamService>();
return services;
}
}
→ Create IPlayerService.cs
public interface IPlayerService
{
List<Player> GetList();
Player Get(int id);
void Post(Player request, Stream file);
void Delete(int playerId);
void Update(int playerId, Player body);
}
→Create TeamService.cs
public class TeamService : ITeamService
{
private readonly ITeamRepository _teamRepository;
public TeamService(ITeamRepository teamRepository)
{
_teamRepository = teamRepository;
}
public List<Team> GetList()
{
return (List<Team>)_teamRepository.ListAll();
}
public Team Get(int TeamId)
{
return _teamRepository.GetById(TeamId);
}
public void Post(Team request)
{
_teamRepository.Add(request);
}
}
→ Create ITeamService.cs
public interface ITeamService
{
List<Team> GetList();
Team Get(int id);
void Post(Team request);
}
Create folder Context
→Create SoccerNetCoreDbContext.cs
public class SoccerNetCoreDbContext : DbContext, ISoccerNetCoreDbContext
{
private readonly IConfiguration _configuration;
public DbSet<Player> Player { get; set; }
public DbSet<Team> Team { get; set; }
public SoccerNetCoreDbContext(IConfiguration configuration) : base()
{
_configuration = configuration;
} public SoccerNetCoreDbContext(IConfiguration configuration, DbContextOptions<SoccerNetCoreDbContext> options) : base(options)
{
_configuration = configuration;
}
public SoccerNetCoreDbContext
(DbContextOptions<SoccerNetCoreDbContext> options) : base(options)
{}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); base.OnModelCreating(builder); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseMySQL("server=localhost;port=3306;user=root;password=;database=soccernetcore"); }
}
}
→ ISoccerNetCoreDbContext.
public interface ISoccerNetCoreDbContext
{
DbSet<Player> Player { get; set; }
DbSet<Team> Team { get; set; }
}
Add the services in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddDbContextCheck<SoccerNetCoreDbContext>();
services.SetupSwagger();
services.AddMappers();
services.AddRepository(Configuration);
services.AddODataConfiguration();
services.AddService();
services.AddControllers(options => options.EnableEndpointRouting = false).AddNewtonsoftJson(options =>options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseSwaggerConfig();
app.UseEndpoints(endpoints =>
{endpoints.MapControllers();});
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Filter().Expand().OrderBy().Count().MaxTop(null);routeBuilder.MapODataServiceRoute("odata", "odata", ODataConfiguration.GetEdmModel());
routeBuilder.EnableDependencyInjection();});
}
Add the controllers.
PlayersController.cs
[ApiController]
[Route("api/[controller]")]
public class PlayersController : ControllerBase
{
readonly IPlayerService _playerService;
private readonly IMapper _mapper;
public PlayersController(IPlayerService playersService, IMapper mapper)
{
_playerService = playersService;
_mapper = mapper;
}
//Decorator for Odata - For example: players?$filter=contains(name, 'Lionel')
[EnableQuery]
[HttpGet]
public ActionResult<IEnumerable<Player>> Get()
{
return _playerService.GetList();
}[HttpGet("{id}")]
public ActionResult<Player> Get(int id)
{
return _playerService.Get(id);
}[HttpPost]
public async Task<IActionResult> Post([FromForm] Player request, IFormFile FileLogo)
{
var bodyPlayer = _mapper.Map<Player>(request);
bodyPlayer.Logo = FileLogo.FileName;
var streamFile = new MemoryStream();
FileLogo.CopyTo(streamFile);
_playerService.Post(bodyPlayer, streamFile);
return Ok();
}[HttpDelete("{playerId}")]
public async Task<IActionResult> Delete([FromRoute] int playerId)
{
try
{
_playerService.Delete(playerId);
return Ok();
}
catch (System.Exception ex)
{
return BadRequest(ex.Message);
}
}[HttpPut("{playerId}")]public async Task<IActionResult> Put([FromRoute] int playerId, [FromForm] Player request)
{
try
{
var bodyPlayer = _mapper.Map<Player>(request);
_playerService.Update(playerId, bodyPlayer);
return Ok();
}
catch (System.Exception ex)
{
return BadRequest(ex.Message);
}
}
}
TeamsController.cs
[ApiController]
[Route("api/[controller]")]
public class TeamsController : ControllerBase
{
readonly ITeamService _teamService;
private readonly IMapper _mapper;
public TeamsController(IMapper mapper, ITeamService teamService)
{
_teamService = teamService;
_mapper = mapper;
}[EnableQuery]
[HttpGet]
public ActionResult<IEnumerable<Team>> Get()
{
return _teamService.GetList();
}[HttpGet("{id}")]
public ActionResult<Team> Get(int id)
{
return _teamService.Get(id);
}[HttpPost]
public async Task<IActionResult> Post([FromForm] Team request)
{
var team = _mapper.Map<Team>(request);
_teamService.Post(team);
return Ok();
}
Test and Run Soccer microservice
We are about to Test and Run Soccer Microservice. Now the Soccer microservice Web API application is ready to run.
To access swagger https://localhost:5001/swagger/index.html
Sources: Medium - Agustinafassina
The Tech Platform
Comments