Compare commits
No commits in common. 'master' and 'ApiSkill' have entirely different histories.
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 68 KiB |
@ -1,97 +1,168 @@
|
|||||||
|
# prepaLoL
|
||||||
## LOLProject
|
|
||||||
|
## Diagramme de classes du modèle
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class LargeImage{
|
||||||
**LOLProject** est un projet reliant une API C# et EntityFramework afin de produire une API qui renvoie les informations d'une base de données SQLite sur un client MAUI
|
+/Base64 : string
|
||||||
|
}
|
||||||
Merci de noter la v1 de l'api qui est tenu a jour la v2 sert uniquement a montrer que nous pouvons versionner.
|
class Champion{
|
||||||
|
+/Name : string
|
||||||
## :floppy_disk: FEATURES
|
+/Bio : string
|
||||||
|
+/Icon : string
|
||||||
- L'API dispose des principales requêtes CRUD sur les champions, skills, skins, runes, runepages aussi consultables sur le swagger UI.
|
+/Characteristics : Dictionary~string, int~
|
||||||
- L'ORM réalisé avec EntityFramework afin d'enregistrer dans une base de données SQLite
|
~ AddSkin(skin : Skin) bool
|
||||||
- L'application MAUI pour faire des requêtes depuis un client et les afficher.
|
~ RemoveSkin(skin: Skin) bool
|
||||||
|
+ AddSkill(skill: Skill) bool
|
||||||
|
+ RemoveSkill(skill: Skill) bool
|
||||||

|
+ AddCharacteristics(someCharacteristics : params Tuple~string, int~[])
|
||||||
|
+ RemoveCharacteristics(label : string) bool
|
||||||
## :dizzy: Getting Started
|
+ this~label : string~ : int?
|
||||||
|
}
|
||||||
Une fois le dépot cloné, vous pouvez lancer le code sur votre téléphone Android grâce à l'outil Android Studio ou grâce à un émulateur Android.
|
Champion --> "1" LargeImage : Image
|
||||||
|
class ChampionClass{
|
||||||
|
<<enumeration>>
|
||||||
## Architecture
|
Unknown,
|
||||||
|
Assassin,
|
||||||

|
Fighter,
|
||||||
Ce schéma d'architecure globale permet de comprendre la composition interne de la solution.
|
Mage,
|
||||||
|
Marksman,
|
||||||
Sur la partie gauche on peut voir la partie client qui fait appel a l'api via des requetes http en utilisant les routes de l'api Rest Full.
|
Support,
|
||||||
Pour tout a fait comprendre, comment communiquent et fonctionnent les différentes briques de la solution nous allons vous détailler brique par brique, relation par relation les différentes point rouge du schéma.
|
Tank,
|
||||||
|
}
|
||||||
## 1 - La déserialization
|
Champion --> "1" ChampionClass : Class
|
||||||
Le client est une solution qui va intérragir avec notre api grace des requetes sur internet. Il nécessite donc impérativement d'une connexion internet afin de pouvoir communiquer grace a des requetes http(s). Une fois qu'il a récupéré les données demandé. Il doit transoformer ce document json en classe métier de son model. Cela s'appel la déserialization. Ce processus ce traduit ar le code suivant en C#.
|
class Skin{
|
||||||
|
+/Name : string
|
||||||

|
+/Description : string
|
||||||
|
+/Icon : string
|
||||||
|
+/Price : float
|
||||||
## 2 - La communication Client - Api
|
}
|
||||||
Maintenant que vous savez comment le client traite les données renvoyées par l'API, nous allons a présent voir comment ils communiquent entre eux. Cette communication se fait par des requetes http(s) sous la forme suivante.
|
Skin --> "1" LargeImage : Image
|
||||||
|
Champion "1" -- "*" Skin
|
||||||
"codefirst.iut.uca.fr/containers/lucasdelanier-containerlol/api/v{version}/{controller}"
|
class Skill{
|
||||||
|
+/Name : string
|
||||||
Lors de l'appel de l'API, le client peut choisir la version ( v1, v2, etc) mais aussi indiquer le controlleur qu'il souhaite intérroger. Par exemple Champion lui permettra de récuperer des informations sur les champions que connait l'API. Il est aussi possible de rajouter de précisions en ajoutant par exemple un nom apres le controller pour demander les informations spécifique a un champion en particulié. Lors des communications, les objects sons traduit sous la forme DTO. Cela permet de controller l'envoie de certaines données au client comme pr exemple un id unique ou des données sensibles qui ne doivent pas etre connu par l'utilisateur. Voici un exemple.
|
+/Description : string
|
||||||
|
}
|
||||||

