Переглянути джерело

Merge branch 'master' of http://139.155.15.221:3000/zoulei/DW5S

wyq 3 місяців тому
батько
коміт
a4f1de1f6a

+ 20 - 0
AdService/AdService.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+	<ImplicitUsings>enable</ImplicitUsings>
+	<Nullable>disable</Nullable>
+	<GenerateDocumentationFile>True</GenerateDocumentationFile>
+	<RootNamespace>AdService.Controller</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.19" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DW5S.DTO\02.DW5S.DTO.csproj" />
+    <ProjectReference Include="..\DW5S.WebApi\05.DW5S.WebApi.csproj" />
+  </ItemGroup>
+
+</Project>

+ 25 - 0
AdService/Controllers/AdController.cs

@@ -0,0 +1,25 @@
+using DW5S.WebApi;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AdService.Controllers
+{
+
+    /// <summary>
+    /// 采集接口
+    /// </summary>
+    public class AdController : BaseController
+    {
+
+
+        /// <summary>
+        /// 开始采集
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost]
+        public string StartAD()
+        {
+            return "aaaaaaaaaaa";
+        }
+
+    }
+}

+ 46 - 0
AdService/Controllers/AdFileController.cs

@@ -0,0 +1,46 @@
+using DW5S.WebApi;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AdService.Controller.Controllers
+{
+
+    /// <summary>
+    /// 采集文件操作接口
+    /// </summary>
+    public class AdFileController : BaseController
+    {
+        /// <summary>
+        /// 下载采集的文件
+        /// </summary>
+        /// <param name="fileName">采集返回的名称</param>
+        /// <returns></returns>
+        [HttpGet]
+        public IActionResult Download(string fileName)
+        {
+            if (string.IsNullOrWhiteSpace(fileName))
+            {
+                return NotFound("必须指定要下载的文件");
+            }
+            if (fileName.StartsWith("/"))
+                fileName = fileName.Substring(1);
+            string localFile = Path.Combine("D:\\work", fileName);
+            try
+            {
+                if (!System.IO.File.Exists(localFile))
+                {
+                    //IpsLogger.Error($"下载失败,文件[{localFile}]不存在");
+                    return NotFound($"文件[{fileName}]不存在");
+                }
+                var fileStream = new FileStream(localFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, true);  //异步读取文件
+                return File(fileStream, "application/octet-stream", fileName, true);  //为true时,支持断点续传
+            }
+            catch (Exception ex)
+            {
+                //IpsLogger.Error($"文件[{localFile}]下载失败", ex);
+                return NotFound($"文件[{fileName}]下载失败");
+            }
+        }
+
+
+    }
+}

+ 31 - 0
AdService/Program.cs

@@ -0,0 +1,31 @@
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+    app.UseSwagger();
+    app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Run();
+
+
+/*WebApiHelper.Start(_localPort: 7011,
+               dtoXmlName: "02.DW5S.DTO.xml",
+               controllerXmlName: "AdService.Controller.xml",
+               dllKey: "DW5S");*/

+ 41 - 0
AdService/Properties/launchSettings.json

@@ -0,0 +1,41 @@
+{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:57796",
+      "sslPort": 44367
+    }
+  },
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:5248",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "https": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "https://localhost:7070;http://localhost:5248",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 37 - 0
AdService/Service/AdReportService.cs

@@ -0,0 +1,37 @@
+using DW5S.DTO;
+
+namespace AdService.Service
+{
+
+    /// <summary>
+    /// 服务上报服务(3s)
+    /// </summary>
+    public class AdReportService : BackgroundService
+    {
+        /// <summary>
+        /// 服务上报服务
+        /// </summary>
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            
+            await Task.Run(async () =>
+            {
+                while (!stoppingToken.IsCancellationRequested)
+                {
+                    SvrStateReportDto dto = new SvrStateReportDto()
+                    {
+                        DD = TimeSpan.FromSeconds(1),
+                        SvrType = EnumSvrType.AdCgSvr,
+                        SvrID = "AdService",
+                        BaseHttpAddr = "",
+                        SwaggerAddr="",
+                        ReportType = 0,
+                    };
+                    // var res = await HttpHelper.PostRequestAsync<CpuCgResDto>("" + "SvrReport/Report", dto);
+                    await Task.Delay(3 * 1000, stoppingToken);
+                }
+            }, stoppingToken);
+        }
+
+    }
+}

