From 9e6c5f23bfee1ac71d991df38e553cf1c8181942 Mon Sep 17 00:00:00 2001 From: shanj <18996038927@163.com> Date: Sun, 13 Feb 2022 02:43:10 +0800 Subject: [PATCH] =?UTF-8?q?=20=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Binance.TradeRobot.API.csproj | 11 ++ .../CustomExceptionMiddleWare.cs | 91 ++++++++++++ .../Extensions/StartupExtenions.cs | 139 ++++++++++++++++++ .../Filters/ResultFilter.cs | 30 ++++ Binance.TradeRobot.API/NLog.config | 14 ++ Binance.TradeRobot.API/Startup.cs | 37 ++++- Binance.TradeRobot.API/appsettings.json | 6 +- .../Binance.TradeRobot.Business.csproj | 7 + Binance.TradeRobot.Business/NLogManager.cs | 36 +++++ Binance.TradeRobot.Model/Base/ApiResponse.cs | 16 ++ Binance.TradeRobot.Model/Base/Enums.cs | 17 ++- .../Binance.TradeRobot.Model.csproj | 5 +- Binance.TradeRobot.Model/Db/User.cs | 45 ++++++ .../Db/UserAccountFundChangeRecord.cs | 46 ++++++ .../Db/UserAccountProfitLossRecord.cs | 59 ++++++++ .../Db/代码生成/__重新生成.bat | 1 + 16 files changed, 548 insertions(+), 12 deletions(-) create mode 100644 Binance.TradeRobot.API/CustomMiddleWare/CustomExceptionMiddleWare.cs create mode 100644 Binance.TradeRobot.API/Extensions/StartupExtenions.cs create mode 100644 Binance.TradeRobot.API/Filters/ResultFilter.cs create mode 100644 Binance.TradeRobot.API/NLog.config create mode 100644 Binance.TradeRobot.Business/NLogManager.cs create mode 100644 Binance.TradeRobot.Model/Base/ApiResponse.cs create mode 100644 Binance.TradeRobot.Model/Db/User.cs create mode 100644 Binance.TradeRobot.Model/Db/UserAccountFundChangeRecord.cs create mode 100644 Binance.TradeRobot.Model/Db/UserAccountProfitLossRecord.cs create mode 100644 Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat diff --git a/Binance.TradeRobot.API/Binance.TradeRobot.API.csproj b/Binance.TradeRobot.API/Binance.TradeRobot.API.csproj index 05a0c37..a880a34 100644 --- a/Binance.TradeRobot.API/Binance.TradeRobot.API.csproj +++ b/Binance.TradeRobot.API/Binance.TradeRobot.API.csproj @@ -2,8 +2,19 @@ netcoreapp3.1 + True + + + + + + + + + + diff --git a/Binance.TradeRobot.API/CustomMiddleWare/CustomExceptionMiddleWare.cs b/Binance.TradeRobot.API/CustomMiddleWare/CustomExceptionMiddleWare.cs new file mode 100644 index 0000000..3e4657d --- /dev/null +++ b/Binance.TradeRobot.API/CustomMiddleWare/CustomExceptionMiddleWare.cs @@ -0,0 +1,91 @@ +using Binance.TradeRobot.Business; +using Binance.TradeRobot.Model.Base; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Binance.TradeRobot.API.Middlewares +{ + public class CustomExceptionMiddleWare + { + /// + /// 管道请求委托 + /// + private RequestDelegate _next; + + /// + /// 需要处理的状态码字典 + /// + private IDictionary _exceptionStatusCodeDic; + + private NLogManager nLogManager; + + /// + /// + /// + /// + /// + public CustomExceptionMiddleWare(RequestDelegate next, NLogManager nLogManager) + { + _next = next; + this.nLogManager = nLogManager; + _exceptionStatusCodeDic = new Dictionary + { + { 401, "未授权的请求" }, + { 404, "找不到该资源" }, + { 403, "访问被拒绝" }, + { 500, "服务器发生意外的错误" }, + { 503, "服务不可用" } + //其余状态自行扩展 + }; + } + + public async Task Invoke(HttpContext context) + { + try + { + await _next(context); //调用管道执行下一个中间件 + } + catch (Exception ex) + { + if (ex is BusinessException) + { + var busEx = ex as BusinessException; + context.Response.StatusCode = 200; //业务异常时将Http状态码改为200 + await ErrorHandle(context, busEx.Code, busEx.Message); + } + else + { + context.Response.Clear(); + context.Response.StatusCode = 500; //发生未捕获的异常,手动设置状态码 + nLogManager.Default().Error(ex); //记录错误 + } + } + finally + { + if (_exceptionStatusCodeDic.TryGetValue(context.Response.StatusCode, out string exMsg)) + { + await ErrorHandle(context, context.Response.StatusCode, exMsg); + } + } + } + + /// + /// 处理方式:返回Json格式 + /// + /// + /// + /// + /// + private async Task ErrorHandle(HttpContext context, int code, string exMsg) + { + var apiResponse = new ApiResponse() { Code = code, Message = exMsg }; + var serialzeStr = JsonConvert.SerializeObject(apiResponse); + context.Response.ContentType = "application/json"; + await context.Response.WriteAsync(serialzeStr, Encoding.UTF8); + } + } +} diff --git a/Binance.TradeRobot.API/Extensions/StartupExtenions.cs b/Binance.TradeRobot.API/Extensions/StartupExtenions.cs new file mode 100644 index 0000000..53d6a81 --- /dev/null +++ b/Binance.TradeRobot.API/Extensions/StartupExtenions.cs @@ -0,0 +1,139 @@ +using Binance.TradeRobot.API.Middlewares; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Binance.TradeRobot.API.Extensions +{ + public static class StartupExtenions + { + /// + /// 批量注册服务 + /// + /// DI服务 + /// 需要批量注册的程序集集合 + /// 基础类/接口 + /// 服务生命周期 + /// + public static IServiceCollection BatchRegisterService(this IServiceCollection services, Assembly[] assemblys, Type baseType, ServiceLifetime serviceLifetime = ServiceLifetime.Singleton) + { + List typeList = new List(); //所有符合注册条件的类集合 + foreach (var assembly in assemblys) + { + //筛选当前程序集下符合条件的类 + var types = assembly.GetTypes().Where(t => !t.IsInterface && !t.IsSealed && !t.IsAbstract && baseType.IsAssignableFrom(t)); + if (types != null && types.Count() > 0) + typeList.AddRange(types); + } + if (typeList.Count() == 0) + return services; + + var typeDic = new Dictionary(); //待注册集合 + foreach (var type in typeList) + { + var interfaces = type.GetInterfaces(); //获取接口 + typeDic.Add(type, interfaces); + } + if (typeDic.Keys.Count() > 0) + { + foreach (var instanceType in typeDic.Keys) + { + foreach (var interfaceType in typeDic[instanceType]) + { + //根据指定的生命周期进行注册 + services.Add(new ServiceDescriptor(interfaceType, instanceType, serviceLifetime)); + } + } + } + return services; + } + + /// + /// 注册自定义异常中间件 + /// + /// + /// + public static IApplicationBuilder UseCustomException(this IApplicationBuilder app) + { + return app.UseMiddleware(); + } + + /// + /// 添加Swagger服务 + /// + /// + /// + /// + public static IServiceCollection AddSwagger(this IServiceCollection services, string title) + { + return services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo + { + Version = "v1.0.0", + Title = title, + Description = "注意事项\r\n1.返回参数名称采用大驼峰命名\r\n2.ApiResponse为基础返回对象(Code,Data,Message),接口中所有的返回值均属于Data属性\r\n3.正常返回Code=200" + }); + // JWT认证 + c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme + { + Scheme = JwtBearerDefaults.AuthenticationScheme, + BearerFormat = "JWT", + Type = SecuritySchemeType.ApiKey, + Name = "Authorization", + In = ParameterLocation.Header, + Description = "Authorization:Bearer {your JWT token}
", + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme{Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = JwtBearerDefaults.AuthenticationScheme + } + }, + new string[] { } + } + }); + + var executingAssembly = Assembly.GetExecutingAssembly(); + var assemblyNames = executingAssembly.GetReferencedAssemblies().Union(new AssemblyName[] { executingAssembly.GetName() }).ToArray(); + Array.ForEach(assemblyNames, (assemblyName) => + { + //var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlFile = $"{assemblyName.Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + if (!File.Exists(xmlPath)) + return; + c.IncludeXmlComments(xmlPath); + }); + }); + } + + //public static IServiceCollection AddWebSocket(this IServiceCollection services) + //{ + // services.AddSingleton(); + // services.AddSingleton(); + // return services; + //} + + /// + /// 注册websocket中间件 + /// + /// + /// + /// + //public static IApplicationBuilder UseWebSocketMiddleware(this IApplicationBuilder app, WebSocketHandler handler) + //{ + // // return app.Map(path, (_app) => _app.UseMiddleware(handler)); + // return app.UseMiddleware(handler); + //} + } +} diff --git a/Binance.TradeRobot.API/Filters/ResultFilter.cs b/Binance.TradeRobot.API/Filters/ResultFilter.cs new file mode 100644 index 0000000..888915c --- /dev/null +++ b/Binance.TradeRobot.API/Filters/ResultFilter.cs @@ -0,0 +1,30 @@ +using Binance.TradeRobot.Model.Base; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Binance.TradeRobot.API.Filters +{ + public class ResultFilter : IResultFilter + { + public void OnResultExecuted(ResultExecutedContext context) + { + + } + + public void OnResultExecuting(ResultExecutingContext context) + { + if (context.Result is ObjectResult) + { + var objectResult = context.Result as ObjectResult; + if (!(objectResult.Value is ApiResponse)) + { + objectResult.Value = new ApiResponse() { Data = objectResult.Value }; + } + } + else if (context.Result is EmptyResult) + { + context.Result = new ObjectResult(new ApiResponse()); + } + } + } +} diff --git a/Binance.TradeRobot.API/NLog.config b/Binance.TradeRobot.API/NLog.config new file mode 100644 index 0000000..1a5b523 --- /dev/null +++ b/Binance.TradeRobot.API/NLog.config @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Binance.TradeRobot.API/Startup.cs b/Binance.TradeRobot.API/Startup.cs index 7d66225..c0ee4a2 100644 --- a/Binance.TradeRobot.API/Startup.cs +++ b/Binance.TradeRobot.API/Startup.cs @@ -1,15 +1,11 @@ +using Binance.TradeRobot.API.Filters; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using Newtonsoft.Json.Serialization; +using Yitter.IdGenerator; namespace Binance.TradeRobot.API { @@ -25,7 +21,32 @@ namespace Binance.TradeRobot.API // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); + var fsql = new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.SqlServer, Configuration.GetConnectionString("DB")).Build(); + services.AddSingleton(typeof(IFreeSql), fsql); + + var idOption = new IdGeneratorOptions(1); + var idGenerator = new DefaultIdGenerator(idOption); + services.AddSingleton(typeof(IIdGenerator), idGenerator); + + services.AddHttpContextAccessor(); + services.AddHttpClient(); + services.AddCors(options => + { + options.AddDefaultPolicy(p => + { + p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); + }); + }); + services.AddControllers(configure => + { + configure.Filters.Add(); + }).AddNewtonsoftJson(setupAction => + { + setupAction.SerializerSettings.ContractResolver = new DefaultContractResolver(); + setupAction.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + setupAction.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include; + setupAction.SerializerSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Include; + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/Binance.TradeRobot.API/appsettings.json b/Binance.TradeRobot.API/appsettings.json index d9d9a9b..c97a722 100644 --- a/Binance.TradeRobot.API/appsettings.json +++ b/Binance.TradeRobot.API/appsettings.json @@ -6,5 +6,9 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + //"DB": "Data Source=192.168.201.44;Initial Catalog=HY.TradingRobot.DB;User ID=sa;Pwd=kaicn1132+-;" + "DB": "Data Source=.;Initial Catalog=Binance.TradeRobot.DB;User ID=sa;Pwd=pc911103;" + } } diff --git a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj index 6f073a2..10ef69a 100644 --- a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj +++ b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj @@ -5,6 +5,13 @@ enable + + + + + + + diff --git a/Binance.TradeRobot.Business/NLogManager.cs b/Binance.TradeRobot.Business/NLogManager.cs new file mode 100644 index 0000000..b92a168 --- /dev/null +++ b/Binance.TradeRobot.Business/NLogManager.cs @@ -0,0 +1,36 @@ +using NLog; +using System.Collections.Generic; + +namespace Binance.TradeRobot.Business +{ + public class NLogManager + { + private IDictionary loggerDictionary = new Dictionary(); + private string defaultLoggerName = "default"; + + public NLogManager() + { + loggerDictionary = new Dictionary() + { + { "default",NLog.LogManager.GetLogger(defaultLoggerName)} + }; + } + + public ILogger Default() + { + return loggerDictionary[defaultLoggerName]; + } + + public ILogger GetLogger(string loggerName) + { + if (string.IsNullOrEmpty(loggerName)) + return Default(); + if (!loggerDictionary.TryGetValue(loggerName, out ILogger logger)) + { + logger = NLog.LogManager.GetLogger(loggerName); + loggerDictionary.TryAdd(loggerName, logger); + } + return logger; + } + } +} diff --git a/Binance.TradeRobot.Model/Base/ApiResponse.cs b/Binance.TradeRobot.Model/Base/ApiResponse.cs new file mode 100644 index 0000000..ad31899 --- /dev/null +++ b/Binance.TradeRobot.Model/Base/ApiResponse.cs @@ -0,0 +1,16 @@ +namespace Binance.TradeRobot.Model.Base +{ + public class ApiResponse + { + public int Code { get; set; } = 200; + + public T Data { get; set; } + + public string Message { get; set; } + } + + public class ApiResponse : ApiResponse + { + + } +} diff --git a/Binance.TradeRobot.Model/Base/Enums.cs b/Binance.TradeRobot.Model/Base/Enums.cs index 32b3399..d3a6d44 100644 --- a/Binance.TradeRobot.Model/Base/Enums.cs +++ b/Binance.TradeRobot.Model/Base/Enums.cs @@ -4,6 +4,21 @@ namespace Binance.TradeRobot.Model.Base { public class Enums { + #region 基本 + public enum BusinessType + { + /// + /// 现货 + /// + Spot = 0, + /// + /// 合约 + /// + Prep = 1 + } + + #endregion + #region 用户资金 /// /// 资金变更类型 追投=0,提现=1,转移=2 @@ -40,9 +55,7 @@ namespace Binance.TradeRobot.Model.Base /// public enum RobotStatus { - [Description("停止")] Stop = 0, - [Description("运行中")] Runing = 1 } #endregion diff --git a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.csproj b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.csproj index 2f1c21b..d3054bb 100644 --- a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.csproj +++ b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.csproj @@ -6,8 +6,11 @@ - + + + + diff --git a/Binance.TradeRobot.Model/Db/User.cs b/Binance.TradeRobot.Model/Db/User.cs new file mode 100644 index 0000000..d327eaa --- /dev/null +++ b/Binance.TradeRobot.Model/Db/User.cs @@ -0,0 +1,45 @@ +using FreeSql.DataAnnotations; +using System; + +namespace Binance.TradeRobot.Model.Db +{ + + [Table(DisableSyncStructure = true)] + public partial class User { + + [Column(IsPrimary = true)] + public long Id { get; set; } + + /// + /// 投资本金 + /// + [ Column(DbType = "decimal(18,8)")] + public decimal CostAmount { get; set; } = 0.0M; + + [Column(InsertValueSql = "getdate()")] + public DateTime? CreateTime { get; set; } + + /// + /// 收益 + /// + [Column(DbType = "decimal(18,8)")] + public decimal Profit { get; set; } = 0.0M; + + [Column(StringLength = 20)] + public string Pwd { get; set; } + + [Column(InsertValueSql = "getdate()")] + public DateTime? UpdateTime { get; set; } + + [Column(StringLength = 20)] + public string UserName { get; set; } + + /// + /// 提前金额 + /// + [Column(DbType = "decimal(18,8)")] + public decimal WithdrawAmount { get; set; } = 0.0M; + + } + +} diff --git a/Binance.TradeRobot.Model/Db/UserAccountFundChangeRecord.cs b/Binance.TradeRobot.Model/Db/UserAccountFundChangeRecord.cs new file mode 100644 index 0000000..0475840 --- /dev/null +++ b/Binance.TradeRobot.Model/Db/UserAccountFundChangeRecord.cs @@ -0,0 +1,46 @@ +using Binance.TradeRobot.Model.Base; +using FreeSql.DataAnnotations; +using System; + +namespace Binance.TradeRobot.Model.Db +{ + + [Table(DisableSyncStructure = true)] + public partial class UserAccountFundChangeRecord + { + + [Column(IsPrimary = true)] + public long Id { get; set; } + + /// + /// 变更金额 + /// + [Column(DbType = "decimal(18,8)")] + public decimal ChangeAmount { get; set; } + + [Column(InsertValueSql = "getdate()")] + public DateTime? CreateTime { get; set; } + + [Column(MapType = typeof(int))] + public Enums.FundDirection Direction { get; set; } + + [Column(MapType = typeof(int))] + public Enums.CapitalChangeType OperationType { get; set; } + + /// + /// 操作者Id + /// + public long OperationUserId { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 对端用户Id + /// + public long? ToUserId { get; set; } + } + +} diff --git a/Binance.TradeRobot.Model/Db/UserAccountProfitLossRecord.cs b/Binance.TradeRobot.Model/Db/UserAccountProfitLossRecord.cs new file mode 100644 index 0000000..3d74bf3 --- /dev/null +++ b/Binance.TradeRobot.Model/Db/UserAccountProfitLossRecord.cs @@ -0,0 +1,59 @@ +using Binance.TradeRobot.Model.Base; +using FreeSql.DataAnnotations; +using System; + +namespace Binance.TradeRobot.Model.Db +{ + + [Table(DisableSyncStructure = true)] + public partial class UserAccountProfitLossRecord + { + + /// + /// 业务类型 + /// + [Column(MapType = typeof(int))] + public Enums.BusinessType BusinessType { get; set; } + + /// + /// 变更金额 + /// + [Column(DbType = "decimal(18,8)")] + public decimal ChangeAmount { get; set; } = 0.0M; + + [Column(InsertValueSql = "getdate()")] + public DateTime? CreateTime { get; set; } + + /// + /// 分红比例 + /// + [Column(DbType = "decimal(18,2)")] + public decimal DividendRatio { get; set; } = 0.0M; + + + public long? Id { get; set; } + + + public long OrderId { get; set; } + + /// + /// 订单利润 + /// + [Column(DbType = "decimal(18,8)")] + public decimal OrderProfit { get; set; } = 0.0M; + + + public long RobotId { get; set; } + + + public long UserId { get; set; } + + /// + /// 用户投资收益 + /// + [Column(DbType = "decimal(18,8)")] + public decimal UserProfit { get; set; } = 0.0M; + + } + +} diff --git a/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat b/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat new file mode 100644 index 0000000..00aec37 --- /dev/null +++ b/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat @@ -0,0 +1 @@ +FreeSql.Generator -Razor 1 -NameOptions 1,0,0,0 -NameSpace Binance.TradeRobot.Model.Db -DB "SqlServer,data source=.;initial catalog=Binance.TradeRobot.DB;User Id=sa;Password=pc911103;TrustServerCertificate=true;pooling=true;max pool size=2" -FileName "{name}.cs"