|
class SkillType{
|
||||||
|
<<enumeration>>
|
||||||
Ci dessus on voit que l'object champion a une nouvelle "forme" ChampionDTO que l'on construit a partir des attributs d'un champion. Dans l'exemple, il reprend les memes informations qu'un champion mais on aurait put imaginer qu'il en perde certains que l'on ne veut pas renvoyer a l'utilisateur. Pour permettre le passage d'un DTO en object et d'un object en DTO il faut ce qu'on appel des Mappers. Voici l'exemple des méthodes ToModel() et ToDTO()
|
Unknown,
|
||||||
|
Basic,
|
||||||

|
Passive,
|
||||||
|
Ultimate,
|
||||||
## 3 - L'utilisation du stub dans l'API
|
}
|
||||||
Avant de faire la relation avec une base de données. Il était impotant de pouvoir tester l'application avec un Stub qui est une classe contenant des listes d'object. Une sorte de base de données fictive. Pour permettre a l'api d'intéroger ce stub, il a fallut faire un manager spécialement destiné à l'utilisation du stub (StubData) qui hérite d'un manager commun qui est une interface composé des méthodes nécessaire a l'interrogation des données (IDataManager).
|
Skill --> "1" SkillType : Type
|
||||||
|
Champion --> "*" Skill
|
||||||

