Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing Details

IRC_NewDev
he 2024-10-21 17:58:30 +08:00
commit 15701ef073
9 changed files with 95 additions and 188 deletions

View File

@ -315,7 +315,7 @@ namespace IRaCIS.Core.SCP.Service
_SCPStudyIdList.Add(scpStudyId);
}
var series = await _seriesRepository.FindAsync(seriesId);
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
//没有缩略图
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))

View File

@ -75,9 +75,9 @@ namespace IRaCIS.Core.SCP.Service
//using (@lock.Acquire())
{
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
var findStudy = await _studyRepository.FindAsync(studyId);
var findSerice = await _seriesRepository.FindAsync(seriesId);
var findInstance = await _instanceRepository.FindAsync(instanceId);
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
@ -307,7 +307,7 @@ namespace IRaCIS.Core.SCP.Service
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
}
//await _studyRepository.SaveChangesAsync();
await _studyRepository.SaveChangesAsync();
return findStudy.Id;
}

View File

@ -76,7 +76,7 @@
<PackageReference Include="LogDashboard" Version="1.4.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.9.0" />
</ItemGroup>

View File

@ -80,6 +80,7 @@ builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
//健康检查
builder.Services.AddHealthChecks();
builder.Services.AddSerilog();
//本地化
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
@ -197,7 +198,7 @@ app.UseExceptionHandler(o => { });
app.UseIRacisHostStaticFileStore(env);
//本地化
await app.UseLocalization(app.Services);
await app.UseLocalization(app.Services);
app.UseForwardedHeaders();

View File

@ -1,7 +1,10 @@
using IRaCIS.Core.API._PipelineExtensions.Serilog;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Serilog;
using System.Linq;
namespace IRaCIS.Core.API
{
@ -17,8 +20,66 @@ namespace IRaCIS.Core.API
app.UseSerilogRequestLogging(opts
=>
{
opts.MessageTemplate = "{TokenUserRealName} {TokenUserTypeShortName} {ClientIp} {LocalIP} {Host} {Protocol} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
opts.EnrichDiagnosticContext = SerilogHelper.EnrichFromRequest;
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
opts.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
var request = httpContext.Request;
// Set all the common properties available for every request
diagnosticContext.Set("Host", request.Host.Value);
// Only set it if available. You're not sending sensitive data in a querystring right?!
if (request.QueryString.HasValue)
{
diagnosticContext.Set("QueryString", request.QueryString.Value);
}
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.RealName)?.Value);
diagnosticContext.Set("UserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value);
var clientIp = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
httpContext.Connection.RemoteIpAddress?.ToString();
if (clientIp.StartsWith("::ffff:"))
{
clientIp = clientIp.Substring(7); // 移除前缀
}
diagnosticContext.Set("UserIp", clientIp);
#region 非必要不记录
//diagnosticContext.Set("Protocol", request.Protocol);
//diagnosticContext.Set("Scheme", request.Scheme);
//// Retrieve the IEndpointFeature selected for the request
//var endpoint = httpContext.GetEndpoint();
//if (endpoint is object) // endpoint != null
//{
// diagnosticContext.Set("EndpointName", endpoint.DisplayName);
//}
// Set the content-type of the Response at this point
//diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
#endregion
#region old 未用
//这种获取的Ip不准 配置服务才行
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
//这种方式可以但是serilog提供了 就不用了
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
//这种方式不行 读取的body为空字符串 必须在中间件中读取
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
//diagnosticContext.Set("RequestBody", RequestPayload);
#endregion
};
});

View File

