Merge pull request #330 from HuiJiOnGit/middleware_migration

resolve #329 迁移应用中间件启动服务到`HostedService`中
This commit is contained in:
ansonzhang 2023-02-14 20:00:31 +08:00 committed by GitHub
commit b94e2b4656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 290 additions and 201 deletions

3
.gitignore vendored
View File

@ -35,6 +35,9 @@ bld/
# Visual Studio 2017 auto generated files
Generated\ Files/
# Visual Studio Code
.vscode
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

View File

@ -1,19 +1,17 @@

// 以下为asp.net 6.0的写法如果用5.0请看Program.five.cs文件
// 以下为asp.net 6.0的写法如果用5.0请看Program.five.cs文件
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Text;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Blog.Core;
using Blog.Core.Common;
using Blog.Core.Common.LogHelper;
using Blog.Core.Common.Seed;
using Blog.Core.Extensions;
using Blog.Core.Extensions.Apollo;
using Blog.Core.Extensions.Middlewares;
using Blog.Core.Filter;
using Blog.Core.Hubs;
using Blog.Core.IServices;
using Blog.Core.Tasks;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
@ -21,9 +19,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
@ -49,7 +44,6 @@ builder.Host
config.AddConfigurationApollo("appsettings.apollo.json");
});
// 2、配置服务
builder.Services.AddSingleton(new AppSettings(builder.Configuration));
builder.Services.AddSingleton(new LogLock(builder.Environment.ContentRootPath));
@ -79,7 +73,7 @@ builder.Services.AddRabbitMQSetup();
builder.Services.AddKafkaSetup(builder.Configuration);
builder.Services.AddEventBusSetup();
builder.Services.AddNacosSetup(builder.Configuration);
builder.Services.AddInitializationHostServiceSetup();
builder.Services.AddAuthorizationSetup();
if (Permissions.IsUseIds4 || Permissions.IsUseAuthing)
{
@ -129,7 +123,6 @@ builder.Services.AddEndpointsApiExplorer();
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// 3、配置中间件
var app = builder.Build();
@ -182,16 +175,5 @@ app.UseEndpoints(endpoints =>
endpoints.MapHub<ChatHub>("/api2/chatHub");
});
var scope = app.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
var myContext = scope.ServiceProvider.GetRequiredService<MyContext>();
var tasksQzServices = scope.ServiceProvider.GetRequiredService<ITasksQzServices>();
var schedulerCenter = scope.ServiceProvider.GetRequiredService<ISchedulerCenter>();
var lifetime = scope.ServiceProvider.GetRequiredService<IHostApplicationLifetime>();
app.UseSeedDataMiddle(myContext, builder.Environment.WebRootPath);
app.UseQuartzJobMiddleware(tasksQzServices, schedulerCenter);
app.UseConsulMiddle(builder.Configuration, lifetime);
app.ConfigureEventBus();
// 4、运行
app.Run();
app.Run();

View File

