修改模块化逻辑
This commit is contained in:
parent
67dfab8a3c
commit
8a03c6d1ff
@ -0,0 +1,30 @@
|
|||||||
|
using Hangfire;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System.Reflection;
|
||||||
|
using JiShe.CollectBus.Common.Jobs;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 添加TcpService服务。
|
||||||
|
/// </summary>
|
||||||
|
public static IServiceCollection AddJobs(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var interfaceType = typeof(IBaseJob);
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
|
var types = assembly.GetTypes();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (type.IsClass && type.GetInterfaces().Contains(interfaceType))
|
||||||
|
{
|
||||||
|
RecurringJob.AddOrUpdate(type.Name, ()=>((type as IBaseJob)!).Execute(), Cron.Minutely, TimeZoneInfo.Utc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Hangfire.Core" Version="1.8.15" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
using JiShe.CollectBus.Common.Interfaces;
|
||||||
|
using JiShe.CollectBus.Common.Models;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Application
|
||||||
|
{
|
||||||
|
public class JiSheCollectBusApplicationModule: IJiSheModule
|
||||||
|
{
|
||||||
|
public void ConfigureServices(ServiceContext context)
|
||||||
|
{
|
||||||
|
var configuration = context.Configuration;
|
||||||
|
context.Services.AddJobs(configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
JiShe.CollectBus.Application/Jobs/TestJob.cs
Normal file
29
JiShe.CollectBus.Application/Jobs/TestJob.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JiShe.CollectBus.Common.Jobs;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Application.Jobs
|
||||||
|
{
|
||||||
|
public class TestJob : IBaseJob
|
||||||
|
{
|
||||||
|
private readonly ILogger<TestJob> _logger;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
|
public TestJob(ILogger<TestJob> logger, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Execute()
|
||||||
|
{
|
||||||
|
//to do something
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
JiShe.CollectBus.Common/Attributes/DependsOnAttribute.cs
Normal file
24
JiShe.CollectBus.Common/Attributes/DependsOnAttribute.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using JiShe.CollectBus.Common.Interfaces;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Common.Attributes
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||||
|
public class DependsOnAttribute : Attribute
|
||||||
|
{
|
||||||
|
// 依赖的模块
|
||||||
|
public Type ModuleType { get; private init; }
|
||||||
|
public DependsOnAttribute(Type type)
|
||||||
|
{
|
||||||
|
ModuleType = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||||
|
public sealed class DependsOnAttribute<TModule> : DependsOnAttribute
|
||||||
|
where TModule : IJiSheModule
|
||||||
|
{
|
||||||
|
public DependsOnAttribute() : base(typeof(TModule))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
using JiShe.CollectBus.Common.Extensions.DependencyInjections;
|
||||||
|
using System.Reflection;
|
||||||
|
using JiShe.CollectBus.Common.Interfaces;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public static class DependencyInjectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection ModuleRegister(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var assemblies = GetBinAssemblies();
|
||||||
|
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
|
{
|
||||||
|
var allTypes = assembly.GetTypes();
|
||||||
|
foreach (var type in allTypes)
|
||||||
|
{
|
||||||
|
if (typeof(IJiSheModule).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false })
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"正在加载模块{type.Name}...");
|
||||||
|
var instance = Activator.CreateInstance(type);
|
||||||
|
_ = (type.GetMethod("ConfigureServices")?.Invoke(instance, [services, configuration]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection ServiceRegister(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
var assemblies = GetBinAssemblies();
|
||||||
|
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
|
{
|
||||||
|
var allTypes = assembly.GetTypes();
|
||||||
|
foreach (var type in allTypes)
|
||||||
|
{
|
||||||
|
if (type is not { IsClass: true, IsAbstract: false }) continue;
|
||||||
|
if (typeof(ISingletonDependency).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ISingletonDependency") && !p.FullName.Contains("IDisposable"));
|
||||||
|
foreach (var interfaceType in interfaceTypes)
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"正在IOC注入ISingletonDependency {type.Name}...");
|
||||||
|
services.AddSingleton(interfaceType, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(ITransientDependency).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ITransientDependency") && !p.FullName.Contains("IDisposable"));
|
||||||
|
foreach (var interfaceType in interfaceTypes)
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"正在IOC注入ITransientDependency {type.Name}...");
|
||||||
|
services.AddTransient(interfaceType, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(IScopedDependency).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("IScopedDependency") && !p.FullName.Contains("IDisposable"));
|
||||||
|
foreach (var interfaceType in interfaceTypes)
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"正在IOC注入IScopedDependency {type.Name}...");
|
||||||
|
services.AddScoped(interfaceType, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Assembly> GetBinAssemblies()
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
|
||||||
|
if (!directory.Exists) return [];
|
||||||
|
|
||||||
|
var files = directory.GetFiles("JiShe.CollectBus.*.dll");
|
||||||
|
|
||||||
|
var assemblies = new List<Assembly>();
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assembly = Assembly.LoadFrom(file.FullName);
|
||||||
|
assemblies.Add(assembly);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error loading assembly from {file.FullName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return assemblies;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using JiShe.CollectBus.Common.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
@ -6,6 +7,10 @@ namespace JiShe.CollectBus.Common.Interfaces
|
|||||||
{
|
{
|
||||||
public interface IJiSheModule
|
public interface IJiSheModule
|
||||||
{
|
{
|
||||||
void ConfigureServices(IServiceCollection services,HostBuilderContext hostContext);
|
/// <summary>
|
||||||
|
/// 模块中的依赖注入
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">模块服务上下文</param>
|
||||||
|
void ConfigureServices(ServiceContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
13
JiShe.CollectBus.Common/Jobs/IBaseJob.cs
Normal file
13
JiShe.CollectBus.Common/Jobs/IBaseJob.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Common.Jobs
|
||||||
|
{
|
||||||
|
public interface IBaseJob
|
||||||
|
{
|
||||||
|
Task Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
29
JiShe.CollectBus.Common/Models/ServiceContext.cs
Normal file
29
JiShe.CollectBus.Common/Models/ServiceContext.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Common.Models
|
||||||
|
{
|
||||||
|
public class ServiceContext
|
||||||
|
{
|
||||||
|
internal ServiceContext(IServiceCollection serviceCollection, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Services = serviceCollection;
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 依赖注入服务
|
||||||
|
/// </summary>
|
||||||
|
public IServiceCollection Services { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置
|
||||||
|
/// </summary>
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,68 +12,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
{
|
{
|
||||||
public static class DependencyInjectionExtensions
|
public static class DependencyInjectionExtensions
|
||||||
{
|
{
|
||||||
public static void ModuleRegister(this IServiceCollection services, HostBuilderContext hostContext)
|
|
||||||
{
|
|
||||||
var assemblies = GetBinAssemblies();
|
|
||||||
|
|
||||||
foreach (var assembly in assemblies)
|
|
||||||
{
|
|
||||||
var allTypes = assembly.GetTypes();
|
|
||||||
foreach (var type in allTypes)
|
|
||||||
{
|
|
||||||
if (typeof(IJiSheModule).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false })
|
|
||||||
{
|
|
||||||
Log.Logger.Information($"正在加载模块{type.Name}...");
|
|
||||||
var instance = Activator.CreateInstance(type);
|
|
||||||
_ = (type.GetMethod("ConfigureServices")?.Invoke(instance, [services, hostContext]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ServiceRegister(this IServiceCollection services)
|
|
||||||
{
|
|
||||||
var assemblies = GetBinAssemblies();
|
|
||||||
|
|
||||||
foreach (var assembly in assemblies)
|
|
||||||
{
|
|
||||||
var allTypes = assembly.GetTypes();
|
|
||||||
foreach (var type in allTypes)
|
|
||||||
{
|
|
||||||
if (type is not { IsClass: true, IsAbstract: false }) continue;
|
|
||||||
if (typeof(ISingletonDependency).IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ISingletonDependency") && !p.FullName.Contains("IDisposable"));
|
|
||||||
foreach (var interfaceType in interfaceTypes)
|
|
||||||
{
|
|
||||||
Log.Logger.Information($"正在IOC注入ISingletonDependency {type.Name}...");
|
|
||||||
services.AddSingleton(interfaceType, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(ITransientDependency).IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ITransientDependency") && !p.FullName.Contains("IDisposable"));
|
|
||||||
foreach (var interfaceType in interfaceTypes)
|
|
||||||
{
|
|
||||||
Log.Logger.Information($"正在IOC注入ITransientDependency {type.Name}...");
|
|
||||||
services.AddTransient(interfaceType, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(IScopedDependency).IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("IScopedDependency") && !p.FullName.Contains("IDisposable"));
|
|
||||||
foreach (var interfaceType in interfaceTypes)
|
|
||||||
{
|
|
||||||
Log.Logger.Information($"正在IOC注入IScopedDependency {type.Name}...");
|
|
||||||
services.AddScoped(interfaceType, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PluginServiceRegister(this IServiceCollection services, string pluginPath = "")
|
public static void PluginServiceRegister(this IServiceCollection services, string pluginPath = "")
|
||||||
{
|
{
|
||||||
if (pluginPath.IsNullOrWhiteSpace())
|
if (pluginPath.IsNullOrWhiteSpace())
|
||||||
@ -152,29 +90,5 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
|
|
||||||
return assemblies;
|
return assemblies;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Assembly> GetBinAssemblies()
|
|
||||||
{
|
|
||||||
var directory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
|
|
||||||
if (!directory.Exists) return [];
|
|
||||||
|
|
||||||
var files = directory.GetFiles("JiShe.CollectBus.*.dll");
|
|
||||||
|
|
||||||
var assemblies = new List<Assembly>();
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var assembly = Assembly.LoadFrom(file.FullName);
|
|
||||||
assemblies.Add(assembly);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error loading assembly from {file.FullName}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return assemblies;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using JiShe.CollectBus.Core.Plugins;
|
using JiShe.CollectBus.Core.Plugins;
|
||||||
using JiShe.CollectBus.Core.Services;
|
using JiShe.CollectBus.Core.Services;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.Adapters;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using TouchSocket.Core;
|
using TouchSocket.Core;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
@ -17,6 +18,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddTcpService(config =>
|
services.AddTcpService(config =>
|
||||||
{
|
{
|
||||||
config.SetListenIPHosts(int.Parse(configuration["TCP:ClientPort"] ?? "10500"))
|
config.SetListenIPHosts(int.Parse(configuration["TCP:ClientPort"] ?? "10500"))
|
||||||
|
//.SetTcpDataHandlingAdapter(()=>new StandardFixedHeaderDataHandlingAdapter())
|
||||||
.ConfigurePlugins(a =>
|
.ConfigurePlugins(a =>
|
||||||
{
|
{
|
||||||
a.Add<TcpClosePlugin>();
|
a.Add<TcpClosePlugin>();
|
||||||
|
|||||||
@ -52,9 +52,9 @@ namespace JiShe.CollectBus.Console
|
|||||||
lc.ReadFrom.Configuration(configuration)
|
lc.ReadFrom.Configuration(configuration)
|
||||||
.ReadFrom.Services(context);
|
.ReadFrom.Services(context);
|
||||||
});
|
});
|
||||||
services.ServiceRegister();
|
services.ServiceRegister()
|
||||||
services.PluginServiceRegister();
|
.ModuleRegister(configuration)
|
||||||
services.ModuleRegister(hostContext);
|
.PluginServiceRegister();
|
||||||
services.AddTcp(configuration);
|
services.AddTcp(configuration);
|
||||||
//services.AddUdp(configuration);
|
//services.AddUdp(configuration);
|
||||||
services.AddStackExchangeRedisCache(options =>
|
services.AddStackExchangeRedisCache(options =>
|
||||||
|
|||||||
@ -27,8 +27,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true",
|
"Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"
|
||||||
"ClickHouse": "host=localhost;port=8123;user=default;password=;database=default"
|
|
||||||
},
|
},
|
||||||
"MongoSettings": {
|
"MongoSettings": {
|
||||||
"Connection": "mongodb://backups_admin:jishe_mongodb_backups@118.190.144.92:27037",
|
"Connection": "mongodb://backups_admin:jishe_mongodb_backups@118.190.144.92:27037",
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using Hangfire;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.Adapters;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using TouchSocket.Core;
|
||||||
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,21 +7,26 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Hangfire" Version="1.8.15" />
|
||||||
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.15" />
|
||||||
|
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Hangfire.HttpJob" Version="3.8.5" />
|
||||||
|
<PackageReference Include="Hangfire.MySqlStorage" Version="2.0.3" />
|
||||||
<PackageReference Include="Serilog" Version="4.1.0" />
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\JiShe.CollectBus.Core\JiShe.CollectBus.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\JiShe.CollectBus.EntityFrameworkCore\JiShe.CollectBus.EntityFrameworkCore.csproj" />
|
||||||
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
|
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.RabbitMQ.csproj" />
|
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.RabbitMQ.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Extensions\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,13 +1,39 @@
|
|||||||
namespace JiShe.CollectBus.Host
|
using Hangfire;
|
||||||
|
using Hangfire.Dashboard.BasicAuthorization;
|
||||||
|
using Hangfire.HttpJob;
|
||||||
|
using Hangfire.MySql;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Host
|
||||||
{
|
{
|
||||||
public class Startup(IConfiguration configuration)
|
public class Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
|
||||||
services.AddEndpointsApiExplorer();
|
services.AddEndpointsApiExplorer();
|
||||||
services.AddSwaggerGen();
|
services.AddSwaggerGen();
|
||||||
|
services.AddHangfire(config =>
|
||||||
|
{
|
||||||
|
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
||||||
|
.UseSimpleAssemblyNameTypeSerializer()
|
||||||
|
.UseRecommendedSerializerSettings();
|
||||||
|
|
||||||
|
config.UseStorage(
|
||||||
|
new MySqlStorage(
|
||||||
|
configuration.GetConnectionString("Default"),
|
||||||
|
new MySqlStorageOptions
|
||||||
|
{
|
||||||
|
QueuePollInterval = TimeSpan.FromSeconds(15), //- 作业队列轮询间隔。默认值为15秒。
|
||||||
|
JobExpirationCheckInterval = TimeSpan.FromHours(1), //- 作业到期检查间隔(管理过期记录)。默认值为1小时。
|
||||||
|
CountersAggregateInterval = TimeSpan.FromMinutes(5), //- 聚合计数器的间隔。默认为5分钟。
|
||||||
|
PrepareSchemaIfNecessary = true, //- 如果设置为true,则创建数据库表。默认是true。
|
||||||
|
DashboardJobListLimit = 50000, //- 仪表板作业列表限制。默认值为50000。
|
||||||
|
TransactionTimeout = TimeSpan.FromMinutes(1), //- 交易超时。默认为1分钟。
|
||||||
|
}));
|
||||||
|
config.UseHangfireHttpJob();
|
||||||
|
});
|
||||||
|
services.AddHangfireServer();
|
||||||
|
services.ServiceRegister().ModuleRegister(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
@ -26,10 +52,37 @@
|
|||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
//app.UseEndpoints(endpoints =>
|
var dashboardOptions = new DashboardOptions();
|
||||||
//{
|
|
||||||
// endpoints.MapRazorPages();
|
if (env.IsProduction())
|
||||||
//});
|
{
|
||||||
|
dashboardOptions = new DashboardOptions
|
||||||
|
{
|
||||||
|
Authorization = new[]
|
||||||
|
{
|
||||||
|
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
|
||||||
|
{
|
||||||
|
SslRedirect = false,
|
||||||
|
RequireSsl = false,
|
||||||
|
LoginCaseSensitive = false,
|
||||||
|
Users =
|
||||||
|
[
|
||||||
|
new BasicAuthAuthorizationUser
|
||||||
|
{
|
||||||
|
Login = "admin",
|
||||||
|
PasswordClear = "lixiao1980"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
app.UseHangfireDashboard("/hangfire", dashboardOptions);
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoint =>
|
||||||
|
{
|
||||||
|
endpoint.MapControllers();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
namespace JiShe.CollectBus.Host
|
|
||||||
{
|
|
||||||
public class WeatherForecast
|
|
||||||
{
|
|
||||||
public DateOnly Date { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureC { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
|
||||||
|
|
||||||
public string? Summary { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,51 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"LogLevel": {
|
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||||
"Default": "Information",
|
"MinimumLevel": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"System": "Warning"
|
||||||
|
},
|
||||||
|
"WriteTo": [
|
||||||
|
{ "Name": "Console" },
|
||||||
|
{
|
||||||
|
"Name": "File",
|
||||||
|
"Args": {
|
||||||
|
"path": "Logs/log-.txt",
|
||||||
|
"rollingInterval": "Day"
|
||||||
|
//"rollOnFileSizeLimit": true,
|
||||||
|
//"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
|
||||||
|
|
||||||
|
"Properties": {
|
||||||
|
"Application": "CollectBus",
|
||||||
|
"Environment": "Development"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"
|
||||||
|
},
|
||||||
|
"MongoSettings": {
|
||||||
|
"Connection": "mongodb://backups_admin:jishe_mongodb_backups@118.190.144.92:27037",
|
||||||
|
"DatabaseName": "JiSheCollectBus"
|
||||||
|
},
|
||||||
|
"RedisCache": {
|
||||||
|
"ConnectionString": "123456@qwer@localhost:6379",
|
||||||
|
"InstanceName": "CollectBus"
|
||||||
|
},
|
||||||
|
"MQ": {
|
||||||
|
"Host": "118.190.144.92",
|
||||||
|
"Port": "5672",
|
||||||
|
"VirtualHost": "/",
|
||||||
|
"UserName": "collectbus",
|
||||||
|
"Password": "123456",
|
||||||
|
"Queue": {
|
||||||
|
"Received": "Received_Command",
|
||||||
|
"Issued": "Issued_Command"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,17 +1,16 @@
|
|||||||
using JiShe.CollectBus.Common.Interfaces;
|
using JiShe.CollectBus.Common.Interfaces;
|
||||||
|
using JiShe.CollectBus.Common.Models;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using MongoDB.Driver;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.MongoDB
|
namespace JiShe.CollectBus.MongoDB
|
||||||
{
|
{
|
||||||
public class JiSheCollectBusMongoDbModule: IJiSheModule
|
public class JiSheCollectBusMongoDbModule: IJiSheModule
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostContext)
|
public void ConfigureServices(ServiceContext context)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IMongoContext, MongoContext>();
|
context.Services.AddSingleton<IMongoContext, MongoContext>();
|
||||||
services.AddSingleton<IUnitOfWork, UnitOfWork>();
|
context.Services.AddSingleton<IUnitOfWork, UnitOfWork>();
|
||||||
services.AddSingleton(typeof(IMongoRepository<>), typeof(MongoBaseRepository<>));
|
context.Services.AddSingleton(typeof(IMongoRepository<>), typeof(MongoBaseRepository<>));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,12 +41,15 @@ namespace JiShe.CollectBus.Protocol.Contracts.Interfaces
|
|||||||
|
|
||||||
public bool OnParsingHeader(ReadOnlySpan<byte> header)
|
public bool OnParsingHeader(ReadOnlySpan<byte> header)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnParsingBody(ReadOnlySpan<byte> body)
|
public bool OnParsingBody(ReadOnlySpan<byte> body)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int BodyLength { get; }
|
public int BodyLength { get; }
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
using JiShe.CollectBus.Common.Interfaces;
|
using JiShe.CollectBus.Common.Interfaces;
|
||||||
|
using JiShe.CollectBus.Common.Models;
|
||||||
using JiShe.CollectBus.RabbitMQ.Consumers;
|
using JiShe.CollectBus.RabbitMQ.Consumers;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
@ -9,10 +11,10 @@ namespace JiShe.CollectBus.RabbitMQ
|
|||||||
{
|
{
|
||||||
public class JiSheCollectBusRabbitMqModule: IJiSheModule
|
public class JiSheCollectBusRabbitMqModule: IJiSheModule
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostContext)
|
public void ConfigureServices(ServiceContext context)
|
||||||
{
|
{
|
||||||
var configuration = hostContext.Configuration;
|
var configuration = context.Configuration;
|
||||||
services.AddMassTransit(x =>
|
context.Services.AddMassTransit(x =>
|
||||||
{
|
{
|
||||||
x.AddConsumer<MessageReceivedConsumer>(cfg =>
|
x.AddConsumer<MessageReceivedConsumer>(cfg =>
|
||||||
{
|
{
|
||||||
@ -27,11 +29,11 @@ namespace JiShe.CollectBus.RabbitMQ
|
|||||||
x.AddConsumer<MessageReceivedLoginConsumer>();
|
x.AddConsumer<MessageReceivedLoginConsumer>();
|
||||||
x.AddConsumer<MessageReceivedHeartbeatConsumer>();
|
x.AddConsumer<MessageReceivedHeartbeatConsumer>();
|
||||||
|
|
||||||
x.AddConfigureEndpointsCallback((context, name, cfg) =>
|
x.AddConfigureEndpointsCallback((c, name, cfg) =>
|
||||||
{
|
{
|
||||||
cfg.UseDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
|
cfg.UseDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
|
||||||
cfg.UseMessageRetry(r => r.Immediate(5));
|
cfg.UseMessageRetry(r => r.Immediate(5));
|
||||||
cfg.UseInMemoryOutbox(context);
|
cfg.UseInMemoryOutbox(c);
|
||||||
|
|
||||||
//cfg.UseMessageRetry(r =>
|
//cfg.UseMessageRetry(r =>
|
||||||
//{
|
//{
|
||||||
@ -40,7 +42,7 @@ namespace JiShe.CollectBus.RabbitMQ
|
|||||||
//});
|
//});
|
||||||
});
|
});
|
||||||
|
|
||||||
x.UsingRabbitMq((context, cfg) =>
|
x.UsingRabbitMq((c, cfg) =>
|
||||||
{
|
{
|
||||||
cfg.Host(configuration["MQ:Host"], ushort.Parse(configuration["MQ:Port"] ?? string.Empty), configuration["MQ:VirtualHost"], h =>
|
cfg.Host(configuration["MQ:Host"], ushort.Parse(configuration["MQ:Port"] ?? string.Empty), configuration["MQ:VirtualHost"], h =>
|
||||||
{
|
{
|
||||||
@ -52,28 +54,28 @@ namespace JiShe.CollectBus.RabbitMQ
|
|||||||
cfg.ReceiveEndpoint(configuration["MQ:Queue:Received"] ?? string.Empty,configurator =>
|
cfg.ReceiveEndpoint(configuration["MQ:Queue:Received"] ?? string.Empty,configurator =>
|
||||||
{
|
{
|
||||||
configurator.ConfigureConsumeTopology = false;
|
configurator.ConfigureConsumeTopology = false;
|
||||||
configurator.Consumer<MessageReceivedConsumer>(context);
|
configurator.Consumer<MessageReceivedConsumer>(c);
|
||||||
configurator.Durable = true;
|
configurator.Durable = true;
|
||||||
});
|
});
|
||||||
// 登录
|
// 登录
|
||||||
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Login", configurator =>
|
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Login", configurator =>
|
||||||
{
|
{
|
||||||
configurator.ConfigureConsumeTopology = false;
|
configurator.ConfigureConsumeTopology = false;
|
||||||
configurator.Consumer<MessageReceivedLoginConsumer>(context);
|
configurator.Consumer<MessageReceivedLoginConsumer>(c);
|
||||||
configurator.Durable = true;
|
configurator.Durable = true;
|
||||||
});
|
});
|
||||||
// 心跳
|
// 心跳
|
||||||
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Heartbeat", configurator =>
|
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Heartbeat", configurator =>
|
||||||
{
|
{
|
||||||
configurator.ConfigureConsumeTopology = false;
|
configurator.ConfigureConsumeTopology = false;
|
||||||
configurator.Consumer<MessageReceivedHeartbeatConsumer>(context);
|
configurator.Consumer<MessageReceivedHeartbeatConsumer>(c);
|
||||||
configurator.Durable = true;
|
configurator.Durable = true;
|
||||||
});
|
});
|
||||||
// 消息下发队列
|
// 消息下发队列
|
||||||
cfg.ReceiveEndpoint(configuration["MQ:Queue:Issued"] ?? string.Empty, configurator =>
|
cfg.ReceiveEndpoint(configuration["MQ:Queue:Issued"] ?? string.Empty, configurator =>
|
||||||
{
|
{
|
||||||
configurator.ConfigureConsumeTopology = false;
|
configurator.ConfigureConsumeTopology = false;
|
||||||
configurator.Consumer<MessageIssuedConsumer>(context);
|
configurator.Consumer<MessageIssuedConsumer>(c);
|
||||||
configurator.Durable = true;
|
configurator.Durable = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,7 +31,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Host", "Ji
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.demo", "4.demo", "{43E8E19B-555A-4633-9926-B4F3C01D972A}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.demo", "4.demo", "{43E8E19B-555A-4633-9926-B4F3C01D972A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Test", "JiShe.CollectBus.Test\JiShe.CollectBus.Test.csproj", "{6ED66F52-B4A0-403E-AE89-8E9A679C0885}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Test", "JiShe.CollectBus.Test\JiShe.CollectBus.Test.csproj", "{6ED66F52-B4A0-403E-AE89-8E9A679C0885}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Application", "JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj", "{2760AC98-D2FA-4074-8396-FAE10BE20A3C}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -83,6 +85,10 @@ Global
|
|||||||
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -99,6 +105,7 @@ Global
|
|||||||
{223DBDB1-6CD3-4D4E-8795-42550BC0A871} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}
|
{223DBDB1-6CD3-4D4E-8795-42550BC0A871} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}
|
||||||
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131} = {B68027BA-BD9D-4110-A383-708B87BC425D}
|
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131} = {B68027BA-BD9D-4110-A383-708B87BC425D}
|
||||||
{6ED66F52-B4A0-403E-AE89-8E9A679C0885} = {3A04FB29-EA75-4499-BBF3-AF24C7D46A1D}
|
{6ED66F52-B4A0-403E-AE89-8E9A679C0885} = {3A04FB29-EA75-4499-BBF3-AF24C7D46A1D}
|
||||||
|
{2760AC98-D2FA-4074-8396-FAE10BE20A3C} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {33261859-9CD1-4A43-B181-AB75C247D1CD}
|
SolutionGuid = {33261859-9CD1-4A43-B181-AB75C247D1CD}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user