@ -1,56 +0,0 @@
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Http;
using Serilog;
namespace IRaCIS.Core.API
{
public class SerilogHelper
{
//public static string RequestPayload = "";
public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext)
{
var request = httpContext.Request;
// Set all the common properties available for every request
diagnosticContext.Set("Host", request.Host);
diagnosticContext.Set("Protocol", request.Protocol);
diagnosticContext.Set("Scheme", request.Scheme);
#region old 未用
//这种获取的Ip不准 配置服务才行
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
//这种方式可以但是serilog提供了 就不用了
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
//这种方式不行 读取的body为空字符串 必须在中间件中读取
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
//diagnosticContext.Set("RequestBody", RequestPayload);
#endregion
// Only set it if available. You're not sending sensitive data in a querystring right?!
if (request.QueryString.HasValue)
{
diagnosticContext.Set("QueryString", request.QueryString.Value);
}
// Set the content-type of the Response at this point
diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
diagnosticContext.Set("TokenUserRealName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.RealName)?.Value);
diagnosticContext.Set("TokenUserTypeShortName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value);
// Retrieve the IEndpointFeature selected for the request
var endpoint = httpContext.GetEndpoint();
if (endpoint is object) // endpoint != null
{
diagnosticContext.Set("EndpointName", endpoint.DisplayName);
}
}
}
}

View File

@ -1,29 +0,0 @@
using Microsoft.AspNetCore.Http;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using System;
namespace IRaCIS.Core.API
{
public static class EnricherExtensions
{
public static LoggerConfiguration WithHttpContextInfo(this LoggerEnrichmentConfiguration enrich, IServiceProvider serviceProvider)
{
if (enrich == null)
throw new ArgumentNullException(nameof(enrich));
return enrich.With(new HttpContextEnricher(serviceProvider));
}
public static LoggerConfiguration WithHttpContextInfo(this LoggerEnrichmentConfiguration enrich, IServiceProvider serviceProvider, Action<LogEvent, ILogEventPropertyFactory, HttpContext> enrichAction)
{
if (enrich == null)
throw new ArgumentNullException(nameof(enrich));
return enrich.With(new HttpContextEnricher(serviceProvider, enrichAction));
}
}
}

View File

@ -1,86 +0,0 @@
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Serilog.Core;
using Serilog.Events;
using System;
using System.IO;
using System.Threading.Tasks;
namespace IRaCIS.Core.API
{
public class HttpContextEnricher : ILogEventEnricher
{
private readonly IServiceProvider _serviceProvider;
private readonly Action<LogEvent, ILogEventPropertyFactory, HttpContext> _enrichAction;
public HttpContextEnricher(IServiceProvider serviceProvider) : this(serviceProvider, null)
{ }
public HttpContextEnricher(IServiceProvider serviceProvider, Action<LogEvent, ILogEventPropertyFactory, HttpContext> enrichAction)
{
_serviceProvider = serviceProvider;
if (enrichAction == null)
{
_enrichAction = (logEvent, propertyFactory, httpContext) =>
{
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", httpContext.Connection.RemoteIpAddress.ToString()));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("LocalIP", httpContext.Connection.LocalIpAddress.MapToIPv4().ToString()));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
//这样读取没用
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestBody", await ReadRequestBody(httpContext.Request)));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Referer", httpContext.Request.Headers["Referer"].ToString()));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method));
//if (httpContext.Response.HasStarted)
//{
// logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("response_status", httpContext.Response.StatusCode));
//}
};
}
else
{
_enrichAction = enrichAction;
}
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var httpContext = _serviceProvider.GetService<IHttpContextAccessor>()?.HttpContext;
if (null != httpContext)
{
_enrichAction.Invoke(logEvent, propertyFactory, httpContext);
}
}
private async Task<string> ReadRequestBody(HttpRequest request)
{
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
request.EnableBuffering();
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
var requestBody = await streamReader.ReadToEndAsync();
// Reset the request's body stream position for next middleware in the pipeline.
request.Body.Position = 0;
return requestBody == null ? String.Empty : requestBody.Trim();
}
private async Task<string> ReadResponseBody(HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
string responseBody = await new StreamReader(response.Body).ReadToEndAsync();
response.Body.Seek(0, SeekOrigin.Begin);
return $"{responseBody}";
}
}
}

View File

@ -1,5 +1,7 @@
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Compact;
//using Serilog.Sinks.Email;
using System;
@ -16,18 +18,32 @@ namespace IRaCIS.Core.API
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning)
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
.Enrich.WithClientIp()
//如果有反向代理并不会获取到用户的真实IP
//.Enrich.WithClientIp()
//.Enrich.WithRequestHeader("User-Agent")
.Enrich.FromLogContext()
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
//https://github.com/serilog/serilog-formatting-compact
// 控制台输出 JSON 格式
.WriteTo.Console(formatter: new CompactJsonFormatter(),LogEventLevel.Warning)
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}");
// 文件输出 JSON 格式
.WriteTo.File(new CompactJsonFormatter(), $"{AppContext.BaseDirectory}Serilogs/.json", rollingInterval: RollingInterval.Day);
////控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
//.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
// outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {ClientIp} {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
//.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
// outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {ClientIp} {SourceContext:l} || {Message} || {Exception} ||end {NewLine}");
Log.Logger = config.CreateLogger();
//.WriteTo.MSSqlServer("Data Source=DESKTOP-4TU9A6M;Initial Catalog=CoreFrame;User ID=sa;Password=123456", "logs", autoCreateSqlTable: true, restrictedToMinimumLevel: LogEventLevel.Information)//从左至右四个参数分别是数据库连接字符串、表名、如果表不存在是否创建、最低等级。Serilog会默认创建一些列。
@ -46,7 +62,7 @@ namespace IRaCIS.Core.API
//}
//扩展方法 获取上下文的ip 用户名 用户类型
Log.Logger = config.Enrich.WithHttpContextInfo(serviceProvider).CreateLogger();
//Log.Logger = config.Enrich.WithHttpContextInfo(serviceProvider).CreateLogger();
}
}