+ 9 - 0
AdService/Service/AdService.cs

@@ -0,0 +1,9 @@
+namespace AdService.Service
+{
+    /// <summary>
+    /// 采集服务
+    /// </summary>
+    public class AdService
+    {
+    }
+}

+ 29 - 0
AdService/Service/CearDirService.cs

@@ -0,0 +1,29 @@
+using DW5S.DTO;
+
+namespace AdService.Service
+{
+
+    /// <summary>
+    /// 数据清理服务(每隔5分钟扫描一次)
+    /// </summary>
+    public class CearDirService : BackgroundService
+    {
+        /// <summary>
+        /// 数据清理服务
+        /// </summary>
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+
+            await Task.Run(async () =>
+            {
+                while (!stoppingToken.IsCancellationRequested)
+                {
+                   
+                    await Task.Delay(3 * 1000, stoppingToken);
+                }
+            }, stoppingToken);
+        }
+
+
+    }
+}

+ 9 - 0
AdService/appsettings.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*"
+}

+ 3 - 0
DW5S.App/App.config

@@ -17,6 +17,8 @@
 	</applicationSettings>
 	<connectionStrings>
 		<add name="OracleCon" connectionString="Data Source=192.168.1.111:1521/ORCL;User ID=DW5S;Password=123456"/>
+
+		<add name="SqliteCon" connectionString="Data Source=D:/work/DW5S/DW5S.App/dw5s.db"/>
 	</connectionStrings>
 	<appSettings>
 		<!--程序标题-->
@@ -57,5 +59,6 @@
 		
 		<!--星地任务是否使用仿真时频差等进行流程测试-->
 		<add key="ForTest" value="true"/>
+		
 	</appSettings>
 </configuration>

+ 3 - 0
DW5S.App/DW5S.App.csproj

@@ -56,6 +56,9 @@
     <None Update="data.gmdb">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Update="dw5s.db">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Update="Image\XlCalc.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>

BIN
DW5S.App/dw5s.db


+ 6 - 0
DW5S.DTO/SvrStateDto.cs

