添加项目文件。

This commit is contained in:
2026-10-12 16:22:04 +08:00
parent 7c68a0ca0a
commit aad11be43d
1000 changed files with 120807 additions and 0 deletions
@@ -0,0 +1,55 @@
using System.Reflection;
using Autofac;
using CommonService;
using MongoRepository;
using RedisService;
namespace SharpAbp.Infrastructure.Api.Autofac
{
public abstract class ApplicationModule : global::Autofac.Module
{
protected abstract Assembly CurrentAssembly { get; }
protected virtual Assembly[] GetServiceAssemblies()
{
return new[] { CurrentAssembly };
}
protected virtual bool RegisterMongoBaseService => true;
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(MongoBaseRepository<>))
.As(typeof(IMongoBaseRepository<>))
.InstancePerLifetimeScope();
if (RegisterMongoBaseService)
{
builder.RegisterGeneric(typeof(MongoBaseService<>))
.As(typeof(IMongoBaseService<>))
.InstancePerLifetimeScope();
}
builder.RegisterType<RedisService.RedisService>()
.As<RedisService.IRedisService>()
.InstancePerLifetimeScope();
var serviceAssemblies = GetServiceAssemblies();
foreach (var assembly in serviceAssemblies)
{
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Service") && !t.IsAbstract)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
foreach (var assembly in serviceAssemblies)
{
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Repository") && !t.IsAbstract)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}
}
}
@@ -0,0 +1,56 @@
namespace SharpAbp.Infrastructure.Api.Configuration
{
public class JwtConfig
{
public string TokenKey { get; set; } = "token";
public string Issuer { get; set; } = "admin";
public string Audience { get; set; } = "";
public string SecretKey { get; set; } = "";
public bool ValidateIssuer { get; set; } = false;
public bool ValidateAudience { get; set; } = false;
public bool ValidateIssuerSigningKey { get; set; } = false;
public bool ValidateLifetime { get; set; } = false;
}
public class CapConfig
{
public string Host { get; set; } = "localhost";
public string UserName { get; set; } = "admin";
public string Password { get; set; } = "";
public string VirtualHost { get; set; } = "/";
public string PGLogHost { get; set; } = "";
}
public class RedisConfig
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 6379;
public string UserName { get; set; } = "";
public string Password { get; set; } = "";
public int Database { get; set; } = 0;
}
public class WXConfig
{
public string AppId { get; set; } = "";
public string Secret { get; set; } = "";
public string Url { get; set; } = "";
}
public class AppSettings
{
public JwtConfig JwtConfig { get; set; } = new();
public string PgSqlConnection { get; set; } = "";
public CapConfig CapConfig { get; set; } = new();
public RedisConfig RedisConfig { get; set; } = new();
public MongoDbSettings MongoDbSettings { get; set; } = new();
public WXConfig WXConfig { get; set; } = new();
}
public class MongoDbSettings
{
public string Username { get; set; } = "";
public string Password { get; set; } = "";
public string ServerUrl { get; set; } = "";
}
}
@@ -0,0 +1,100 @@
namespace SharpAbp.Infrastructure.Api.Configuration
{
public static class ConfigurationHelper
{
public static string GetString(string key, string defaultValue = null)
{
var envValue = Environment.GetEnvironmentVariable(key);
if (!string.IsNullOrEmpty(envValue))
{
return envValue;
}
return defaultValue;
}
public static int GetInt(string key, int defaultValue = 0)
{
var envValue = Environment.GetEnvironmentVariable(key);
if (int.TryParse(envValue, out var result))
{
return result;
}
return defaultValue;
}
public static bool GetBool(string key, bool defaultValue = false)
{
var envValue = Environment.GetEnvironmentVariable(key);
if (bool.TryParse(envValue, out var result))
{
return result;
}
return defaultValue;
}
public static string GetConnectionString(string type)
{
return type.ToLower() switch
{
"mongodb" => GetMongoDBConnectionString(),
"redis" => GetRedisConnectionString(),
"rabbitmq" => GetRabbitMQConnectionString(),
"mysql" => GetMySQLConnectionString(),
_ => throw new ArgumentException($"Unknown connection type: {type}")
};
}
private static string GetMongoDBConnectionString()
{
var host = GetString("MONGODB_HOST", "localhost");
var port = GetString("MONGODB_PORT", "27017");
var user = GetString("MONGODB_USER", "");
var password = GetString("MONGODB_PASSWORD", "");
var database = GetString("MONGODB_DATABASE", "data_0524");
if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password))
{
return $"mongodb://{user}:{password}@{host}:{port}/{database}";
}
return $"mongodb://{host}:{port}/{database}";
}
private static string GetRedisConnectionString()
{
var host = GetString("REDIS_HOST", "localhost");
var port = GetString("REDIS_PORT", "6379");
var password = GetString("REDIS_PASSWORD", "");
var database = GetString("REDIS_DB", "0");
var connectionString = $"{host}:{port}";
if (!string.IsNullOrEmpty(password))
{
connectionString += $",password={password}";
}
connectionString += $",defaultDatabase={database}";
return connectionString;
}
private static string GetRabbitMQConnectionString()
{
var host = GetString("RABBITMQ_HOST", "localhost");
var port = GetString("RABBITMQ_PORT", "5672");
var user = GetString("RABBITMQ_USER", "guest");
var password = GetString("RABBITMQ_PASSWORD", "guest");
return $"amqp://{user}:{password}@{host}:{port}";
}
private static string GetMySQLConnectionString()
{
var host = GetString("MYSQL_HOST", "localhost");
var port = GetString("MYSQL_PORT", "3306");
var user = GetString("MYSQL_USER", "root");
var password = GetString("MYSQL_PASSWORD", "");
var database = GetString("MYSQL_DATABASE", "data_0524");
return $"Server={host};Port={port};Database={database};User={user};Password={password};";
}
}
}
@@ -0,0 +1,57 @@
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
namespace SharpAbp.Infrastructure.Api.Controllers
{
[ApiController]
public abstract class BaseController : Controller
{
public LoginUser loginUser
{
get
{
return GetLoginUser();
}
}
protected virtual LoginUser GetLoginUser()
{
var claims = User?.Claims?.ToList();
if (claims == null || claims.Count == 0)
{
return null;
}
var userId = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
var userName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
var role = claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value;
return new LoginUser
{
userId = userId,
userName = userName,
role = role
};
}
protected virtual string GetClientIp()
{
var ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (string.IsNullOrEmpty(ip))
{
ip = HttpContext.Connection.RemoteIpAddress?.ToString();
}
return ip ?? "unknown";
}
}
public class LoginUser
{
public string userId { get; set; }
public string userName { get; set; }
public string role { get; set; }
}
}
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using Common;
using Microsoft.AspNetCore.Mvc;
namespace SharpAbp.Infrastructure.Api.Extensions
{
public static class ControllerExtensions
{
public static BaseResponse<T> ToFailResult<T>(
this Controller controller,
string info) => new BaseResponse<T>() { Info = info, Code = CommonResponseCodeEnum.ResultFail };
public static ListResponse<T> ToListFailResult<T>(
this Controller controller,
string info) => new ListResponse<T>()
{ Info = info, Code = CommonResponseCodeEnum.ResultFail };
public static PageResponse<T> ToPageFailResult<T>(
this Controller controller,
string info) => new PageResponse<T>()
{
Code = CommonResponseCodeEnum.ResultFail,
Info = info
};
public static BaseResponse<T> ToResult<T>(
this Controller controller,
T obj, string info = null) => new BaseResponse<T>()
{
Data = obj,
Info = info,
Code = CommonResponseCodeEnum.Success
};
public static ListResponse<T> ToListResult<T>(
this Controller controller,
IEnumerable<T> list, string info = null) => new ListResponse<T>()
{
Data = list,
Code = CommonResponseCodeEnum.Success,
Info = info
};
public static PageResponse<T> ToPageResult<T>(
this Controller controller,
IEnumerable<T> list, int count = 0, string info = null) => new PageResponse<T>()
{
Code = CommonResponseCodeEnum.Success,
Info = info,
Count = count,
Data = list
};
public static BaseResponse<T> ToNoLoginResult<T>(
this Controller controller) => new BaseResponse<T>()
{
Info = "未登录",
Code = CommonResponseCodeEnum.NoLogin
};
public static BaseResponse<T> ToTokenInvalidResult<T>(
this Controller controller) => new BaseResponse<T>()
{
Info = "token失效",
Code = CommonResponseCodeEnum.TokenInvalid
};
public static BaseResponse<T> ToParamErrorResult<T>(
this Controller controller,
string info = "请求参数错误") => new BaseResponse<T>()
{
Info = info,
Code = CommonResponseCodeEnum.ParamError
};
}
}
@@ -0,0 +1,82 @@
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace SharpAbp.Infrastructure.Api.Middleware
{
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception ex)
{
if (ex is Common.BusinessException bizEx)
{
return WriteJsonResponse(context, Common.CommonResponseCodeEnum.Error, bizEx.Message);
}
if (ex is UnauthorizedAccessException)
{
return WriteJsonResponse(context, Common.CommonResponseCodeEnum.NoAuth, "未授权访问");
}
if (ex is ArgumentException argEx)
{
return WriteJsonResponse(context, Common.CommonResponseCodeEnum.ParamError, argEx.Message);
}
if (ex is TimeoutException || ex is OperationCanceledException)
{
return WriteJsonResponse(context, Common.CommonResponseCodeEnum.Error, "操作超时,请稍后重试: " + ex.Message);
}
_logger.LogError(ex, "系统异常: {Message}", ex.Message);
return WriteJsonResponse(context, Common.CommonResponseCodeEnum.Exception, ex.Message);
}
private static Task WriteJsonResponse(HttpContext context, Common.CommonResponseCodeEnum code, string message)
{
context.Response.StatusCode = 200;
context.Response.ContentType = "application/json";
return context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
code = code,
info = message,
data = (object?)null
}));
}
}
public static class GlobalExceptionMiddlewareExtensions
{
public static IApplicationBuilder UseGlobalExceptionHandler(this IApplicationBuilder app)
{
return app.UseMiddleware<GlobalExceptionMiddleware>();
}
}
}
@@ -0,0 +1,191 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace SharpAbp.Infrastructure.Api.Resilience
{
public enum CircuitState
{
Closed,
Open,
HalfOpen
}
public class CircuitBreakerOptions
{
public int FailureThreshold { get; set; } = 5;
public int BreakDurationSeconds { get; set; } = 30;
public int HalfOpenAttempts { get; set; } = 3;
public int SuccessThreshold { get; set; } = 2;
}
public class CircuitBreaker
{
private readonly CircuitBreakerOptions _options;
private readonly ILogger _logger;
private int _failureCount;
private int _successCount;
private int _halfOpenAttempts;
private CircuitState _state = CircuitState.Closed;
private DateTime _lastFailureTime;
private readonly object _lock = new();
public CircuitBreaker(string name, CircuitBreakerOptions options, ILogger logger)
{
Name = name;
_options = options;
_logger = logger;
}
public string Name { get; }
public CircuitState State => _state;
public async Task<T> ExecuteAsync<T>(Func<Task<T>> action)
{
if (!CanExecute())
{
throw new CircuitBreakerOpenException($"Circuit breaker '{Name}' is open");
}
try
{
var result = await action();
OnSuccess();
return result;
}
catch (Exception ex)
{
OnFailure(ex);
throw;
}
}
public async Task ExecuteAsync(Func<Task> action)
{
if (!CanExecute())
{
throw new CircuitBreakerOpenException($"Circuit breaker '{Name}' is open");
}
try
{
await action();
OnSuccess();
}
catch (Exception ex)
{
OnFailure(ex);
throw;
}
}
private bool CanExecute()
{
lock (_lock)
{
switch (_state)
{
case CircuitState.Closed:
return true;
case CircuitState.Open:
var elapsed = (DateTime.UtcNow - _lastFailureTime).TotalSeconds;
if (elapsed >= _options.BreakDurationSeconds)
{
_state = CircuitState.HalfOpen;
_halfOpenAttempts = 0;
return true;
}
return false;
case CircuitState.HalfOpen:
return _halfOpenAttempts < _options.HalfOpenAttempts;
default:
return true;
}
}
}
private void OnSuccess()
{
lock (_lock)
{
switch (_state)
{
case CircuitState.Closed:
_failureCount = 0;
break;
case CircuitState.HalfOpen:
_successCount++;
_halfOpenAttempts++;
if (_successCount >= _options.SuccessThreshold)
{
_state = CircuitState.Closed;
_failureCount = 0;
_successCount = 0;
}
break;
}
}
}
private void OnFailure(Exception ex)
{
lock (_lock)
{
_failureCount++;
_lastFailureTime = DateTime.UtcNow;
switch (_state)
{
case CircuitState.Closed:
if (_failureCount >= _options.FailureThreshold)
{
_state = CircuitState.Open;
}
break;
case CircuitState.HalfOpen:
_state = CircuitState.Open;
_halfOpenAttempts = _options.HalfOpenAttempts;
break;
}
}
}
}
public class CircuitBreakerOpenException : Exception
{
public CircuitBreakerOpenException(string message) : base(message) { }
}
public class CircuitBreakerFactory
{
private readonly ConcurrentDictionary<string, CircuitBreaker> _breakers = new();
private readonly ILoggerFactory _loggerFactory;
public CircuitBreakerFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public CircuitBreaker GetOrCreate(string name, CircuitBreakerOptions options = null)
{
return _breakers.GetOrAdd(name, n =>
{
var opts = options ?? new CircuitBreakerOptions();
var logger = _loggerFactory.CreateLogger<CircuitBreaker>();
return new CircuitBreaker(n, opts, logger);
});
}
}
}
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>SharpAbp.Infrastructure.Api</RootNamespace>
<AssemblyName>SharpAbp.Infrastructure.Api</AssemblyName>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Autofac" Version="8.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\CommonService\CommonService.csproj" />
<ProjectReference Include="..\..\RedisService\RedisService.csproj" />
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
</Project>