以下 services. 的方法均在 ConfigureServices,app. 的均在 Configure 中
配置 MvcOptions
services.Configure((MvcOptions options) =>
{
//该值确定路由是否应在内部使用终结点,或者是否应使用旧路由逻辑。端点路由用于将HTTP请求与MVC操作匹配,并使用IUrlHelper生成url。
//options.EnableEndpointRouting = false;
//自定义模型验证,响应是否是jsonp
options.Filters.Add<GlobalAction>();
// MVC层面全局异常过滤
options.Filters.Add<GlobalExceptionsFilter>();
//options.Conventions.Insert(0, new GlobalModelConvention(new RouteAttribute("/capi")));
});
配置压缩并加入管道
//添加响应压缩功能
services.AddResponseCompression(options =>
{
options.Providers.Add<GzipCompressionProvider>();//添加GZIP的压缩
//响应内容-要压缩的类型。
//options.MimeTypes= ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json", "text/css", "application/javascript" , "text/html" });
//响应内容-不压缩的MIME类型。
// options.ExcludedMimeTypes = new[] { "image/png", "image/jpg", "application/json" };
});
services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal; //压缩等级:
});
app.UseResponseCompression();//开启响应压缩
配置响应缓存并加入管道
services.AddResponseCaching(options =>
{
options.UseCaseSensitivePaths = false; //Response 的缓存,head 头部换成小写
});
app.UseResponseCaching();//开启响应缓存
配置api控制器,模型验证器
/*
MvcCoreServiceCollectionExtensions:
services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<ApiBehaviorOptions>, ApiBehaviorOptionsSetup>());
初始化 ApiBehaviorOptions接口,直接使用 ApiBehaviorOptionsSetup实现类,
而 ApiBehaviorOptionsSetup在实例化的时候,就直接写死 new BadRequestObjectResult
当任何人使用 ApiBehaviorOptionsSetup 时,最后使用的就是 BadRequestBojectResult
比如 :ModelStateInvalidFilterFactory,使用时需要 IOptions<ApiBehaviorOptions>,传给ModelStateInvalidFilter去实例化,
ModelStateInvalidFilter 有个短路方法,
public void OnActionExecuting(ActionExecutingContext context)
{
_apiBehaviorOptions 就是上一级传输的值
if (context.Result == null && !context.ModelState.IsValid)
{
_logger.ModelStateInvalidFilterExecuting();
context.Result = _apiBehaviorOptions.InvalidModelStateResponseFactory(context); //最后执行了 BadRequestObjectResult
}
}
*/
services.Configure<ApiBehaviorOptions>(options =>
{
//options.SuppressModelStateInvalidFilter = true; // true:禁用框架自带模型验证
options.InvalidModelStateResponseFactory = actionContext =>
{
var ModelState = actionContext.ModelState;
List<ValidationError> errorList = new List<ValidationError>();
foreach (var key in ModelState.Keys)
{
foreach (var error in ModelState[key].Errors)
{
errorList.Add(new ValidationError(key, error.ErrorMessage));
}
}
//var errors = ModelState.Keys.SelectMany(key => ModelState[key].Errors.Select(x => new ValidationError(key, x.ErrorMessage)));
return new JsonResult(new MessageModel() { Response = errorList, Success = false, Message = "参数错误!" });
};
});
配置全局上下文,通过依赖注入的方式,可以拿到 httpcontext
// 注入 httpcontext 上下文,httpcontext 在 HttpContextAccessor 中
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
管道路由拦截并重写成新路由
//以mvc路由 “.ip”结尾的,拦截路由,处理得到新的路由
services.AddSingleton<DynamicRoute>();
//MVC 路由终结点
app.UseEndpoints(endpoints =>
{
//以mvc路由 “.ip”结尾的,拦截路由,处理得到新的路由
endpoints.MapDynamicControllerRoute<DynamicRoute>("{some}.ip");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=index}/{id?}");
});
配置内存缓存
services.AddMemoryCache();
配置会话并加入管道
//配置session的有效时间,单位秒
services.AddSession(options =>
{
options.IdleTimeout = System.TimeSpan.FromSeconds(30);
});
app.UseSession();
管道加入url重写
app.UseRewriter(new RewriteOptions()
//如果正则表达式匹配HttpContext的路径字符串,则重定向请求
.AddRedirect("a/", "swagger")
////匹配根目录
.AddRedirect("^$", "swagger")
// 如果正则表达式与HttpContext的路径字符串匹配,则添加一个重写路径的规则。 谨慎正则
//.AddRewrite(@"^(.*)/sw/(.*)", "swagger", skipRemainingRules: true)
);
配置Json序列化关于时间格式,大小写等
#region System.Text.Json 与 NewtonsoftJson配置
services.Configure<MvcNewtonsoftJsonOptions>(option =>
{
option.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
option.SerializerSettings.ContractResolver = new DefaultContractResolver();
option.SerializerSettings.Converters.Add(new StringEnumConverter());
option.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
});
services.Configure<JsonOptions>(option =>
{
option.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
option.JsonSerializerOptions.IgnoreNullValues = true;// 忽略null数据
option.JsonSerializerOptions.PropertyNamingPolicy = null;//json字符串大小写原样输出
});
#endregion
配置CORS跨域并加入管道
// 注意 AllowAnyOrigin 不能和 AllowCredentials一起公用
services.AddCors(o => o.AddPolicy("LimitRequests",p => p
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()));
app.UseCors("LimitRequests");// CORS 加入管道
//========================使用===========================//
[EnableCors("LimitRequests")] //在控制器上面打上 特性
public class ProjectUserController : Controller
{}
//如果想全局加入,则需要在配置路由加上 RequireCors
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("LimitRequests");
});
配置认证和配置授权并加入管道
配置认证并加入管道
AuthenticationBuilder authbuild = services.AddAuthentication(options =>
{
options.DefaultScheme = jwtSchemeName; //多种认证方法的默认方案
//options.DefaultChallengeScheme //Default 开头的都是设置默认方案,认证的各个环节都可以自定义,不加入全局,则需要在控制打上 [Authorize(AuthenticationSchemes="xxx方案")] 特性,告知使用的方案是哪一个
options.AddScheme<OverwriteAuthentication>(OverwriteSchemeName, "重写自定义认证")
});
// 自定义认证,通过 authbuild去添加其他认证方案
authbuild.AddJwtBearer(jwt =>
{
}
app.UseAuthentication(); //将认证中间件配置到管道
配置授权并加入管道
如果只是简单授权则 services.AddAuthorization()
都采取默认授权配置,自定义扩展如下 添加自定义授权策略
// [Authorize(CustomAuthonizationOptions.PolicyName)] //控制器就这样使用,
services.AddAuthorization(options =>
{
options.AddPolicy(CustomAuthonizationOptions.PolicyName,
policy => policy.Requirements.Add(new CustomAuthonizationOptions()
{
age = 888888
}));
});
// 覆写 AuthorizationHandler 实现自定义的授权
services.AddScoped<IAuthorizationHandler, CustomAuthonizationHandler>();
// 添加完全自定义的授权<可以写,但是注册不了,因为都是用添加 Policy 实现自定义,完全的授权逻辑无法注入到授权容器中,要扩展是能从策略进行扩展
// services.AddScoped<IAuthorizationHandler, OverwriteAuthorization>();
#endregion
app.UseAuthorization();//将授权中间件配置到管道
管道加入静态文件的响应
using Microsoft.AspNetCore.StaticFiles;
app.UseDefaultFiles();//采取默认的静态文件响应,这一句就可以了
// 1.如果需要根据指定的路由响应指定的文件
var defaultFilesOptions = new DefaultFilesOptions
{
//RequestPath = "/spadi",
FileProvider = new PhysicalFileProvider($"{env.ContentRootPath}/SPA")
};
defaultFilesOptions.DefaultFileNames.Clear();//我们可以清除掉系统默认的默认文件名称
defaultFilesOptions.DefaultFileNames.Add("Imain.html");
app.UseDefaultFiles(defaultFilesOptions);
// 2. 增加可以响应处理的其他文件类型,注意 UseDefaultFiles 要在 UseStaticFiles 前面
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".html3"] = "text/html";
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider, // 自定义MimeType 映射关系
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "SPA")),
//RequestPath = "/SPA",
OnPrepareResponse = A =>
{
//System.Console.WriteLine("准备读取静态文件-" + A.File.Name);
A.Context.Response.Headers.Append("Cache-Control", $"public, max-age=3600");
},
});
// 3.指定目录进行游览
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
RequestPath = "/spadi",
FileProvider = new PhysicalFileProvider($"{env.ContentRootPath}/SPA")
});
健康检查
services.AddHealthChecks();
app.UseHealthChecks("/health");
持续补充中……