@@ -49,6 +49,12 @@ namespace DW5S.DTO
     public enum EnumSvrType
     {
 
+        /// <summary>
+        /// 采集服务
+        /// </summary>
+        [Display(Name = "采集服务")]
+        AdCgSvr,
+
         /// <summary>
         /// CPU参估服务
         /// </summary>

+ 2 - 0
DW5S.Repostory/04.DW5S.Repostory.csproj

@@ -14,11 +14,13 @@
 			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 		</PackageReference>
 		<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.20" />
+		<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.2" />
 		<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.20">
 			<PrivateAssets>all</PrivateAssets>
 			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 		</PackageReference>
 		<PackageReference Include="Oracle.EntityFrameworkCore" Version="7.21.13" />
+		<PackageReference Include="SQLitePCLRaw.provider.e_sqlite3" Version="2.1.10" />
 	</ItemGroup>
 	<ItemGroup>
 	  <ProjectReference Include="..\DW5S.Entity\03.DW5S.Entity.csproj" />

+ 153 - 0
DW5S.Repostory/EFContext/SqilteContext.cs

@@ -0,0 +1,153 @@
+using DW5S.Entity;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Conventions;
+using Microsoft.Extensions.Logging;
+using System.Configuration;
+
+namespace DW5S.Repostory
+{
+    public class SqliteContext : DbContext
+    {
+        public SqliteContext()
+        {
+            //发布为单文件后找不到Microsoft.EntityFrameworkCore.Relational.dll,需要将这个dll拷贝到AddIns中
+        }
+        public async Task ExecuteSqlAsync(string sql)
+        {
+            await this.Database.ExecuteSqlRawAsync(sql);
+        }
+
+        /// <summary>
+        /// 执行SQL查询(查询最大ID需要给int?等可空类型,否则会出错)
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="sql"></param>
+        /// <returns></returns>
+        public async Task<List<T>> SqlQuery<T>(string sql)
+        {
+            var res = await this.Database.SqlQueryRaw<T>(sql).ToListAsync();
+            return res;
+        }
+        /// <summary>
+        /// 更新所有表的序列值为对应表的最大ID(更新后需要重新编译触发器)
+        /// </summary>
+        public void UpdateSeq()
+        {
+            List<string> tables = new List<string>();
+            var props = typeof(OracleContext).GetProperties().Where(p => p.PropertyType.Name.StartsWith("DbSet")).ToList();
+            foreach (var item in props)
+            {
+                var tb = item.PropertyType.GetGenericArguments().First().Name.ToUpper();
+                tables.Add(tb);
+            }
+            foreach (var tb in tables)
+            {
+                try
+                {
+                    int? idMax = this.SqlQuery<int?>($"select max(id) from {tb}").Result.FirstOrDefault();
+                    if (idMax == null)
+                        idMax = 1;
+                    string sql = $"DROP SEQUENCE SQ_{tb}";
+                    this.ExecuteSqlAsync(sql).Wait();
+                    sql = $"CREATE SEQUENCE SQ_{tb} INCREMENT BY 1 START WITH {idMax}";
+                    this.ExecuteSqlAsync(sql).Wait();
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine(ex.Message);
+                }
+            }
+
+        }
+        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+        {
+            var conStr = ConfigurationManager.ConnectionStrings["SqliteCon"].ToString();
+
+            optionsBuilder.UseSqlite(@conStr);
+
+            //sql语句输出到日志文件
+            var loggerFactory = new LoggerFactory();
+            loggerFactory.AddProvider(new SqlLoggerProvider());
+            optionsBuilder.UseLoggerFactory(loggerFactory);
+
+            base.OnConfiguring(optionsBuilder);
+        }
+        protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
+        {
+            //EFCore默认表名会带上复数形式,通过这句话删除复数约定
+            configurationBuilder.Conventions.Remove(typeof(TableNameFromDbSetConvention));
+        }
+        protected override void OnModelCreating(ModelBuilder modelBuilder)
+        {
+            //在Oracle11g中列名、索引、字段、表名、序列、触发器等名称长度均不能超过30个字符
+            //自动生成的超出30个字符的需要在下面自定义
+            modelBuilder.Entity<CgRes>().HasOne(p => p.StationRes).WithMany()
+                .HasConstraintName("FK_CGRES_STATIONRESID");
+            modelBuilder.Entity<SampleInfo>().HasOne(p => p.SigInfo).WithOne()
+                .HasConstraintName("FK_SAMPLEINFO_SIGINFOID");
+            modelBuilder.Entity<PosRes>().HasOne(p => p.StationRes).WithOne()
+                .HasConstraintName("FK_POSRES_STATIONRESID");
+            modelBuilder.Entity<PosRes>().HasOne(p => p.TargetInfo).WithOne()
+                .HasConstraintName("FK_POSRES_TARGETINFOID");
+            modelBuilder.Entity<RefTaskFreq>().HasOne(p => p.SampleInfo).WithOne()
+                .HasConstraintName("FK_REFTASKFREQ_SAMPLEINFOID");
+            modelBuilder.Entity<RefTaskFreq>().HasOne(p => p.SatInfo).WithOne()
+                .HasConstraintName("FK_REFTASKFREQ_SATINFOID");
+
+            modelBuilder.Entity<LogRes>().HasIndex(p => new { p.Module, p.LogTime, p.LogType })
+                .HasDatabaseName("IX_LOGRES_MODULE_TIME_TYPE");
+            modelBuilder.Entity<RefCgRes>().HasIndex(p => new { p.FileTime, p.FrequpHz, p.YbSnr })
+                .HasDatabaseName("IX_REFCGRES_TIME_FREQ_SNR");
+            modelBuilder.Entity<CgRes>().HasIndex(p => new { p.TaskID, p.SigTime, p.FrequpHz })
+                .HasDatabaseName("IX_CGRES_TASKID_TIME_FREQ");
+            modelBuilder.Entity<PosRes>().HasIndex(p => new { p.TaskID, p.SigTime, p.FrequpHz })
+                .HasDatabaseName("IX_POSRES_TASKID_TIME_FREQ");
+            
+
+
+        }
+        public DbSet<XlInfo> XlInfos { set; get; }
+
+        public DbSet<TaskInfo> TaskInfos { set; get; }
+
+        public DbSet<TaskSig> TaskSigs { set; get; }
+
+        public DbSet<TxInfo> TxInfos { get; set; }
+
+        public DbSet<AdCard> AdCards { get; set; }
+
+        public DbSet<AdChannel> AdChannels { get; set; }
+
+        public DbSet<SatInfo> SatInfos { get; set; }
+
+        public DbSet<FixedStation> FixedStation { get; set; }
+
+        public DbSet<SigInfo> SigInfos { get; set; }
+
+        public DbSet<SigDelay> SigDelays { get; set; }
+
+        public DbSet<TargetInfo> TargetInfos { get; set; }
+
+        public DbSet<SysSetings> SysSetings { get; set; }
+
+        public DbSet<TaskRunnningInfo> TaskRunnningInfos { get; set; }
+
+        public DbSet<SampleInfo> SampleInfos { get; set; }
+
+        public DbSet<RefTaskFreq> RefTaskFreqs { get; set; }
+
+        /*以下是Range分区表的DbSet*/
+
+        public DbSet<AdRes> AdRes { get; set; }
+
+        public DbSet<LogRes> LogRes { set; get; }
+        public DbSet<StationRes> StationRes { get; set; }
+        public DbSet<CxRes> CxRes { get; set; }
+        public DbSet<CgRes> CgRes { get; set; }
+
+        public DbSet<RefCgRes> RefCgRes { get; set; }
+        public DbSet<CgXgfRes> CgXgfRes { get; set; }
+        public DbSet<PosRes> PosRes { get; set; }
+        public DbSet<CheckRes> CheckRes { get; set; }
+    }
+}

+ 3 - 2
DW5S.Repostory/Repository/IRepository.cs

@@ -50,10 +50,11 @@ namespace DW5S.Repostory
 
     public class Repository<T, IDType> : IRepository<T, IDType> where T : BaseEntity<IDType>
     {
-        protected readonly OracleContext ctx;
+        protected readonly SqliteContext ctx;
+
         protected readonly DbSet<T> dbSet;
 
-        public Repository(OracleContext ctx)
+        public Repository(SqliteContext ctx)
         {
             this.ctx = ctx;
             this.dbSet = ctx.Set<T>();

+ 1 - 1
DW5S.Repostory/Repository/XlRepository.cs

@@ -21,7 +21,7 @@ namespace DW5S.Repostory
         /// 
         /// </summary>
         /// <param name="ctx"></param>
-        public XlRepository(OracleContext ctx)
+        public XlRepository(SqliteContext ctx)
             : base(ctx)
         {
         }

+ 2 - 2
DW5S.Repostory/UnitOfWork.cs

@@ -24,7 +24,7 @@ namespace DW5S.Repostory
     }
     public class UnitOfWork : IUnitOfWork
     {
-        public readonly OracleContext ctx;
+        public readonly SqliteContext ctx;
 
         public IRepository<TEntity, IDType> OfType<TEntity, IDType>() where TEntity : BaseEntity<IDType>
         {
@@ -45,7 +45,7 @@ namespace DW5S.Repostory
             var reps = IocContainer.GetService<IRepository<TEntity, long>>(ctx);
             return reps;
         }
-        public UnitOfWork(OracleContext ctx)
+        public UnitOfWork(SqliteContext ctx)
         {
             this.ctx = ctx;
         }

+ 4 - 4
DW5S.WebApi/WebApiHelper.cs

@@ -45,7 +45,7 @@ namespace DW5S.WebApi
         /// <param name="staticDir">要启用的静态目录预览及文件下载的目录(已经包含upload、download、logs三个目录)</param>
         /// <param name="dllKey">使用DI注入时程序集标识</param>
         /// <exception cref="Exception"></exception>
-        public static void Start(int _localPort, string dtoXmlName = null, string[] staticDir = null, string controllerXmlName = null, string dllKey = "DW5S")
+        public  static void Start(int _localPort, string dtoXmlName = null, string[] staticDir = null, string controllerXmlName = null, string dllKey = "DW5S")
         {
             BaseController.EnsureAssemblyLoaded();
             _cts = new CancellationTokenSource();
@@ -114,7 +114,7 @@ namespace DW5S.WebApi
             builder.Host.UseSerilog((builderContext, config) =>
             {
                 var basePath = AppContext.BaseDirectory;
-                var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}[线程={ThreadId}][{Level:u3}]{Message:lj}{NewLine}\t{Exception}";
+                var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}[线程={ThreadId}][{Level:u3}]{Message:lj}{NewLine}{Exception}";
                 config.Enrich.FromLogContext()
                     .Enrich.With(new SerilogEnricher())
                     .WriteTo.Console(outputTemplate: outputTemplate)
@@ -182,7 +182,7 @@ namespace DW5S.WebApi
                     .InstancePerLifetimeScope();
 
                 //注入DbContext
-                builder.RegisterType<OracleContext>()
+                builder.RegisterType<SqliteContext>()
                     .InstancePerLifetimeScope();
 
                 //注入IUnitOfWork
@@ -302,7 +302,7 @@ namespace DW5S.WebApi
             app.MapControllers();
             //app.Map("/", () => "必须通过GRPC客户端访问此接口");
 
-            app.RunAsync(_cts.Token);
+             app.RunAsync(_cts.Token);
             //app.Run();
         }
 

+ 12 - 0
DW5S.sln

@@ -23,6 +23,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "07.DW5S.Service", "DW5S.Ser
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "09.DW5S.ViewModel", "DW5S.ViewModel\09.DW5S.ViewModel.csproj", "{5D3296E4-851B-4D85-9578-62068DD8551C}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdService", "AdService\AdService.csproj", "{DE3D49C4-E632-4B93-B17A-C37A71490111}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GpuService", "GpuService\GpuService.csproj", "{8DFE5755-CD4B-46C7-B9A5-C0745241D288}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -69,6 +73,14 @@ Global
 		{5D3296E4-851B-4D85-9578-62068DD8551C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{5D3296E4-851B-4D85-9578-62068DD8551C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{5D3296E4-851B-4D85-9578-62068DD8551C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DE3D49C4-E632-4B93-B17A-C37A71490111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DE3D49C4-E632-4B93-B17A-C37A71490111}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DE3D49C4-E632-4B93-B17A-C37A71490111}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DE3D49C4-E632-4B93-B17A-C37A71490111}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8DFE5755-CD4B-46C7-B9A5-C0745241D288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8DFE5755-CD4B-46C7-B9A5-C0745241D288}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8DFE5755-CD4B-46C7-B9A5-C0745241D288}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8DFE5755-CD4B-46C7-B9A5-C0745241D288}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 32 - 0
