diff --git a/PARR.DAL/PARR.DAL.csproj b/PARR.DAL/PARR.DAL.csproj new file mode 100644 index 00000000..cfadb03d --- /dev/null +++ b/PARR.DAL/PARR.DAL.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/PARR_API/Contracts/V1/ApiRoutes.cs b/PARR_API/Contracts/V1/ApiRoutes.cs new file mode 100644 index 00000000..17adcd4f --- /dev/null +++ b/PARR_API/Contracts/V1/ApiRoutes.cs @@ -0,0 +1,42 @@ +namespace PARR_API.Contracts.V1 +{ + // https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/ + + //----------URL должен отражать структуру вложенных ресурсов---------- + // GET /shops/2/products получить список продуктов из магазина 2. + // GET /shops/2/products/31 получить детали продукта 31 из магазина 2. + // DELETE /shops/2/products/31 удалить продукт 31 из магазина 2. + // PUT /shops/2/products/31 обновить данные о продукте 31. Используйте PUT на URL ресурса, а не коллекции. + // POST /shops создать новый магазин и вернуть данные о нём.Используйте POST на URL коллекции. + + //---------URL должен начинаться с коллекции и заканчиваться идентификатором--------- + // GET /shops/:shopId/ или GET /category/:categoryId + + public static class ApiRoutes + { + public const string Root = "api"; + + public const string Version = "v1"; + + public const string Base = Root + "/" + Version; + + public static class ApiStatus + { + public const string Version = Base + "/version"; + public const string Health = Base + "/health"; + public const string Metrics = Base + "/metrics"; + } + + //public static class Layer + //{ + // public const string GetAll = Base + "/layers/"; + // public const string Get = Base + "/layers/" + getParam; + + // public const string GetAreas = Base + "/layers/" + getParam + "/areas"; + // public const string GetPlaces = Base + "/layers/" + getParam + "/places"; + // public const string GetTemplates = Base + "/layers/" + getParam + "/templates"; + + // public const string getParam = "{id}"; + //} + } +} diff --git a/PARR_API/Controllers/V1/ApiStatusController.cs b/PARR_API/Controllers/V1/ApiStatusController.cs new file mode 100644 index 00000000..b9b9d8ea --- /dev/null +++ b/PARR_API/Controllers/V1/ApiStatusController.cs @@ -0,0 +1,9 @@ +using PARR_API.Controllers.V1.Base; + +namespace PARR_API.Controllers.V1 +{ + public class ApiStatusController : BaseApiController + { + //TODO: + } +} diff --git a/PARR_API/Controllers/V1/Base/BaseApiController.cs b/PARR_API/Controllers/V1/Base/BaseApiController.cs new file mode 100644 index 00000000..aa33350a --- /dev/null +++ b/PARR_API/Controllers/V1/Base/BaseApiController.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Mvc; + +namespace PARR_API.Controllers.V1.Base +{ + [ApiController] + public class BaseApiController : ControllerBase + { + + } +} diff --git a/PARR_API/Controllers/WeatherForecastController.cs b/PARR_API/Controllers/WeatherForecastController.cs deleted file mode 100644 index 087f6681..00000000 --- a/PARR_API/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace PARR_API.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} \ No newline at end of file diff --git a/PARR_API/Installers/ApiServicesInstaller.cs b/PARR_API/Installers/ApiServicesInstaller.cs new file mode 100644 index 00000000..32078df9 --- /dev/null +++ b/PARR_API/Installers/ApiServicesInstaller.cs @@ -0,0 +1,28 @@ +using PARR_API.Services.Implementations; +using PARR_API.Services.Interfaces; + +namespace PARR_API.Installers +{ + /// + /// Самописные сервисы которые используются для АПИ + /// + public static class ApiServicesInstaller + { + public static void InstallApiServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(provider => + { + var accessor = provider.GetRequiredService(); + var request = accessor.HttpContext.Request; + var absoluteUri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent(), "/"); + + return new UriService(absoluteUri); + }); + + + //services.AddTransient(); + + + } + } +} diff --git a/PARR_API/Installers/CorsInstaller.cs b/PARR_API/Installers/CorsInstaller.cs new file mode 100644 index 00000000..b760c21b --- /dev/null +++ b/PARR_API/Installers/CorsInstaller.cs @@ -0,0 +1,25 @@ +using PARR_API.Settings; + +namespace PARR_API.Installers +{ + public static class CorsInstaller + { + public static void InstallCorsServices(this IServiceCollection services) + { + services.AddCors(); + } + + public static void InstallCors(this WebApplication app, WebApplicationBuilder builder) + { + var corsSettings = new CorsSettings(); + builder.Configuration.GetSection(nameof(CorsSettings)).Bind(corsSettings); + + app.UseCors(opt => + opt.WithOrigins(corsSettings.AllowHostsArray) + .AllowAnyHeader() + .AllowAnyMethod() + ); + } + + } +} diff --git a/PARR_API/Installers/SettingsInstaller.cs b/PARR_API/Installers/SettingsInstaller.cs new file mode 100644 index 00000000..46c5420d --- /dev/null +++ b/PARR_API/Installers/SettingsInstaller.cs @@ -0,0 +1,17 @@ +namespace PARR_API.Installers +{ + /// + /// Биндинги из конфига appsettings + /// + public static class SettingsInstaller + { + public static void InstallSettings(this IServiceCollection services, IConfiguration configuration) + { + //var storageSettings = new StorageSettings(); + //configuration.GetSection(nameof(StorageSettings)).Bind(storageSettings); + //services.AddSingleton(storageSettings); + + //TODO: add other + } + } +} diff --git a/PARR_API/Installers/SwaggerInstaller.cs b/PARR_API/Installers/SwaggerInstaller.cs new file mode 100644 index 00000000..a53be633 --- /dev/null +++ b/PARR_API/Installers/SwaggerInstaller.cs @@ -0,0 +1,47 @@ +using Microsoft.OpenApi.Models; +using System.Reflection; + +namespace PARR_API.Installers +{ + public static class SwaggerInstaller + { + public static void InstallSwaggerService(this IServiceCollection services, IConfiguration configuration) + { + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + services.AddEndpointsApiExplorer(); + + var version = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion ?? "1.0.0"; + + services.AddSwaggerGen(x => + { + //TODO: + x.SwaggerDoc( + "v1", + new OpenApiInfo + { + Title = "GEO API", + Version = $"v{version}", + Description = "API for the project \"GEO DVGD\"", + Contact = new OpenApiContact { Email = "IVC_TrubnikovME@dvgd.rzd;IVC_KuznetsovMV@dvgd.rzd", Name = "Trubnikov M.E., Kuznetsov M.V." }, + License = new OpenApiLicense { Name = "© PTK-DVGD Software LLC" } + }); + + // Set the comments path for the Swagger JSON and UI. + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + x.IncludeXmlComments(xmlPath); + }); + } + + + public static void InstallSwagger(this WebApplication app) + { + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + } + } +} diff --git a/PARR_API/MappingProfiles/DomainToResponseProfile.cs b/PARR_API/MappingProfiles/DomainToResponseProfile.cs new file mode 100644 index 00000000..ec5db6c0 --- /dev/null +++ b/PARR_API/MappingProfiles/DomainToResponseProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace PARR_API.MappingProfiles +{ + public class DomainToResponseProfile : Profile + { + public DomainToResponseProfile() + { + // из проекта наружу + } + } +} diff --git a/PARR_API/MappingProfiles/RequestToDomainProfile.cs b/PARR_API/MappingProfiles/RequestToDomainProfile.cs new file mode 100644 index 00000000..6c9fae67 --- /dev/null +++ b/PARR_API/MappingProfiles/RequestToDomainProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace PARR_API.MappingProfiles +{ + public class RequestToDomainProfile : Profile + { + public RequestToDomainProfile() + { + // снаружи в проект + } + } +} diff --git a/PARR_API/PARR_API.csproj b/PARR_API/PARR_API.csproj index 0dd093e9..3616e162 100644 --- a/PARR_API/PARR_API.csproj +++ b/PARR_API/PARR_API.csproj @@ -4,11 +4,33 @@ net7.0 enable enable + True + + + + 1701;1702;1591;1587;1573;NU1803 + + + + 1701;1702;1591;1587;1573;NU1803 - - + + + + + + + + + + + + + + + diff --git a/PARR_API/Program.cs b/PARR_API/Program.cs index df2434ce..54062b05 100644 --- a/PARR_API/Program.cs +++ b/PARR_API/Program.cs @@ -1,20 +1,36 @@ +using FluentValidation; +using PARR_API.Installers; +using Serilog; +using System.Reflection; + var builder = WebApplication.CreateBuilder(args); +builder.Host.UseSerilog((context, config) => +{ + config + .WriteTo.Console() + .ReadFrom.Configuration(builder.Configuration); +}); + // Add services to the container. +builder.Services.InstallApiServices(builder.Configuration); +builder.Services.InstallSettings(builder.Configuration); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + +builder.Services.AddHttpContextAccessor(); builder.Services.AddControllers(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.InstallSwaggerService(builder.Configuration); + var app = builder.Build(); // Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} +app.InstallSwagger(); app.UseAuthorization(); diff --git a/PARR_API/Services/Implementations/UriService.cs b/PARR_API/Services/Implementations/UriService.cs new file mode 100644 index 00000000..c42c35e7 --- /dev/null +++ b/PARR_API/Services/Implementations/UriService.cs @@ -0,0 +1,35 @@ +using PARR_API.Services.Interfaces; + +namespace PARR_API.Services.Implementations +{ + public class UriService : IUriService + { + private readonly string baseUri; + + public UriService(string baseUri) + { + this.baseUri = baseUri; + } + + public Uri GetAllUri(string apiRoutesGetAll) + { + return new Uri(baseUri + apiRoutesGetAll); + } + + public Uri GetUri(string apiRoutesGet, string apiRoutesGetParam, string value) + { + var modifiedUri = apiRoutesGet.Replace(apiRoutesGetParam, value); + return new Uri(baseUri + modifiedUri); + } + + public Uri GetUri(string apiRoutesGet, string apiRoutesGetParam, Guid value) + { + return GetUri(apiRoutesGet, apiRoutesGetParam, value.ToString()); + } + + public Uri GetBaseUri() + { + return new Uri(baseUri); + } + } +} diff --git a/PARR_API/Services/Interfaces/IUriService.cs b/PARR_API/Services/Interfaces/IUriService.cs new file mode 100644 index 00000000..79aa67e0 --- /dev/null +++ b/PARR_API/Services/Interfaces/IUriService.cs @@ -0,0 +1,10 @@ +namespace PARR_API.Services.Interfaces +{ + public interface IUriService + { + Uri GetBaseUri(); + Uri GetUri(string apiRoutesGet, string apiRoutesGetParam, string value); + Uri GetUri(string apiRoutesGet, string apiRoutesGetParam, Guid value); + Uri GetAllUri(string apiRoutesGetAll); + } +} diff --git a/PARR_API/Settings/CorsSettings.cs b/PARR_API/Settings/CorsSettings.cs new file mode 100644 index 00000000..165882b5 --- /dev/null +++ b/PARR_API/Settings/CorsSettings.cs @@ -0,0 +1,9 @@ +namespace PARR_API.Settings +{ + public class CorsSettings + { + public string AllowedHosts { get; set; } = string.Empty; + + public string[] AllowHostsArray => AllowedHosts.Split(';').Select(t => t.Trim()).ToArray(); + } +} diff --git a/PARR_API/WeatherForecast.cs b/PARR_API/WeatherForecast.cs deleted file mode 100644 index 1a6557ed..00000000 --- a/PARR_API/WeatherForecast.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PARR_API -{ - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } - } -} \ No newline at end of file diff --git a/PARR_API/appsettings.json b/PARR_API/appsettings.json index 10f68b8c..2c17a37e 100644 --- a/PARR_API/appsettings.json +++ b/PARR_API/appsettings.json @@ -1,9 +1,33 @@ { + "ConnectionStrings": { + "DefaultConnection": "Server=10.99.253.184;Database=geo;User Id=app_geo; Password=Khdlifg(G875904HJFfd@3;" + }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "log/log-.txt", + "rollingInterval": "Day" + } + } + ] + }, + "AllowedHosts": "*", + "CorsSettings": { + "AllowedHosts": "*" + } }