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