|
class Rune{
|
||||||
|
+/Name : string
|
||||||
|
+/Description : string
|
||||||
## 4 - Lien entre API et Entityframework
|
}
|
||||||
Pour relier l'API avec la partie EntityFramework, cela se passe du côté de l'API. En effet, en ayant implémenter des managers en EntityFramework, il suffit de les instancier côté API puis de demander la requête adéquate pour obtenir les données de la base de données avec l'API. Ces managers regroupent plusieurs petits managers gérant chacun une entité de la base de données (Champion, RunePage, Rune, ...). Il n'y a pas de managers de Skill car ceux-ci sont compris dans le manager Champion (un peu comme les mappers côté API).
|
Rune --> "1" LargeImage : Image
|
||||||
|
class RuneFamily{
|
||||||
|
<<enumeration>>
|
||||||
## 5 - Mappage des classes métier en tables
|
Unknown,
|
||||||
Afin de rentrer les classes métiers en base de données, il faut avant tout les mapper. Ainsi, il y a un mapper pour chaque entité de la base de données (même pour Skill par exemple). Ensuite, il faut deux méthodes pour chaque mapper :
|
Precision,
|
||||||
<br> 1- ToEntity : elle prend en paramètre un objet du modèle et permet de le transformer en entité afin de pouvoir l'insérer en base de données.
|
Domination
|
||||||
<br> 2- ToModel : elle prend en paramètre une entité et permet de la transformer en objet.
|
}
|
||||||
Grâce à ces deux méthodes, nous pouvons facilement mapper des entités en objet et inversement.
|
Rune --> "1" RuneFamily : Family
|
||||||
|
class Category{
|
||||||
|
<<enumeration>>
|
||||||
## 6 - Lien avec base de données SQLite
|
Major,
|
||||||
Il y a deux manières d'utiliser la base de données SQLite. On peut soit, utiliser la base de données interne à l'appareil ou bien utiliser la mémoire de l'appareil pour sauvegarder les données en local. Pour créer la base, il faut avoir des classes entités représentant chacune une table de la base. Il peut aussi y avoir des entités représentant des liaisons entre deux tables (RunePageRuneEntity par exemple représente la table entre RunePage et Rune). Ensuite, il faut un contexte (SQLiteContext pour notre projet) qui a pour attributs des DbSets, des listes d'entités à mettre en base de données. Pour remplir la base de données, avec un Stub par exemple, on peut utiliser la méthode onCreate du contexte pour insérer des entités créees manuellement. Cependant, pour mettre des objets en base, il faut donc les mapper en entité puis, passer par un manager (dans notre cas) pour enfin le rentrer en base.
|
Minor1,
|
||||||
|
Minor2,
|
||||||
|
Minor3,
|
||||||
## :wrench: SUPPORT
|
OtherMinor1,
|
||||||
En cas de problème lors de l'utilisation de l'application, vous pouvez nous contacter aux adresses suivantes :
|
OtherMinor2
|
||||||
|
}
|
||||||
|
class RunePage{
|
||||||
Lucas Delanier : **Lucas.DELANIER@etu.uca.fr** </br>
|
+/Name : string
|
||||||
Louison Parant : **Louison.PARANT@etu.uca.fr**
|
+/this[category : Category] : Rune?
|
||||||

|
- CheckRunes(newRuneCategory : Category)
|
||||||
|
- CheckFamilies(cat1 : Category, cat2 : Category) bool?
|
||||||
|
- UpdateMajorFamily(minor : Category, expectedValue : bool)
|
||||||
|
}
|
||||||
## ✨ Contributors
|
RunePage --> "*" Rune : Dictionary~Category,Rune~
|
||||||
|
```
|
||||||
<a href = "https://codefirst.iut.uca.fr/git/lucas.delanier">
|
|
||||||
<img src ="https://codefirst.iut.uca.fr/git/avatars/6a3835d734392fccff3949f7c82a63b9?size=870" height="50px">
|
## Diagramme de classes des interfaces de gestion de l'accès aux données
|
||||||
</a>
|
```mermaid
|
||||||
<a href = "https://codefirst.iut.uca.fr/git/louison.parant">
|
classDiagram
|
||||||
<img src ="https://codefirst.iut.uca.fr/git/avatars/b337a607f680a2d9af25eb09ea457be9?size=870" height="50px">
|
direction LR;
|
||||||
</a>
|
class IGenericDataManager~T~{
|
||||||
|
<<interface>>
|
||||||
|
GetNbItems() Task~int~
|
||||||
|
GetItems(index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~
|
||||||
|
GetNbItemsByName(substring : string)
|
||||||
|
GetItemsByName(substring : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~
|
||||||
|
UpdateItem(oldItem : T, newItem : T) Task~T~~
|
||||||
|
AddItem(item : T) Task~T~
|
||||||
|
DeleteItem(item : T) Task~bool~
|
||||||
|
}
|
||||||
|
class IChampionsManager{
|
||||||
|
<<interface>>
|
||||||
|
GetNbItemsByCharacteristic(charName : string)
|
||||||
|
GetItemsByCharacteristic(charName : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
|
||||||
|
GetNbItemsByClass(championClass : ChampionClass)
|
||||||
|
GetItemsByClass(championClass : ChampionClass, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
|
||||||
|
GetNbItemsBySkill(skill : Skill?)
|
||||||
|
GetItemsBySkill(skill : Skill?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
|
||||||
|
GetNbItemsBySkill(skill : string)
|
||||||
|
GetItemsBySkill(skill : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
|
||||||
|
GetNbItemsByRunePage(runePage : RunePage?)
|
||||||
|
GetItemsByRunePage(runePage : RunePage?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
|
||||||
|
}
|
||||||
|
class ISkinsManager{
|
||||||
|
<<interface>>
|
||||||
|
GetNbItemsByChampion(champion : Champion?)
|
||||||
|
GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Skin?~~
|
||||||
|
}
|
||||||
|
class IRunesManager{
|
||||||
|
<<interface>>
|
||||||
|
GetNbItemsByFamily(family : RuneFamily)
|
||||||
|
GetItemsByFamily(family : RuneFamily, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Rune?~~
|
||||||
|
}
|
||||||
|
class IRunePagesManager{
|
||||||
|
<<interface>>
|
||||||
|
GetNbItemsByRune(rune : Rune?)
|
||||||
|
GetItemsByRune(rune : Rune?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~
|
||||||
|
GetNbItemsByChampion(champion : Champion?)
|
||||||
|
GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~
|
||||||
|
}
|
||||||
|
|
||||||
|
IGenericDataManager~Champion?~ <|.. IChampionsManager : T--Champion?
|
||||||
|
IGenericDataManager~Skin?~ <|.. ISkinsManager : T--Skin?
|
||||||
|
IGenericDataManager~Rune?~ <|.. IRunesManager : T--Rune?
|
||||||
|
IGenericDataManager~RunePage?~ <|.. IRunePagesManager : T--RunePage?
|
||||||
|
class IDataManager{
|
||||||
|
<<interface>>
|
||||||
|
}
|
||||||
|
IChampionsManager <-- IDataManager : ChampionsMgr
|
||||||
|
ISkinsManager <-- IDataManager : SkinsMgr
|
||||||
|
IRunesManager <-- IDataManager : RunesMgr
|
||||||
|
IRunePagesManager <-- IDataManager : RunePagesMgr
|
||||||
|
```
|
||||||
|
|
||||||
|
## Diagramme de classes simplifié du Stub
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
direction TB;
|
||||||
|
|
||||||
|
IDataManager <|.. StubData
|
||||||
|
|
||||||
|
ChampionsManager ..|> IChampionsManager
|
||||||
|
StubData --> ChampionsManager
|
||||||
|
|
||||||
|
RunesManager ..|> IRunesManager
|
||||||
|
StubData --> RunesManager
|
||||||
|
|
||||||
|
RunePagesManager ..|> IRunePagesManager
|
||||||
|
StubData --> RunePagesManager
|
||||||
|
|
||||||
|
SkinsManager ..|> ISkinsManager
|
||||||
|
StubData --> SkinsManager
|
||||||
|
|
||||||
|
StubData --> RunesManager
|
||||||
|
StubData --> "*" Champion
|
||||||
|
StubData --> "*" Rune
|
||||||
|
StubData --> "*" RunePages
|
||||||
|
StubData --> "*" Skins
|
||||||
|
```
|
@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace TestsEF.Controllers
|
namespace APILOL.Controllers
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
@ -1,35 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace APILOL.Controllers.v1
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/v{version:apiVersion}/[controller]")]
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
public class WeatherForecastController : ControllerBase
|
|
||||||
{
|
|
||||||
private static readonly string[] Summaries = new[]
|
|
||||||
{
|
|
||||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly ILogger<WeatherForecastController> _logger;
|
|
||||||
|
|
||||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet(Name = "GetWeatherForecast")]
|
|
||||||
[MapToApiVersion("1.0")]
|
|
||||||
public IEnumerable<WeatherForecast> Get()
|
|
||||||
{
|
|
||||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
|
||||||
{
|
|
||||||
Date = DateTime.Now.AddDays(index),
|
|
||||||
TemperatureC = Random.Shared.Next(-20, 55),
|
|
||||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
|
||||||
})
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace APILOL.Controllers.v2
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/v{version:apiVersion}/[controller]")]
|
|
||||||
[ApiVersion("2.0")]
|
|
||||||
public class WeatherForecastController : ControllerBase
|
|
||||||
{
|
|
||||||
private static readonly string[] Summaries = new[]
|
|
||||||
{
|
|
||||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly ILogger<WeatherForecastController> _logger;
|
|
||||||
|
|
||||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
[MapToApiVersion("2.0")]
|
|
||||||
[HttpGet(Name = "GetWeatherForecast")]
|
|
||||||
public IEnumerable<WeatherForecast> Get()
|
|
||||||
{
|
|
||||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
|
||||||
{
|
|
||||||
Date = DateTime.Now.AddDays(index),
|
|
||||||
TemperatureC = Random.Shared.Next(-20, 55),
|
|
||||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
|
||||||
})
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +1,28 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
|
||||||
using Model;
|
using Model;
|
||||||
using StubLib;
|
using StubLib;
|
||||||
using Swashbuckle.Swagger;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddSingleton<IDataManager, StubData>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
|
builder.Services.AddSingleton<IDataManager, StubData>();
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
builder.Services.AddApiVersioning(opt =>
|
|
||||||
{
|
|
||||||
opt.DefaultApiVersion = new ApiVersion(1, 0);
|
|
||||||
opt.ApiVersionReader = new UrlSegmentApiVersionReader();
|
|
||||||
});
|
|
||||||
// Add ApiExplorer to discover versions
|
|
||||||
builder.Services.AddVersionedApiExplorer(setup =>
|
|
||||||
{
|
|
||||||
setup.GroupNameFormat = "'v'VVV";
|
|
||||||
setup.SubstituteApiVersionInUrl = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(options =>
|
app.UseSwaggerUI();
|
||||||
{
|
|
||||||
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
|
|
||||||
{
|
|
||||||
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
|
|
||||||
description.GroupName.ToUpperInvariant());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.UseStaticFiles();
|
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
Binary file not shown.
@ -1,25 +0,0 @@
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
// Add services to the container.
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
|
||||||
builder.Services.AddSwaggerGen();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseSwagger();
|
|
||||||
app.UseSwaggerUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
app.Run();
|
|
@ -1,13 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,13 +0,0 @@
|
|||||||
namespace TestsEF
|
|
||||||
{
|
|
||||||
public class WeatherForecast
|
|
||||||
{
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureC { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
|
||||||
|
|
||||||
public string? Summary { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
Loading…
Reference in new issue