├── .vs ├── Demo │ ├── FileContentIndex │ │ └── read.lock │ ├── v17 │ │ ├── .suo │ │ └── .futdcache.v1 │ └── DesignTimeBuild │ │ └── .dtbcache.v2 └── ProjectEvaluation │ ├── demo.metadata.v1 │ └── demo.projects.v1 ├── Program.cs ├── README.md ├── Startup.cs ├── settings.xml ├── settings.json ├── settings.yml ├── .gitignore ├── appsettings.Development.json ├── Models ├── PublishersAuthors.cs ├── Mapper.cs ├── AuthorDTO.cs ├── Publisher.cs ├── Book.cs ├── Author.cs └── BookDetails.cs ├── appsettings.Production.json ├── .dockerignore ├── GraphQl ├── Subscription.cs ├── Mutation.cs └── Query.cs ├── Configurations ├── DB │ ├── DBConfigurationSource.cs │ ├── DBConfigurationExtantions.cs │ ├── DBConfigurationProvider.cs │ └── DBConfigurationContext.cs └── Dynamic │ └── DynamicValueConfiguration.cs ├── Mappers ├── Register.cs ├── IAuthorMapper.cs └── AuthorMapper.g.cs ├── appsettings.json ├── Demo.csproj.user ├── Properties └── launchSettings.json ├── Dockerfile ├── Health └── CustumHealth.cs ├── Filters └── ExceptionFilter.cs ├── GlobalSuppressions.cs ├── LICENSE.md ├── HttpHandler ├── HttpTrackerHandler.cs └── HttpRequestInterceptor.cs ├── DBContext ├── DemoRepository.cs └── DemoContext.cs ├── BackgroundService ├── BookAVG.cs └── TCPServer.cs ├── Controllers ├── DTOController.cs ├── PublisherController.cs └── AuthorsController.cs ├── LongPollingQuery.cs ├── Demo.csproj ├── nlog.config ├── Migrations ├── 20211106063701_start.cs ├── DemoContextModelSnapshot.cs └── 20211106063701_start.Designer.cs ├── Demo.xml └── Client └── DemoClient.cs /.vs/Demo/FileContentIndex/read.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/Program.cs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/README.md -------------------------------------------------------------------------------- /Startup.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/Startup.cs -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 2 | Ключ XML1 3 | -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "JSONKey1": "Значение JSON1" 4 | } 5 | } -------------------------------------------------------------------------------- /.vs/Demo/v17/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/.vs/Demo/v17/.suo -------------------------------------------------------------------------------- /settings.yml: -------------------------------------------------------------------------------- 1 | yamlkey1: Значение yaml1 2 | yamlkey2: Значение yaml2 3 | yamlkey3: 4 | v1: Значение yaml3 -------------------------------------------------------------------------------- /.vs/Demo/v17/.futdcache.v1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/.vs/Demo/v17/.futdcache.v1 -------------------------------------------------------------------------------- /.vs/Demo/DesignTimeBuild/.dtbcache.v2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/.vs/Demo/DesignTimeBuild/.dtbcache.v2 -------------------------------------------------------------------------------- /.vs/ProjectEvaluation/demo.metadata.v1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/.vs/ProjectEvaluation/demo.metadata.v1 -------------------------------------------------------------------------------- /.vs/ProjectEvaluation/demo.projects.v1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderZhelnin/DEMO/HEAD/.vs/ProjectEvaluation/demo.projects.v1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /bin 5 | /obj 6 | 7 | 8 | # Visual Studio 9 | .vs/* -------------------------------------------------------------------------------- /appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "key1": "value5" 10 | } 11 | -------------------------------------------------------------------------------- /Models/PublishersAuthors.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Models; 2 | 3 | public class PublishersAuthors 4 | { 5 | public int AuthorId { get; set; } 6 | public Author Author { get; set; } 7 | public int PublisherId { get; set; } 8 | public Publisher Publisher { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /appsettings.Production.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "ConnectionStrings": { 10 | "DefaultConnection": "Server=127.0.0.1;Port=5432;Database=authors;User Id=test;Password=test;" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Models/Mapper.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Models 2 | { 3 | public static class Mapper 4 | { 5 | /// 6 | /// Ручное сопоставление 7 | /// 8 | //public static AuthorDTO MapTo(this Author author) => new() 9 | //{ 10 | // Id = author.Id, 11 | // Name = author.Name 12 | //}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Models/AuthorDTO.cs: -------------------------------------------------------------------------------- 1 | using GreenDonut; 2 | 3 | namespace Demo.Models; 4 | 5 | /// 6 | /// Автор для передачи данных 7 | /// 8 | public partial class AuthorDTO 9 | { 10 | /** Уникальный идентификатор */ 11 | public int Id { get; set; } 12 | 13 | /** Имя автора */ 14 | public string Name { get; set; } 15 | 16 | public string Name1 { get; set; } 17 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /GraphQl/Subscription.cs: -------------------------------------------------------------------------------- 1 | using Demo.Models; 2 | using HotChocolate; 3 | using HotChocolate.Types; 4 | 5 | namespace Demo.GraphQl; 6 | 7 | /// 8 | /// Подписки 9 | /// 10 | public class Subscription 11 | { 12 | /// 13 | /// Добавлен новый автор 14 | /// 15 | /// 16 | /// Автор 17 | [Subscribe] 18 | public Author OnAuthorChanged([EventMessage] Author author) 19 | => author; 20 | } 21 | -------------------------------------------------------------------------------- /Configurations/DB/DBConfigurationSource.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Configurations.DB; 2 | 3 | 4 | public class DBConfigurationSource : IConfigurationSource 5 | { 6 | private readonly string _connectionString; 7 | 8 | 9 | /** Строка подключения к базе данных */ 10 | public DBConfigurationSource(string connectionString) 11 | { 12 | _connectionString = connectionString; 13 | } 14 | 15 | public IConfigurationProvider Build(IConfigurationBuilder builder) => 16 | new DBConfigurationProvider(_connectionString); 17 | } -------------------------------------------------------------------------------- /Mappers/Register.cs: -------------------------------------------------------------------------------- 1 | using Demo.Models; 2 | using Mapster; 3 | 4 | namespace Demo.Mappers 5 | { 6 | /// 7 | /// Регистрация сопоставления 8 | /// 9 | public class RegisterMapper : IRegister 10 | { 11 | /** */ 12 | public void Register(TypeAdapterConfig config) 13 | { 14 | config.NewConfig() 15 | .Map(adto => adto.Name1, a => a.Name + "1") 16 | .RequireDestinationMemberSource(true); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "ConnectionStrings": { 10 | "DefaultConnection": "Server=127.0.0.1;Port=5432;Database=authors;User Id=test;Password=test;" 11 | }, 12 | "AllowedHosts": "*", 13 | "Authentication": { 14 | "OAUTH_PATH": "http://localhost:8080/auth/realms/SAT/", 15 | "OAUTH_CLIENT_ID": "DEMO" 16 | }, 17 | "key1": "value4" 18 | } 19 | -------------------------------------------------------------------------------- /Mappers/IAuthorMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Demo.Models; 4 | using Mapster; 5 | 6 | namespace Demo; 7 | 8 | /// 9 | /// Интерфейс для генерации сопоставления 10 | /// 11 | [Mapper] 12 | public interface IAuthorMapper 13 | { 14 | Expression> AuthorProjection { get; } 15 | AuthorDTO MapTo(Author author); 16 | AuthorDTO MapTo(Author author, AuthorDTO authordto); 17 | 18 | //Author MapTo(AuthorDTO author); 19 | //Author MapTo(AuthorDTO authordto, Author author); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Configurations/DB/DBConfigurationExtantions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Sqlite; 2 | 3 | namespace Demo.Configurations.DB; 4 | 5 | /** Для удобной регистрации */ 6 | public static class DBConfigurationExtantions 7 | { 8 | public static IConfigurationBuilder AddDB(this IConfigurationBuilder builder) 9 | { 10 | 11 | return builder.Add( 12 | new DBConfigurationSource( 13 | new SqliteConnectionStringBuilder 14 | { 15 | DataSource = System.IO.Path.Combine(AppContext.BaseDirectory, "config.db") 16 | }.ToString())); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Demo.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MvcControllerEmptyScaffolder 5 | root/Common/MVC/Controller 6 | Demo 7 | 8 | 9 | ProjectDebugger 10 | 11 | -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "Demo": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": "true", 7 | "launchBrowser": true, 8 | "launchUrl": "swagger", 9 | "applicationUrl": "http://localhost:5000", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | }, 14 | "Docker": { 15 | "commandName": "Docker", 16 | "launchBrowser": true, 17 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/graphql", 18 | "publishAllPorts": true, 19 | "useSSL": true 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:6.0.4-alpine3.15-amd64 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build 9 | WORKDIR /src 10 | COPY "Demo.csproj" "Demo.csproj" 11 | RUN dotnet restore "Demo.csproj" 12 | COPY . . 13 | WORKDIR "/src" 14 | RUN dotnet build "Demo.csproj" -c Release -o /app/build 15 | 16 | FROM build AS publish 17 | RUN dotnet publish "Demo.csproj" -c Release -o /app/publish 18 | 19 | FROM base AS final 20 | WORKDIR /app 21 | COPY --from=publish /app/publish . 22 | ENTRYPOINT ["dotnet", "Demo.dll"] -------------------------------------------------------------------------------- /Configurations/Dynamic/DynamicValueConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Configurations.Dynamic; 2 | 3 | class DynamicValueConfigurationSource : IConfigurationSource 4 | { 5 | public IConfigurationProvider Build(IConfigurationBuilder builder) => 6 | new DynamicValueConfigurationProvider(); 7 | } 8 | 9 | class DynamicValueConfigurationProvider : ConfigurationProvider 10 | { 11 | private int _count = 0; 12 | 13 | public override void Load() 14 | { 15 | Data = new Dictionary { { "DynamicKey1", "" } }; 16 | } 17 | 18 | public override bool TryGet(string key, out string value) 19 | { 20 | if (!Data.TryGetValue(key, out value)) return false; 21 | 22 | value = $"динамическая конфигурация {++_count}"; 23 | return true; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Models/Publisher.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Demo.Models; 4 | 5 | /// 6 | /// Издатель 7 | /// 8 | public class Publisher 9 | { 10 | public Publisher() 11 | { 12 | 13 | } 14 | /** Уникальный идентификатор */ 15 | public int Id { get; set; } 16 | 17 | /** Название издателя */ 18 | public string Name { get; set; } 19 | 20 | /** Авторы */ 21 | [Newtonsoft.Json.JsonIgnore] 22 | [System.Text.Json.Serialization.JsonIgnore] 23 | public ICollection Authors { get; set; } = new List(); 24 | 25 | /** Связь многие ко многим Издатели/Авторы */ 26 | [Newtonsoft.Json.JsonIgnore] 27 | [System.Text.Json.Serialization.JsonIgnore] 28 | public List PublishersAuthors { get; set; } = new List(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Health/CustumHealth.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Diagnostics.HealthChecks; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Demo.Health; 6 | 7 | /// 8 | /// Кастомная провека работоспособности 9 | /// 10 | public class CustumHealthCheck : IHealthCheck 11 | { 12 | /// 13 | /// Фукнция проверки 14 | /// 15 | /// 16 | /// 17 | /// 18 | public Task CheckHealthAsync( 19 | HealthCheckContext context, 20 | CancellationToken cancellationToken = new CancellationToken()) 21 | { 22 | 23 | return Task.FromResult(HealthCheckResult.Healthy("Моя проверка работает")); 24 | 25 | // return Task.FromResult(HealthCheckResult.Unhealthy("Моя проверка не работает")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Filters/ExceptionFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.Filters; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Demo.Filters; 9 | 10 | /// 11 | /// Фильтр ошибок 12 | /// 13 | public class ExceptionFilter : IExceptionFilter 14 | { 15 | /// 16 | /// Обработчик фильтра ошибок 17 | /// 18 | /// 19 | public void OnException(ExceptionContext context) 20 | { 21 | switch (context.Exception) 22 | { 23 | case ArgumentException e: 24 | context.Result = new NotFoundObjectResult(e.Message); 25 | break; 26 | case InvalidOperationException e: 27 | context.Result = new BadRequestObjectResult(e.Message); 28 | break; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Configurations/DB/DBConfigurationProvider.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.Data.Sqlite; 3 | 4 | namespace Demo.Configurations.DB 5 | { 6 | public class DBConfigurationProvider : ConfigurationProvider 7 | { 8 | /** Строка подключения к базе данных */ 9 | private readonly string _connectionString; 10 | 11 | /** Конструктор */ 12 | public DBConfigurationProvider(string connectionString) 13 | { 14 | _connectionString = connectionString; 15 | } 16 | 17 | /** Загрузка конфигурации из базы данных */ 18 | public override void Load() 19 | { 20 | 21 | using var dbContext = new DBConfigurationContext(_connectionString); 22 | dbContext.Database.EnsureCreated(); 23 | 24 | Data = dbContext.Settings.ToDictionary( 25 | s => $"DBConfiguration:{s.Key}", 26 | s => s.Value, 27 | StringComparer.OrdinalIgnoreCase); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Usage", "CA2254:Шаблон должен быть статическим выражением", Justification = "<Ожидание>", Scope = "member", Target = "~M:Demo.TCPServer.ExecuteAsync(System.Threading.CancellationToken)~System.Threading.Tasks.Task")] 9 | [assembly: SuppressMessage("Reliability", "CA2016:Перенаправьте параметр \"CancellationToken\" в методы", Justification = "<Ожидание>", Scope = "member", Target = "~M:Demo.TCPServer.ExecuteAsync(System.Threading.CancellationToken)~System.Threading.Tasks.Task")] 10 | [assembly: SuppressMessage("Usage", "CA2254:Шаблон должен быть статическим выражением", Justification = "<Ожидание>", Scope = "member", Target = "~M:Demo.BookAVG.ExecuteAsync(System.Threading.CancellationToken)~System.Threading.Tasks.Task")] 11 | -------------------------------------------------------------------------------- /Models/Book.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Demo.Models; 8 | 9 | /** Книга */ 10 | public class Book 11 | { 12 | /** Уникальный идентификатор */ 13 | public int Id { get; set; } 14 | 15 | /** Название книги */ 16 | public string Title { get; set; } 17 | 18 | /** Описание книги */ 19 | public string Description { get; set; } 20 | 21 | /** Обложка */ 22 | public string ImageUrl { get; set; } 23 | 24 | /** Уникльный идентификатор автора */ 25 | public int AuthorId { get; set; } 26 | /** Автор */ 27 | [Newtonsoft.Json.JsonIgnore] 28 | [System.Text.Json.Serialization.JsonIgnore] 29 | public Author Author { get; set; } 30 | 31 | /** Идентификатор ISBN10 */ 32 | public string ISBN_10 { get; set; } 33 | /** Идентификатор ISBN13 */ 34 | public string ISBN_13 { get; set; } 35 | 36 | /** Дополнительная информация по книге */ 37 | public BookDetails Details { get; set; } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 AlexanderZhelnin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Mappers/AuthorMapper.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Demo; 4 | using Demo.Models; 5 | 6 | namespace Demo 7 | { 8 | public partial class AuthorMapper : IAuthorMapper 9 | { 10 | public Expression> AuthorProjection => p1 => new AuthorDTO() 11 | { 12 | Id = p1.Id, 13 | Name = p1.Name, 14 | Name1 = p1.Name + "1" 15 | }; 16 | public AuthorDTO MapTo(Author p2) 17 | { 18 | return p2 == null ? null : new AuthorDTO() 19 | { 20 | Id = p2.Id, 21 | Name = p2.Name, 22 | Name1 = p2.Name + "1" 23 | }; 24 | } 25 | public AuthorDTO MapTo(Author p3, AuthorDTO p4) 26 | { 27 | if (p3 == null) 28 | { 29 | return null; 30 | } 31 | AuthorDTO result = p4 ?? new AuthorDTO(); 32 | 33 | result.Id = p3.Id; 34 | result.Name = p3.Name; 35 | result.Name1 = p3.Name + "1"; 36 | return result; 37 | 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /HttpHandler/HttpTrackerHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Demo.HttpHandler; 8 | 9 | /// 10 | /// Передача аргументов запроса в вызов 11 | /// 12 | public class HttpTrackerHandler : DelegatingHandler 13 | { 14 | private readonly IHttpContextAccessor _context; 15 | 16 | /** Конструктор */ 17 | public HttpTrackerHandler(IHttpContextAccessor context) 18 | { 19 | _context = context; 20 | } 21 | 22 | /** Асинхронный метод вызова */ 23 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 24 | { 25 | if (_context.HttpContext.Request.Headers.TryGetValue("Authorization", out var jwt)) 26 | request.Headers.Add("Authorization", jwt.FirstOrDefault()); 27 | 28 | if (_context.HttpContext.Request.Headers.TryGetValue("TraceId", out var traceid)) 29 | request.Headers.Add("TraceId", traceid.FirstOrDefault()); 30 | 31 | return base.SendAsync(request, cancellationToken); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Models/Author.cs: -------------------------------------------------------------------------------- 1 | using HotChocolate; 2 | using HotChocolate.AspNetCore.Authorization; 3 | using Mapster; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Linq; 8 | using System.Runtime.Serialization; 9 | using System.Threading.Tasks; 10 | using DefaultValueAttribute = HotChocolate.Types.DefaultValueAttribute; 11 | 12 | namespace Demo.Models; 13 | 14 | /// 15 | /// Автор 16 | /// 17 | public class Author 18 | { 19 | /** Уникальный идентификатор */ 20 | public int Id { get; set; } 21 | 22 | /** Имя автора */ 23 | [DefaultValue("Вася")] 24 | public string Name { get; set; } 25 | 26 | /** Книги автора */ 27 | //[Authorize(Roles = new[] { "admin" })] 28 | public ICollection Books { get; set; } = new List(); 29 | 30 | /** Издательства */ 31 | public List Publishers { get; set; } = new List(); 32 | 33 | /** Связь многие ко многим Издатели/Авторы */ 34 | [Newtonsoft.Json.JsonIgnore] 35 | [System.Text.Json.Serialization.JsonIgnore] 36 | [GraphQLIgnore] 37 | public List PublishersAuthors { get; set; } = new List(); 38 | 39 | public override string ToString() => $"{Id}:{Name}"; 40 | } 41 | -------------------------------------------------------------------------------- /Configurations/DB/DBConfigurationContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Demo.Configurations.DB; 4 | 5 | public class Settings 6 | { 7 | public string Key { get; set; } 8 | public string Value { get; set; } 9 | } 10 | 11 | /** Контекст базы данных для конфигурации */ 12 | public class DBConfigurationContext: DbContext 13 | { 14 | private readonly string _connectionString; 15 | 16 | public DbSet Settings { get; set; } 17 | 18 | public DBConfigurationContext(string connectionString) 19 | { 20 | _connectionString = connectionString; 21 | } 22 | 23 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 24 | { 25 | 26 | optionsBuilder.UseSqlite(_connectionString); 27 | } 28 | 29 | protected override void OnModelCreating(ModelBuilder modelBuilder) 30 | { 31 | modelBuilder.Entity(b => 32 | { 33 | b.HasKey(a => a.Key); 34 | 35 | b.HasData( 36 | new() { Key = "DBKey1", Value = "DB Значение 1" }, 37 | new() { Key = "DBKey2", Value = "DB Значение 2" }, 38 | new() { Key = "DBKey3", Value = "DB Значение 3" } 39 | 40 | 41 | ); 42 | }); 43 | } 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /DBContext/DemoRepository.cs: -------------------------------------------------------------------------------- 1 | using Demo.Models; 2 | using System; 3 | using System.Linq; 4 | 5 | namespace Demo.DB; 6 | 7 | /** Демо репозиторий */ 8 | public class DemoRepository 9 | { 10 | private readonly DemoContext _ctx; 11 | 12 | /** Конструктор */ 13 | public DemoRepository(DemoContext ctx) 14 | { 15 | _ctx = ctx; 16 | } 17 | 18 | /// 19 | /// Получить автора по иникальному идентификатору 20 | /// 21 | /// Уникальный идентификатор 22 | /// 23 | public Author Get(int id) 24 | { 25 | var author = _ctx.Authors.FirstOrDefault(x => x.Id == id); 26 | if (author == null) throw new ArgumentException($"Автора с заданным Id: {id} не существует"); 27 | return author; 28 | } 29 | /// 30 | /// Обновить автора 31 | /// 32 | /// автор для обновления 33 | public void Update(Author author) 34 | { 35 | var a = Get(author.Id); 36 | 37 | try 38 | { 39 | _ctx.Update(author); 40 | _ctx.SaveChanges(); 41 | } 42 | catch 43 | { 44 | throw new InvalidOperationException($"Не удалось обновить автора {author.Id}"); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /HttpHandler/HttpRequestInterceptor.cs: -------------------------------------------------------------------------------- 1 | using HotChocolate.AspNetCore; 2 | using HotChocolate.Execution; 3 | using Microsoft.AspNetCore.Http; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Security.Claims; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace Demo.HttpHandler; 12 | 13 | public class HttpRequestInterceptor : DefaultHttpRequestInterceptor 14 | { 15 | public override ValueTask OnCreateAsync(HttpContext context, 16 | IRequestExecutor requestExecutor, IQueryRequestBuilder requestBuilder, 17 | CancellationToken cancellationToken) 18 | { 19 | var identity = new ClaimsIdentity(); 20 | var rolesv = context.User.FindFirstValue("realm_access"); 21 | if (rolesv != null) 22 | { 23 | dynamic roles = Newtonsoft.Json.Linq.JObject.Parse(rolesv); 24 | foreach (var r in roles.roles) 25 | identity.AddClaim(new Claim(ClaimTypes.Role, r.Value)); 26 | } 27 | 28 | var namev = context.User.FindFirstValue("preferred_username"); 29 | if (namev != null) 30 | identity.AddClaim(new Claim(ClaimTypes.Name, namev)); 31 | 32 | context.User.AddIdentity(identity); 33 | 34 | return base.OnCreateAsync(context, requestExecutor, requestBuilder, 35 | cancellationToken); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /BackgroundService/BookAVG.cs: -------------------------------------------------------------------------------- 1 | using Demo.DB; 2 | using Demo.Models; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Microsoft.Extensions.Logging; 6 | using System; 7 | using System.Diagnostics; 8 | using System.Linq; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace Demo; 13 | 14 | /** Фоновый процесс расчёта среднего колличества отзывов */ 15 | public class BookAVG : BackgroundService 16 | { 17 | private readonly ILogger _logger; 18 | private readonly DemoContext _ctx; 19 | private readonly TimeSpan _interval = TimeSpan.FromMinutes(5); 20 | 21 | /// 22 | /// Конструктор 23 | /// 24 | /// 25 | /// контекст базы данных 26 | public BookAVG(ILogger logger, DemoContext ctx) 27 | { 28 | _logger = logger; 29 | _ctx = ctx; 30 | } 31 | 32 | /// 33 | /// Выполнение фонового процесса 34 | /// 35 | /// токен завершения 36 | /// 37 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 38 | { 39 | while (!stoppingToken.IsCancellationRequested) 40 | { 41 | _logger.LogDebug(_ctx.BookDetails.Average(db => db.Reviews).ToString()); 42 | 43 | await Task.Delay(_interval, stoppingToken); 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Controllers/DTOController.cs: -------------------------------------------------------------------------------- 1 | using Demo.DB; 2 | using Demo.Models; 3 | using Mapster; 4 | using MapsterMapper; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace Demo.Controllers; 10 | 11 | /** Пример контроллера для показа работы Mapster */ 12 | [Route("api/[controller]")] 13 | [ApiController] 14 | public class DTOController : ControllerBase 15 | { 16 | private readonly IMapper _mapper; 17 | private readonly DemoContext _ctx; 18 | 19 | /// 20 | /// Конструктор 21 | /// 22 | /// мапинг 23 | /// контекст базы данных 24 | public DTOController( 25 | IMapper mapper, 26 | DemoContext ctx 27 | ) 28 | { 29 | _mapper = mapper; 30 | _ctx = ctx; 31 | } 32 | 33 | /// 34 | /// Получить авторов DTO 35 | /// 36 | /// 37 | [HttpGet("", Name = nameof(GetDTOAuthors))] 38 | public IQueryable GetDTOAuthors() 39 | { 40 | return _mapper 41 | .From(_ctx.Authors) 42 | .ProjectToType(); 43 | } 44 | 45 | 46 | /// 47 | /// Получить автора по уникальному идентификатору 48 | /// 49 | /// 50 | /// 51 | /// GET api/Authors/1 52 | [HttpGet("{id}", Name = nameof(GetAuthorDTOById))] 53 | [ProducesResponseType(StatusCodes.Status200OK)] 54 | [ProducesDefaultResponseType] 55 | public ActionResult GetAuthorDTOById(int id) 56 | { 57 | var result = _ctx.Authors.FirstOrDefault(a => a.Id == id); 58 | 59 | if (result == null) return NotFound(); 60 | 61 | return result.Adapt(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Models/BookDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Demo.Models; 4 | 5 | /** Статус книги */ 6 | public enum StatusEnum 7 | { 8 | /** Книга завершена */ 9 | complite = 0, 10 | /** Книга пишется */ 11 | write = 1, 12 | } 13 | 14 | /** Язык */ 15 | public enum LanguageEnum 16 | { 17 | /** Русский */ 18 | ru = 0, 19 | /** Английский */ 20 | en = 1, 21 | } 22 | 23 | /** Жанр книги */ 24 | public enum GenreEnum 25 | { 26 | /** Фантастика */ 27 | fantastic, 28 | /** Фантази */ 29 | fantasy, 30 | /** litRPG */ 31 | litrpg, 32 | /** Научная литература */ 33 | scientific, 34 | /** Историческая литература */ 35 | historical 36 | } 37 | 38 | 39 | /** Дополнительная информация по книге */ 40 | public class BookDetails 41 | { 42 | 43 | /** Уникальный идентификатор */ 44 | public int BookId { get; set; } 45 | /** Книга */ 46 | public Book Book { get; set; } 47 | 48 | /** Ранк книги */ 49 | public double Rank { get; set; } 50 | /** Статус книги */ 51 | public StatusEnum Status { get; set; } = StatusEnum.complite; 52 | 53 | /** Стоимость книги в мягком переплёте */ 54 | public decimal PeperbackCost { get; set; } 55 | 56 | /** Стоимость книги в твёрдом переплёте */ 57 | public decimal HardcoverCost { get; set; } 58 | /** Дата выпуска */ 59 | public DateTime Year { get; set; } 60 | 61 | /** Редакция */ 62 | public string Editor { get; set; } 63 | 64 | /** иллюстратор */ 65 | public string Illustrator { get; set; } 66 | 67 | /** Колличество страниц */ 68 | public int PageCount { get; set; } 69 | 70 | /** Язык */ 71 | public LanguageEnum Language { get; set; } 72 | 73 | /** Возростные ограничения */ 74 | public byte ReadingAge { get; set; } 75 | 76 | /** Жанр */ 77 | public GenreEnum Genre { get; set; } 78 | /** Отзывы */ 79 | public int Reviews { get; set; } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /BackgroundService/TCPServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Net; 5 | using System.Net.Sockets; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Demo; 11 | 12 | /** Сервер TCP */ 13 | public class TCPServer : BackgroundService 14 | { 15 | private readonly ILogger _logger; 16 | private const int port = 8888; 17 | 18 | /// 19 | /// Конструктор 20 | /// 21 | /// 22 | public TCPServer(ILogger logger) 23 | { 24 | _logger = logger; 25 | 26 | } 27 | 28 | /// 29 | /// Выполнение фонового процесса 30 | /// 31 | /// 32 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 33 | { 34 | TcpListener server = null; 35 | try 36 | { 37 | server = new TcpListener(IPAddress.Any, port); 38 | 39 | // запуск слушателя 40 | server.Start(); 41 | 42 | while (!stoppingToken.IsCancellationRequested) 43 | { 44 | _logger.LogTrace("Ожидание подключений... "); 45 | 46 | // получаем входящее подключение 47 | using var client = server.AcceptTcpClient(); 48 | _logger.LogTrace("Подключен клиент. Выполнение запроса..."); 49 | 50 | // получаем сетевой поток для чтения и записи 51 | using var stream = client.GetStream(); 52 | 53 | // сообщение для отправки клиенту 54 | var response = "Привет мир"; 55 | // преобразуем сообщение в массив байтов 56 | var data = Encoding.UTF8.GetBytes(response); 57 | 58 | // отправка сообщения 59 | await stream.WriteAsync(new ReadOnlyMemory(data), stoppingToken); 60 | _logger.LogTrace($"Отправлено сообщение: {response}"); 61 | 62 | } 63 | } 64 | catch (Exception e) 65 | { 66 | _logger.LogError(e.Message); 67 | } 68 | finally 69 | { 70 | server?.Stop(); 71 | } 72 | } 73 | 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /LongPollingQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reactive.Linq; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace Demo; 9 | 10 | #region LongPollingValue 11 | /// 12 | /// Значение очереди 13 | /// 14 | /// 15 | public class LongPollingValue 16 | { 17 | /// 18 | /// Текущие занчение 19 | /// 20 | public K Value { get; set; } 21 | /// 22 | /// Маркер по котором считываем новые значения 23 | /// 24 | public DateTime Marker { get; set; } 25 | 26 | /// 27 | /// Следующий элемент в связанном списке 28 | /// 29 | [JsonIgnore] 30 | public LongPollingValue Next { get; set; } 31 | } 32 | #endregion 33 | 34 | /// 35 | /// Очередь реализующаю паттерн LongPolling ( "Длительный Опрос" ) 36 | /// 37 | /// generetic тип очереди 38 | public class LongPollingQuery 39 | { 40 | #region Свойства 41 | private LongPollingValue _first { get; set; } 42 | private LongPollingValue _last { get; set; } 43 | 44 | /// 45 | /// Максимальное время удержания запроса, когда нет подходящих данных 46 | /// 47 | public TimeSpan TimeOut { get; set; } = TimeSpan.FromSeconds(10); 48 | 49 | /// 50 | /// Время устаревания данных в очереди 51 | /// 52 | public TimeSpan WatchDogTimeOut { get; set; } = TimeSpan.FromMinutes(5); 53 | #endregion 54 | 55 | #region События 56 | private event Action Added; 57 | #endregion 58 | 59 | #region Конструктор 60 | /// 61 | /// Конструктор 62 | /// 63 | public LongPollingQuery() 64 | { 65 | var clearwatchdog = Observable.FromEvent(h => Added += h, h => Added -= h); 66 | 67 | clearwatchdog 68 | .Sample(TimeSpan.FromMinutes(1)) 69 | .Subscribe(_ => 70 | { 71 | var dt = DateTime.Now - WatchDogTimeOut; 72 | while (_first != null && _first.Marker < dt) _first = _first.Next; 73 | }); 74 | } 75 | #endregion 76 | 77 | private readonly object _lock = new(); 78 | #region Add 79 | /// 80 | /// Добавление в очередь 81 | /// 82 | public void Add(T value) 83 | { 84 | lock (_lock) 85 | { 86 | var added = new LongPollingValue { Value = value, Marker = DateTime.Now }; 87 | if (_first == null) 88 | _first = _last = added; 89 | else 90 | _last = _last.Next = added; 91 | } 92 | Added(); 93 | } 94 | #endregion 95 | 96 | #region Read 97 | /// 98 | /// Чтение из очереди 99 | /// 100 | /// маркер после которого происходит чтение данных из очереди 101 | /// 102 | public async IAsyncEnumerable> Read(DateTime marker) 103 | { 104 | await Task.Delay(500); 105 | var dtstart = DateTime.Now; 106 | var fined = false; 107 | do 108 | { 109 | var item = _first; 110 | while (item != null) 111 | { 112 | fined = item.Marker > marker; 113 | if (fined) yield return item; 114 | 115 | item = item.Next; 116 | } 117 | if (!fined) await Task.Delay(500); 118 | } 119 | while (!fined && (DateTime.Now - dtstart) < TimeOut); 120 | } 121 | #endregion 122 | } 123 | -------------------------------------------------------------------------------- /GraphQl/Mutation.cs: -------------------------------------------------------------------------------- 1 | using Demo.DB; 2 | using Demo.Models; 3 | using HotChocolate; 4 | using HotChocolate.Subscriptions; 5 | using System; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace Demo.GraphQl; 10 | 11 | /// 12 | /// Изменения GraphQL 13 | /// Главное отличие в том что подзапросы выполняются последовательно, в том же порядке что указано в запросе 14 | /// 15 | public class Mutation 16 | { 17 | #region Create 18 | /// 19 | /// Создание автора 20 | /// 21 | /// Создаваемый автор 22 | /// Контекст базы данных Entity 23 | /// Автор 24 | public Author Create(Author author, [Service] DemoContext ctx) 25 | { 26 | ctx.Add(author); 27 | ctx.SaveChanges(); 28 | return author; 29 | } 30 | #endregion 31 | 32 | #region Update 33 | /// 34 | /// Обновление автора 35 | /// 36 | /// Обновляемый автор 37 | /// Контекст базы данных Entity 38 | /// Автор 39 | public Author Update(Author author, [Service] DemoContext ctx) 40 | { 41 | ctx.Update(author); 42 | ctx.SaveChanges(); 43 | return author; 44 | } 45 | #endregion 46 | 47 | #region Delete 48 | /// 49 | /// Удаление автора 50 | /// 51 | /// Уникальный идентификатор автора 52 | /// Контекст базы данных Entity 53 | /// Автор 54 | public Author Delete(int id, [Service] DemoContext ctx) 55 | { 56 | var author = ctx.Authors.FirstOrDefault(a => a.Id == id); 57 | if (author == null) 58 | throw new ArgumentException("Автор не найден"); 59 | ctx.Remove(author); 60 | ctx.SaveChanges(); 61 | return author; 62 | } 63 | #endregion 64 | 65 | #region CreateOrUpdate 66 | /// 67 | /// Создать или обновить автора тут логика такая, если Id равен 0, то это однозначно новый автор 68 | /// 69 | /// Контекст базы данных Entity 70 | /// Создать или обновить автора 71 | /// 72 | /// Автор 73 | public async Task CreateOrUpdate(Author author, [Service] DemoContext ctx, [Service] ITopicEventSender sender) 74 | { 75 | if (author.Id == 0 || !ctx.Authors.Any(a => a.Id == author.Id)) 76 | ctx.Add(author); 77 | else 78 | ctx.Update(author); 79 | 80 | ctx.SaveChanges(); 81 | 82 | // по инициативе сервера отправляем клиентам данные 83 | await sender.SendAsync(nameof(Subscription.OnAuthorChanged), author); 84 | return author; 85 | } 86 | #endregion 87 | 88 | #region ThrowError 89 | /// 90 | /// Генерация ошибки для проверки транзакции 91 | /// 92 | /// Автор 93 | public Author ThrowError() 94 | { 95 | throw new Exception("Специально сгенерированная ошибка"); 96 | } 97 | #endregion 98 | 99 | #region TestDateTime 100 | /// 101 | /// Проверка даты 102 | /// 103 | /// 104 | /// 105 | public DateTime TestDateTime(DateTime dt) 106 | { 107 | return dt; 108 | } 109 | #endregion 110 | 111 | public int[] Test1() 112 | { 113 | return new int[] { 1, 2, 3 }; 114 | } 115 | 116 | 117 | public string Test2(int[] ids) 118 | { 119 | return string.Join(',', ids); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | true 7 | b7a1d7c8-f8b1-4ec6-a192-45531ffa65c8 8 | Linux 9 | c:\Project\DEMO\DEMO\Demo.xml 10 | https://github.com/AlexanderZhelnin/DEMO 11 | 12 | 13 | 14 | $(DefineConstants)TRACE SQLITE 15 | 16 | 17 | 18 | $(DefineConstants)TRACE SQLITE 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Always 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | all 56 | runtime; build; native; contentfiles; analyzers; buildtransitive 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Always 71 | 72 | 73 | Always 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /Controllers/PublisherController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Demo.Models; 6 | using Microsoft.AspNetCore.Http; 7 | using System.Net.Http; 8 | using Microsoft.AspNetCore.Authorization; 9 | using System.Threading.Tasks; 10 | using Microsoft.EntityFrameworkCore; 11 | using Demo.DB; 12 | 13 | namespace Demo.Controllers; 14 | 15 | /// 16 | /// Контроллер издателей 17 | /// 18 | [Route("api/[controller]")] 19 | [ApiController] 20 | public class PublisherController : ControllerBase 21 | { 22 | 23 | #region Переменные 24 | internal static int _id = 20; 25 | private readonly DemoContext _ctx; 26 | private readonly IHttpClientFactory _httpClientFactory; 27 | #endregion 28 | 29 | #region Конструктор 30 | /// 31 | /// Конструктор 32 | /// 33 | public PublisherController(DemoContext ctx, IHttpClientFactory httpClientFactory) 34 | { 35 | _ctx = ctx; 36 | _httpClientFactory = httpClientFactory; 37 | } 38 | #endregion 39 | 40 | /// 41 | /// Получение всех издателей 42 | /// 43 | [HttpGet("", Name = nameof(GetAllPublishers))] 44 | public IQueryable GetAllPublishers() => 45 | _ctx.Publishers 46 | .Include(a => a.Authors); 47 | 48 | /// 49 | /// Получить издателя по уникальному идентификатору 50 | /// 51 | /// 52 | /// 53 | /// GET api/Authors/1 54 | [HttpGet("{id}", Name = nameof(GetPublisherById))] 55 | [ProducesResponseType(StatusCodes.Status200OK)] 56 | [ProducesDefaultResponseType] 57 | [Authorize] 58 | public ActionResult GetPublisherById(int id) 59 | { 60 | var result = _ctx.Publishers.FirstOrDefault(a => a.Id == id); 61 | 62 | if (result == null) return NotFound(); 63 | 64 | return result; 65 | } 66 | 67 | /// 68 | /// Получение авторов по уникальному идентификатору издателя 69 | /// 70 | /// 71 | /// 72 | /// GET api/Publisher/1/Author 73 | [HttpGet("{id}/Author", Name = nameof(GetAuthor))] 74 | [ProducesResponseType(StatusCodes.Status200OK)] 75 | [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] 76 | public ActionResult> GetAuthor(int id) 77 | { 78 | var result = _ctx.Publishers.FirstOrDefault(a => a.Id == id); 79 | 80 | if (result == null) 81 | return BadRequest($"Издательства с заданным Id: {id} не существует"); 82 | 83 | return result.Authors.ToArray(); 84 | } 85 | 86 | /// 87 | /// Создание нового издательства 88 | /// 89 | /// новый издательство 90 | /// POST api/Authors 91 | [HttpPost(Name = nameof(CreatePublisher))] 92 | public void CreatePublisher([FromBody] Publisher publisher) 93 | { 94 | publisher.Id = ++_id; 95 | _ctx.Publishers.Add(publisher); 96 | } 97 | 98 | /// 99 | /// Добавление Автора к издателю 100 | /// 101 | /// Уникальный идентификатор издателя 102 | /// Уникальный идентификатор автора 103 | 104 | /// POST api/Authors 105 | [HttpPost("{id}/AddAuthor/{authorId}", Name = nameof(AddAuthor))] 106 | [ProducesResponseType(StatusCodes.Status200OK)] 107 | [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] 108 | [ProducesDefaultResponseType] 109 | public ActionResult AddAuthor(int id, int authorId) 110 | { 111 | #region Валидация 112 | var author = _ctx.Authors.FirstOrDefault(a => a.Id == authorId); 113 | if (author == null) 114 | return BadRequest($"Автора с заданным Id: {authorId} не существует"); 115 | 116 | var publisher = _ctx.Publishers 117 | // .Include(p => p.Authors) 118 | .FirstOrDefault(a => a.Id == id); 119 | if (publisher == null) 120 | return BadRequest($"Издателя с заданным Id: {id} не существует"); 121 | 122 | var relation = _ctx.PublishersAuthors.FirstOrDefault(a => a.PublisherId == id && a.AuthorId == authorId); 123 | if (relation != null) 124 | return BadRequest($"Автор с заданным Id: {authorId} уже добавлен в издалеля {id}"); 125 | #endregion 126 | 127 | //publisher.Authors.Add(author); 128 | _ctx.PublishersAuthors.Add(new() { AuthorId = authorId, PublisherId = id }); 129 | _ctx.SaveChangesAsync(); 130 | return Ok(true); 131 | } 132 | 133 | /// 134 | /// Изменение автора 135 | /// 136 | /// издатель 137 | /// PUT api/Publisher 138 | [HttpPut("", Name = nameof(UpdatePublisher))] 139 | public ActionResult UpdatePublisher([FromBody] Publisher publisher) 140 | { 141 | _ctx.Update(publisher); 142 | _ctx.SaveChanges(); 143 | 144 | return publisher; 145 | } 146 | 147 | /// 148 | /// Удаление издателя 149 | /// 150 | /// 151 | /// DELETE api/Publisher/1 152 | [HttpDelete("{id}", Name = nameof(DeletePublisher))] 153 | public void DeletePublisher(int id) 154 | { 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /nlog.config: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 29 | 30 | 32 | 33 | Server=127.0.0.1;Port=5432;Database=logs;User Id=test;Password=test; 34 | 35 | 36 | insert into "logs".logging(log_date,log_level,log_logger,log_message, stacktrace) values(@time_stamp, @level, @logger, @message, @stacktrace); 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | Data Source=${basedir}\logs.db 50 | 51 | 52 | insert into logging(log_date,log_level,log_logger,log_message,stacktrace) values(@time_stamp, @level, @logger, @message, @stacktrace); 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 76 | 77 | 78 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /Controllers/AuthorsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Demo.Models; 6 | using Microsoft.AspNetCore.Http; 7 | using System.Net.Http; 8 | using Microsoft.AspNetCore.Authorization; 9 | using System.Threading.Tasks; 10 | using Microsoft.EntityFrameworkCore; 11 | using Demo.DB; 12 | using Mapster; 13 | 14 | namespace Demo.Controllers; 15 | 16 | /// 17 | /// Контроллер авторов 18 | /// 19 | [Route("api/[controller]")] 20 | [ApiController] 21 | public partial class AuthorsController : ControllerBase 22 | { 23 | #region Переменные 24 | internal static int _id = 20; 25 | private readonly LongPollingQuery _longpolling; 26 | private readonly DemoContext _ctx; 27 | private readonly DemoRepository _repository; 28 | private readonly IHttpClientFactory _httpClientFactory; 29 | private readonly ILogger _logger; 30 | #endregion 31 | 32 | #region Конструктор 33 | /// 34 | /// Конструктор 35 | /// 36 | public AuthorsController( 37 | 38 | LongPollingQuery longpolling, 39 | DemoContext ctx, 40 | DemoRepository repository, 41 | IHttpClientFactory httpClientFactory, 42 | ILogger logger) 43 | { 44 | _longpolling = longpolling; 45 | _ctx = ctx; 46 | _repository = repository; 47 | _httpClientFactory = httpClientFactory; 48 | _logger = logger; 49 | } 50 | #endregion 51 | 52 | #region TestTrace 53 | /// 54 | /// Тестовая функция с получением данных из "другого" микросервиса, с авторизацией 55 | /// 56 | [HttpGet("TestTrace", Name = nameof(TestTrace))] 57 | public async Task> TestTrace() 58 | { 59 | var demoClient = new Client.DemoClient("http://localhost:5004", _httpClientFactory.CreateClient("auth")); 60 | 61 | var bs = await demoClient.GetByIdAsync(1); 62 | 63 | //var responce = await _httpClientFactory.CreateClient("auth").GetAsync("http://localhost:5004/api/authors/1"); 64 | //var result = await responce.Content.ReadAsStringAsync(); 65 | return _ctx.Authors; 66 | } 67 | #endregion 68 | 69 | /// 70 | /// Получение всех авторов 71 | /// 72 | [HttpGet("", Name = nameof(GetAllAuthors))] 73 | public IQueryable GetAllAuthors() 74 | { 75 | return _ctx.Authors 76 | .AsNoTracking() 77 | .Include(a => a.Books) 78 | .Include(a => a.Publishers); 79 | } 80 | 81 | 82 | /// 83 | /// Получить автора по уникальному идентификатору 84 | /// 85 | /// 86 | /// 87 | /// GET api/Authors/1 88 | [HttpGet("{id}", Name = nameof(GetAuthorById))] 89 | [ProducesResponseType(StatusCodes.Status200OK)] 90 | [ProducesDefaultResponseType] 91 | [Authorize] 92 | public ActionResult GetAuthorById(int id) 93 | { 94 | var result = _ctx.Authors.FirstOrDefault(a => a.Id == id); 95 | 96 | if (result == null) return NotFound(); 97 | 98 | return result; 99 | } 100 | 101 | /// 102 | /// Получение книг по уникальному идентификатору и названию 103 | /// 104 | /// 105 | /// 106 | /// 107 | /// GET api/Authors/1/Book/Первая книга Васи 108 | [HttpGet("{id}/Book/{title?}", Name = nameof(GetBook))] 109 | [ProducesResponseType(StatusCodes.Status200OK)] 110 | [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] 111 | public ActionResult> GetBook(int id, string title) 112 | { 113 | var result = _ctx.Authors.FirstOrDefault(a => a.Id == id); 114 | 115 | if (result == null) 116 | return BadRequest($"Автора с заданным Id: {id} не существует"); 117 | 118 | return title == null 119 | ? result.Books.ToArray() 120 | : result.Books.Where(b => string.Equals(b.Title, title, StringComparison.OrdinalIgnoreCase)).ToArray(); 121 | } 122 | 123 | /// 124 | /// Метод чтения реализующий паттерн LongPolling 125 | /// 126 | /// маркер после которого происходит чтение данных из очереди 127 | /// коллекция результат 128 | /// GET api/Authors/GetChanges/ 129 | [HttpGet("getchages/{marker}", Name = nameof(GetChanges))] 130 | public IAsyncEnumerable> GetChanges(string marker) 131 | { 132 | if (marker == "0") 133 | marker = DateTime.MinValue.ToString("o"); 134 | 135 | if (!DateTime.TryParse(marker, out var dt)) 136 | return AsyncEnumerable.Empty>(); ; 137 | 138 | return _longpolling.Read(dt); 139 | } 140 | 141 | /// 142 | /// Создание нового автора 143 | /// 144 | /// новый автор 145 | /// POST api/Authors 146 | [HttpPost(Name = nameof(CreateAuthor))] 147 | public void CreateAuthor([FromBody] Author author) 148 | { 149 | author.Id = ++_id; 150 | 151 | _ctx.Authors.Add(author); 152 | _longpolling.Add(author); 153 | } 154 | 155 | /// 156 | /// Изменение автора 157 | /// 158 | /// 159 | /// PUT api/Authors 160 | [HttpPut("", Name = nameof(UpdateAuthor))] 161 | public ActionResult UpdateAuthor([FromBody] Author author) 162 | { 163 | //var existAuthor = _ctx.Authors.FirstOrDefault(a => a.Id == author.Id); 164 | //if (existAuthor == null) 165 | // return NotFound($"Не удалось найти автора для обновления {author.Id}"); 166 | 167 | //try 168 | //{ 169 | // _ctx.Update(author); 170 | // _ctx.SaveChanges(); 171 | //} 172 | //catch (Exception exception) 173 | //{ 174 | // // 175 | // // тут будет запись ошибки в лог 176 | // // 177 | 178 | // return BadRequest($"Не удалось обновить автора {author.Id}"); 179 | //} 180 | 181 | //return author; 182 | 183 | _repository.Update(author); 184 | return author; 185 | } 186 | 187 | /// 188 | /// Удаление автора 189 | /// 190 | /// 191 | /// DELETE api/Authors/1 192 | [HttpDelete("{id}", Name = nameof(DeleteAuthor))] 193 | public void DeleteAuthor(int id) 194 | { 195 | } 196 | 197 | /// 198 | /// Создание нового автора 199 | /// 200 | /// новый автор 201 | /// POST api/Authors 202 | [HttpPost("upsert", Name = nameof(UpsertAuthor))] 203 | public void UpsertAuthor([FromBody] Author author) 204 | { 205 | //author.Id = ++_id; 206 | author.Name ??= "Вася"; 207 | 208 | _ctx.Upsert(author).Run(); 209 | //_ctx.Set(author).addor 210 | //_ctx.Authors.Add(author); 211 | //_longpolling.Add(author); 212 | //_ctx.SaveChanges(); 213 | } 214 | 215 | /// 216 | /// Тестовая функция с получением данных из "другого" микросервиса, с авторизацией 217 | /// 218 | [HttpGet("TestDate", Name = nameof(TestDate))] 219 | public DateTime TestDate(DateTime dt) 220 | { 221 | return dt; 222 | } 223 | 224 | 225 | } 226 | -------------------------------------------------------------------------------- /GraphQl/Query.cs: -------------------------------------------------------------------------------- 1 | using Demo.Models; 2 | using HotChocolate; 3 | using HotChocolate.AspNetCore.Authorization; 4 | using HotChocolate.Data; 5 | using HotChocolate.Types; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Security.Claims; 12 | using Microsoft.Extensions.Logging; 13 | using HotChocolate.Types.Pagination; 14 | using System.Threading.Tasks; 15 | using Microsoft.EntityFrameworkCore; 16 | using Microsoft.Extensions.Options; 17 | using Demo.DB; 18 | 19 | namespace Demo.GraphQl; 20 | 21 | /// 22 | /// Запросы GraphQl 23 | /// Главное отличик запроса в том что его подзапросы выполняются параллельно 24 | /// 25 | public partial class Query 26 | { 27 | [LoggerMessage(0, LogLevel.Information, "Чтение {Author}")] 28 | partial void LogRead(Author author); 29 | 30 | private readonly ILogger _logger; 31 | private readonly IConfiguration _configuration; 32 | //private readonly IOptionsMonitor _settings; 33 | 34 | //private static Dictionary Permissions = new Dictionary 35 | //{ 36 | // { "admin", new int[] { 1 } }, 37 | // { "Вася", new int[] { 2 } } 38 | //}; 39 | 40 | /// 41 | /// Конструктор 42 | /// 43 | public Query(ILogger logger, IConfiguration configuration)//, IOptionsMonitor settings) 44 | { 45 | (_logger, _configuration) = (logger, configuration); 46 | 47 | logger.LogInformation("Инициализация"); 48 | //_settings = settings; 49 | } 50 | 51 | /// 52 | /// Возвращает первую версию 53 | /// 54 | /// 55 | public Api1 V1() => 56 | new Api1(); 57 | 58 | 59 | #region Authors 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | /// 66 | /// 67 | [UseDbContext(typeof(DemoContext))] 68 | [UsePaging(IncludeTotalCount = true)] 69 | [UseProjection] 70 | public Connection MyLogicPaginAuthors(string? after, int? first, string sortBy, [ScopedService] DemoContext ctx) 71 | { 72 | 73 | var pageSize = first ?? 10; 74 | var authors = ((IQueryable)ctx.Authors); 75 | var count = authors.Count(); 76 | var hasNextPage = false; 77 | 78 | if (after != null) 79 | { 80 | var split = after.IndexOf('_'); 81 | var id = Convert.ToInt32(after[..split]); 82 | var name = after[(split + 1)..]; 83 | 84 | authors = 85 | authors 86 | .Where(a => string.Compare(a.Name, name) == 1 || (a.Name == name && a.Id > id)); 87 | } 88 | 89 | var edges = 90 | authors 91 | .OrderBy(a => a.Name) 92 | .ThenBy(a => a.Id) 93 | .Select(a => new Edge(a, $"{a.Id}_{a.Name}")) 94 | .Take(pageSize + 1) 95 | .ToList(); 96 | 97 | 98 | hasNextPage = edges.Count > pageSize; 99 | 100 | edges = edges.SkipLast(1).ToList(); 101 | 102 | var pageInfo = 103 | new ConnectionPageInfo( 104 | hasNextPage, 105 | false, 106 | edges.FirstOrDefault()?.Cursor, 107 | edges.LastOrDefault()?.Cursor); 108 | 109 | var connection = 110 | new Connection( 111 | edges, 112 | pageInfo, 113 | ct => ValueTask.FromResult(count)); 114 | 115 | return connection; 116 | } 117 | 118 | /// 119 | /// Запрос чтения 120 | /// 121 | /// Контекст базы данных Entity 122 | /// Авторы 123 | [UseDbContext(typeof(DemoContext))] 124 | //[UsePaging(IncludeTotalCount = true)] 125 | //[UseOffsetPaging] 126 | [UseProjection] 127 | [UseFiltering()] 128 | //[UseFiltering(typeof(AuthorFilterType))] 129 | [UseSorting()] 130 | public IQueryable Authors([ScopedService] DemoContext ctx)//, ClaimsPrincipal claimsPrincipal) 131 | { 132 | #region MyRegion 133 | //var roles = claimsPrincipal.FindAll(ClaimTypes.Role).ToArray(); 134 | //var accessIds = new List(); 135 | //foreach (var r in roles) 136 | // if (Permissions.TryGetValue(r.Value, out var ids)) accessIds.AddRange(ids); 137 | //return ((IQueryable)ctx.Authors).Where(a => accessIds.Contains(a.Id)); 138 | #endregion 139 | 140 | //var resutl = ((IQueryable)ctx.Authors).Where(a => EF.Functions.ILike(a.Name, "автор 4")).ToList(); 141 | var resutl = ((IQueryable)ctx.Authors.AsNoTracking()).Where(a => a.Name.ToLower() == "автор 4".ToLower()).ToList(); 142 | 143 | return ctx.Authors; 144 | } 145 | 146 | #endregion 147 | #region AuthorsById 148 | /// 149 | /// Чтение по уникальным идентификаторам, это функция по факту не нужна, легко заменяется функцией Authors с фильтром 150 | /// 151 | /// 152 | /// 153 | /// Авторы 154 | [UseProjection] 155 | public IQueryable AuthorsByIds([Service] DemoContext ctx, IEnumerable ids) => 156 | ((IQueryable)ctx.Authors).Where(a => ids.Contains(a.Id)); 157 | #endregion 158 | 159 | #region AuthorById 160 | /// 161 | /// Получить автора по иникальному идентификатору 162 | /// 163 | /// Контекст базы данных 164 | /// Уникальный идентификатор книги 165 | /// Автор книги 166 | /// 167 | public Author AuthorById([Service] DemoContext ctx, int id) 168 | { 169 | var author = ((IQueryable)ctx.Authors).FirstOrDefault(a => a.Id == id); 170 | 171 | if (author == null) throw new ArgumentException($"Автор с заданным id: {id} не существует"); 172 | 173 | return author; 174 | } 175 | #endregion 176 | 177 | #region Book 178 | /// 179 | /// Запрос получения книг 180 | /// 181 | /// Контекст базы данных Entity 182 | /// Книги 183 | [UseProjection] 184 | [UseFiltering()] 185 | [UseSorting()] 186 | public IQueryable Books([Service] DemoContext ctx) => ctx.Books; 187 | #endregion 188 | 189 | #region AuthorizeQuery 190 | /// 191 | /// Тестовая функция с авторизацией 192 | /// 193 | /// 194 | /// 195 | [Authorize(Roles = new[] { "admin" })] 196 | public bool AuthorizeQuery([Service] IHttpContextAccessor context, ClaimsPrincipal claimsPrincipal) 197 | { 198 | var user = context.HttpContext.User; 199 | var username = user.FindFirstValue("preferred_username"); 200 | return true; 201 | 202 | } 203 | #endregion 204 | 205 | 206 | /** Проверяем конфигурацию на прямую */ 207 | public string TestConfigurationDirectly() 208 | { 209 | return _configuration["key1"]; 210 | } 211 | 212 | /** Проверяем конфигурацию из JSON */ 213 | public string TestConfigurationJSON() 214 | { 215 | return _configuration["settings:JSONKey1"]; 216 | } 217 | 218 | /** Проверяем работу значений из YAML файла */ 219 | public string TestConfigurationYaml() 220 | { 221 | return _configuration["yamlkey3:v1"]; 222 | } 223 | 224 | /** Проверяем конфигурацию из xml */ 225 | public string TestConfigurationXML() 226 | { 227 | return _configuration["XMLKey1"]; 228 | } 229 | 230 | /** Проверяем простейшие опции */ 231 | public string TestOptions([Service] IOptions settings) 232 | { 233 | return settings.Value.OAUTH_PATH; 234 | } 235 | 236 | /** Проверяем простейшие опции снимка */ 237 | public string TestOptionsSnapshot([Service] IOptionsSnapshot settings) 238 | { 239 | return settings.Value.OAUTH_PATH; 240 | } 241 | 242 | /** Проверяем работу опций типа монитор */ 243 | public string TestOptionsMonitor([Service] IOptionsMonitor settings) 244 | { 245 | return settings.CurrentValue.OAUTH_PATH; 246 | } 247 | 248 | /** Проверяем работу динамических значений */ 249 | public string TestConfigurationDynamic() 250 | { 251 | return _configuration["DynamicKey1"]; 252 | } 253 | 254 | /** Проверяем работу значений из базы данных */ 255 | public string TestConfigurationDB() 256 | { 257 | return _configuration["DBConfiguration:DBKey1"]; 258 | } 259 | 260 | public int[] Test1() 261 | { 262 | return new int[] { 1, 2, 3 }; 263 | } 264 | 265 | 266 | public string Test2(int[] ids) 267 | { 268 | return string.Join(',', ids); 269 | } 270 | 271 | } 272 | 273 | public class Api1 274 | { 275 | /// 276 | /// Запрос чтения 277 | /// 278 | /// Контекст базы данных Entity 279 | /// Авторы 280 | [UseDbContext(typeof(DemoContext))] 281 | [UseProjection] 282 | [UseFiltering()] 283 | [UseSorting()] 284 | public IQueryable Authors([ScopedService] DemoContext ctx) 285 | { 286 | return ctx.Authors; 287 | } 288 | } -------------------------------------------------------------------------------- /DBContext/DemoContext.cs: -------------------------------------------------------------------------------- 1 | using Demo.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | 7 | namespace Demo.DB; 8 | 9 | /** */ 10 | public class DemoContext : DbContext 11 | { 12 | /// 13 | /// Констрктор DemoContext 14 | /// 15 | /// свойства контекста 16 | public DemoContext(DbContextOptions o) : base(o) 17 | { 18 | #if SQLITE 19 | try 20 | { 21 | Database.EnsureCreated(); 22 | } 23 | catch (Exception e) 24 | { 25 | Debug.Print(e.ToString()); 26 | } 27 | #endif 28 | } 29 | 30 | /** Авторы */ 31 | public DbSet Authors { get; set; } 32 | /** Книги */ 33 | public DbSet Books { get; set; } 34 | 35 | /** Издательства */ 36 | public DbSet Publishers { get; set; } 37 | 38 | /** Дополнительная информация по книге */ 39 | public DbSet BookDetails { get; set; } 40 | 41 | /** Связь многие ко многим между Издателями и Авторами */ 42 | public DbSet PublishersAuthors { get; set; } 43 | 44 | /// 45 | /// Настройка свойств модели 46 | /// 47 | protected override void OnModelCreating(ModelBuilder modelBuilder) 48 | { 49 | //modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS"); 50 | modelBuilder.HasDefaultSchema("authors"); 51 | #region Данные по умолчанию 52 | //var authors = new Author[] 53 | // { 54 | // new() { Id = 1, Name = "Вася", }, 55 | // new() { Id = 2, Name = "Петя", } 56 | // }; 57 | 58 | var authors = Enumerable.Range(1, 500).Select(i => new Author { Id = i, Name = "Автор " + i }); 59 | var publishers = new Publisher[] 60 | { 61 | new() { Id = 1, Name = "Издательство ООО \"Сервер\"" }, 62 | new() { Id = 2, Name = "Издательство ООО \"Восток\"" } 63 | }; 64 | #endregion 65 | 66 | modelBuilder.Entity(b => 67 | { 68 | //b.Property(a => a.Id).ValueGeneratedNever(); 69 | b.HasKey(a => a.Id); 70 | b.HasIndex(b => b.Name).IsUnique(); 71 | 72 | //b.Property(c => c.Name) 73 | // .UseCollation("SQL_Latin1_General_CP1_CI_AS"); 74 | 75 | #region Данные по умолчанию 76 | b.HasData(authors); 77 | #endregion 78 | 79 | // Один ко многим 80 | b 81 | .HasMany(a => a.Books) 82 | .WithOne(b => b.Author); 83 | }); 84 | 85 | modelBuilder.Entity(b => 86 | { 87 | #region Данные по умолчанию 88 | b.HasData( 89 | new() 90 | { 91 | Id = 3, 92 | AuthorId = 1, 93 | Title = "Первая книга Васи", 94 | Description = "Биографическое описание жизни", 95 | 96 | }, 97 | new() 98 | { 99 | Id = 4, 100 | AuthorId = 1, 101 | Title = "Вторая книга Васи", 102 | Description = "Фантастическая книга о приключениях", 103 | }, 104 | new() 105 | { 106 | Id = 5, 107 | AuthorId = 1, 108 | Title = "Третья книга Васи", 109 | Description = "Историческая книга", 110 | 111 | }, 112 | new() 113 | { 114 | Id = 6, 115 | AuthorId = 2, 116 | Title = "Первая книга Пети", 117 | Description = "Фентази об эльфах", 118 | }, 119 | new() 120 | { 121 | Id = 7, 122 | AuthorId = 2, 123 | Title = "Вторая книга Пети", 124 | Description = "Научная литература, докозательство 3-й теорему Фихтенгольца", 125 | }, 126 | new() 127 | { 128 | Id = 8, 129 | AuthorId = 2, 130 | Title = "Третья книга Пети", 131 | Description = "Научная фантастика и приключение героя в далёком космосе", 132 | 133 | }); 134 | #endregion 135 | }); 136 | 137 | modelBuilder.Entity(b => 138 | { 139 | b.HasKey(d => d.BookId); 140 | // Один к одному 141 | b.HasOne(d => d.Book); 142 | 143 | #region Данные по умолчанию 144 | b.HasData( 145 | new() 146 | { 147 | BookId = 3, 148 | Year = new DateTime(2000, 1, 1), 149 | Genre = GenreEnum.historical, 150 | HardcoverCost = 100, 151 | Illustrator = "МИКЕЛАНДЖЕЛО", 152 | Editor = "Не известен", 153 | Language = LanguageEnum.ru, 154 | PageCount = 100, 155 | ReadingAge = 18, 156 | Rank = 7.112 157 | }, 158 | new() 159 | { 160 | BookId = 4, 161 | Year = new DateTime(2001, 1, 1), 162 | Genre = GenreEnum.fantastic, 163 | HardcoverCost = 110, 164 | Illustrator = "ЙОХАННЕС ВЕРМЕЕР", 165 | Editor = "Не известен", 166 | Language = LanguageEnum.ru, 167 | PageCount = 200, 168 | ReadingAge = 12, 169 | Rank = 4.343 170 | }, 171 | new() 172 | { 173 | BookId = 5, 174 | Year = new DateTime(2002, 1, 1), 175 | Genre = GenreEnum.historical, 176 | HardcoverCost = 120, 177 | Illustrator = "ПАБЛО ПИКАССО", 178 | Editor = "Не известен", 179 | Language = LanguageEnum.ru, 180 | PageCount = 300, 181 | ReadingAge = 10, 182 | Rank = 9.2 183 | }, 184 | new() 185 | { 186 | BookId = 6, 187 | Year = new DateTime(2003, 1, 1), 188 | Genre = GenreEnum.fantasy, 189 | HardcoverCost = 130, 190 | Illustrator = "ВИНСЕНТ ВАН ГОГ", 191 | Editor = "Не известен", 192 | Language = LanguageEnum.ru, 193 | PageCount = 400, 194 | ReadingAge = 5, 195 | Rank = 8.345 196 | }, 197 | new() 198 | { 199 | BookId = 7, 200 | Year = new DateTime(2004, 1, 1), 201 | Genre = GenreEnum.scientific, 202 | HardcoverCost = 140, 203 | Illustrator = "РЕМБРАНДТ ВАН РЕЙН", 204 | Editor = "Не известен", 205 | Language = LanguageEnum.en, 206 | PageCount = 500, 207 | ReadingAge = 10, 208 | Rank = 1 209 | }, 210 | new() 211 | { 212 | BookId = 8, 213 | Year = new DateTime(2005, 1, 1), 214 | Genre = GenreEnum.fantastic, 215 | HardcoverCost = 150, 216 | Illustrator = "ЛЕОНАРДО ДА ВИНЧИ", 217 | Editor = "Не известен", 218 | Language = LanguageEnum.ru, 219 | PageCount = 600, 220 | ReadingAge = 18, 221 | Rank = 5 222 | } 223 | ); 224 | #endregion 225 | }); 226 | 227 | modelBuilder.Entity(b => 228 | { 229 | // Многие ко многим 230 | b 231 | .HasMany(p => p.Authors) 232 | .WithMany(a => a.Publishers) 233 | .UsingEntity( 234 | author => author 235 | .HasOne(pa => pa.Author) 236 | .WithMany(a => a.PublishersAuthors) 237 | .HasForeignKey(pa => pa.AuthorId), 238 | publisher => publisher 239 | .HasOne(pa => pa.Publisher) 240 | .WithMany(p => p.PublishersAuthors) 241 | .HasForeignKey(pa => pa.PublisherId) 242 | ); 243 | 244 | b.HasData(publishers); 245 | }); 246 | 247 | modelBuilder.Entity(b => 248 | { 249 | #region Данные по умолчанию 250 | b.HasData( 251 | new() { PublisherId = 1, AuthorId = 1 }, 252 | new() { PublisherId = 1, AuthorId = 2 }, 253 | new() { PublisherId = 2, AuthorId = 1 } 254 | //new() { PublisherId = 2, AuthorId = 2 } 255 | ); 256 | #endregion 257 | }); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /Migrations/20211106063701_start.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 4 | 5 | namespace Demo.Migrations; 6 | 7 | public partial class start : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.EnsureSchema( 12 | name: "authors"); 13 | 14 | migrationBuilder.CreateTable( 15 | name: "authors", 16 | schema: "authors", 17 | columns: table => new 18 | { 19 | id = table.Column(type: "integer", nullable: false) 20 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), 21 | name = table.Column(type: "text", nullable: true) 22 | }, 23 | constraints: table => 24 | { 25 | table.PrimaryKey("pk_authors", x => x.id); 26 | }); 27 | 28 | migrationBuilder.CreateTable( 29 | name: "publishers", 30 | schema: "authors", 31 | columns: table => new 32 | { 33 | id = table.Column(type: "integer", nullable: false) 34 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), 35 | name = table.Column(type: "text", nullable: true) 36 | }, 37 | constraints: table => 38 | { 39 | table.PrimaryKey("pk_publishers", x => x.id); 40 | }); 41 | 42 | migrationBuilder.CreateTable( 43 | name: "books", 44 | schema: "authors", 45 | columns: table => new 46 | { 47 | id = table.Column(type: "integer", nullable: false) 48 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), 49 | title = table.Column(type: "text", nullable: true), 50 | description = table.Column(type: "text", nullable: true), 51 | image_url = table.Column(type: "text", nullable: true), 52 | author_id = table.Column(type: "integer", nullable: false), 53 | isbn_10 = table.Column(type: "text", nullable: true), 54 | isbn_13 = table.Column(type: "text", nullable: true) 55 | }, 56 | constraints: table => 57 | { 58 | table.PrimaryKey("pk_books", x => x.id); 59 | table.ForeignKey( 60 | name: "fk_books_authors_author_id", 61 | column: x => x.author_id, 62 | principalSchema: "authors", 63 | principalTable: "authors", 64 | principalColumn: "id", 65 | onDelete: ReferentialAction.Cascade); 66 | }); 67 | 68 | migrationBuilder.CreateTable( 69 | name: "publishers_authors", 70 | schema: "authors", 71 | columns: table => new 72 | { 73 | author_id = table.Column(type: "integer", nullable: false), 74 | publisher_id = table.Column(type: "integer", nullable: false) 75 | }, 76 | constraints: table => 77 | { 78 | table.PrimaryKey("pk_publishers_authors", x => new { x.author_id, x.publisher_id }); 79 | table.ForeignKey( 80 | name: "fk_publishers_authors_authors_author_id", 81 | column: x => x.author_id, 82 | principalSchema: "authors", 83 | principalTable: "authors", 84 | principalColumn: "id", 85 | onDelete: ReferentialAction.Cascade); 86 | table.ForeignKey( 87 | name: "fk_publishers_authors_publishers_publisher_id", 88 | column: x => x.publisher_id, 89 | principalSchema: "authors", 90 | principalTable: "publishers", 91 | principalColumn: "id", 92 | onDelete: ReferentialAction.Cascade); 93 | }); 94 | 95 | migrationBuilder.CreateTable( 96 | name: "book_details", 97 | schema: "authors", 98 | columns: table => new 99 | { 100 | book_id = table.Column(type: "integer", nullable: false), 101 | rank = table.Column(type: "double precision", nullable: false), 102 | status = table.Column(type: "integer", nullable: false), 103 | peperback_cost = table.Column(type: "numeric", nullable: false), 104 | hardcover_cost = table.Column(type: "numeric", nullable: false), 105 | year = table.Column(type: "timestamp without time zone", nullable: false), 106 | editor = table.Column(type: "text", nullable: true), 107 | illustrator = table.Column(type: "text", nullable: true), 108 | page_count = table.Column(type: "integer", nullable: false), 109 | language = table.Column(type: "integer", nullable: false), 110 | reading_age = table.Column(type: "smallint", nullable: false), 111 | genre = table.Column(type: "integer", nullable: false), 112 | reviews = table.Column(type: "integer", nullable: false) 113 | }, 114 | constraints: table => 115 | { 116 | table.PrimaryKey("pk_book_details", x => x.book_id); 117 | table.ForeignKey( 118 | name: "fk_book_details_books_book_id", 119 | column: x => x.book_id, 120 | principalSchema: "authors", 121 | principalTable: "books", 122 | principalColumn: "id", 123 | onDelete: ReferentialAction.Cascade); 124 | }); 125 | 126 | migrationBuilder.InsertData( 127 | schema: "authors", 128 | table: "authors", 129 | columns: new[] { "id", "name" }, 130 | values: new object[,] 131 | { 132 | { 1, "Вася" }, 133 | { 2, "Петя" } 134 | }); 135 | 136 | migrationBuilder.InsertData( 137 | schema: "authors", 138 | table: "publishers", 139 | columns: new[] { "id", "name" }, 140 | values: new object[,] 141 | { 142 | { 1, "Издательство ООО \"Сервер\"" }, 143 | { 2, "Издательство ООО \"Восток\"" } 144 | }); 145 | 146 | migrationBuilder.InsertData( 147 | schema: "authors", 148 | table: "books", 149 | columns: new[] { "id", "author_id", "description", "isbn_10", "isbn_13", "image_url", "title" }, 150 | values: new object[,] 151 | { 152 | { 3, 1, "Биографическое описание жизни", null, null, null, "Первая книга Васи" }, 153 | { 4, 1, "Фантастическая книга о приключениях", null, null, null, "Вторая книга Васи" }, 154 | { 5, 1, "Историческая книга", null, null, null, "Третья книга Васи" }, 155 | { 6, 2, "Фентази об эльфах", null, null, null, "Первая книга Пети" }, 156 | { 7, 2, "Научная литература, докозательство 3-й теорему Фихтенгольца", null, null, null, "Вторая книга Пети" }, 157 | { 8, 2, "Научная фантастика и приключение героя в далёком космосе", null, null, null, "Третья книга Пети" } 158 | }); 159 | 160 | migrationBuilder.InsertData( 161 | schema: "authors", 162 | table: "publishers_authors", 163 | columns: new[] { "author_id", "publisher_id" }, 164 | values: new object[,] 165 | { 166 | { 1, 1 }, 167 | { 2, 1 }, 168 | { 1, 2 } 169 | }); 170 | 171 | migrationBuilder.InsertData( 172 | schema: "authors", 173 | table: "book_details", 174 | columns: new[] { "book_id", "editor", "genre", "hardcover_cost", "illustrator", "language", "page_count", "peperback_cost", "rank", "reading_age", "reviews", "status", "year" }, 175 | values: new object[,] 176 | { 177 | { 3, "Не известен", 4, 100m, "МИКЕЛАНДЖЕЛО", 0, 100, 0m, 7.1120000000000001, (byte)18, 0, 0, new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, 178 | { 4, "Не известен", 0, 110m, "ЙОХАННЕС ВЕРМЕЕР", 0, 200, 0m, 4.343, (byte)12, 0, 0, new DateTime(2001, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, 179 | { 5, "Не известен", 4, 120m, "ПАБЛО ПИКАССО", 0, 300, 0m, 9.1999999999999993, (byte)10, 0, 0, new DateTime(2002, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, 180 | { 6, "Не известен", 1, 130m, "ВИНСЕНТ ВАН ГОГ", 0, 400, 0m, 8.3450000000000006, (byte)5, 0, 0, new DateTime(2003, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, 181 | { 7, "Не известен", 3, 140m, "РЕМБРАНДТ ВАН РЕЙН", 1, 500, 0m, 1.0, (byte)10, 0, 0, new DateTime(2004, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, 182 | { 8, "Не известен", 0, 150m, "ЛЕОНАРДО ДА ВИНЧИ", 0, 600, 0m, 5.0, (byte)18, 0, 0, new DateTime(2005, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) } 183 | }); 184 | 185 | migrationBuilder.CreateIndex( 186 | name: "ix_authors_name", 187 | schema: "authors", 188 | table: "authors", 189 | column: "name", 190 | unique: true); 191 | 192 | migrationBuilder.CreateIndex( 193 | name: "ix_books_author_id", 194 | schema: "authors", 195 | table: "books", 196 | column: "author_id"); 197 | 198 | migrationBuilder.CreateIndex( 199 | name: "ix_publishers_authors_publisher_id", 200 | schema: "authors", 201 | table: "publishers_authors", 202 | column: "publisher_id"); 203 | } 204 | 205 | protected override void Down(MigrationBuilder migrationBuilder) 206 | { 207 | migrationBuilder.DropTable( 208 | name: "book_details", 209 | schema: "authors"); 210 | 211 | migrationBuilder.DropTable( 212 | name: "publishers_authors", 213 | schema: "authors"); 214 | 215 | migrationBuilder.DropTable( 216 | name: "books", 217 | schema: "authors"); 218 | 219 | migrationBuilder.DropTable( 220 | name: "publishers", 221 | schema: "authors"); 222 | 223 | migrationBuilder.DropTable( 224 | name: "authors", 225 | schema: "authors"); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /Migrations/DemoContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Demo.DB; 4 | using Demo.Models; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore.Infrastructure; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 9 | 10 | namespace Demo.Migrations; 11 | 12 | [DbContext(typeof(DemoContext))] 13 | partial class DemoContextModelSnapshot : ModelSnapshot 14 | { 15 | protected override void BuildModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasDefaultSchema("authors") 20 | .HasAnnotation("Relational:MaxIdentifierLength", 63) 21 | .HasAnnotation("ProductVersion", "5.0.11") 22 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 23 | 24 | modelBuilder.Entity("Demo.Model.Author", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("integer") 29 | .HasColumnName("id") 30 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 31 | 32 | b.Property("Name") 33 | .HasColumnType("text") 34 | .HasColumnName("name"); 35 | 36 | b.HasKey("Id") 37 | .HasName("pk_authors"); 38 | 39 | b.HasIndex("Name") 40 | .IsUnique() 41 | .HasDatabaseName("ix_authors_name"); 42 | 43 | b.ToTable("authors"); 44 | 45 | b.HasData( 46 | new 47 | { 48 | Id = 1, 49 | Name = "Вася" 50 | }, 51 | new 52 | { 53 | Id = 2, 54 | Name = "Петя" 55 | }); 56 | }); 57 | 58 | modelBuilder.Entity("Demo.Model.Book", b => 59 | { 60 | b.Property("Id") 61 | .ValueGeneratedOnAdd() 62 | .HasColumnType("integer") 63 | .HasColumnName("id") 64 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 65 | 66 | b.Property("AuthorId") 67 | .HasColumnType("integer") 68 | .HasColumnName("author_id"); 69 | 70 | b.Property("Description") 71 | .HasColumnType("text") 72 | .HasColumnName("description"); 73 | 74 | b.Property("ISBN_10") 75 | .HasColumnType("text") 76 | .HasColumnName("isbn_10"); 77 | 78 | b.Property("ISBN_13") 79 | .HasColumnType("text") 80 | .HasColumnName("isbn_13"); 81 | 82 | b.Property("ImageUrl") 83 | .HasColumnType("text") 84 | .HasColumnName("image_url"); 85 | 86 | b.Property("Title") 87 | .HasColumnType("text") 88 | .HasColumnName("title"); 89 | 90 | b.HasKey("Id") 91 | .HasName("pk_books"); 92 | 93 | b.HasIndex("AuthorId") 94 | .HasDatabaseName("ix_books_author_id"); 95 | 96 | b.ToTable("books"); 97 | 98 | b.HasData( 99 | new 100 | { 101 | Id = 3, 102 | AuthorId = 1, 103 | Description = "Биографическое описание жизни", 104 | Title = "Первая книга Васи" 105 | }, 106 | new 107 | { 108 | Id = 4, 109 | AuthorId = 1, 110 | Description = "Фантастическая книга о приключениях", 111 | Title = "Вторая книга Васи" 112 | }, 113 | new 114 | { 115 | Id = 5, 116 | AuthorId = 1, 117 | Description = "Историческая книга", 118 | Title = "Третья книга Васи" 119 | }, 120 | new 121 | { 122 | Id = 6, 123 | AuthorId = 2, 124 | Description = "Фентази об эльфах", 125 | Title = "Первая книга Пети" 126 | }, 127 | new 128 | { 129 | Id = 7, 130 | AuthorId = 2, 131 | Description = "Научная литература, докозательство 3-й теорему Фихтенгольца", 132 | Title = "Вторая книга Пети" 133 | }, 134 | new 135 | { 136 | Id = 8, 137 | AuthorId = 2, 138 | Description = "Научная фантастика и приключение героя в далёком космосе", 139 | Title = "Третья книга Пети" 140 | }); 141 | }); 142 | 143 | modelBuilder.Entity("Demo.Model.BookDetails", b => 144 | { 145 | b.Property("BookId") 146 | .HasColumnType("integer") 147 | .HasColumnName("book_id"); 148 | 149 | b.Property("Editor") 150 | .HasColumnType("text") 151 | .HasColumnName("editor"); 152 | 153 | b.Property("Genre") 154 | .HasColumnType("integer") 155 | .HasColumnName("genre"); 156 | 157 | b.Property("HardcoverCost") 158 | .HasColumnType("numeric") 159 | .HasColumnName("hardcover_cost"); 160 | 161 | b.Property("Illustrator") 162 | .HasColumnType("text") 163 | .HasColumnName("illustrator"); 164 | 165 | b.Property("Language") 166 | .HasColumnType("integer") 167 | .HasColumnName("language"); 168 | 169 | b.Property("PageCount") 170 | .HasColumnType("integer") 171 | .HasColumnName("page_count"); 172 | 173 | b.Property("PeperbackCost") 174 | .HasColumnType("numeric") 175 | .HasColumnName("peperback_cost"); 176 | 177 | b.Property("Rank") 178 | .HasColumnType("double precision") 179 | .HasColumnName("rank"); 180 | 181 | b.Property("ReadingAge") 182 | .HasColumnType("smallint") 183 | .HasColumnName("reading_age"); 184 | 185 | b.Property("Reviews") 186 | .HasColumnType("integer") 187 | .HasColumnName("reviews"); 188 | 189 | b.Property("Status") 190 | .HasColumnType("integer") 191 | .HasColumnName("status"); 192 | 193 | b.Property("Year") 194 | .HasColumnType("timestamp without time zone") 195 | .HasColumnName("year"); 196 | 197 | b.HasKey("BookId") 198 | .HasName("pk_book_details"); 199 | 200 | b.ToTable("book_details"); 201 | 202 | b.HasData( 203 | new 204 | { 205 | BookId = 3, 206 | Editor = "Не известен", 207 | Genre = 4, 208 | HardcoverCost = 100m, 209 | Illustrator = "МИКЕЛАНДЖЕЛО", 210 | Language = 0, 211 | PageCount = 100, 212 | PeperbackCost = 0m, 213 | Rank = 7.1120000000000001, 214 | ReadingAge = (byte)18, 215 | Reviews = 0, 216 | Status = 0, 217 | Year = new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 218 | }, 219 | new 220 | { 221 | BookId = 4, 222 | Editor = "Не известен", 223 | Genre = 0, 224 | HardcoverCost = 110m, 225 | Illustrator = "ЙОХАННЕС ВЕРМЕЕР", 226 | Language = 0, 227 | PageCount = 200, 228 | PeperbackCost = 0m, 229 | Rank = 4.343, 230 | ReadingAge = (byte)12, 231 | Reviews = 0, 232 | Status = 0, 233 | Year = new DateTime(2001, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 234 | }, 235 | new 236 | { 237 | BookId = 5, 238 | Editor = "Не известен", 239 | Genre = 4, 240 | HardcoverCost = 120m, 241 | Illustrator = "ПАБЛО ПИКАССО", 242 | Language = 0, 243 | PageCount = 300, 244 | PeperbackCost = 0m, 245 | Rank = 9.1999999999999993, 246 | ReadingAge = (byte)10, 247 | Reviews = 0, 248 | Status = 0, 249 | Year = new DateTime(2002, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 250 | }, 251 | new 252 | { 253 | BookId = 6, 254 | Editor = "Не известен", 255 | Genre = 1, 256 | HardcoverCost = 130m, 257 | Illustrator = "ВИНСЕНТ ВАН ГОГ", 258 | Language = 0, 259 | PageCount = 400, 260 | PeperbackCost = 0m, 261 | Rank = 8.3450000000000006, 262 | ReadingAge = (byte)5, 263 | Reviews = 0, 264 | Status = 0, 265 | Year = new DateTime(2003, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 266 | }, 267 | new 268 | { 269 | BookId = 7, 270 | Editor = "Не известен", 271 | Genre = 3, 272 | HardcoverCost = 140m, 273 | Illustrator = "РЕМБРАНДТ ВАН РЕЙН", 274 | Language = 1, 275 | PageCount = 500, 276 | PeperbackCost = 0m, 277 | Rank = 1.0, 278 | ReadingAge = (byte)10, 279 | Reviews = 0, 280 | Status = 0, 281 | Year = new DateTime(2004, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 282 | }, 283 | new 284 | { 285 | BookId = 8, 286 | Editor = "Не известен", 287 | Genre = 0, 288 | HardcoverCost = 150m, 289 | Illustrator = "ЛЕОНАРДО ДА ВИНЧИ", 290 | Language = 0, 291 | PageCount = 600, 292 | PeperbackCost = 0m, 293 | Rank = 5.0, 294 | ReadingAge = (byte)18, 295 | Reviews = 0, 296 | Status = 0, 297 | Year = new DateTime(2005, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 298 | }); 299 | }); 300 | 301 | modelBuilder.Entity("Demo.Model.Publisher", b => 302 | { 303 | b.Property("Id") 304 | .ValueGeneratedOnAdd() 305 | .HasColumnType("integer") 306 | .HasColumnName("id") 307 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 308 | 309 | b.Property("Name") 310 | .HasColumnType("text") 311 | .HasColumnName("name"); 312 | 313 | b.HasKey("Id") 314 | .HasName("pk_publishers"); 315 | 316 | b.ToTable("publishers"); 317 | 318 | b.HasData( 319 | new 320 | { 321 | Id = 1, 322 | Name = "Издательство ООО \"Сервер\"" 323 | }, 324 | new 325 | { 326 | Id = 2, 327 | Name = "Издательство ООО \"Восток\"" 328 | }); 329 | }); 330 | 331 | modelBuilder.Entity("Demo.Model.PublishersAuthors", b => 332 | { 333 | b.Property("AuthorId") 334 | .HasColumnType("integer") 335 | .HasColumnName("author_id"); 336 | 337 | b.Property("PublisherId") 338 | .HasColumnType("integer") 339 | .HasColumnName("publisher_id"); 340 | 341 | b.HasKey("AuthorId", "PublisherId") 342 | .HasName("pk_publishers_authors"); 343 | 344 | b.HasIndex("PublisherId") 345 | .HasDatabaseName("ix_publishers_authors_publisher_id"); 346 | 347 | b.ToTable("publishers_authors"); 348 | 349 | b.HasData( 350 | new 351 | { 352 | AuthorId = 1, 353 | PublisherId = 1 354 | }, 355 | new 356 | { 357 | AuthorId = 2, 358 | PublisherId = 1 359 | }, 360 | new 361 | { 362 | AuthorId = 1, 363 | PublisherId = 2 364 | }); 365 | }); 366 | 367 | modelBuilder.Entity("Demo.Model.Book", b => 368 | { 369 | b.HasOne("Demo.Model.Author", "Author") 370 | .WithMany("Books") 371 | .HasForeignKey("AuthorId") 372 | .HasConstraintName("fk_books_authors_author_id") 373 | .OnDelete(DeleteBehavior.Cascade) 374 | .IsRequired(); 375 | 376 | b.Navigation("Author"); 377 | }); 378 | 379 | modelBuilder.Entity("Demo.Model.BookDetails", b => 380 | { 381 | b.HasOne("Demo.Model.Book", "Book") 382 | .WithOne("Detatils") 383 | .HasForeignKey("Demo.Model.BookDetails", "BookId") 384 | .HasConstraintName("fk_book_details_books_book_id") 385 | .OnDelete(DeleteBehavior.Cascade) 386 | .IsRequired(); 387 | 388 | b.Navigation("Book"); 389 | }); 390 | 391 | modelBuilder.Entity("Demo.Model.PublishersAuthors", b => 392 | { 393 | b.HasOne("Demo.Model.Author", "Author") 394 | .WithMany("PublishersAuthors") 395 | .HasForeignKey("AuthorId") 396 | .HasConstraintName("fk_publishers_authors_authors_author_id") 397 | .OnDelete(DeleteBehavior.Cascade) 398 | .IsRequired(); 399 | 400 | b.HasOne("Demo.Model.Publisher", "Publisher") 401 | .WithMany("PublishersAuthors") 402 | .HasForeignKey("PublisherId") 403 | .HasConstraintName("fk_publishers_authors_publishers_publisher_id") 404 | .OnDelete(DeleteBehavior.Cascade) 405 | .IsRequired(); 406 | 407 | b.Navigation("Author"); 408 | 409 | b.Navigation("Publisher"); 410 | }); 411 | 412 | modelBuilder.Entity("Demo.Model.Author", b => 413 | { 414 | b.Navigation("Books"); 415 | 416 | b.Navigation("PublishersAuthors"); 417 | }); 418 | 419 | modelBuilder.Entity("Demo.Model.Book", b => 420 | { 421 | b.Navigation("Detatils"); 422 | }); 423 | 424 | modelBuilder.Entity("Demo.Model.Publisher", b => 425 | { 426 | b.Navigation("PublishersAuthors"); 427 | }); 428 | #pragma warning restore 612, 618 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /Migrations/20211106063701_start.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Demo.DB; 4 | using Demo.Models; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore.Infrastructure; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 10 | 11 | namespace Demo.Migrations; 12 | 13 | [DbContext(typeof(DemoContext))] 14 | [Migration("20211106063701_start")] 15 | partial class start 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasDefaultSchema("authors") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 63) 23 | .HasAnnotation("ProductVersion", "5.0.11") 24 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 25 | 26 | modelBuilder.Entity("Demo.Model.Author", b => 27 | { 28 | b.Property("Id") 29 | .ValueGeneratedOnAdd() 30 | .HasColumnType("integer") 31 | .HasColumnName("id") 32 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 33 | 34 | b.Property("Name") 35 | .HasColumnType("text") 36 | .HasColumnName("name"); 37 | 38 | b.HasKey("Id") 39 | .HasName("pk_authors"); 40 | 41 | b.HasIndex("Name") 42 | .IsUnique() 43 | .HasDatabaseName("ix_authors_name"); 44 | 45 | b.ToTable("authors"); 46 | 47 | b.HasData( 48 | new 49 | { 50 | Id = 1, 51 | Name = "Вася" 52 | }, 53 | new 54 | { 55 | Id = 2, 56 | Name = "Петя" 57 | }); 58 | }); 59 | 60 | modelBuilder.Entity("Demo.Model.Book", b => 61 | { 62 | b.Property("Id") 63 | .ValueGeneratedOnAdd() 64 | .HasColumnType("integer") 65 | .HasColumnName("id") 66 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 67 | 68 | b.Property("AuthorId") 69 | .HasColumnType("integer") 70 | .HasColumnName("author_id"); 71 | 72 | b.Property("Description") 73 | .HasColumnType("text") 74 | .HasColumnName("description"); 75 | 76 | b.Property("ISBN_10") 77 | .HasColumnType("text") 78 | .HasColumnName("isbn_10"); 79 | 80 | b.Property("ISBN_13") 81 | .HasColumnType("text") 82 | .HasColumnName("isbn_13"); 83 | 84 | b.Property("ImageUrl") 85 | .HasColumnType("text") 86 | .HasColumnName("image_url"); 87 | 88 | b.Property("Title") 89 | .HasColumnType("text") 90 | .HasColumnName("title"); 91 | 92 | b.HasKey("Id") 93 | .HasName("pk_books"); 94 | 95 | b.HasIndex("AuthorId") 96 | .HasDatabaseName("ix_books_author_id"); 97 | 98 | b.ToTable("books"); 99 | 100 | b.HasData( 101 | new 102 | { 103 | Id = 3, 104 | AuthorId = 1, 105 | Description = "Биографическое описание жизни", 106 | Title = "Первая книга Васи" 107 | }, 108 | new 109 | { 110 | Id = 4, 111 | AuthorId = 1, 112 | Description = "Фантастическая книга о приключениях", 113 | Title = "Вторая книга Васи" 114 | }, 115 | new 116 | { 117 | Id = 5, 118 | AuthorId = 1, 119 | Description = "Историческая книга", 120 | Title = "Третья книга Васи" 121 | }, 122 | new 123 | { 124 | Id = 6, 125 | AuthorId = 2, 126 | Description = "Фентази об эльфах", 127 | Title = "Первая книга Пети" 128 | }, 129 | new 130 | { 131 | Id = 7, 132 | AuthorId = 2, 133 | Description = "Научная литература, докозательство 3-й теорему Фихтенгольца", 134 | Title = "Вторая книга Пети" 135 | }, 136 | new 137 | { 138 | Id = 8, 139 | AuthorId = 2, 140 | Description = "Научная фантастика и приключение героя в далёком космосе", 141 | Title = "Третья книга Пети" 142 | }); 143 | }); 144 | 145 | modelBuilder.Entity("Demo.Model.BookDetails", b => 146 | { 147 | b.Property("BookId") 148 | .HasColumnType("integer") 149 | .HasColumnName("book_id"); 150 | 151 | b.Property("Editor") 152 | .HasColumnType("text") 153 | .HasColumnName("editor"); 154 | 155 | b.Property("Genre") 156 | .HasColumnType("integer") 157 | .HasColumnName("genre"); 158 | 159 | b.Property("HardcoverCost") 160 | .HasColumnType("numeric") 161 | .HasColumnName("hardcover_cost"); 162 | 163 | b.Property("Illustrator") 164 | .HasColumnType("text") 165 | .HasColumnName("illustrator"); 166 | 167 | b.Property("Language") 168 | .HasColumnType("integer") 169 | .HasColumnName("language"); 170 | 171 | b.Property("PageCount") 172 | .HasColumnType("integer") 173 | .HasColumnName("page_count"); 174 | 175 | b.Property("PeperbackCost") 176 | .HasColumnType("numeric") 177 | .HasColumnName("peperback_cost"); 178 | 179 | b.Property("Rank") 180 | .HasColumnType("double precision") 181 | .HasColumnName("rank"); 182 | 183 | b.Property("ReadingAge") 184 | .HasColumnType("smallint") 185 | .HasColumnName("reading_age"); 186 | 187 | b.Property("Reviews") 188 | .HasColumnType("integer") 189 | .HasColumnName("reviews"); 190 | 191 | b.Property("Status") 192 | .HasColumnType("integer") 193 | .HasColumnName("status"); 194 | 195 | b.Property("Year") 196 | .HasColumnType("timestamp without time zone") 197 | .HasColumnName("year"); 198 | 199 | b.HasKey("BookId") 200 | .HasName("pk_book_details"); 201 | 202 | b.ToTable("book_details"); 203 | 204 | b.HasData( 205 | new 206 | { 207 | BookId = 3, 208 | Editor = "Не известен", 209 | Genre = 4, 210 | HardcoverCost = 100m, 211 | Illustrator = "МИКЕЛАНДЖЕЛО", 212 | Language = 0, 213 | PageCount = 100, 214 | PeperbackCost = 0m, 215 | Rank = 7.1120000000000001, 216 | ReadingAge = (byte)18, 217 | Reviews = 0, 218 | Status = 0, 219 | Year = new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 220 | }, 221 | new 222 | { 223 | BookId = 4, 224 | Editor = "Не известен", 225 | Genre = 0, 226 | HardcoverCost = 110m, 227 | Illustrator = "ЙОХАННЕС ВЕРМЕЕР", 228 | Language = 0, 229 | PageCount = 200, 230 | PeperbackCost = 0m, 231 | Rank = 4.343, 232 | ReadingAge = (byte)12, 233 | Reviews = 0, 234 | Status = 0, 235 | Year = new DateTime(2001, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 236 | }, 237 | new 238 | { 239 | BookId = 5, 240 | Editor = "Не известен", 241 | Genre = 4, 242 | HardcoverCost = 120m, 243 | Illustrator = "ПАБЛО ПИКАССО", 244 | Language = 0, 245 | PageCount = 300, 246 | PeperbackCost = 0m, 247 | Rank = 9.1999999999999993, 248 | ReadingAge = (byte)10, 249 | Reviews = 0, 250 | Status = 0, 251 | Year = new DateTime(2002, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 252 | }, 253 | new 254 | { 255 | BookId = 6, 256 | Editor = "Не известен", 257 | Genre = 1, 258 | HardcoverCost = 130m, 259 | Illustrator = "ВИНСЕНТ ВАН ГОГ", 260 | Language = 0, 261 | PageCount = 400, 262 | PeperbackCost = 0m, 263 | Rank = 8.3450000000000006, 264 | ReadingAge = (byte)5, 265 | Reviews = 0, 266 | Status = 0, 267 | Year = new DateTime(2003, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 268 | }, 269 | new 270 | { 271 | BookId = 7, 272 | Editor = "Не известен", 273 | Genre = 3, 274 | HardcoverCost = 140m, 275 | Illustrator = "РЕМБРАНДТ ВАН РЕЙН", 276 | Language = 1, 277 | PageCount = 500, 278 | PeperbackCost = 0m, 279 | Rank = 1.0, 280 | ReadingAge = (byte)10, 281 | Reviews = 0, 282 | Status = 0, 283 | Year = new DateTime(2004, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 284 | }, 285 | new 286 | { 287 | BookId = 8, 288 | Editor = "Не известен", 289 | Genre = 0, 290 | HardcoverCost = 150m, 291 | Illustrator = "ЛЕОНАРДО ДА ВИНЧИ", 292 | Language = 0, 293 | PageCount = 600, 294 | PeperbackCost = 0m, 295 | Rank = 5.0, 296 | ReadingAge = (byte)18, 297 | Reviews = 0, 298 | Status = 0, 299 | Year = new DateTime(2005, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 300 | }); 301 | }); 302 | 303 | modelBuilder.Entity("Demo.Model.Publisher", b => 304 | { 305 | b.Property("Id") 306 | .ValueGeneratedOnAdd() 307 | .HasColumnType("integer") 308 | .HasColumnName("id") 309 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); 310 | 311 | b.Property("Name") 312 | .HasColumnType("text") 313 | .HasColumnName("name"); 314 | 315 | b.HasKey("Id") 316 | .HasName("pk_publishers"); 317 | 318 | b.ToTable("publishers"); 319 | 320 | b.HasData( 321 | new 322 | { 323 | Id = 1, 324 | Name = "Издательство ООО \"Сервер\"" 325 | }, 326 | new 327 | { 328 | Id = 2, 329 | Name = "Издательство ООО \"Восток\"" 330 | }); 331 | }); 332 | 333 | modelBuilder.Entity("Demo.Model.PublishersAuthors", b => 334 | { 335 | b.Property("AuthorId") 336 | .HasColumnType("integer") 337 | .HasColumnName("author_id"); 338 | 339 | b.Property("PublisherId") 340 | .HasColumnType("integer") 341 | .HasColumnName("publisher_id"); 342 | 343 | b.HasKey("AuthorId", "PublisherId") 344 | .HasName("pk_publishers_authors"); 345 | 346 | b.HasIndex("PublisherId") 347 | .HasDatabaseName("ix_publishers_authors_publisher_id"); 348 | 349 | b.ToTable("publishers_authors"); 350 | 351 | b.HasData( 352 | new 353 | { 354 | AuthorId = 1, 355 | PublisherId = 1 356 | }, 357 | new 358 | { 359 | AuthorId = 2, 360 | PublisherId = 1 361 | }, 362 | new 363 | { 364 | AuthorId = 1, 365 | PublisherId = 2 366 | }); 367 | }); 368 | 369 | modelBuilder.Entity("Demo.Model.Book", b => 370 | { 371 | b.HasOne("Demo.Model.Author", "Author") 372 | .WithMany("Books") 373 | .HasForeignKey("AuthorId") 374 | .HasConstraintName("fk_books_authors_author_id") 375 | .OnDelete(DeleteBehavior.Cascade) 376 | .IsRequired(); 377 | 378 | b.Navigation("Author"); 379 | }); 380 | 381 | modelBuilder.Entity("Demo.Model.BookDetails", b => 382 | { 383 | b.HasOne("Demo.Model.Book", "Book") 384 | .WithOne("Detatils") 385 | .HasForeignKey("Demo.Model.BookDetails", "BookId") 386 | .HasConstraintName("fk_book_details_books_book_id") 387 | .OnDelete(DeleteBehavior.Cascade) 388 | .IsRequired(); 389 | 390 | b.Navigation("Book"); 391 | }); 392 | 393 | modelBuilder.Entity("Demo.Model.PublishersAuthors", b => 394 | { 395 | b.HasOne("Demo.Model.Author", "Author") 396 | .WithMany("PublishersAuthors") 397 | .HasForeignKey("AuthorId") 398 | .HasConstraintName("fk_publishers_authors_authors_author_id") 399 | .OnDelete(DeleteBehavior.Cascade) 400 | .IsRequired(); 401 | 402 | b.HasOne("Demo.Model.Publisher", "Publisher") 403 | .WithMany("PublishersAuthors") 404 | .HasForeignKey("PublisherId") 405 | .HasConstraintName("fk_publishers_authors_publishers_publisher_id") 406 | .OnDelete(DeleteBehavior.Cascade) 407 | .IsRequired(); 408 | 409 | b.Navigation("Author"); 410 | 411 | b.Navigation("Publisher"); 412 | }); 413 | 414 | modelBuilder.Entity("Demo.Model.Author", b => 415 | { 416 | b.Navigation("Books"); 417 | 418 | b.Navigation("PublishersAuthors"); 419 | }); 420 | 421 | modelBuilder.Entity("Demo.Model.Book", b => 422 | { 423 | b.Navigation("Detatils"); 424 | }); 425 | 426 | modelBuilder.Entity("Demo.Model.Publisher", b => 427 | { 428 | b.Navigation("PublishersAuthors"); 429 | }); 430 | #pragma warning restore 612, 618 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /Demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Demo 5 | 6 | 7 | 8 | Фоновый процесс расчёта среднего колличества отзывов 9 | 10 | 11 | 12 | Конструктор 13 | 14 | 15 | контекст базы данных 16 | 17 | 18 | 19 | Выполнение фонового процесса 20 | 21 | токен завершения 22 | 23 | 24 | 25 | Сервер TCP 26 | 27 | 28 | 29 | Конструктор 30 | 31 | 32 | 33 | 34 | 35 | Выполнение фонового процесса 36 | 37 | 38 | 39 | 40 | Получение всех авторов 41 | Success 42 | A server side error occurred. 43 | 44 | 45 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 46 | Получение всех авторов 47 | Success 48 | A server side error occurred. 49 | 50 | 51 | Создание нового автора 52 | новый автор 53 | Success 54 | A server side error occurred. 55 | 56 | 57 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 58 | Создание нового автора 59 | новый автор 60 | Success 61 | A server side error occurred. 62 | 63 | 64 | Изменение автора 65 | Success 66 | A server side error occurred. 67 | 68 | 69 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 70 | Изменение автора 71 | Success 72 | A server side error occurred. 73 | 74 | 75 | Получить автора по уникальному идентификатору 76 | Success 77 | A server side error occurred. 78 | 79 | 80 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 81 | Получить автора по уникальному идентификатору 82 | Success 83 | A server side error occurred. 84 | 85 | 86 | Удаление автора 87 | Success 88 | A server side error occurred. 89 | 90 | 91 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 92 | Удаление автора 93 | Success 94 | A server side error occurred. 95 | 96 | 97 | Получение книг по уникальному идентификатору и названию 98 | Success 99 | A server side error occurred. 100 | 101 | 102 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 103 | Получение книг по уникальному идентификатору и названию 104 | Success 105 | A server side error occurred. 106 | 107 | 108 | Метод чтения реализующий паттерн LongPolling 109 | маркер после которого происходит чтение данных из очереди 110 | Success 111 | A server side error occurred. 112 | 113 | 114 | A cancellation token that can be used by other objects or threads to receive notice of cancellation. 115 | Метод чтения реализующий паттерн LongPolling 116 | маркер после которого происходит чтение данных из очереди 117 | Success 118 | A server side error occurred. 119 | 120 | 121 | Автор 122 | 123 | 124 | Уникальный идентификатор 125 | 126 | 127 | Имя автора 128 | 129 | 130 | Книги автора 131 | 132 | 133 | Значение очереди 134 | 135 | 136 | Маркер по котором считываем новые значения 137 | 138 | 139 | Статус книги 140 | 141 | 142 | Контекст базы данных для конфигурации 143 | 144 | 145 | Для удобной регистрации 146 | 147 | 148 | Строка подключения к базе данных 149 | 150 | 151 | Конструктор 152 | 153 | 154 | Загрузка конфигурации из базы данных 155 | 156 | 157 | Строка подключения к базе данных 158 | 159 | 160 | 161 | Контроллер авторов 162 | 163 | 164 | 165 | 166 | Конструктор 167 | 168 | 169 | 170 | 171 | Тестовая функция с получением данных из "другого" микросервиса, с авторизацией 172 | 173 | 174 | 175 | 176 | Получение всех авторов 177 | 178 | 179 | 180 | 181 | Получить автора по уникальному идентификатору 182 | 183 | 184 | 185 | GET api/Authors/1 186 | 187 | 188 | 189 | Получение книг по уникальному идентификатору и названию 190 | 191 | 192 | 193 | 194 | GET api/Authors/1/Book/Первая книга Васи 195 | 196 | 197 | 198 | Метод чтения реализующий паттерн LongPolling 199 | 200 | маркер после которого происходит чтение данных из очереди 201 | коллекция результат 202 | GET api/Authors/GetChanges/ 203 | 204 | 205 | 206 | Создание нового автора 207 | 208 | новый автор 209 | POST api/Authors 210 | 211 | 212 | 213 | Изменение автора 214 | 215 | 216 | PUT api/Authors 217 | 218 | 219 | 220 | Удаление автора 221 | 222 | 223 | DELETE api/Authors/1 224 | 225 | 226 | 227 | Создание нового автора 228 | 229 | новый автор 230 | POST api/Authors 231 | 232 | 233 | 234 | Тестовая функция с получением данных из "другого" микросервиса, с авторизацией 235 | 236 | 237 | 238 | Пример контроллера для показа работы Mapster 239 | 240 | 241 | 242 | Конструктор 243 | 244 | мапинг 245 | контекст базы данных 246 | 247 | 248 | 249 | Получить авторов DTO 250 | 251 | 252 | 253 | 254 | 255 | Получить автора по уникальному идентификатору 256 | 257 | 258 | 259 | GET api/Authors/1 260 | 261 | 262 | 263 | Контроллер издателей 264 | 265 | 266 | 267 | 268 | Конструктор 269 | 270 | 271 | 272 | 273 | Получение всех издателей 274 | 275 | 276 | 277 | 278 | Получить издателя по уникальному идентификатору 279 | 280 | 281 | 282 | GET api/Authors/1 283 | 284 | 285 | 286 | Получение авторов по уникальному идентификатору издателя 287 | 288 | 289 | 290 | GET api/Publisher/1/Author 291 | 292 | 293 | 294 | Создание нового издательства 295 | 296 | новый издательство 297 | POST api/Authors 298 | 299 | 300 | 301 | Добавление Автора к издателю 302 | 303 | Уникальный идентификатор издателя 304 | Уникальный идентификатор автора 305 | POST api/Authors 306 | 307 | 308 | 309 | Изменение автора 310 | 311 | издатель 312 | PUT api/Publisher 313 | 314 | 315 | 316 | Удаление издателя 317 | 318 | 319 | DELETE api/Publisher/1 320 | 321 | 322 | 323 | 324 | 325 | 326 | Констрктор DemoContext 327 | 328 | свойства контекста 329 | 330 | 331 | Авторы 332 | 333 | 334 | Книги 335 | 336 | 337 | Издательства 338 | 339 | 340 | Дополнительная информация по книге 341 | 342 | 343 | Связь многие ко многим между Издателями и Авторами 344 | 345 | 346 | 347 | Настройка свойств модели 348 | 349 | 350 | 351 | Демо репозиторий 352 | 353 | 354 | Конструктор 355 | 356 | 357 | 358 | Получить автора по иникальному идентификатору 359 | 360 | Уникальный идентификатор 361 | 362 | 363 | 364 | 365 | Обновить автора 366 | 367 | автор для обновления 368 | 369 | 370 | 371 | Фильтр ошибок 372 | 373 | 374 | 375 | 376 | Обработчик фильтра ошибок 377 | 378 | 379 | 380 | 381 | 382 | Изменения GraphQL 383 | Главное отличие в том что подзапросы выполняются последовательно, в том же порядке что указано в запросе 384 | 385 | 386 | 387 | 388 | Создание автора 389 | 390 | Создаваемый автор 391 | Контекст базы данных Entity 392 | Автор 393 | 394 | 395 | 396 | Обновление автора 397 | 398 | Обновляемый автор 399 | Контекст базы данных Entity 400 | Автор 401 | 402 | 403 | 404 | Удаление автора 405 | 406 | Уникальный идентификатор автора 407 | Контекст базы данных Entity 408 | Автор 409 | 410 | 411 | 412 | Создать или обновить автора тут логика такая, если Id равен 0, то это однозначно новый автор 413 | 414 | Контекст базы данных Entity 415 | Создать или обновить автора 416 | 417 | Автор 418 | 419 | 420 | 421 | Генерация ошибки для проверки транзакции 422 | 423 | Автор 424 | 425 | 426 | 427 | Проверка даты 428 | 429 | 430 | 431 | 432 | 433 | 434 | Запросы GraphQl 435 | Главное отличик запроса в том что его подзапросы выполняются параллельно 436 | 437 | 438 | 439 | 440 | Конструктор 441 | 442 | 443 | 444 | 445 | Возвращает первую версию 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | Запрос чтения 461 | 462 | Контекст базы данных Entity 463 | Авторы 464 | 465 | 466 | 467 | Чтение по уникальным идентификаторам, это функция по факту не нужна, легко заменяется функцией Authors с фильтром 468 | 469 | 470 | 471 | Авторы 472 | 473 | 474 | 475 | Получить автора по иникальному идентификатору 476 | 477 | Контекст базы данных 478 | Уникальный идентификатор книги 479 | Автор книги 480 | 481 | 482 | 483 | 484 | Запрос получения книг 485 | 486 | Контекст базы данных Entity 487 | Книги 488 | 489 | 490 | 491 | Тестовая функция с авторизацией 492 | 493 | 494 | 495 | 496 | 497 | Проверяем конфигурацию на прямую 498 | 499 | 500 | Проверяем конфигурацию из JSON 501 | 502 | 503 | Проверяем работу значений из YAML файла 504 | 505 | 506 | Проверяем конфигурацию из xml 507 | 508 | 509 | Проверяем простейшие опции 510 | 511 | 512 | Проверяем простейшие опции снимка 513 | 514 | 515 | Проверяем работу опций типа монитор 516 | 517 | 518 | Проверяем работу динамических значений 519 | 520 | 521 | Проверяем работу значений из базы данных 522 | 523 | 524 | 525 | Запрос чтения 526 | 527 | Контекст базы данных Entity 528 | Авторы 529 | 530 | 531 | 532 | Подписки 533 | 534 | 535 | 536 | 537 | Добавлен новый автор 538 | 539 | 540 | Автор 541 | 542 | 543 | 544 | Кастомная провека работоспособности 545 | 546 | 547 | 548 | 549 | Фукнция проверки 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | Передача аргументов запроса в вызов 558 | 559 | 560 | 561 | Конструктор 562 | 563 | 564 | Асинхронный метод вызова 565 | 566 | 567 | 568 | Значение очереди 569 | 570 | 571 | 572 | 573 | 574 | Текущие занчение 575 | 576 | 577 | 578 | 579 | Маркер по котором считываем новые значения 580 | 581 | 582 | 583 | 584 | Следующий элемент в связанном списке 585 | 586 | 587 | 588 | 589 | Очередь реализующаю паттерн LongPolling ( "Длительный Опрос" ) 590 | 591 | generetic тип очереди 592 | 593 | 594 | 595 | Максимальное время удержания запроса, когда нет подходящих данных 596 | 597 | 598 | 599 | 600 | Время устаревания данных в очереди 601 | 602 | 603 | 604 | 605 | Конструктор 606 | 607 | 608 | 609 | 610 | Добавление в очередь 611 | 612 | 613 | 614 | 615 | Чтение из очереди 616 | 617 | маркер после которого происходит чтение данных из очереди 618 | 619 | 620 | 621 | 622 | Интерфейс для генерации сопоставления 623 | 624 | 625 | 626 | 627 | Регистрация сопоставления 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | Автор 636 | 637 | 638 | 639 | Уникальный идентификатор 640 | 641 | 642 | Имя автора 643 | 644 | 645 | Книги автора 646 | 647 | 648 | Издательства 649 | 650 | 651 | Связь многие ко многим Издатели/Авторы 652 | 653 | 654 | 655 | Автор для передачи данных 656 | 657 | 658 | 659 | Уникальный идентификатор 660 | 661 | 662 | Имя автора 663 | 664 | 665 | Книга 666 | 667 | 668 | Уникальный идентификатор 669 | 670 | 671 | Название книги 672 | 673 | 674 | Описание книги 675 | 676 | 677 | Обложка 678 | 679 | 680 | Уникльный идентификатор автора 681 | 682 | 683 | Автор 684 | 685 | 686 | Идентификатор ISBN10 687 | 688 | 689 | Идентификатор ISBN13 690 | 691 | 692 | Дополнительная информация по книге 693 | 694 | 695 | Статус книги 696 | 697 | 698 | Книга завершена 699 | 700 | 701 | Книга пишется 702 | 703 | 704 | Язык 705 | 706 | 707 | Русский 708 | 709 | 710 | Английский 711 | 712 | 713 | Жанр книги 714 | 715 | 716 | Фантастика 717 | 718 | 719 | Фантази 720 | 721 | 722 | litRPG 723 | 724 | 725 | Научная литература 726 | 727 | 728 | Историческая литература 729 | 730 | 731 | Дополнительная информация по книге 732 | 733 | 734 | Уникальный идентификатор 735 | 736 | 737 | Книга 738 | 739 | 740 | Ранк книги 741 | 742 | 743 | Статус книги 744 | 745 | 746 | Стоимость книги в мягком переплёте 747 | 748 | 749 | Стоимость книги в твёрдом переплёте 750 | 751 | 752 | Дата выпуска 753 | 754 | 755 | Редакция 756 | 757 | 758 | иллюстратор 759 | 760 | 761 | Колличество страниц 762 | 763 | 764 | Язык 765 | 766 | 767 | Возростные ограничения 768 | 769 | 770 | Жанр 771 | 772 | 773 | Отзывы 774 | 775 | 776 | 777 | Издатель 778 | 779 | 780 | 781 | Уникальный идентификатор 782 | 783 | 784 | Название издателя 785 | 786 | 787 | Авторы 788 | 789 | 790 | Связь многие ко многим Издатели/Авторы 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | Отслеживание изменения конфигурации 806 | 807 | 808 | * 809 | 810 | 811 | Конфигурация * 812 | 813 | 814 | Функция записи результата проверки работоспособности 815 | 816 | 817 | * 818 | 819 | 820 | Конфигурация сервисов * 821 | 822 | 823 | Конфигурация midlware * 824 | 825 | 826 | 827 | -------------------------------------------------------------------------------- /Client/DemoClient.cs: -------------------------------------------------------------------------------- 1 | //---------------------- 2 | // 3 | // Generated using the NSwag toolchain v13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org) 4 | // 5 | //---------------------- 6 | 7 | #pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." 8 | #pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." 9 | #pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' 10 | #pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... 11 | #pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." 12 | #pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" 13 | #pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" 14 | 15 | namespace Demo.Client 16 | { 17 | using System = global::System; 18 | 19 | [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")] 20 | public partial class DemoClient 21 | { 22 | private string _baseUrl = ""; 23 | private System.Net.Http.HttpClient _httpClient; 24 | private System.Lazy _settings; 25 | 26 | public DemoClient(string baseUrl, System.Net.Http.HttpClient httpClient) 27 | { 28 | BaseUrl = baseUrl; 29 | _httpClient = httpClient; 30 | _settings = new System.Lazy(CreateSerializerSettings); 31 | } 32 | 33 | private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() 34 | { 35 | var settings = new Newtonsoft.Json.JsonSerializerSettings(); 36 | UpdateJsonSerializerSettings(settings); 37 | return settings; 38 | } 39 | 40 | public string BaseUrl 41 | { 42 | get { return _baseUrl; } 43 | set { _baseUrl = value; } 44 | } 45 | 46 | protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } 47 | 48 | partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); 49 | 50 | 51 | partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); 52 | partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); 53 | partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); 54 | /// Получение всех авторов 55 | /// Success 56 | /// A server side error occurred. 57 | public System.Threading.Tasks.Task> GetAllAsync() 58 | { 59 | return GetAllAsync(System.Threading.CancellationToken.None); 60 | } 61 | 62 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 63 | /// Получение всех авторов 64 | /// Success 65 | /// A server side error occurred. 66 | public async System.Threading.Tasks.Task> GetAllAsync(System.Threading.CancellationToken cancellationToken) 67 | { 68 | var urlBuilder_ = new System.Text.StringBuilder(); 69 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors"); 70 | 71 | var client_ = _httpClient; 72 | var disposeClient_ = false; 73 | try 74 | { 75 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 76 | { 77 | request_.Method = new System.Net.Http.HttpMethod("GET"); 78 | request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); 79 | 80 | PrepareRequest(client_, request_, urlBuilder_); 81 | 82 | var url_ = urlBuilder_.ToString(); 83 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 84 | 85 | PrepareRequest(client_, request_, url_); 86 | 87 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 88 | var disposeResponse_ = true; 89 | try 90 | { 91 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 92 | if (response_.Content != null && response_.Content.Headers != null) 93 | { 94 | foreach (var item_ in response_.Content.Headers) 95 | headers_[item_.Key] = item_.Value; 96 | } 97 | 98 | ProcessResponse(client_, response_); 99 | 100 | var status_ = (int)response_.StatusCode; 101 | if (status_ == 200) 102 | { 103 | var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); 104 | if (objectResponse_.Object == null) 105 | { 106 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 107 | } 108 | return objectResponse_.Object; 109 | } 110 | else 111 | { 112 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 113 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 114 | } 115 | } 116 | finally 117 | { 118 | if (disposeResponse_) 119 | response_.Dispose(); 120 | } 121 | } 122 | } 123 | finally 124 | { 125 | if (disposeClient_) 126 | client_.Dispose(); 127 | } 128 | } 129 | 130 | /// Создание нового автора 131 | /// новый автор 132 | /// Success 133 | /// A server side error occurred. 134 | public System.Threading.Tasks.Task CreateAsync(Author body) 135 | { 136 | return CreateAsync(body, System.Threading.CancellationToken.None); 137 | } 138 | 139 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 140 | /// Создание нового автора 141 | /// новый автор 142 | /// Success 143 | /// A server side error occurred. 144 | public async System.Threading.Tasks.Task CreateAsync(Author body, System.Threading.CancellationToken cancellationToken) 145 | { 146 | var urlBuilder_ = new System.Text.StringBuilder(); 147 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors"); 148 | 149 | var client_ = _httpClient; 150 | var disposeClient_ = false; 151 | try 152 | { 153 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 154 | { 155 | var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); 156 | content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); 157 | request_.Content = content_; 158 | request_.Method = new System.Net.Http.HttpMethod("POST"); 159 | 160 | PrepareRequest(client_, request_, urlBuilder_); 161 | 162 | var url_ = urlBuilder_.ToString(); 163 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 164 | 165 | PrepareRequest(client_, request_, url_); 166 | 167 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 168 | var disposeResponse_ = true; 169 | try 170 | { 171 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 172 | if (response_.Content != null && response_.Content.Headers != null) 173 | { 174 | foreach (var item_ in response_.Content.Headers) 175 | headers_[item_.Key] = item_.Value; 176 | } 177 | 178 | ProcessResponse(client_, response_); 179 | 180 | var status_ = (int)response_.StatusCode; 181 | if (status_ == 200) 182 | { 183 | return; 184 | } 185 | else 186 | { 187 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 188 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 189 | } 190 | } 191 | finally 192 | { 193 | if (disposeResponse_) 194 | response_.Dispose(); 195 | } 196 | } 197 | } 198 | finally 199 | { 200 | if (disposeClient_) 201 | client_.Dispose(); 202 | } 203 | } 204 | 205 | /// Изменение автора 206 | /// Success 207 | /// A server side error occurred. 208 | public System.Threading.Tasks.Task UpdateAsync(Author body) 209 | { 210 | return UpdateAsync(body, System.Threading.CancellationToken.None); 211 | } 212 | 213 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 214 | /// Изменение автора 215 | /// Success 216 | /// A server side error occurred. 217 | public async System.Threading.Tasks.Task UpdateAsync(Author body, System.Threading.CancellationToken cancellationToken) 218 | { 219 | var urlBuilder_ = new System.Text.StringBuilder(); 220 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors"); 221 | 222 | var client_ = _httpClient; 223 | var disposeClient_ = false; 224 | try 225 | { 226 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 227 | { 228 | var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); 229 | content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); 230 | request_.Content = content_; 231 | request_.Method = new System.Net.Http.HttpMethod("PUT"); 232 | request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); 233 | 234 | PrepareRequest(client_, request_, urlBuilder_); 235 | 236 | var url_ = urlBuilder_.ToString(); 237 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 238 | 239 | PrepareRequest(client_, request_, url_); 240 | 241 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 242 | var disposeResponse_ = true; 243 | try 244 | { 245 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 246 | if (response_.Content != null && response_.Content.Headers != null) 247 | { 248 | foreach (var item_ in response_.Content.Headers) 249 | headers_[item_.Key] = item_.Value; 250 | } 251 | 252 | ProcessResponse(client_, response_); 253 | 254 | var status_ = (int)response_.StatusCode; 255 | if (status_ == 200) 256 | { 257 | var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); 258 | if (objectResponse_.Object == null) 259 | { 260 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 261 | } 262 | return objectResponse_.Object; 263 | } 264 | else 265 | { 266 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 267 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 268 | } 269 | } 270 | finally 271 | { 272 | if (disposeResponse_) 273 | response_.Dispose(); 274 | } 275 | } 276 | } 277 | finally 278 | { 279 | if (disposeClient_) 280 | client_.Dispose(); 281 | } 282 | } 283 | 284 | /// Получить автора по уникальному идентификатору 285 | /// Success 286 | /// A server side error occurred. 287 | public System.Threading.Tasks.Task GetByIdAsync(int id) 288 | { 289 | return GetByIdAsync(id, System.Threading.CancellationToken.None); 290 | } 291 | 292 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 293 | /// Получить автора по уникальному идентификатору 294 | /// Success 295 | /// A server side error occurred. 296 | public async System.Threading.Tasks.Task GetByIdAsync(int id, System.Threading.CancellationToken cancellationToken) 297 | { 298 | if (id == null) 299 | throw new System.ArgumentNullException("id"); 300 | 301 | var urlBuilder_ = new System.Text.StringBuilder(); 302 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors/{id}"); 303 | urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); 304 | 305 | var client_ = _httpClient; 306 | var disposeClient_ = false; 307 | try 308 | { 309 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 310 | { 311 | request_.Method = new System.Net.Http.HttpMethod("GET"); 312 | request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); 313 | 314 | PrepareRequest(client_, request_, urlBuilder_); 315 | 316 | var url_ = urlBuilder_.ToString(); 317 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 318 | 319 | PrepareRequest(client_, request_, url_); 320 | 321 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 322 | var disposeResponse_ = true; 323 | try 324 | { 325 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 326 | if (response_.Content != null && response_.Content.Headers != null) 327 | { 328 | foreach (var item_ in response_.Content.Headers) 329 | headers_[item_.Key] = item_.Value; 330 | } 331 | 332 | ProcessResponse(client_, response_); 333 | 334 | var status_ = (int)response_.StatusCode; 335 | if (status_ == 200) 336 | { 337 | var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); 338 | if (objectResponse_.Object == null) 339 | { 340 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 341 | } 342 | return objectResponse_.Object; 343 | } 344 | else 345 | { 346 | var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); 347 | if (objectResponse_.Object == null) 348 | { 349 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 350 | } 351 | throw new ApiException("Error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); 352 | } 353 | } 354 | finally 355 | { 356 | if (disposeResponse_) 357 | response_.Dispose(); 358 | } 359 | } 360 | } 361 | finally 362 | { 363 | if (disposeClient_) 364 | client_.Dispose(); 365 | } 366 | } 367 | 368 | /// Удаление автора 369 | /// Success 370 | /// A server side error occurred. 371 | public System.Threading.Tasks.Task DeleteAsync(int id) 372 | { 373 | return DeleteAsync(id, System.Threading.CancellationToken.None); 374 | } 375 | 376 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 377 | /// Удаление автора 378 | /// Success 379 | /// A server side error occurred. 380 | public async System.Threading.Tasks.Task DeleteAsync(int id, System.Threading.CancellationToken cancellationToken) 381 | { 382 | if (id == null) 383 | throw new System.ArgumentNullException("id"); 384 | 385 | var urlBuilder_ = new System.Text.StringBuilder(); 386 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors/{id}"); 387 | urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); 388 | 389 | var client_ = _httpClient; 390 | var disposeClient_ = false; 391 | try 392 | { 393 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 394 | { 395 | request_.Method = new System.Net.Http.HttpMethod("DELETE"); 396 | 397 | PrepareRequest(client_, request_, urlBuilder_); 398 | 399 | var url_ = urlBuilder_.ToString(); 400 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 401 | 402 | PrepareRequest(client_, request_, url_); 403 | 404 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 405 | var disposeResponse_ = true; 406 | try 407 | { 408 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 409 | if (response_.Content != null && response_.Content.Headers != null) 410 | { 411 | foreach (var item_ in response_.Content.Headers) 412 | headers_[item_.Key] = item_.Value; 413 | } 414 | 415 | ProcessResponse(client_, response_); 416 | 417 | var status_ = (int)response_.StatusCode; 418 | if (status_ == 200) 419 | { 420 | return; 421 | } 422 | else 423 | { 424 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 425 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 426 | } 427 | } 428 | finally 429 | { 430 | if (disposeResponse_) 431 | response_.Dispose(); 432 | } 433 | } 434 | } 435 | finally 436 | { 437 | if (disposeClient_) 438 | client_.Dispose(); 439 | } 440 | } 441 | 442 | /// Получение книг по уникальному идентификатору и названию 443 | /// Success 444 | /// A server side error occurred. 445 | public System.Threading.Tasks.Task> GetBookAsync(int id, string title) 446 | { 447 | return GetBookAsync(id, title, System.Threading.CancellationToken.None); 448 | } 449 | 450 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 451 | /// Получение книг по уникальному идентификатору и названию 452 | /// Success 453 | /// A server side error occurred. 454 | public async System.Threading.Tasks.Task> GetBookAsync(int id, string title, System.Threading.CancellationToken cancellationToken) 455 | { 456 | if (id == null) 457 | throw new System.ArgumentNullException("id"); 458 | 459 | if (title == null) 460 | throw new System.ArgumentNullException("title"); 461 | 462 | var urlBuilder_ = new System.Text.StringBuilder(); 463 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors/{id}/Book/{title}"); 464 | urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); 465 | urlBuilder_.Replace("{title}", System.Uri.EscapeDataString(ConvertToString(title, System.Globalization.CultureInfo.InvariantCulture))); 466 | 467 | var client_ = _httpClient; 468 | var disposeClient_ = false; 469 | try 470 | { 471 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 472 | { 473 | request_.Method = new System.Net.Http.HttpMethod("GET"); 474 | request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); 475 | 476 | PrepareRequest(client_, request_, urlBuilder_); 477 | 478 | var url_ = urlBuilder_.ToString(); 479 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 480 | 481 | PrepareRequest(client_, request_, url_); 482 | 483 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 484 | var disposeResponse_ = true; 485 | try 486 | { 487 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 488 | if (response_.Content != null && response_.Content.Headers != null) 489 | { 490 | foreach (var item_ in response_.Content.Headers) 491 | headers_[item_.Key] = item_.Value; 492 | } 493 | 494 | ProcessResponse(client_, response_); 495 | 496 | var status_ = (int)response_.StatusCode; 497 | if (status_ == 200) 498 | { 499 | var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); 500 | if (objectResponse_.Object == null) 501 | { 502 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 503 | } 504 | return objectResponse_.Object; 505 | } 506 | else 507 | if (status_ == 400) 508 | { 509 | var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); 510 | if (objectResponse_.Object == null) 511 | { 512 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 513 | } 514 | throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); 515 | } 516 | else 517 | { 518 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 519 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 520 | } 521 | } 522 | finally 523 | { 524 | if (disposeResponse_) 525 | response_.Dispose(); 526 | } 527 | } 528 | } 529 | finally 530 | { 531 | if (disposeClient_) 532 | client_.Dispose(); 533 | } 534 | } 535 | 536 | /// Метод чтения реализующий паттерн LongPolling 537 | /// маркер после которого происходит чтение данных из очереди 538 | /// Success 539 | /// A server side error occurred. 540 | public System.Threading.Tasks.Task> GetChangesAsync(string marker) 541 | { 542 | return GetChangesAsync(marker, System.Threading.CancellationToken.None); 543 | } 544 | 545 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 546 | /// Метод чтения реализующий паттерн LongPolling 547 | /// маркер после которого происходит чтение данных из очереди 548 | /// Success 549 | /// A server side error occurred. 550 | public async System.Threading.Tasks.Task> GetChangesAsync(string marker, System.Threading.CancellationToken cancellationToken) 551 | { 552 | if (marker == null) 553 | throw new System.ArgumentNullException("marker"); 554 | 555 | var urlBuilder_ = new System.Text.StringBuilder(); 556 | urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Authors/getchages/{marker}"); 557 | urlBuilder_.Replace("{marker}", System.Uri.EscapeDataString(ConvertToString(marker, System.Globalization.CultureInfo.InvariantCulture))); 558 | 559 | var client_ = _httpClient; 560 | var disposeClient_ = false; 561 | try 562 | { 563 | using (var request_ = new System.Net.Http.HttpRequestMessage()) 564 | { 565 | request_.Method = new System.Net.Http.HttpMethod("GET"); 566 | request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); 567 | 568 | PrepareRequest(client_, request_, urlBuilder_); 569 | 570 | var url_ = urlBuilder_.ToString(); 571 | request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); 572 | 573 | PrepareRequest(client_, request_, url_); 574 | 575 | var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 576 | var disposeResponse_ = true; 577 | try 578 | { 579 | var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); 580 | if (response_.Content != null && response_.Content.Headers != null) 581 | { 582 | foreach (var item_ in response_.Content.Headers) 583 | headers_[item_.Key] = item_.Value; 584 | } 585 | 586 | ProcessResponse(client_, response_); 587 | 588 | var status_ = (int)response_.StatusCode; 589 | if (status_ == 200) 590 | { 591 | var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); 592 | if (objectResponse_.Object == null) 593 | { 594 | throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); 595 | } 596 | return objectResponse_.Object; 597 | } 598 | else 599 | { 600 | var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 601 | throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); 602 | } 603 | } 604 | finally 605 | { 606 | if (disposeResponse_) 607 | response_.Dispose(); 608 | } 609 | } 610 | } 611 | finally 612 | { 613 | if (disposeClient_) 614 | client_.Dispose(); 615 | } 616 | } 617 | 618 | protected struct ObjectResponseResult 619 | { 620 | public ObjectResponseResult(T responseObject, string responseText) 621 | { 622 | this.Object = responseObject; 623 | this.Text = responseText; 624 | } 625 | 626 | public T Object { get; } 627 | 628 | public string Text { get; } 629 | } 630 | 631 | public bool ReadResponseAsString { get; set; } 632 | 633 | protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) 634 | { 635 | if (response == null || response.Content == null) 636 | { 637 | return new ObjectResponseResult(default(T), string.Empty); 638 | } 639 | 640 | if (ReadResponseAsString) 641 | { 642 | var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 643 | try 644 | { 645 | var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); 646 | return new ObjectResponseResult(typedBody, responseText); 647 | } 648 | catch (Newtonsoft.Json.JsonException exception) 649 | { 650 | var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; 651 | throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); 652 | } 653 | } 654 | else 655 | { 656 | try 657 | { 658 | using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) 659 | using (var streamReader = new System.IO.StreamReader(responseStream)) 660 | using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) 661 | { 662 | var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); 663 | var typedBody = serializer.Deserialize(jsonTextReader); 664 | return new ObjectResponseResult(typedBody, string.Empty); 665 | } 666 | } 667 | catch (Newtonsoft.Json.JsonException exception) 668 | { 669 | var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; 670 | throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); 671 | } 672 | } 673 | } 674 | 675 | private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) 676 | { 677 | if (value == null) 678 | { 679 | return ""; 680 | } 681 | 682 | if (value is System.Enum) 683 | { 684 | var name = System.Enum.GetName(value.GetType(), value); 685 | if (name != null) 686 | { 687 | var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); 688 | if (field != null) 689 | { 690 | var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) 691 | as System.Runtime.Serialization.EnumMemberAttribute; 692 | if (attribute != null) 693 | { 694 | return attribute.Value != null ? attribute.Value : name; 695 | } 696 | } 697 | 698 | var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); 699 | return converted == null ? string.Empty : converted; 700 | } 701 | } 702 | else if (value is bool) 703 | { 704 | return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); 705 | } 706 | else if (value is byte[]) 707 | { 708 | return System.Convert.ToBase64String((byte[])value); 709 | } 710 | else if (value.GetType().IsArray) 711 | { 712 | var array = System.Linq.Enumerable.OfType((System.Array)value); 713 | return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); 714 | } 715 | 716 | var result = System.Convert.ToString(value, cultureInfo); 717 | return result == null ? "" : result; 718 | } 719 | } 720 | 721 | /// Автор 722 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 723 | public partial class Author 724 | { 725 | /// Уникальный идентификатор 726 | [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 727 | public int Id { get; set; } 728 | 729 | /// Имя автора 730 | [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 731 | public string Name { get; set; } = "\u0412\u0430\u0441\u044f"; 732 | 733 | /// Книги автора 734 | [Newtonsoft.Json.JsonProperty("books", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 735 | public System.Collections.Generic.ICollection Books { get; set; } 736 | 737 | 738 | } 739 | 740 | /// Значение очереди 741 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 742 | public partial class AuthorLongPollingValue 743 | { 744 | [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 745 | public Author Value { get; set; } 746 | 747 | /// Маркер по котором считываем новые значения 748 | [Newtonsoft.Json.JsonProperty("marker", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 749 | public System.DateTimeOffset Marker { get; set; } 750 | 751 | 752 | } 753 | 754 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 755 | public partial class Book 756 | { 757 | [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 758 | public int Id { get; set; } 759 | 760 | [Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 761 | public string Title { get; set; } 762 | 763 | [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 764 | public string Description { get; set; } 765 | 766 | [Newtonsoft.Json.JsonProperty("year", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 767 | public System.DateTimeOffset Year { get; set; } 768 | 769 | [Newtonsoft.Json.JsonProperty("authorId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 770 | public int AuthorId { get; set; } 771 | 772 | [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 773 | public StatusEnum Status { get; set; } 774 | 775 | [Newtonsoft.Json.JsonProperty("rank", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 776 | public double Rank { get; set; } 777 | 778 | [Newtonsoft.Json.JsonProperty("peperbackCost", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 779 | public double PeperbackCost { get; set; } 780 | 781 | [Newtonsoft.Json.JsonProperty("hardcoverCost", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 782 | public double HardcoverCost { get; set; } 783 | 784 | [Newtonsoft.Json.JsonProperty("publisherId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 785 | public int PublisherId { get; set; } 786 | 787 | [Newtonsoft.Json.JsonProperty("editor", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 788 | public string Editor { get; set; } 789 | 790 | [Newtonsoft.Json.JsonProperty("illustrator", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 791 | public string Illustrator { get; set; } 792 | 793 | [Newtonsoft.Json.JsonProperty("pageCount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 794 | public int PageCount { get; set; } 795 | 796 | [Newtonsoft.Json.JsonProperty("language", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 797 | public LanguageEnum Language { get; set; } 798 | 799 | [Newtonsoft.Json.JsonProperty("readingAge", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 800 | public int ReadingAge { get; set; } 801 | 802 | [Newtonsoft.Json.JsonProperty("genre", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 803 | public GenreEnum Genre { get; set; } 804 | 805 | [Newtonsoft.Json.JsonProperty("isbN_10", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 806 | public string IsbN_10 { get; set; } 807 | 808 | [Newtonsoft.Json.JsonProperty("isbN_13", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 809 | public string IsbN_13 { get; set; } 810 | 811 | [Newtonsoft.Json.JsonProperty("reviews", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 812 | public int Reviews { get; set; } 813 | 814 | 815 | } 816 | 817 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 818 | public enum GenreEnum 819 | { 820 | Fantastic = 0, 821 | 822 | Fantasy = 1, 823 | 824 | Litrpg = 2, 825 | 826 | Scientific = 3, 827 | 828 | Historical = 4, 829 | 830 | } 831 | 832 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 833 | public enum LanguageEnum 834 | { 835 | Ru = 0, 836 | 837 | En = 1, 838 | 839 | } 840 | 841 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 842 | public partial class ProblemDetails 843 | { 844 | [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 845 | public string Type { get; set; } 846 | 847 | [Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 848 | public string Title { get; set; } 849 | 850 | [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 851 | public int? Status { get; set; } 852 | 853 | [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 854 | public string Detail { get; set; } 855 | 856 | [Newtonsoft.Json.JsonProperty("instance", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] 857 | public string Instance { get; set; } 858 | 859 | private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); 860 | 861 | [Newtonsoft.Json.JsonExtensionData] 862 | public System.Collections.Generic.IDictionary AdditionalProperties 863 | { 864 | get { return _additionalProperties; } 865 | set { _additionalProperties = value; } 866 | } 867 | 868 | 869 | } 870 | 871 | /// Статус книги 872 | [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")] 873 | public enum StatusEnum 874 | { 875 | Complite = 0, 876 | 877 | Write = 1, 878 | 879 | } 880 | 881 | [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")] 882 | public partial class ApiException : System.Exception 883 | { 884 | public int StatusCode { get; private set; } 885 | 886 | public string Response { get; private set; } 887 | 888 | public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } 889 | 890 | public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) 891 | : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) 892 | { 893 | StatusCode = statusCode; 894 | Response = response; 895 | Headers = headers; 896 | } 897 | 898 | public override string ToString() 899 | { 900 | return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); 901 | } 902 | } 903 | 904 | [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")] 905 | public partial class ApiException : ApiException 906 | { 907 | public TResult Result { get; private set; } 908 | 909 | public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) 910 | : base(message, statusCode, response, headers, innerException) 911 | { 912 | Result = result; 913 | } 914 | } 915 | 916 | } 917 | 918 | #pragma warning restore 1591 919 | #pragma warning restore 1573 920 | #pragma warning restore 472 921 | #pragma warning restore 114 922 | #pragma warning restore 108 923 | #pragma warning restore 3016 --------------------------------------------------------------------------------