Commit 09cdfa56 authored by Jason Ouellet's avatar Jason Ouellet

Reclasser les projets, ajout appel API Geocoder et Route

parent 49907444
<?xml version="1.0"?>
<doc>
<assembly>
<name>Here</name>
</assembly>
<members>
</members>
</doc>
using Here.Api.Properties;
using Here.Geocoder;
using Here.Models;
using Here.Options.Geocoder;
using Here.Options.Route;
using Here.Route;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Here.Api.Controllers
{
/// <summary>
///
/// </summary>
[Route("api/[controller]")]
[ApiController]
[FormatFilter]
public class HereController : ControllerBase
{
private readonly ILogger<HereController> _logger;
private readonly IConfiguration _config;
private readonly IHereRouteTruckService _routeSrv;
private readonly IHereGeocodeService _geoSrv;
public HereController(ILogger<HereController> logger, IConfiguration config, IHereRouteTruckService routeSrv, IHereGeocodeService geoSrv)
{
_config = config;
_logger = logger;
_routeSrv = routeSrv;
_geoSrv = geoSrv;
}
// GET: api/Here
[HttpGet("{format?}")]
public async Task<IActionResult> GetAsync()
{
HttpClient client = new HttpClient();
//Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
IActionResult retour = null;
//TODO: Devrait être reçu en paramètre!
RouteDistanceModel parametres = new RouteDistanceModel();
//Obtenir le point Géolocalisé pour l'origine et la destination
var geoOptions = new GeocoderOptions();
geoOptions.AddAdresse(parametres.Depart);
var origine = await _geoSrv.ObtenirLocalisationAsync(geoOptions).ConfigureAwait(false);
geoOptions = new GeocoderOptions();
geoOptions.AddAdresse(parametres.Destination);
var destination = await _geoSrv.ObtenirLocalisationAsync(geoOptions).ConfigureAwait(false);
//Construire les options de recherche
var options = new RouteTruckOptions();
options.AddLocalisation(origine, 0);
options.AddLocalisation(destination, 1);
options.AddMode(new Mode[] { Mode.fastest, Mode.truck, Mode.trafficDisabled });
options.AddLimitedWeight(parametres.Poids);
options.AddLength(parametres.Longueur);
options.AddWidth(parametres.Largeur);
//Obtenir la distance "Camion" entre 2 points géolocalisés
try
{
var retourSrv = await _routeSrv.ObtenirDistanceAsync(options).ConfigureAwait(false);
retour = Ok(retourSrv);
}
catch (Exception)
{
retour = BadRequest("Une erreur est survenue lors de l'appel du service");
}
client.Dispose();
return retour;
}
}
}
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["Here/Here.csproj", "Here/"]
RUN dotnet restore "Here/Here.csproj"
COPY . .
WORKDIR "/src/Here"
RUN dotnet build "Here.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Here.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Here.dll"]
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>db90d3fd-c30e-4a8f-be61-382200637cac</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AssemblyName>Here</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG</DefineConstants>
<DocumentationFile></DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Controllers\WeatherForecastController.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.5-beta1.final">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.9.5" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0-rc3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.0.0-rc3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Here.Core\Here.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace Here
{
public static class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
\ No newline at end of file
//------------------------------------------------------------------------------
// <auto-generated>
// Ce code a été généré par un outil.
// Version du runtime :4.0.30319.42000
//
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Here.Api.Properties {
using System;
/// <summary>
/// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
/// </summary>
// Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
// à l'aide d'un outil, tel que ResGen ou Visual Studio.
// Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
// avec l'option /str ou régénérez votre projet VS.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Here.Api.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Remplace la propriété CurrentUICulture du thread actuel pour toutes
/// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Recherche une chaîne localisée semblable à Exécution de la fonction {0}.
/// </summary>
internal static string LogExecutionFonctionX {
get {
return ResourceManager.GetString("LogExecutionFonctionX", resourceCulture);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="LogExecutionFonctionX" xml:space="preserve">
<value>Exécution de la fonction {0}</value>
<comment>Permet le logger l'exécution d'une fonction</comment>
</data>
</root>
\ No newline at end of file

# Implémentation de la sérialisation dans les classe Exception
https://stackoverflow.com/questions/94488/what-is-the-correct-way-to-make-a-custom-net-exception-serializable
using Here.Configuration;
using Here.Geocoder;
using Here.Route;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System;
namespace Here
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration env)
{
}
// This method gets called by the runtime. Use this method to add services to the container.
public static void ConfigureServices(IServiceCollection services, IWebHostEnvironment env)
{
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true; // false by default
})
.AddXmlSerializerFormatters()
.AddJsonOptions(options =>
{
// Use the default property (Pascal) casing.
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.WriteIndented = true;
});
//.AddNewtonsoftJson(options =>
// {
// // Use the default property (Pascal) casing
// //options.SerializerSettings.ContractResolver = new DefautlContractResolver();
// options.UseCamelCasing(true);
// options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
// });
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Here Middleware", Version = "v1" });
});
services.AddScoped<IHereConfig, HereConfig>();
services.AddScoped<IHereRouteTruckService, HereRouteTruckService>();
services.AddScoped<IHereGeocodeService, HereGeocodeService>();
if (!env.IsDevelopment())
{
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
options.ExcludedHosts.Add("example.com");
options.ExcludedHosts.Add("www.example.com");
});
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.RoutePrefix = string.Empty;
});
app.UseHttpsRedirection();
app.UseHsts();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
\ No newline at end of file
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
{
"https_port": 443,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"HereConfig": {
"AppId": "3mzBHZDl7SekT31Ki6sM",
"AppCode": "ZUDKQW72vNpBRi3Hf-D5Mg",
"UriServices": {
"RouteSvc": "https://route.api.here.com/routing/7.2/calculateroute.json",
"GeocoderSvc": "https://geocoder.api.here.com/6.2/geocode.json"
}
}
}
using System;
using System.Runtime.Serialization;
namespace Here.Configuration
{
[Serializable]
public class ConfigurationException : Exception
{
private const string MessageFormat = "La valeur {0} n'est pas configuré correctement";
public ConfigurationException()
{
}
public ConfigurationException(string configValue) :
base(string.Format(MessageFormat, configValue))
{
}
public ConfigurationException(string configValue, Exception innerException) :
base(string.Format(MessageFormat, configValue), innerException)
{
}
protected ConfigurationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace Here.Configuration
{
public class HereConfig : IHereConfig
{
public string AppId { get; set; }
public string AppCode { get; set; }
public IDictionary<String, String> UriServices { get; set; }
public HereConfig()
{
}
}
}
\ No newline at end of file
using System.Collections.Generic;
namespace Here.Configuration
{
public interface IHereConfig
{
string AppCode { get; set; }
string AppId { get; set; }
IDictionary<string, string> UriServices { get; set; }
}
}
\ No newline at end of file