using Autofac;
using Autofac.Extensions.DependencyInjection;
using Ips.Library.Basic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Serilog;
using Serilog.Extensions.Logging;
using System.Diagnostics;
using System.Reflection;
namespace Ips.Library.WebApi
{
///
///
///
public static class WebApiHelper
{
private static CancellationTokenSource _cts;
///
/// 启动AspNetCore WebAPI
/// (如果Controller所在程序集未被代码使用,且入口Exe被发布为自包含程序,会找不到Controller)
///
/// 本地端口
/// Controller所在程序集XML描述文档名称,默认使用入口程序生成的xml
/// DTO所在程序集XML描述文档,默认使用入口程序生成的xml
/// 要启用的静态目录预览及文件下载的目录(已经包含upload、download、logs三个目录)
/// 使用DI注入时程序集的前缀
///
public static void Start(int _localPort, string dtoXmlName = null, string[] staticDir = null, string controllerXmlName = null, string prefix = "ips")
{
_cts = new CancellationTokenSource();
if (controllerXmlName == null)
controllerXmlName = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
if (dtoXmlName == null)
dtoXmlName = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
List listDir = new List();
if (staticDir != null)
{
listDir.AddRange(staticDir.Select(p => p.ToLower()).Distinct());
}
if (!listDir.Contains("upload"))
{
listDir.Add("upload");
}
if (!listDir.Contains("download"))
{
listDir.Add("download");
}
if (!listDir.Contains("logs"))
{
listDir.Add("logs");
}
staticDir = listDir.ToArray();
var assemblies = AppDomain.CurrentDomain.GetAllAssemblies(prefix);
if (assemblies == null)
{
throw new Exception($"未扫描到{prefix}前缀的程序集");
}
foreach (var item in assemblies)
{
IpsLogger.Info($"已加载DI注入程序集[{item.FullName}]", false);
}
var controllerAssemblies = assemblies.Where(p => p.GetTypes().Any(q =>
{
if (q.Name.EndsWith("Controller") && q.IsSubclassOf(typeof(BaseController)))
return true;
return false;
})).ToList();
if (controllerAssemblies == null || !controllerAssemblies.Any())
{
throw new Exception("未找到Controller所在的程序集");
}
var builder = WebApplication.CreateBuilder();
builder.Services.AddRouting(t => t.LowercaseUrls = true);//全部路由默认显示小写
#region 请求大小限制200MB及Http2支持
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 200 << 20;//200MB
options.ListenAnyIP(Convert.ToInt32(_localPort), listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
});
});
builder.Services.Configure(options =>
{
options.MultipartBodyLengthLimit = 200 << 20;//通过表单上传最大200MB
});
#endregion
#region 初始化日志
//取消默认的日志Provider
builder.Logging.ClearProviders();
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}";
config.Enrich.FromLogContext()
.Enrich.With(new SerilogEnricher())
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Information)
.WriteTo.File(Path.Combine(basePath, "Logs", "Info", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate))
.WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Warning)
.WriteTo.File(Path.Combine(basePath, "Logs", "Warning", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate))
.WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Error)
.WriteTo.File(Path.Combine(basePath, "Logs", "Error", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate));
});
builder.Logging.AddSerilog();
#endregion
#region 启用静态文件缓存和压缩(已屏蔽,采集文件压缩率不高)
//builder.Services.AddResponseCaching();
//builder.Services.AddResponseCompression();
#endregion
#region 注入常用服务
//系统缓存,可以其它地方使用IMemoryCache接口
builder.Services.AddMemoryCache();
//http上下文
builder.Services.AddSingleton();
//HttpClient
builder.Services.AddHttpClient();//IHttpClientFactory
builder.Services.AddGrpc();
//builder.Services.AddGrpcClient