Implement unified API controller pattern
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
/packages/
|
/packages/
|
||||||
.blob
|
*.blob
|
||||||
.idea/
|
.idea/
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using EstusShots.Shared.Dto;
|
using EstusShots.Client.Routes;
|
||||||
|
using EstusShots.Shared.Interfaces;
|
||||||
using EstusShots.Shared.Models;
|
using EstusShots.Shared.Models;
|
||||||
|
|
||||||
namespace EstusShots.Client
|
namespace EstusShots.Client
|
||||||
@@ -13,49 +13,52 @@ namespace EstusShots.Client
|
|||||||
{
|
{
|
||||||
private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
|
private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true
|
||||||
};
|
};
|
||||||
|
|
||||||
private string ApiUrl { get; }
|
|
||||||
private HttpClient HttpClient { get; }
|
private HttpClient HttpClient { get; }
|
||||||
|
|
||||||
|
public string ApiUrl { get; }
|
||||||
|
|
||||||
|
// API Routes
|
||||||
|
public Seasons Seasons { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="EstusShotsClient"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiUrl">Base URL of the Estus Shots API host</param>
|
||||||
public EstusShotsClient(string apiUrl)
|
public EstusShotsClient(string apiUrl)
|
||||||
{
|
{
|
||||||
ApiUrl = apiUrl;
|
ApiUrl = apiUrl;
|
||||||
HttpClient = new HttpClient {Timeout = TimeSpan.FromSeconds(10)};
|
HttpClient = new HttpClient {Timeout = TimeSpan.FromSeconds(10)};
|
||||||
|
|
||||||
|
Seasons = new Seasons(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(OperationResult, List<Season>)> GetSeasons()
|
/// <summary>
|
||||||
|
/// Generic method to post a request to the API
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">URL to the desired action</param>
|
||||||
|
/// <param name="parameter">The API parameter object instance</param>
|
||||||
|
/// <typeparam name="TResult">API response class that implements <see cref="IApiResponse"/></typeparam>
|
||||||
|
/// <typeparam name="TParam">API parameter class that implements <see cref="IApiParameter"/></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResponse<TResult>> PostToApi<TResult, TParam>(string url, TParam parameter)
|
||||||
|
where TParam : IApiParameter, new()
|
||||||
|
where TResult : class, IApiResponse, new()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await HttpClient.GetAsync(ApiUrl + "seasons");
|
var serialized = JsonSerializer.Serialize(parameter);
|
||||||
var jsonData = await response.Content.ReadAsStringAsync();
|
var content = new StringContent(serialized, Encoding.UTF8, "application/json");
|
||||||
var data = JsonSerializer.Deserialize<List<Season>>(jsonData, _serializerOptions);
|
var response = await HttpClient.PostAsync(url, content);
|
||||||
return (new OperationResult(), data);
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var result = JsonSerializer.Deserialize<ApiResponse<TResult>>(json, _serializerOptions);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return (new OperationResult(e), new List<Season>());
|
return new ApiResponse<TResult>(new OperationResult(e));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(OperationResult, Guid)> CreateSeason(Season season)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var content = new StringContent(JsonSerializer.Serialize(season), Encoding.UTF8, "application/json");
|
|
||||||
var response = await HttpClient.PostAsync(ApiUrl + "season", content);
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return (new OperationResult(false, response.ReasonPhrase), Guid.Empty);
|
|
||||||
}
|
|
||||||
// TODO should give the created id
|
|
||||||
return (new OperationResult(), Guid.Empty);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return (new OperationResult(e), Guid.Empty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
EstusShots.Client/Routes/Seasons.cs
Normal file
30
EstusShots.Client/Routes/Seasons.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using EstusShots.Shared.Interfaces;
|
||||||
|
using EstusShots.Shared.Models;
|
||||||
|
using EstusShots.Shared.Models.Parameters;
|
||||||
|
|
||||||
|
namespace EstusShots.Client.Routes
|
||||||
|
{
|
||||||
|
public class Seasons : ISeasonsController
|
||||||
|
{
|
||||||
|
private readonly EstusShotsClient _client;
|
||||||
|
|
||||||
|
public Seasons(EstusShotsClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ActionUrl([CallerMemberName]string caller = "") =>
|
||||||
|
$"{_client.ApiUrl}{nameof(Seasons)}/{caller}";
|
||||||
|
|
||||||
|
public async Task<ApiResponse<GetSeasonsResponse>> GetSeasons(GetSeasonsParameter parameter) =>
|
||||||
|
await _client.PostToApi<GetSeasonsResponse, GetSeasonsParameter>(ActionUrl(), parameter);
|
||||||
|
|
||||||
|
public async Task<ApiResponse<GetSeasonResponse>> GetSeason(GetSeasonParameter parameter) =>
|
||||||
|
await _client.PostToApi<GetSeasonResponse, GetSeasonParameter>(ActionUrl(), parameter);
|
||||||
|
|
||||||
|
public async Task<ApiResponse<SaveSeasonResponse>> SaveSeason(SaveSeasonParameter parameter)=>
|
||||||
|
await _client.PostToApi<SaveSeasonResponse, SaveSeasonParameter>(ActionUrl(), parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
|||||||
using EstusShots.Client;
|
using EstusShots.Client;
|
||||||
using EstusShots.Gtk.Controls;
|
using EstusShots.Gtk.Controls;
|
||||||
using EstusShots.Shared.Dto;
|
using EstusShots.Shared.Dto;
|
||||||
|
using EstusShots.Shared.Models.Parameters;
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using UI = Gtk.Builder.ObjectAttribute;
|
using UI = Gtk.Builder.ObjectAttribute;
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ namespace EstusShots.Gtk
|
|||||||
private async void NewSeasonButtonOnClicked(object sender, EventArgs e)
|
private async void NewSeasonButtonOnClicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var _ = new LoadingMode(this);
|
using var _ = new LoadingMode(this);
|
||||||
|
// TODO real season edit control
|
||||||
var season = new Season
|
var season = new Season
|
||||||
{
|
{
|
||||||
Game = "Test Game",
|
Game = "Test Game",
|
||||||
@@ -70,14 +72,13 @@ namespace EstusShots.Gtk
|
|||||||
Start = DateTime.Now,
|
Start = DateTime.Now,
|
||||||
Description = "This is a demo description!"
|
Description = "This is a demo description!"
|
||||||
};
|
};
|
||||||
|
var parameter = new SaveSeasonParameter(season);
|
||||||
var (res, _) = await Client.CreateSeason(season);
|
var res = await Client.Seasons.SaveSeason(parameter);
|
||||||
if (!res.Success)
|
if (!res.OperationResult.Success)
|
||||||
{
|
{
|
||||||
_infoLabel.Text = $"Error while creating Season: {res.ShortMessage}";
|
_infoLabel.Text = $"Error while creating Season: {res.OperationResult.ShortMessage}";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReloadSeasons();
|
await ReloadSeasons();
|
||||||
Info("Created new Season");
|
Info("Created new Season");
|
||||||
}
|
}
|
||||||
@@ -91,14 +92,15 @@ namespace EstusShots.Gtk
|
|||||||
|
|
||||||
private async Task ReloadSeasons()
|
private async Task ReloadSeasons()
|
||||||
{
|
{
|
||||||
var (res, seasons) = await Task.Factory.StartNew(() => Client.GetSeasons().Result);
|
var res = await Task.Factory.StartNew(
|
||||||
if (!res.Success)
|
() => Client.Seasons.GetSeasons(new GetSeasonsParameter()).Result);
|
||||||
|
if (!res.OperationResult.Success)
|
||||||
{
|
{
|
||||||
_infoLabel.Text = $"Refresh Failed: {res.ShortMessage}";
|
_infoLabel.Text = $"Refresh Failed: {res.OperationResult.ShortMessage}";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SeasonsControl.Items = seasons;
|
SeasonsControl.Items = res.Data.Seasons;
|
||||||
SeasonsControl.DataBind();
|
SeasonsControl.DataBind();
|
||||||
Info("List Refreshed");
|
Info("List Refreshed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AutoMapper;
|
|
||||||
using EstusShots.Server.Models;
|
|
||||||
using EstusShots.Server.Services;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Dto = EstusShots.Shared.Dto;
|
|
||||||
|
|
||||||
namespace EstusShots.Server.Controllers
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("/api/[controller]")]
|
|
||||||
public class SeasonController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly EstusShotsContext _context;
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public SeasonController(EstusShotsContext context, IMapper mapper, ILogger<SeasonController> logger)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
_mapper = mapper;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
public async Task<ActionResult<Dto.Season>> GetSeason(Guid id)
|
|
||||||
{
|
|
||||||
var season = await _context.Seasons.FindAsync(id);
|
|
||||||
if (season == null) {return NotFound();}
|
|
||||||
|
|
||||||
var seasonDto = _mapper.Map<Dto.Season>(season);
|
|
||||||
return seasonDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<Dto.Season>> CreateSeason(Dto.Season season)
|
|
||||||
{
|
|
||||||
var dbSeason = _mapper.Map<Season>(season);
|
|
||||||
_context.Seasons.Add(dbSeason);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
_logger.LogInformation("New season created");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.LogError(e, "Error while saving Season");
|
|
||||||
}
|
|
||||||
return CreatedAtAction(nameof(GetSeason), new {id = dbSeason.SeasonId}, dbSeason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +1,70 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AutoMapper;
|
|
||||||
using EstusShots.Server.Services;
|
using EstusShots.Server.Services;
|
||||||
|
using EstusShots.Shared.Interfaces;
|
||||||
|
using EstusShots.Shared.Models;
|
||||||
|
using EstusShots.Shared.Models.Parameters;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.Extensions.Logging;
|
||||||
using Dto = EstusShots.Shared.Dto;
|
|
||||||
|
|
||||||
namespace EstusShots.Server.Controllers
|
namespace EstusShots.Server.Controllers
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/api/[controller]")]
|
[Route("/api/[controller]/[action]")]
|
||||||
public class SeasonsController : ControllerBase
|
public class SeasonsController : ControllerBase, ISeasonsController
|
||||||
{
|
{
|
||||||
private readonly EstusShotsContext _context;
|
private readonly ILogger _logger;
|
||||||
private readonly IMapper _mapper;
|
private readonly SeasonsService _seasonsService;
|
||||||
|
|
||||||
|
|
||||||
public SeasonsController(EstusShotsContext context, IMapper mapper)
|
public SeasonsController(ILogger<SeasonsController> logger, SeasonsService seasonsService)
|
||||||
{
|
{
|
||||||
_context = context;
|
_seasonsService = seasonsService;
|
||||||
_mapper = mapper;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpPost]
|
||||||
public async Task<ActionResult<List<Dto.Season>>> GetSeasons()
|
public async Task<ApiResponse<GetSeasonsResponse>> GetSeasons(GetSeasonsParameter parameter)
|
||||||
{
|
{
|
||||||
var seasons = await _context.Seasons.ToListAsync();
|
try
|
||||||
var dtos = _mapper.Map<List<Dto.Season>>(seasons);
|
{
|
||||||
return dtos;
|
_logger.LogInformation($"Request received from client '{Request.HttpContext.Connection.RemoteIpAddress}'");
|
||||||
|
return await _seasonsService.GetSeasons(parameter);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Exception Occured");
|
||||||
|
return new ApiResponse<GetSeasonsResponse>(new OperationResult(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ApiResponse<GetSeasonResponse>> GetSeason(GetSeasonParameter parameter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Request received from client '{Request.HttpContext.Connection.RemoteIpAddress}'");
|
||||||
|
return await _seasonsService.GetSeason(parameter);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Exception Occured");
|
||||||
|
return new ApiResponse<GetSeasonResponse>(new OperationResult(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<SaveSeasonResponse>> SaveSeason(SaveSeasonParameter parameter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Request received from client '{Request.HttpContext.Connection.RemoteIpAddress}'");
|
||||||
|
return await _seasonsService.SaveSeason(parameter);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Exception Occured");
|
||||||
|
return new ApiResponse<SaveSeasonResponse>(new OperationResult(e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:26850",
|
|
||||||
"sslPort": 44318
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"IIS Express": {
|
"EstusShots.Server (Dev)": {
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "weatherforecast",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"EstusShots.Server": {
|
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": false,
|
"launchBrowser": false,
|
||||||
"launchUrl": "",
|
"launchUrl": "",
|
||||||
@@ -25,6 +9,15 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"EstusShots.Server (Prod)": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": false,
|
||||||
|
"launchUrl": "",
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Production"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
EstusShots.Server/Services/SeasonsService.cs
Normal file
63
EstusShots.Server/Services/SeasonsService.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoMapper;
|
||||||
|
using EstusShots.Server.Models;
|
||||||
|
using EstusShots.Shared.Interfaces;
|
||||||
|
using EstusShots.Shared.Models;
|
||||||
|
using EstusShots.Shared.Models.Parameters;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Dto = EstusShots.Shared.Dto;
|
||||||
|
|
||||||
|
namespace EstusShots.Server.Services
|
||||||
|
{
|
||||||
|
public class SeasonsService : ISeasonsController
|
||||||
|
{
|
||||||
|
private readonly EstusShotsContext _context;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public SeasonsService(EstusShotsContext context, IMapper mapper, ILogger<SeasonsService> logger)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_mapper = mapper;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<GetSeasonsResponse>> GetSeasons(GetSeasonsParameter parameter)
|
||||||
|
{
|
||||||
|
var seasons = await _context.Seasons.ToListAsync();
|
||||||
|
var dtos = _mapper.Map<List<Dto.Season>>(seasons);
|
||||||
|
return new ApiResponse<GetSeasonsResponse>(new GetSeasonsResponse(dtos));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<GetSeasonResponse>> GetSeason(GetSeasonParameter parameter)
|
||||||
|
{
|
||||||
|
var season = await _context.Seasons.FindAsync(parameter.SeasonId);
|
||||||
|
if (season == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Season '{parameter.SeasonId}' not found in database");
|
||||||
|
return new ApiResponse<GetSeasonResponse>(new OperationResult(false, $"Season '{parameter.SeasonId}' not found in database"));
|
||||||
|
}
|
||||||
|
var seasonDto = _mapper.Map<Dto.Season>(season);
|
||||||
|
return new ApiResponse<GetSeasonResponse>(new GetSeasonResponse(seasonDto));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<SaveSeasonResponse>> SaveSeason(SaveSeasonParameter parameter)
|
||||||
|
{
|
||||||
|
var season = _mapper.Map<Season>(parameter.Season);
|
||||||
|
var existing = await _context.Seasons.FindAsync(season.SeasonId);
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
_context.Seasons.Add(season);await _context.SaveChangesAsync();
|
||||||
|
_logger.LogInformation($"New season created: '{season.SeasonId}'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
return new ApiResponse<SaveSeasonResponse>(new SaveSeasonResponse(season.SeasonId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,37 +6,46 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
|
||||||
|
|
||||||
namespace EstusShots.Server
|
namespace EstusShots.Server
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
private bool IsDevelopment { get; set; }
|
||||||
|
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddDbContext<EstusShotsContext>(
|
services.AddDbContext<EstusShotsContext>(
|
||||||
opt => opt.UseInMemoryDatabase("debug.db"));
|
opt => opt.UseInMemoryDatabase("debug.db"));
|
||||||
services.AddAutoMapper(typeof(Startup));
|
services.AddAutoMapper(typeof(Startup));
|
||||||
services.AddControllers();
|
services.AddControllers().AddJsonOptions(options =>
|
||||||
|
{
|
||||||
|
if (IsDevelopment)
|
||||||
|
{
|
||||||
|
options.JsonSerializerOptions.WriteIndented = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
services.AddScoped<SeasonsService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
{
|
{
|
||||||
if (env.IsDevelopment())
|
IsDevelopment = env.IsDevelopment();
|
||||||
|
if (IsDevelopment)
|
||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!env.IsDevelopment())
|
|
||||||
{
|
{
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ namespace EstusShots.Shared.Dto
|
|||||||
|
|
||||||
public int Number { get; set; }
|
public int Number { get; set; }
|
||||||
|
|
||||||
public string Game { get; set; } = default!;
|
public string Game { get; set; }
|
||||||
|
|
||||||
public string? Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
public DateTime Start { get; set; }
|
public DateTime Start { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
12
EstusShots.Shared/Interfaces/IApiParameter.cs
Normal file
12
EstusShots.Shared/Interfaces/IApiParameter.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace EstusShots.Shared.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a class that can be used as a parameter for API requests
|
||||||
|
/// </summary>
|
||||||
|
public interface IApiParameter { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a class as response type that is returned from API requests
|
||||||
|
/// </summary>
|
||||||
|
public interface IApiResponse { }
|
||||||
|
}
|
||||||
23
EstusShots.Shared/Interfaces/ISeasonsController.cs
Normal file
23
EstusShots.Shared/Interfaces/ISeasonsController.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using EstusShots.Shared.Models;
|
||||||
|
using EstusShots.Shared.Models.Parameters;
|
||||||
|
|
||||||
|
namespace EstusShots.Shared.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Access many seasons with one request
|
||||||
|
/// </summary>
|
||||||
|
public interface ISeasonsController
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a list of all seasons in the system
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ApiResponse<GetSeasonsResponse>> GetSeasons(GetSeasonsParameter parameter);
|
||||||
|
|
||||||
|
Task<ApiResponse<GetSeasonResponse>> GetSeason(GetSeasonParameter parameter);
|
||||||
|
|
||||||
|
Task<ApiResponse<SaveSeasonResponse>> SaveSeason(SaveSeasonParameter parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,4 +29,35 @@ namespace EstusShots.Shared.Models
|
|||||||
StackTrace = e.StackTrace;
|
StackTrace = e.StackTrace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ApiResponse<T> where T : class, new()
|
||||||
|
{
|
||||||
|
public OperationResult OperationResult { get; set; }
|
||||||
|
|
||||||
|
public T Data { get; set; }
|
||||||
|
|
||||||
|
public ApiResponse()
|
||||||
|
{
|
||||||
|
OperationResult = new OperationResult();
|
||||||
|
Data = new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiResponse(OperationResult operationResult)
|
||||||
|
{
|
||||||
|
OperationResult = operationResult;
|
||||||
|
Data = new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiResponse(T data)
|
||||||
|
{
|
||||||
|
OperationResult = new OperationResult();
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiResponse(OperationResult operationResult, T data)
|
||||||
|
{
|
||||||
|
OperationResult = operationResult;
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
124
EstusShots.Shared/Models/Parameters/SeasonParameters.cs
Normal file
124
EstusShots.Shared/Models/Parameters/SeasonParameters.cs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EstusShots.Shared.Dto;
|
||||||
|
using EstusShots.Shared.Interfaces;
|
||||||
|
|
||||||
|
namespace EstusShots.Shared.Models.Parameters
|
||||||
|
{
|
||||||
|
// GetSeasons
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class for loading a list of all seasons from the database
|
||||||
|
/// </summary>
|
||||||
|
public class GetSeasonsParameter : IApiParameter { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class returned from the API with all loaded seasons
|
||||||
|
/// </summary>
|
||||||
|
public class GetSeasonsResponse : IApiResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All existing seasons in the database
|
||||||
|
/// </summary>
|
||||||
|
public List<Season> Seasons { get; set; }
|
||||||
|
|
||||||
|
public GetSeasonsResponse(List<Season> seasons)
|
||||||
|
{
|
||||||
|
Seasons = seasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetSeasonsResponse()
|
||||||
|
{
|
||||||
|
Seasons = new List<Season>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSeason
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class for loading a single season object
|
||||||
|
/// </summary>
|
||||||
|
public class GetSeasonParameter : IApiParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID of the season that should be loaded
|
||||||
|
/// </summary>
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
|
||||||
|
public GetSeasonParameter()
|
||||||
|
{
|
||||||
|
SeasonId = Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetSeasonParameter(Guid seasonId)
|
||||||
|
{
|
||||||
|
SeasonId = seasonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class returned from the API after loading a single season object
|
||||||
|
/// </summary>
|
||||||
|
public class GetSeasonResponse : IApiResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The loaded season
|
||||||
|
/// </summary>
|
||||||
|
public Season Season { get; set; }
|
||||||
|
|
||||||
|
public GetSeasonResponse()
|
||||||
|
{
|
||||||
|
Season = new Season();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetSeasonResponse(Season season)
|
||||||
|
{
|
||||||
|
Season = season;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveSeason
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class for saving season objects
|
||||||
|
/// </summary>
|
||||||
|
public class SaveSeasonParameter : IApiParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The season object that should be saved
|
||||||
|
/// </summary>
|
||||||
|
public Season Season { get; set; }
|
||||||
|
|
||||||
|
public SaveSeasonParameter()
|
||||||
|
{
|
||||||
|
Season = new Season();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveSeasonParameter(Season season)
|
||||||
|
{
|
||||||
|
Season = season;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameter class returned from the API after saving a season object
|
||||||
|
/// </summary>
|
||||||
|
public class SaveSeasonResponse : IApiResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID of the season that was updated or created
|
||||||
|
/// </summary>
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
|
||||||
|
public SaveSeasonResponse()
|
||||||
|
{
|
||||||
|
SeasonId = Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveSeasonResponse(Guid seasonId)
|
||||||
|
{
|
||||||
|
SeasonId = seasonId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
EstusShots.sln.DotSettings.user
Normal file
3
EstusShots.sln.DotSettings.user
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=dtos/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Estus/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
Reference in New Issue
Block a user