GpuService/Controllers/WeatherForecastController.cs

@@ -0,0 +1,32 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace GpuService.Controllers;
+
+[ApiController]
+[Route("[controller]")]
+public class WeatherForecastController : ControllerBase
+{
+    private static readonly string[] Summaries = new[]
+    {
+        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+    };
+
+    private readonly ILogger<WeatherForecastController> _logger;
+
+    public WeatherForecastController(ILogger<WeatherForecastController> logger)
+    {
+        _logger = logger;
+    }
+
+    [HttpGet(Name = "GetWeatherForecast")]
+    public IEnumerable<WeatherForecast> Get()
+    {
+        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+        {
+            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
+            TemperatureC = Random.Shared.Next(-20, 55),
+            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
+        })
+        .ToArray();
+    }
+}

+ 14 - 0
GpuService/GpuService.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.19" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
+  </ItemGroup>
+
+</Project>

+ 25 - 0
GpuService/Program.cs

@@ -0,0 +1,25 @@
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+    app.UseSwagger();
+    app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Run();

+ 41 - 0
GpuService/Properties/launchSettings.json

@@ -0,0 +1,41 @@
+{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:41374",
+      "sslPort": 44385
+    }
+  },
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:5038",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "https": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "https://localhost:7029;http://localhost:5038",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 13 - 0
GpuService/WeatherForecast.cs

@@ -0,0 +1,13 @@
+namespace GpuService
+{
+    public class WeatherForecast
+    {
+        public DateOnly Date { get; set; }
+
+        public int TemperatureC { get; set; }
+
+        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+        public string? Summary { get; set; }
+    }
+}

+ 8 - 0
GpuService/appsettings.Development.json

@@ -0,0 +1,8 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  }
+}

+ 9 - 0
GpuService/appsettings.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*"
+}