添加项目文件。
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public class ApiResponseHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("您无权访问该接口")));
|
||||
}
|
||||
|
||||
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("您的权限不允许进行该操作")));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class AuthorizationPolicySetup
|
||||
{
|
||||
|
||||
public static void AddAuthorizationPolicySetup(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
//影像质控策略 只允许 CRC QA进行操作
|
||||
options.AddPolicy("ImageQCPolicy", policyBuilder =>
|
||||
{
|
||||
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.IQC).ToString());
|
||||
});
|
||||
|
||||
//一致性核查策略 只允许 CRC PM APM 进行操作
|
||||
options.AddPolicy("ImageCheckPolicy", policyBuilder =>
|
||||
{
|
||||
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.APM).ToString());
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using Invio.Extensions.Authentication.JwtBearer;
|
||||
using IRaCIS.Core.Application.Auth;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class JWTAuthSetup
|
||||
{
|
||||
public static void AddJWTAuthSetup(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.Configure<JwtSetting>(configuration.GetSection("JwtSetting"));
|
||||
|
||||
var jwtSetting = new JwtSetting();
|
||||
configuration.Bind("JwtSetting", jwtSetting);
|
||||
|
||||
services
|
||||
.AddAuthentication(o=> {
|
||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultChallengeScheme = nameof(ApiResponseHandler);
|
||||
o.DefaultForbidScheme = nameof(ApiResponseHandler);
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidIssuer = jwtSetting.Issuer,
|
||||
ValidAudience = jwtSetting.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecurityKey)),
|
||||
// 默认 300s
|
||||
ClockSkew = TimeSpan.Zero
|
||||
};
|
||||
|
||||
// OPTION 1: use `Invio.Extensions.Authentication.JwtBearer`
|
||||
|
||||
options.AddQueryStringAuthentication();
|
||||
|
||||
// OPTION 2: do it manually
|
||||
|
||||
#region
|
||||
//options.Events = new JwtBearerEvents
|
||||
//{
|
||||
// OnMessageReceived = (context) => {
|
||||
|
||||
// if (!context.Request.Query.TryGetValue("access_token", out StringValues values))
|
||||
// {
|
||||
// return Task.CompletedTask;
|
||||
// }
|
||||
|
||||
// if (values.Count > 1)
|
||||
// {
|
||||
// context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
// context.Fail(
|
||||
// "Only one 'access_token' query string parameter can be defined. " +
|
||||
// $"However, {values.Count:N0} were included in the request."
|
||||
// );
|
||||
|
||||
// return Task.CompletedTask;
|
||||
// }
|
||||
|
||||
// var token = values.Single();
|
||||
|
||||
// if (String.IsNullOrWhiteSpace(token))
|
||||
// {
|
||||
// context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
// context.Fail(
|
||||
// "The 'access_token' query string parameter was defined, " +
|
||||
// "but a value to represent the token was not included."
|
||||
// );
|
||||
|
||||
// return Task.CompletedTask;
|
||||
// }
|
||||
|
||||
// context.Token = token;
|
||||
|
||||
// return Task.CompletedTask;
|
||||
// }
|
||||
//};
|
||||
#endregion
|
||||
|
||||
})
|
||||
.AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using AutoMapper.EquivalencyExpression;
|
||||
using IRaCIS.Core.Application.Service;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class AutoMapperSetup
|
||||
{
|
||||
public static void AddAutoMapperSetup(this IServiceCollection services)
|
||||
{
|
||||
|
||||
services.AddAutoMapper(automapper =>
|
||||
{
|
||||
//AutoMapper.Collection.EntityFrameworkCore
|
||||
automapper.AddCollectionMappers();
|
||||
|
||||
#region 会使 IncludeMembers 失效 不能全局使用
|
||||
//mapping an EntityFramework Core DbContext-object.
|
||||
//automapper.UseEntityFrameworkCoreModel<IRaCISDBContext>(services);
|
||||
|
||||
|
||||
//automapper.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, srcMember, desMenber) =>
|
||||
//{
|
||||
// //// Can test When Guid? -> Guid if source is null will change to Guid.Empty
|
||||
// //Console.WriteLine("srcMember:" + srcMember + "desMenber:" + desMenber);
|
||||
// return srcMember != null && srcMember.ToString() != Guid.Empty.ToString();
|
||||
// // not want to map a null Guid? value to db Guid value
|
||||
//})));
|
||||
#endregion
|
||||
|
||||
}, typeof(QCConfig).Assembly);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using Autofac;
|
||||
using Autofac.Extras.DynamicProxy;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Services;
|
||||
using IRaCIS.Core.API.Utility.AOP;
|
||||
using IRaCIS.Core.Application;
|
||||
using IRaCIS.Core.Application.AOP;
|
||||
using IRaCIS.Core.Application.BackGroundJob;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infra.EFCore.AuthUser;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Panda.DynamicWebApi;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
// ReSharper disable once IdentifierTypo
|
||||
public class AutofacModuleSetup : Autofac.Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder containerBuilder)
|
||||
{
|
||||
|
||||
#region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
|
||||
|
||||
containerBuilder.RegisterGeneric(typeof(Repository<>))
|
||||
.As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
|
||||
|
||||
containerBuilder.RegisterGeneric(typeof(EFUnitOfWork<>))
|
||||
.As(typeof(IEFUnitOfWork<>)).InstancePerLifetimeScope();//注册仓储
|
||||
|
||||
#endregion
|
||||
|
||||
#region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
|
||||
|
||||
//获取所有控制器类型并使用属性注入
|
||||
containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
||||
.Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
||||
.PropertiesAutowired();
|
||||
|
||||
//var controllerBaseType = typeof(ControllerBase);
|
||||
//containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
||||
// .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
|
||||
// .PropertiesAutowired();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll");
|
||||
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
||||
.PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors();
|
||||
|
||||
Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore");
|
||||
containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces();
|
||||
|
||||
containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
|
||||
|
||||
|
||||
|
||||
containerBuilder.RegisterType<DicomFileStoreHelper>().SingleInstance();
|
||||
|
||||
//Autofac 注册拦截器 需要注意的是生成api上服务上的动态代理AOP失效 间接掉用不影响
|
||||
containerBuilder.RegisterType<TrialStatusAutofacAOP>();
|
||||
containerBuilder.RegisterType<UserAddAOP>();
|
||||
//containerBuilder.RegisterType<QANoticeAOP>();
|
||||
//containerBuilder.RegisterType<LogService>().As<ILogService>().SingleInstance();
|
||||
|
||||
|
||||
//注册hangfire任务 依赖注入
|
||||
containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using FellowOakDicom;
|
||||
using FellowOakDicom.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class DicomSetup
|
||||
{
|
||||
public static void AddDicomSetup(this IServiceCollection services)
|
||||
{
|
||||
new DicomSetupBuilder()
|
||||
.RegisterServices(s => s.AddFellowOakDicom()
|
||||
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
.AddImageManager<ImageSharpImageManager>()
|
||||
)
|
||||
.SkipValidation()
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Panda.DynamicWebApi;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class DynamicWebApiSetup
|
||||
{
|
||||
//20210910 避免冗余的控制器层代码编写,仅仅包了一层前后台定义的格式 这里采用动态webAPi+IResultFilter 替代大部分情况
|
||||
public static void AddDynamicWebApiSetup(this IServiceCollection services)
|
||||
{
|
||||
//动态webApi 目前存在的唯一小坑是生成api上服务上的动态代理AOP失效 间接掉用不影响
|
||||
services.AddDynamicWebApi(dynamicWebApiOption =>
|
||||
{
|
||||
//默认是 api
|
||||
dynamicWebApiOption.DefaultApiPrefix = "";
|
||||
//首字母小写
|
||||
dynamicWebApiOption.GetRestFulActionName = (actionName) => char.ToLower(actionName[0]) + actionName.Substring(1);
|
||||
//删除 Service后缀
|
||||
dynamicWebApiOption.RemoveControllerPostfixes.Add("Service");
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class EFSetup
|
||||
{
|
||||
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//services.AddScoped<DbContext, IRaCISDBContext>();
|
||||
|
||||
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||
services.AddDbContext<IRaCISDBContext>(options =>
|
||||
{
|
||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||
|
||||
options.EnableSensitiveDataLogging();
|
||||
|
||||
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||
|
||||
options.AddInterceptors(new AuditingInterceptor(configuration.GetSection("ConnectionStrings:RemoteNew").Value));
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EasyCaching.Core;
|
||||
using EasyCaching.Interceptor.Castle;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class EasyCachingSetup
|
||||
{
|
||||
public static void AddEasyCachingSetup(this IServiceCollection services)
|
||||
{
|
||||
services.AddEasyCaching(options =>
|
||||
{
|
||||
options.UseInMemory();
|
||||
});
|
||||
services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using AspNetCoreRateLimit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
/// <summary>
|
||||
/// IPLimit限流 启动服务
|
||||
/// </summary>
|
||||
public static class IpPolicyRateLimitSetup
|
||||
{
|
||||
public static void AddIpPolicyRateLimitSetup(this IServiceCollection services, IConfiguration Configuration)
|
||||
{
|
||||
|
||||
// needed to store rate limit counters and ip rules
|
||||
services.AddMemoryCache();
|
||||
|
||||
//load general configuration from appsettings.json
|
||||
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
|
||||
|
||||
//load ip rules from appsettings.json
|
||||
//services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
|
||||
|
||||
// inject counter and rules stores
|
||||
services.AddInMemoryRateLimiting();
|
||||
//services.AddDistributedRateLimiting<AsyncKeyLockProcessingStrategy>();
|
||||
//services.AddDistributedRateLimiting<RedisProcessingStrategy>();
|
||||
//services.AddRedisRateLimiting();
|
||||
|
||||
|
||||
|
||||
// configuration (resolvers, counter key builders)
|
||||
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
using LogDashboard;
|
||||
using LogDashboard.Authorization.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class LogDashboardSetup
|
||||
{
|
||||
public static void AddLogDashboardSetup(this IServiceCollection services)
|
||||
{
|
||||
//IIS 配置虚拟路径部署,会出现IIS静态文件404
|
||||
services.AddLogDashboard(opt =>
|
||||
{
|
||||
//opt.PathMatch = "/api/LogDashboard";
|
||||
opt.PathMatch = "/LogDashboard";
|
||||
|
||||
//opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
|
||||
|
||||
//opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//using System;
|
||||
//using Microsoft.Extensions.DependencyInjection;
|
||||
//using StackExchange.Profiling.Storage;
|
||||
|
||||
//namespace IRaCIS.Core.API
|
||||
//{
|
||||
// public class MiniProfilerConfigure
|
||||
// {
|
||||
// public static void ConfigureMiniProfiler(IServiceCollection services)
|
||||
// {
|
||||
|
||||
// services.AddMiniProfiler(options =>
|
||||
// {
|
||||
// // All of this is optional. You can simply call .AddMiniProfiler() for all defaults
|
||||
|
||||
// // (Optional) Path to use for profiler URLs, default is /mini-profiler-resources
|
||||
// options.RouteBasePath = "/profiler";
|
||||
|
||||
// //// (Optional) Control storage
|
||||
// //// (default is 30 minutes in MemoryCacheStorage)
|
||||
// (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
|
||||
|
||||
// //// (Optional) Control which SQL formatter to use, InlineFormatter is the default
|
||||
// //options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
|
||||
|
||||
// //// (Optional) To control authorization, you can use the Func<HttpRequest, bool> options:
|
||||
// //// (default is everyone can access profilers)
|
||||
// //options.ResultsAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
|
||||
// //options.ResultsListAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
|
||||
// //// Or, there are async versions available:
|
||||
// //options.ResultsAuthorizeAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfiler;
|
||||
// //options.ResultsAuthorizeListAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfilerLists;
|
||||
|
||||
// //// (Optional) To control which requests are profiled, use the Func<HttpRequest, bool> option:
|
||||
// //// (default is everything should be profiled)
|
||||
// //options.ShouldProfile = request => MyShouldThisBeProfiledFunction(request);
|
||||
|
||||
// //// (Optional) Profiles are stored under a user ID, function to get it:
|
||||
// //// (default is null, since above methods don't use it by default)
|
||||
// //options.UserIdProvider = request => MyGetUserIdFunction(request);
|
||||
|
||||
// //// (Optional) Swap out the entire profiler provider, if you want
|
||||
// //// (default handles async and works fine for almost all applications)
|
||||
// //options.ProfilerProvider = new MyProfilerProvider();
|
||||
|
||||
// //// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking.
|
||||
// //// (defaults to true, and connection opening/closing is tracked)
|
||||
// //options.TrackConnectionOpenClose = true;
|
||||
|
||||
// //// (Optional) Use something other than the "light" color scheme.
|
||||
// //// (defaults to "light")
|
||||
// //options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto;
|
||||
|
||||
// //// The below are newer options, available in .NET Core 3.0 and above:
|
||||
|
||||
// //// (Optional) You can disable MVC filter profiling
|
||||
// //// (defaults to true, and filters are profiled)
|
||||
// //options.EnableMvcFilterProfiling = true;
|
||||
// //// ...or only save filters that take over a certain millisecond duration (including their children)
|
||||
// //// (defaults to null, and all filters are profiled)
|
||||
// //// options.MvcFilterMinimumSaveMs = 1.0m;
|
||||
|
||||
// //// (Optional) You can disable MVC view profiling
|
||||
// //// (defaults to true, and views are profiled)
|
||||
// //options.EnableMvcViewProfiling = true;
|
||||
// //// ...or only save views that take over a certain millisecond duration (including their children)
|
||||
// //// (defaults to null, and all views are profiled)
|
||||
// //// options.MvcViewMinimumSaveMs = 1.0m;
|
||||
|
||||
// //// (Optional) listen to any errors that occur within MiniProfiler itself
|
||||
// //// options.OnInternalError = e => MyExceptionLogger(e);
|
||||
|
||||
// //// (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage
|
||||
// //// It has a lot of overhead vs. normal profiling and should only be used with that in mind
|
||||
// //// (defaults to false, debug/heavy mode is off)
|
||||
// ////options.EnableDebugMode = true;
|
||||
// });
|
||||
// //.AddEntityFramework();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class NewtonsoftJsonSetup
|
||||
{
|
||||
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder)
|
||||
{
|
||||
|
||||
builder.AddNewtonsoftJson(options =>
|
||||
{
|
||||
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
|
||||
// 忽略循环引用
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
|
||||
|
||||
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
|
||||
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
|
||||
// 设置时间格式
|
||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
|
||||
}).AddControllersAsServices()//动态webApi属性注入需要
|
||||
.ConfigureApiBehaviorOptions(o =>
|
||||
{
|
||||
o.SuppressModelStateInvalidFilter = true; //自己写验证
|
||||
|
||||
////这里是自定义验证结果和返回状态码 因为这里是在[ApiController]控制器层校验,动态webApi的不会校验 所以需要单独写一个Filter
|
||||
//o.InvalidModelStateResponseFactory = (context) =>
|
||||
//{
|
||||
// var error = context.ModelState .Keys
|
||||
// .SelectMany(k => context.ModelState[k].Errors)
|
||||
// .Select(e => e.ErrorMessage)
|
||||
// .ToArray();
|
||||
|
||||
//return new JsonResult(ResponseOutput.NotOk("The inputs supplied to the API are invalid. " + JsonConvert.SerializeObject( error)));
|
||||
//};
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public class NullToEmptyStringResolver : DefaultContractResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建属性
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="memberSerialization">序列化成员</param>
|
||||
/// <returns></returns>
|
||||
//protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
//{
|
||||
// IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||
|
||||
|
||||
// foreach (var jsonProperty in properties)
|
||||
// {
|
||||
// jsonProperty.DefaultValue = new NullToEmptyStringValueProvider(jsonProperty);
|
||||
// }
|
||||
|
||||
// return properties;
|
||||
|
||||
//}
|
||||
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||
|
||||
var list= type.GetProperties()
|
||||
.Select(p =>
|
||||
{
|
||||
var jp = base.CreateProperty(p, memberSerialization);
|
||||
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
|
||||
return jp;
|
||||
}).ToList();
|
||||
|
||||
var uu = list.Select(t => t.PropertyName).ToList();
|
||||
|
||||
//获取复杂对象属性
|
||||
properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList();
|
||||
|
||||
list.AddRange(properties);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
|
||||
public class NullToEmptyStringValueProvider : IValueProvider
|
||||
{
|
||||
PropertyInfo _MemberInfo;
|
||||
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
||||
{
|
||||
_MemberInfo = memberInfo;
|
||||
}
|
||||
public object GetValue(object target)
|
||||
{
|
||||
object result = _MemberInfo.GetValue(target);
|
||||
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
|
||||
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
|
||||
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
|
||||
else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
|
||||
|
||||
return result;
|
||||
}
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
|
||||
if(_MemberInfo.PropertyType == typeof(string))
|
||||
{
|
||||
//去掉前后空格
|
||||
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_MemberInfo.SetValue(target, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class QuartZSetup
|
||||
{
|
||||
public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//services.AddTransient<CacheTrialStatusQuartZJob>();
|
||||
|
||||
//services.AddQuartz(q =>
|
||||
//{
|
||||
// // base quartz scheduler, job and trigger configuration
|
||||
|
||||
// // as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
|
||||
// q.UseMicrosoftDependencyInjectionJobFactory();
|
||||
|
||||
// // 基本Quartz调度器、作业和触发器配置
|
||||
// var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
|
||||
// q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
|
||||
// .WithDescription("Trial regular work")
|
||||
// );
|
||||
// q.AddTrigger(t => t
|
||||
// .WithIdentity("TrialStatusTrigger")
|
||||
// .ForJob(jobKey)
|
||||
// //.StartNow()
|
||||
// //.WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(15))//开始秒数 15s
|
||||
// // .RepeatForever())//持续工作
|
||||
// .WithCronSchedule("0 0 0/2 * * ?")//每小时执行一次
|
||||
// .WithDescription("My regular trial work trigger")
|
||||
// );
|
||||
//});
|
||||
|
||||
//// ASP.NET Core hosting
|
||||
//services.AddQuartzServer(options =>
|
||||
//{
|
||||
// // when shutting down we want jobs to complete gracefully
|
||||
// options.WaitForJobsToComplete = true;
|
||||
//});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class ResponseCompressionSetup
|
||||
{
|
||||
public static void AddResponseCompressionSetup(this IServiceCollection services)
|
||||
{
|
||||
services.AddResponseCompression(options =>
|
||||
{
|
||||
options.Providers.Add<BrotliCompressionProvider>();
|
||||
options.Providers.Add<GzipCompressionProvider>();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using IRaCIS.Core.Infra.EFCore.AuthUser;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
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("RequestBody", await ReadRequestBody(httpContext.Request)));
|
||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst("userTypeEnumName")?.Value));
|
||||
|
||||
//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}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Sinks.Email;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public class SerilogExtension
|
||||
{
|
||||
|
||||
public static void AddSerilogSetup(string environment, IServiceProvider serviceProvider)
|
||||
{
|
||||
|
||||
var config = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.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("Hangfire", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
|
||||
.Enrich.WithClientIp()
|
||||
.Enrich.WithClientAgent()
|
||||
.Enrich.FromLogContext()
|
||||
|
||||
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
|
||||
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} ] {ClientIp} {TokenUserRealName} {TokenUserType} {Message:lj} {Properties:j}{NewLine} {Exception}")
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
|
||||
outputTemplate: "{Timestamp:HH:mm:ss} || {Level} || {SourceContext:l} || {Message} ||{Exception} ||end {NewLine}");
|
||||
//.WriteTo.MSSqlServer("Data Source=DESKTOP-4TU9A6M;Initial Catalog=CoreFrame;User ID=sa;Password=123456", "logs", autoCreateSqlTable: true, restrictedToMinimumLevel: LogEventLevel.Information)//从左至右四个参数分别是数据库连接字符串、表名、如果表不存在是否创建、最低等级。Serilog会默认创建一些列。
|
||||
|
||||
if (environment == "Production")
|
||||
{
|
||||
config.WriteTo.Email(new EmailConnectionInfo()
|
||||
{
|
||||
EmailSubject = "系统警告,请速速查看!",//邮件标题
|
||||
FromEmail = "iracis_grr@163.com",//发件人邮箱
|
||||
MailServer = "smtp.163.com",//smtp服务器地址
|
||||
NetworkCredentials = new NetworkCredential("iracis_grr@163.com", "XLWVQKZAEKLDWOAH"),//两个参数分别是发件人邮箱与客户端授权码
|
||||
Port = 25,//端口号
|
||||
ToEmail = "872297557@qq.com"//收件人
|
||||
}, restrictedToMinimumLevel: LogEventLevel.Error,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [ {Level} {ClientIp} {ClientAgent} {TokenUserRealName} {TokenUserType} ] || [path: {RequestPath} arguments: {RequestBody}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine})");
|
||||
}
|
||||
|
||||
//扩展方法 获取上下文的ip 用户名 用户类型
|
||||
Log.Logger = config.Enrich.WithHttpContextInfo(serviceProvider).CreateLogger();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class StaticFileAuthorizationSetup
|
||||
{
|
||||
public static void AddStaticFileAuthorizationSetup(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public class JsonPatchDocumentFilter : IDocumentFilter
|
||||
{
|
||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
var schemas = swaggerDoc.Components.Schemas.ToList();
|
||||
foreach (var item in schemas)
|
||||
{
|
||||
if (item.Key.StartsWith("Operation") || item.Key.StartsWith("JsonPatchDocument"))
|
||||
swaggerDoc.Components.Schemas.Remove(item.Key);
|
||||
}
|
||||
|
||||
swaggerDoc.Components.Schemas.Add("Operation", new OpenApiSchema
|
||||
{
|
||||
Type = "object",
|
||||
Properties = new Dictionary<string, OpenApiSchema>
|
||||
{
|
||||
{ "op", new OpenApiSchema { Type = "string" } },
|
||||
{"value", new OpenApiSchema{ Type = "object", Nullable = true } },
|
||||
{ "path", new OpenApiSchema { Type = "string" } }
|
||||
}
|
||||
});
|
||||
|
||||
swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema
|
||||
{
|
||||
Type = "array",
|
||||
Items = new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Operation" }
|
||||
},
|
||||
Description = "Array of operations to perform"
|
||||
});
|
||||
|
||||
foreach (var path in swaggerDoc.Paths.SelectMany(p => p.Value.Operations)
|
||||
.Where(p => p.Key == Microsoft.OpenApi.Models.OperationType.Patch))
|
||||
{
|
||||
foreach (var item in path.Value.RequestBody.Content.Where(c => c.Key != "application/json-patch+json"))
|
||||
path.Value.RequestBody.Content.Remove(item.Key);
|
||||
|
||||
var response = path.Value.RequestBody.Content.SingleOrDefault(c => c.Key == "application/json-patch+json");
|
||||
|
||||
response.Value.Schema = new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.Filters;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class SwaggerSetup
|
||||
{
|
||||
public static void AddSwaggerSetup(this IServiceCollection services)
|
||||
{
|
||||
services.AddSwaggerExamplesFromAssemblyOf<JsonPatchUserRequestExample>();
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
//此处的Name 是控制器上分组的名称 Title是界面的大标题
|
||||
//分组
|
||||
options.SwaggerDoc("Reviewer", new OpenApiInfo {Title = "医生模块",Version = "Reviewer", });
|
||||
options.SwaggerDoc("Trial", new OpenApiInfo { Title = "项目模块", Version = "Trial" });
|
||||
options.SwaggerDoc("Enroll", new OpenApiInfo { Title = "入组模块", Version = "Enroll" });
|
||||
options.SwaggerDoc("Workload", new OpenApiInfo { Title = "工作量模块", Version = "Workload" });
|
||||
options.SwaggerDoc("Common", new OpenApiInfo { Title = "通用信息获取", Version = "Common" });
|
||||
options.SwaggerDoc("Institution", new OpenApiInfo { Title = "机构信息模块", Version = "Institution" });
|
||||
options.SwaggerDoc("Dashboard&Statistics", new OpenApiInfo { Title = "统计模块", Version = "Dashboard&Statistics" });
|
||||
|
||||
options.SwaggerDoc("Financial", new OpenApiInfo { Title = "财务模块", Version = "Financial" });
|
||||
options.SwaggerDoc("Management", new OpenApiInfo { Title = "管理模块", Version = "Management" });
|
||||
options.SwaggerDoc("Image", new OpenApiInfo { Title = "影像模块", Version = "Image" });
|
||||
options.SwaggerDoc("Reading", new OpenApiInfo { Title = "读片模块", Version = "Reading" });
|
||||
|
||||
// 接口排序
|
||||
options.OrderActionsBy(o => o.GroupName);
|
||||
|
||||
options.DocInclusionPredicate((docName, apiDes) =>
|
||||
{
|
||||
if (!apiDes.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
|
||||
var versions = methodInfo.DeclaringType.GetCustomAttributes(true)
|
||||
.OfType<ApiExplorerSettingsAttribute>()
|
||||
.Select(attr => attr.GroupName);
|
||||
|
||||
return versions.Any(v => v.ToString() == docName);
|
||||
});
|
||||
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, "IRaCIS.Core.API.xml");//这个就是刚刚配置的xml文件名
|
||||
options.IncludeXmlComments(xmlPath, true);
|
||||
|
||||
var xmlPath2 = Path.Combine(AppContext.BaseDirectory, "IRaCIS.Core.Application.xml");//这个就是刚刚配置的xml文件名
|
||||
options.IncludeXmlComments(xmlPath2, true);
|
||||
//默认的第二个参数是false,这个是controller的注释,记得修改
|
||||
|
||||
|
||||
// 在header中添加token,传递到后台
|
||||
options.OperationFilter<SecurityRequirementsOperationFilter>();
|
||||
|
||||
options.DocumentFilter<JsonPatchDocumentFilter>();
|
||||
|
||||
// 添加登录按钮
|
||||
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||
Name = "Authorization",
|
||||
|
||||
//In = "header",
|
||||
//Type = "apiKey"
|
||||
});
|
||||
|
||||
|
||||
//// Bearer
|
||||
//options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
|
||||
//{
|
||||
// Description = "JWT Authorization header using the Bearer scheme.",
|
||||
// Name = "Authorization",
|
||||
// In = ParameterLocation.Header,
|
||||
// Scheme = "bearer",
|
||||
// Type = SecuritySchemeType.Http,
|
||||
// BearerFormat = "JWT"
|
||||
//});
|
||||
});
|
||||
}
|
||||
|
||||
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
//此处的Name 是页面 选择文档下拉框 显示的名称
|
||||
options.SwaggerEndpoint($"swagger/Reviewer/swagger.json", "医生模块");
|
||||
options.SwaggerEndpoint($"swagger/Trial/swagger.json", "项目模块");
|
||||
options.SwaggerEndpoint($"swagger/Enroll/swagger.json", "入组模块");
|
||||
options.SwaggerEndpoint($"swagger/Workload/swagger.json", "工作量模块");
|
||||
options.SwaggerEndpoint($"swagger/Dashboard&Statistics/swagger.json", "统计模块");
|
||||
options.SwaggerEndpoint($"swagger/Common/swagger.json", "通用模块");
|
||||
|
||||
options.SwaggerEndpoint($"swagger/Financial/swagger.json", "财务模块");
|
||||
options.SwaggerEndpoint($"swagger/Institution/swagger.json", "机构信息模块");
|
||||
options.SwaggerEndpoint($"swagger/Management/swagger.json", "管理模块");
|
||||
options.SwaggerEndpoint($"swagger/Image/swagger.json", "影像模块");
|
||||
options.SwaggerEndpoint($"swagger/Reading/swagger.json", "读片模块");
|
||||
|
||||
//路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,
|
||||
//注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.Route = "doc";
|
||||
//options.RoutePrefix = string.Empty;
|
||||
|
||||
var data = Assembly.GetExecutingAssembly().Location;
|
||||
options.IndexStream = () => Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream("IRaCIS.Core.API.wwwroot.swagger.ui.Index.html");
|
||||
|
||||
options.RoutePrefix = string.Empty;
|
||||
|
||||
//DocExpansion设置为none可折叠所有方法
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||
options.DefaultModelsExpandDepth(-1);
|
||||
|
||||
|
||||
// 引入静态文件添加登录功能
|
||||
// 清除静态文件缓存
|
||||
// options.IndexStream = () => null;
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Hangfire;
|
||||
using Hangfire.SqlServer;
|
||||
using Hangfire.Tags.SqlServer;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public static class hangfireSetup
|
||||
{
|
||||
public static void AddhangfireSetup(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var hangFireConnStr = configuration.GetSection("ConnectionStrings:Hangfire").Value;
|
||||
|
||||
services.AddHangfire(hangFireConfig =>
|
||||
{
|
||||
//指定存储介质
|
||||
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
|
||||
{
|
||||
SchemaName = "hangfire",
|
||||
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
|
||||
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
|
||||
QueuePollInterval = TimeSpan.Zero,
|
||||
UseRecommendedIsolationLevel = true,
|
||||
UsePageLocksOnDequeue = true,
|
||||
DisableGlobalLocks = true
|
||||
});
|
||||
|
||||
hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer
|
||||
//.UseHangfireHttpJob();
|
||||
|
||||
});
|
||||
|
||||
services.AddHangfireServer();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user