first commit

This commit is contained in:
izory
2021-08-23 16:57:25 +08:00
commit 1845017b67
480 changed files with 37611 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Security.Claims;
namespace Infrastructure
{
public static class App
{
/// <summary>
/// 服务提供器
/// </summary>
public static IServiceProvider ServiceProvider => HttpContext?.RequestServices ?? InternalApp.InternalServices.BuildServiceProvider();
/// <summary>
/// 获取请求上下文
/// </summary>
public static HttpContext HttpContext => HttpContextLocal.Current();
/// <summary>
/// 获取请求上下文用户
/// </summary>
public static ClaimsPrincipal User => HttpContext?.User;
/// <summary>
/// 获取请求生命周期的服务
/// </summary>
/// <typeparam name="TService"></typeparam>
/// <returns></returns>
public static TService GetService<TService>()
where TService : class
{
return GetService(typeof(TService)) as TService;
}
/// <summary>
/// 获取请求生命周期的服务
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static object GetService(Type type)
{
return ServiceProvider.GetService(type);
}
/// <summary>
/// 获取请求生命周期的服务
/// </summary>
/// <typeparam name="TService"></typeparam>
/// <returns></returns>
public static TService GetRequiredService<TService>()
where TService : class
{
return GetRequiredService(typeof(TService)) as TService;
}
/// <summary>
/// 获取请求生命周期的服务
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static object GetRequiredService(Type type)
{
return ServiceProvider.GetRequiredService(type);
}
}
}
@@ -0,0 +1,59 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
namespace Microsoft.AspNetCore.Http
{
public static class HttpContextLocal
{
private static Func<object> _asyncLocalAccessor;
private static Func<object, object> _holderAccessor;
private static Func<object, HttpContext> _httpContextAccessor;
/// <summary>
/// 获取当前 HttpContext 对象
/// </summary>
/// <returns></returns>
public static HttpContext Current()
{
var asyncLocal = (_asyncLocalAccessor ??= CreateAsyncLocalAccessor())();
if (asyncLocal == null) return null;
var holder = (_holderAccessor ??= CreateHolderAccessor(asyncLocal))(asyncLocal);
if (holder == null) return null;
return (_httpContextAccessor ??= CreateHttpContextAccessor(holder))(holder);
// 创建异步本地访问器
static Func<object> CreateAsyncLocalAccessor()
{
var fieldInfo = typeof(HttpContextAccessor).GetField("_httpContextCurrent", BindingFlags.Static | BindingFlags.NonPublic);
var field = Expression.Field(null, fieldInfo);
return Expression.Lambda<Func<object>>(field).Compile();
}
// 创建常驻 HttpContext 访问器
static Func<object, object> CreateHolderAccessor(object asyncLocal)
{
var holderType = asyncLocal.GetType().GetGenericArguments()[0];
var method = typeof(AsyncLocal<>).MakeGenericType(holderType).GetProperty("Value").GetGetMethod();
var target = Expression.Parameter(typeof(object));
var convert = Expression.Convert(target, asyncLocal.GetType());
var getValue = Expression.Call(convert, method);
return Expression.Lambda<Func<object, object>>(getValue, target).Compile();
}
// 获取 HttpContext 访问器
static Func<object, HttpContext> CreateHttpContextAccessor(object holder)
{
var target = Expression.Parameter(typeof(object));
var convert = Expression.Convert(target, holder.GetType());
var field = Expression.Field(convert, "Context");
var convertAsResult = Expression.Convert(field, typeof(HttpContext));
return Expression.Lambda<Func<object, HttpContext>>(convertAsResult, target).Compile();
}
}
}
}
@@ -0,0 +1,34 @@
using System;
namespace Infrastructure.Attribute
{
/// <summary>
/// 参考地址:https://www.cnblogs.com/kelelipeng/p/10643556.html
/// 标记服务
/// 如何使用?
/// 1、如果服务是本身 直接在类上使用[AppService]
/// 2、如果服务是接口 在类上使用 [AppService(ServiceType = typeof(实现接口))]
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : System.Attribute
{
/// <summary>
/// 服务声明周期
/// 不给默认值的话注册的是AddSingleton
/// </summary>
public LifeTime ServiceLifetime { get; set; } = LifeTime.Scoped;
/// <summary>
/// 指定服务类型
/// </summary>
public Type ServiceType { get; set; }
/// <summary>
/// 是否可以从第一个接口获取服务类型
/// </summary>
public bool InterfaceServiceType { get; set; }
}
public enum LifeTime
{
Transient, Scoped, Singleton
}
}
+25
View File
@@ -0,0 +1,25 @@
using Infrastructure.Enums;
namespace Infrastructure.Attribute
{
/// <summary>
/// 自定义操作日志记录注解
/// </summary>
public class LogAttribute : System.Attribute
{
public string Title { get; set; }
public BusinessType BusinessType { get; set; }
public LogAttribute() { }
public LogAttribute(string name)
{
Title = name;
}
public LogAttribute(string name, BusinessType businessType)
{
Title = name;
BusinessType = businessType;
}
}
}
+75
View File
@@ -0,0 +1,75 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
/// <summary>
/// 需要引用包
/// Microsoft.Extensions.Configuration;
/// Microsoft.Extensions.DependencyInjection;
namespace Infrastructure
{
public class ConfigUtils
{
#region 单例访问
static ConfigUtils()
{
Config = App.ServiceProvider.GetRequiredService<IConfiguration>();
if (Instance == null)
Instance = new ConfigUtils();
}
public static ConfigUtils Instance { get; private set; }
#endregion
private static IConfiguration Config { get; set; }
/// <summary>
/// 泛型读取配置文件
/// 目前还不能绑定到实体类
/// </summary>
/// <param name="defaultValue">获取不到配置文件设定默认值</param>
/// <param name="key">要获取的配置文件节点名称</param>
/// <returns></returns>
//public T GetConfig<T>(string key, T defaultValue = default)
//{
// //GetValue扩展包需要安装Microsoft.Extensions.Configuration
// var setting = Config.GetValue(key, defaultValue);
// Console.WriteLine($"获取配置文件值key={key},value={setting}");
// return setting;
//}
public T GetAppConfig<T>(string key, T defaultValue = default(T))
{
T setting = (T)Convert.ChangeType(Config[key], typeof(T));
var value = setting;
if (setting == null)
value = defaultValue;
//Console.WriteLine($"获取配置文件值key={key},value={value}");
return value;
}
/// <summary>
/// 获取配置文件
/// </summary>
/// <param name="key">eg: WeChat:Token</param>
/// <returns></returns>
public string GetConfig(string key)
{
return Config[key];
}
/// <summary>
/// 获取数据库字符串连接串
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetConnectionStrings(string key)
{
return Config.GetConnectionString(key);
}
}
}
+88
View File
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Infrastructure.Constant
{
public class HttpStatus
{
/// <summary>
/// 操作成功
/// </summary>
public static readonly int SUCCESS = 200;
/// <summary>
/// 对象创建成功
/// </summary>
public static readonly int CREATED = 201;
/// <summary>
/// 请求已经被接受
/// </summary>
public static readonly int ACCEPTED = 202;
/// <summary>
/// 操作已经执行成功,但是没有返回数据
/// </summary>
public static readonly int NO_CONTENT = 204;
/// <summary>
/// 资源已被移除
/// </summary>
public static readonly int MOVED_PERM = 301;
/// <summary>
/// 重定向
/// </summary>
public static readonly int SEE_OTHER = 303;
/// <summary>
/// 资源没有被修改
/// </summary>
public static readonly int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
public static readonly int BAD_REQUEST = 400;
/// <summary>
/// 未授权
/// </summary>
public static readonly int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
public static readonly int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
public static readonly int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static readonly int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
public static readonly int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
public static readonly int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static readonly int ERROR = 500;
/**
* 接口未实现
*/
public static readonly int NOT_IMPLEMENTED = 501;
}
}
@@ -0,0 +1,37 @@
using System;
namespace Infrastructure
{
public class CustomException : Exception
{
public int Code { get; set; }
public string Msg { get; set; }
public string LogMsg { get; set; }
public CustomException(string msg) : base(msg)
{
}
public CustomException(int code, string msg) : base(msg)
{
Code = code;
Msg = msg;
}
public CustomException(ResultCode resultCode, string msg) : base(msg)
{
Code = (int)resultCode;
}
/// <summary>
/// 自定义异常
/// </summary>
/// <param name="resultCode"></param>
/// <param name="msg"></param>
/// <param name="errorMsg">用于记录详细日志到输出介质</param>
public CustomException(ResultCode resultCode, string msg, object errorMsg) : base(msg)
{
Code = (int)resultCode;
LogMsg = errorMsg.ToString();
}
}
}
@@ -0,0 +1,51 @@
using System.ComponentModel;
namespace Infrastructure
{
public enum ResultCode
{
[Description("success")]
SUCCESS = 200,
[Description("参数错误")]
PARAM_ERROR = 101,
[Description("验证码错误")]
CAPTCHA_ERROR = 103,
[Description("登录错误")]
LOGIN_ERROR = 105,
[Description("NO_DATA")]
NODATA = 106,
FAIL = 1,
[Description("服务端出错啦")]
GLOBAL_ERROR = 500,
[Description("请先绑定手机号")]
NOBIND_PHONENUM = 102,
[Description("自定义异常")]
CUSTOM_ERROR = 110,
[Description("非法签名")]
SIGN_ERROR = 110,
[Description("非法请求")]
INVALID_REQUEST = 116,
[Description("授权失败")]
OAUTH_FAIL = 201,
[Description("未授权")]
DENY = 401,
[Description("授权访问失败")]
FORBIDDEN = 403,
[Description("Bad Request")]
BAD_REQUEST = 400
}
}
+64
View File
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Infrastructure.Enums
{
/**
* 业务操作类型
* 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据
* @author zrry
*/
public enum BusinessType
{
/**
* 其它
*/
OTHER = 0,
/**
* 新增
*/
INSERT = 1,
/**
* 修改
*/
UPDATE = 2,
/**
* 删除
*/
DELETE = 3,
/**
* 授权
*/
GRANT = 4,
/**
* 导出
*/
EXPORT = 5,
/**
* 导入
*/
IMPORT = 6,
/**
* 强退
*/
FORCE = 7,
/**
* 生成代码
*/
GENCODE = 8,
/**
* 清空数据
*/
CLEAN = 9,
}
}
@@ -0,0 +1,71 @@
using Infrastructure.Attribute;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Reflection;
namespace Infrastructure.Extensions
{
public static class AppServiceExtensions
{
/// <summary>
/// 注册引用程序域中所有有AppService标记的类的服务
/// </summary>
/// <param name="services"></param>
public static void AddAppService(this IServiceCollection services)
{
//var assemblies = AppDomain.CurrentDomain.GetAssemblies();
string []cls = new string[] { "ZR.Repository", "ZR.Service", "ZR.Tasks" };
foreach (var item in cls)
{
Assembly assembly = Assembly.Load(item);
Register(services, assembly);
}
}
private static void Register(IServiceCollection services, Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
var serviceAttribute = type.GetCustomAttribute<AppServiceAttribute>();
if (serviceAttribute != null)
{
var serviceType = serviceAttribute.ServiceType;
//情况1 适用于依赖抽象编程,注意这里只获取第一个
if (serviceType == null && serviceAttribute.InterfaceServiceType)
{
serviceType = type.GetInterfaces().FirstOrDefault();
}
//情况2 不常见特殊情况下才会指定ServiceType,写起来麻烦
if (serviceType == null)
{
serviceType = type;
}
switch (serviceAttribute.ServiceLifetime)
{
case LifeTime.Singleton:
services.AddSingleton(serviceType, type);
break;
case LifeTime.Scoped:
services.AddScoped(serviceType, type);
break;
case LifeTime.Transient:
services.AddTransient(serviceType, type);
break;
default:
services.AddTransient(serviceType, type);
break;
}
Console.WriteLine($"注册:{serviceType}");
}
else
{
//Console.WriteLine($"注册:{serviceType}");
}
}
}
}
}
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Infrastructure.Extensions
{
public static class StringExtension
{
/// <summary>
/// SQL条件拼接
/// </summary>
/// <param name="str"></param>
/// <param name="condition"></param>
/// <returns></returns>
public static string If(this string str, bool condition)
{
return condition ? str : string.Empty;
}
/// <summary>
/// 判断是否为空
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool IfNotEmpty(this string str)
{
return !string.IsNullOrEmpty(str);
}
}
}
+17
View File
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Infrastructure
{
/// <summary>
/// 全局静态常量
/// </summary>
public class GlobalConstant
{
/// <summary>
/// 管理员权限
/// </summary>
public static string AdminPerm = "*:*:*";
}
}
+14
View File
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AspectCore.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
</Project>
+29
View File
@@ -0,0 +1,29 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Infrastructure
{
public static class InternalApp
{
/// <summary>
/// 应用服务
/// </summary>
internal static IServiceCollection InternalServices;
/// <summary>
/// 全局配置构建器
/// </summary>
internal static IConfigurationBuilder ConfigurationBuilder;
/// <summary>
/// 获取Web主机环境
/// </summary>
//internal static IWebHostEnvironment WebHostEnvironment;
/// <summary>
/// 获取泛型主机环境
/// </summary>
internal static IHostEnvironment HostEnvironment;
}
}
+120
View File
@@ -0,0 +1,120 @@
using Infrastructure.Constant;
using Newtonsoft.Json;
namespace Infrastructure.Model
{
public class ApiResult
{
public int Code { get; set; }
public string Msg { get; set; }
/// <summary>
/// 如果data值为null,则忽略序列化将不会返回data字段
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public object Data { get; set; }
/// <summary>
/// 初始化一个新创建的APIResult对象,使其表示一个空消息
/// </summary>
public ApiResult()
{
}
/// <summary>
/// 初始化一个新创建的 ApiResult 对象
/// </summary>
/// <param name="code"></param>
/// <param name="msg"></param>
public ApiResult(int code, string msg)
{
Code = code;
Msg = msg;
}
/// <summary>
/// 初始化一个新创建的 ApiResult 对象
/// </summary>
/// <param name="code"></param>
/// <param name="msg"></param>
public ApiResult(int code, string msg, object data)
{
Code = code;
Msg = msg;
if (data != null)
{
Data = data;
}
}
/// <summary>
/// 返回成功消息
/// </summary>
/// <returns></returns>
public ApiResult Success()
{
Code = (int)ResultCode.SUCCESS;
Msg = "success";
return this;
}
/// <summary>
/// 返回成功消息
/// </summary>
/// <param name="data">数据对象</param>
/// <returns>成功消息</returns>
public static ApiResult Success(object data) { return new ApiResult(HttpStatus.SUCCESS, "success", data); }
/// <summary>
/// 返回成功消息
/// </summary>
/// <param name="msg">返回内容</param>
/// <returns>成功消息</returns>
public static ApiResult Success(string msg) { return new ApiResult(HttpStatus.SUCCESS, msg, null); }
/// <summary>
/// 返回成功消息
/// </summary>
/// <param name="msg">返回内容</param>
/// <param name="data">数据对象</param>
/// <returns>成功消息</returns>
public static ApiResult Success(string msg, object data) { return new ApiResult(HttpStatus.SUCCESS, msg, data); }
/// <summary>
/// 访问被拒
/// </summary>
/// <param name="apiResult"></param>
/// <returns></returns>
public ApiResult On401()
{
Code = (int)ResultCode.DENY;
Msg = "access denyed";
return this;
}
public ApiResult Error(ResultCode resultCode, string msg = "")
{
Code = (int)resultCode;
Msg = msg;
return this;
}
/// <summary>
/// 返回失败消息
/// </summary>
/// <param name="code"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static ApiResult Error(int code, string msg) { return new ApiResult(code, msg); }
/// <summary>
/// 返回失败消息
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static ApiResult Error(string msg) { return new ApiResult((int)ResultCode.CUSTOM_ERROR, msg); }
}
public class ApiResult<T> : ApiResult
{
public T Result { get; set; }
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Infrastructure.Model
{
/// <summary>
/// 分页参数
/// </summary>
public class PagedInfo<T>
{
/// <summary>
/// 每页行数
/// </summary>
public int PageSize { get; set; } = 10;
/// <summary>
/// 当前页
/// </summary>
public int PageIndex { get; set; } = 1;
/// <summary>
/// 排序列
/// </summary>
//public string Sort { get; set; }
/// <summary>
/// 排序类型
/// </summary>
//public string SortType { get; set; }
/// <summary>
/// 总记录数
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 总页数
/// </summary>
//public int TotalPage
//{
// get
// {
// if (TotalCount > 0)
// {
// return TotalCount % this.PageSize == 0 ? TotalCount / this.PageSize : TotalCount / this.PageSize + 1;
// }
// else
// {
// return 0;
// }
// }
// set { }
//}
public int TotalPage { get; set; }
public List<T> Result { get; set; }
public PagedInfo()
{
}
public PagedInfo(List<T> source, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = source.Count;
TotalPage = (int)Math.Ceiling(TotalCount / (double)PageSize);//计算总页数
}
}
}
+59
View File
@@ -0,0 +1,59 @@
namespace Infrastructure
{
/// <summary>
/// 获取配置文件POCO实体类
/// </summary>
public class OptionsSetting
{
public static string ConnAdmin = "Conn_admin";
public static string DbType = "DbType";
public static string DbKey = "DbKey";
public string Conn_Admin { get; set; }
public string AppName { get; set; }
/// <summary>
/// 主库
/// </summary>
public string Master { get; set; }
public string Redis { get; set; }
public string Database { get; set; }
/// <summary>
/// 是否演示模式
/// </summary>
public bool DemoMode { get; set; }
public MailOptions MailOptions { get; set; }
public Upload Upload { get; set; }
public ALYUN_OCS ALYUN_OCS { get; set; }
}
/// <summary>
/// 发送邮件数据配置
/// </summary>
public class MailOptions
{
public string From { get; set; }
public string Password { get; set; }
public string Host { get; set; }
public int Port { get; set; }
}
/// <summary>
/// 上传
/// </summary>
public class Upload
{
public string UploadDirectory { get; set; }
public string UploadUrl { get; set; }
}
/// <summary>
/// 阿里云存储
/// </summary>
public class ALYUN_OCS
{
public string REGIONID { get; set; }
public string KEY { get; set; }
public string SECRET { get; set; }
}
}
@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Infrastructure.Startups
{
/// <summary>
/// Program.cs里面的HostBuilder扩展
/// </summary>
public static class HostBuilderExtensions
{
/// <summary>
/// Web 主机注入
/// </summary>
/// <param name="hostBuilder">Web主机构建器</param>
/// <param name="assemblyName">外部程序集名称,如果HostingStartup存在多个程序集中可以使用;分隔,比如HostStartupLib;HostStartupLib2</param>
/// <returns>IWebHostBuilder</returns>
public static IWebHostBuilder Init(this IWebHostBuilder hostBuilder, string assemblyName)
{
hostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, assemblyName);
return hostBuilder;
}
/// <summary>
/// 初始化程序扩展
/// </summary>
/// <param name="builder"></param>
public static void UseAppStartup(this IWebHostBuilder hostBuilder)
{
System.Console.WriteLine("启动类执行了");
// 自动装载配置
hostBuilder.ConfigureAppConfiguration((hostingContext, config) =>
{
// 存储环境对象
InternalApp.HostEnvironment = (IHostEnvironment)hostingContext.HostingEnvironment;
// 加载配置
//InternalApp.AddConfigureFiles(config, InternalApp.WebHostEnvironment);
});
// 自动注入 AddApp() 服务
hostBuilder.ConfigureServices((services) =>
{
// 注册 Startup 过滤器
//services.AddTransient<IStartupFilter, StartupFilter>();
// 添加全局配置和存储服务提供器
InternalApp.InternalServices = services;
// 初始化应用服务
//services.AddApp();
});
}
}
}
+40
View File
@@ -0,0 +1,40 @@
using Infrastructure.Startups;
using Microsoft.AspNetCore.Hosting;
//通过HostingStartup指定要启动的类型
[assembly: HostingStartup(typeof(HostingStartup))]
namespace Infrastructure.Startups
{
public class HostingStartup : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
System.Console.WriteLine("启动类执行了");
// 自动装载配置
builder.ConfigureAppConfiguration((hostingContext, config) =>
{
// 存储环境对象
//InternalApp.HostEnvironment = hostingContext.HostingEnvironment;
//InternalApp.HostEnvironment = (Microsoft.Extensions.Hosting.IHostEnvironment)hostingContext.HostingEnvironment;
// 加载配置
//InternalApp.AddConfigureFiles(config, InternalApp.WebHostEnvironment);
InternalApp.ConfigurationBuilder = config;
});
// 自动注入 AddApp() 服务
builder.ConfigureServices(services =>
{
// 注册 Startup 过滤器
//services.AddTransient<IStartupFilter, StartupFilter>();
// 添加全局配置和存储服务提供器
InternalApp.InternalServices = services;
// 初始化应用服务
//services.AddApp();
});
}
}
}