@ -1,34 +1,28 @@
using Autofac;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Text;
using Autofac;
using Blog.Core.Common;
using Blog.Core.Common.LogHelper;
using Blog.Core.Common.Seed;
using Blog.Core.Extensions;
using Blog.Core.Extensions.Middlewares;
using Blog.Core.Filter;
using Blog.Core.Hubs;
using Blog.Core.IServices;
using Blog.Core.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Text;
using Blog.Core.Extensions.Middlewares;
namespace Blog.Core
{
public class Startup
{
private IServiceCollection _services;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
@ -75,7 +69,7 @@ namespace Blog.Core
services.AddEventBusSetup();
services.AddNacosSetup(Configuration);
services.AddInitializationHostServiceSetup();
// 授权+认证 (jwt or ids4)
services.AddAuthorizationSetup();
if (Permissions.IsUseIds4)
@ -95,7 +89,7 @@ namespace Blog.Core
services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true)
.Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);
services.AddDistributedMemoryCache();
services.AddSession();
services.AddHttpPollySetup();
@ -134,7 +128,7 @@ namespace Blog.Core
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
_services = services;
//支持编码大全 例如:支持 System.Text.Encoding.GetEncoding("GB2312") System.Text.Encoding.GetEncoding("GB18030")
//支持编码大全 例如:支持 System.Text.Encoding.GetEncoding("GB2312") System.Text.Encoding.GetEncoding("GB18030")
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
@ -150,11 +144,11 @@ namespace Blog.Core
{
// Ip限流,尽量放管道外层
app.UseIpLimitMiddle();
// 记录请求与返回数据
// 记录请求与返回数据
app.UseRequestResponseLogMiddle();
// 用户访问记录(必须放到外层,不然如果遇到异常,会报错,因为不能返回流)
app.UseRecordAccessLogsMiddle();
// signalr
// signalr
app.UseSignalRSendMiddle();
// 记录ip请求
app.UseIpLogMiddle();
@ -214,7 +208,6 @@ namespace Blog.Core
// 开启异常中间件,要放到最后
//app.UseExceptionHandlerMidd();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
@ -225,15 +218,13 @@ namespace Blog.Core
});
// 生成种子数据
app.UseSeedDataMiddle(myContext, Env.WebRootPath);
//app.UseSeedDataMiddle(myContext, Env.WebRootPath);
// 开启QuartzNetJob调度服务
app.UseQuartzJobMiddleware(tasksQzServices, schedulerCenter);
//app.UseQuartzJobMiddleware(tasksQzServices, schedulerCenter);
// 服务注册
app.UseConsulMiddle(Configuration, lifetime);
//app.UseConsulMiddle(Configuration, lifetime);
// 事件总线,订阅服务
app.ConfigureEventBus();
//app.ConfigureEventBus();
}
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Consul;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Blog.Core.Extensions.HostedService;
public class ConsulHostedService : IHostedService
{
private readonly IConfiguration _configuration;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly ILogger<ConsulHostedService> _logger;
public ConsulHostedService(IConfiguration configuration, IHostApplicationLifetime hostApplicationLifetime, ILogger<ConsulHostedService> logger)
{
_configuration = configuration;
_hostApplicationLifetime = hostApplicationLifetime;
_logger = logger;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start Consul Service!");
await DoWork();
}
public async Task DoWork()
{
if (_configuration["Middleware:Consul:Enabled"].ObjToBool())
{
var consulClient = new ConsulClient(c =>
{
//consul地址
c.Address = new Uri(_configuration["ConsulSetting:ConsulAddress"]);
});
var registration = new AgentServiceRegistration()
{
ID = Guid.NewGuid().ToString(),//服务实例唯一标识
Name = _configuration["ConsulSetting:ServiceName"],//服务名
Address = _configuration["ConsulSetting:ServiceIP"], //服务IP
Port = int.Parse(_configuration["ConsulSetting:ServicePort"]),//服务端口
Check = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔
HTTP = $"http://{_configuration["ConsulSetting:ServiceIP"]}:{_configuration["ConsulSetting:ServicePort"]}{_configuration["ConsulSetting:ServiceHealthCheck"]}",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)//超时时间
}
};
//服务注册
await consulClient.Agent.ServiceRegister(registration);
//应用程序终止时,取消注册
_hostApplicationLifetime.ApplicationStopping.Register(async () =>
{
await consulClient.Agent.ServiceDeregister(registration.ID);
});
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stop Consul Service!");
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Blog.Core.Common;
using Blog.Core.EventBus;
using Blog.Core.EventBus.EventHandling;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Blog.Core.Extensions.HostedService;
public class EventBusHostedService : IHostedService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<EventBusHostedService> _logger;
public EventBusHostedService(IServiceProvider serviceProvider, ILogger<EventBusHostedService> logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start EventBus Service!");
await DoWork();
}
private Task DoWork()
{
if (AppSettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
{
var eventBus = _serviceProvider.GetRequiredService<IEventBus>();
eventBus.Subscribe<BlogQueryIntegrationEvent, BlogQueryIntegrationEventHandler>();
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stop EventBus Service!");
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Blog.Core.Common;
using Blog.Core.IServices;
using Blog.Core.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Blog.Core.Extensions.HostedService;
public class QuartzJobHostedService : IHostedService
{
private readonly ITasksQzServices _tasksQzServices;
private readonly ISchedulerCenter _schedulerCenter;
private readonly ILogger<QuartzJobHostedService> _logger;
public QuartzJobHostedService(ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter, ILogger<QuartzJobHostedService> logger)
{
_tasksQzServices = tasksQzServices;
_schedulerCenter = schedulerCenter;
_logger = logger;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start QuartzJob Service!");
await DoWork();
}
private async Task DoWork()
{
try
{
if (AppSettings.app("Middleware", "QuartzNetJob", "Enabled").ObjToBool())
{
var allQzServices = await _tasksQzServices.Query();
foreach (var item in allQzServices)
{
if (item.IsStart)
{
var result = await _schedulerCenter.AddScheduleJobAsync(item);
if (result.success)
{
Console.WriteLine($"QuartzNetJob{item.Name}启动成功!");
}
else
{
Console.WriteLine($"QuartzNetJob{item.Name}启动失败!错误信息:{result.msg}");
}
}
}
}
}
catch (Exception e)
{
_logger.LogError(e, "An error was reported when starting the job service.");
throw;
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stop QuartzJob Service!");
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Blog.Core.Common;
using Blog.Core.Common.Seed;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Blog.Core.Extensions;
public sealed class SeedDataHostedService : IHostedService
{
private readonly MyContext _myContext;
private readonly ILogger<SeedDataHostedService> _logger;
private readonly string _webRootPath;
public SeedDataHostedService(
MyContext myContext,
IWebHostEnvironment webHostEnvironment,
ILogger<SeedDataHostedService> logger)
{
_myContext = myContext;
_logger = logger;
_webRootPath = webHostEnvironment.WebRootPath;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start Initialization Db Seed Service!");
await DoWork();
}
private async Task DoWork()
{
try
{
if (AppSettings.app("AppSettings", "SeedDBEnabled").ObjToBool() || AppSettings.app("AppSettings", "SeedDBDataEnabled").ObjToBool())
{
await DBSeed.SeedAsync(_myContext, _webRootPath);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occured seeding the Database.");
throw;
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stop Initialization Db Seed Service!");
return Task.CompletedTask;
}
}

View File

@ -1,52 +0,0 @@
using System;
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
namespace Blog.Core.Extensions.Middlewares
{
/// <summary>
/// Consul 注册服务
/// </summary>
public static class ConsulMiddleware
{
public static IApplicationBuilder UseConsulMiddle(this IApplicationBuilder app, IConfiguration configuration, IHostApplicationLifetime lifetime)
{
if (configuration["Middleware:Consul:Enabled"].ObjToBool())
{
var consulClient = new ConsulClient(c =>
{
//consul地址
c.Address = new Uri(configuration["ConsulSetting:ConsulAddress"]);
});
var registration = new AgentServiceRegistration()
{
ID = Guid.NewGuid().ToString(),//服务实例唯一标识
Name = configuration["ConsulSetting:ServiceName"],//服务名
Address = configuration["ConsulSetting:ServiceIP"], //服务IP
Port = int.Parse(configuration["ConsulSetting:ServicePort"]),//服务端口
Check = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔
HTTP = $"http://{configuration["ConsulSetting:ServiceIP"]}:{configuration["ConsulSetting:ServicePort"]}{configuration["ConsulSetting:ServiceHealthCheck"]}",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)//超时时间
}
};
//服务注册
consulClient.Agent.ServiceRegister(registration).Wait();
//应用程序终止时,取消注册
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(registration.ID).Wait();
});
}
return app;
}
}
}

View File

@ -1,51 +0,0 @@
using System;
using Blog.Core.Common;
using Blog.Core.IServices;
using Blog.Core.Tasks;
using log4net;
using Microsoft.AspNetCore.Builder;
namespace Blog.Core.Extensions.Middlewares
{
/// <summary>
/// Quartz 启动服务
/// </summary>
public static class QuartzJobMiddleware
{
private static readonly ILog Log = LogManager.GetLogger(typeof(QuartzJobMiddleware));
public static void UseQuartzJobMiddleware(this IApplicationBuilder app, ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter)
{
if (app == null) throw new ArgumentNullException(nameof(app));
try
{
if (AppSettings.app("Middleware", "QuartzNetJob", "Enabled").ObjToBool())
{
var allQzServices = tasksQzServices.Query().Result;
foreach (var item in allQzServices)
{
if (item.IsStart)
{
var result = schedulerCenter.AddScheduleJobAsync(item).Result;
if (result.success)
{
Console.WriteLine($"QuartzNetJob{item.Name}启动成功!");
}
else
{
Console.WriteLine($"QuartzNetJob{item.Name}启动失败!错误信息:{result.msg}");
}
}
}
}
}
catch (Exception e)
{
Log.Error($"An error was reported when starting the job service.\n{e.Message}");
throw;
}
}
}
}

View File

@ -1,33 +0,0 @@
using System;
using Blog.Core.Common;
using Blog.Core.Common.Seed;
using log4net;
using Microsoft.AspNetCore.Builder;
namespace Blog.Core.Extensions.Middlewares
{
/// <summary>
/// 生成种子数据中间件服务
/// </summary>
public static class SeedDataMiddleware
{
private static readonly ILog Log = LogManager.GetLogger(typeof(SeedDataMiddleware));
public static void UseSeedDataMiddle(this IApplicationBuilder app, MyContext myContext, string webRootPath)
{
if (app == null) throw new ArgumentNullException(nameof(app));
try
{
if (AppSettings.app("AppSettings", "SeedDBEnabled").ObjToBool() || AppSettings.app("AppSettings", "SeedDBDataEnabled").ObjToBool())
{
DBSeed.SeedAsync(myContext, webRootPath).Wait();
}
}
catch (Exception e)
{
Log.Error($"Error occured seeding the Database.\n{e.Message}");
throw;
}
}
}
}

View File

@ -1,11 +1,9 @@
using Autofac;
using System;
using Autofac;
using Blog.Core.Common;
using Blog.Core.EventBus;
using Blog.Core.EventBus.EventHandling;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace Blog.Core.Extensions
{
@ -43,23 +41,12 @@ namespace Blog.Core.Extensions
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
if(AppSettings.app(new string[] { "Kafka", "Enabled" }).ObjToBool())
if (AppSettings.app(new string[] { "Kafka", "Enabled" }).ObjToBool())
{
services.AddHostedService<KafkaConsumerHostService>();
services.AddSingleton<IEventBus, EventBusKafka>();
}
}
}
public static void ConfigureEventBus(this IApplicationBuilder app)
{
if (AppSettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
{
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<BlogQueryIntegrationEvent, BlogQueryIntegrationEventHandler>();
}
}
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using Blog.Core.Extensions.HostedService;
using Microsoft.Extensions.DependencyInjection;
namespace Blog.Core.Extensions;
public static class InitializationHostServiceSetup
{
/// <summary>
/// 应用初始化服务注入
/// </summary>
/// <param name="services"></param>
public static void AddInitializationHostServiceSetup(this IServiceCollection services)
{
if (services is null)
{
ArgumentNullException.ThrowIfNull(nameof(services));
}
services.AddHostedService<SeedDataHostedService>();
services.AddHostedService<QuartzJobHostedService>();
services.AddHostedService<ConsulHostedService>();
services.AddHostedService<EventBusHostedService>();
}
}