diff --git a/PaySharp.sln b/PaySharp.sln index 68fcab9..0608125 100644 --- a/PaySharp.sln +++ b/PaySharp.sln @@ -13,14 +13,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.Core.Mvc", "src\Pa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.Wechatpay", "src\PaySharp.Wechatpay\PaySharp.Wechatpay.csproj", "{DC8772E4-9F01-4744-93A3-0A795117418C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.UnitTest", "test\PaySharp.UnitTest\PaySharp.UnitTest.csproj", "{B9DD57BE-96FC-4F78-99E9-99CEAD33CC5F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.Demo", "sample\PaySharp.Demo\PaySharp.Demo.csproj", "{8A0208C0-7046-44A7-A67F-DA122AB280A3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.Qpay", "src\PaySharp.Qpay\PaySharp.Qpay.csproj", "{E63F24B7-C8EE-4E92-8897-38FB117CE371}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaySharp.Demo(Net)", "sample\PaySharp.Demo(Net)\PaySharp.Demo(Net).csproj", "{C5D9D464-563B-44FC-A115-25889A73CA23}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.AspNetCore", "src\PaySharp.AspNetCore\PaySharp.AspNetCore.csproj", "{E649A330-1B5C-487B-99F7-208248161B8F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaySharp.AspNet", "src\PaySharp.AspNet\PaySharp.AspNet.csproj", "{D20AC625-43A7-45A1-A111-81C3EDC7F6A5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9B98CFC6-581C-4006-ADB5-A757694915EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaySharp.UnitTest", "test\PaySharp.UnitTest\PaySharp.UnitTest.csproj", "{909EE2D9-5B9E-444B-91DF-A8E35F4D1076}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaySharp.AspNetCoreTest", "test\PaySharp.AspNetCoreTest\PaySharp.AspNetCoreTest.csproj", "{7695B8A5-2737-444A-AC7B-09E43B09B9D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,10 +55,6 @@ Global {DC8772E4-9F01-4744-93A3-0A795117418C}.Debug|Any CPU.Build.0 = Debug|Any CPU {DC8772E4-9F01-4744-93A3-0A795117418C}.Release|Any CPU.ActiveCfg = Release|Any CPU {DC8772E4-9F01-4744-93A3-0A795117418C}.Release|Any CPU.Build.0 = Release|Any CPU - {B9DD57BE-96FC-4F78-99E9-99CEAD33CC5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B9DD57BE-96FC-4F78-99E9-99CEAD33CC5F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B9DD57BE-96FC-4F78-99E9-99CEAD33CC5F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B9DD57BE-96FC-4F78-99E9-99CEAD33CC5F}.Release|Any CPU.Build.0 = Release|Any CPU {8A0208C0-7046-44A7-A67F-DA122AB280A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8A0208C0-7046-44A7-A67F-DA122AB280A3}.Debug|Any CPU.Build.0 = Debug|Any CPU {8A0208C0-7046-44A7-A67F-DA122AB280A3}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -63,10 +67,30 @@ Global {C5D9D464-563B-44FC-A115-25889A73CA23}.Debug|Any CPU.Build.0 = Debug|Any CPU {C5D9D464-563B-44FC-A115-25889A73CA23}.Release|Any CPU.ActiveCfg = Release|Any CPU {C5D9D464-563B-44FC-A115-25889A73CA23}.Release|Any CPU.Build.0 = Release|Any CPU + {E649A330-1B5C-487B-99F7-208248161B8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E649A330-1B5C-487B-99F7-208248161B8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E649A330-1B5C-487B-99F7-208248161B8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E649A330-1B5C-487B-99F7-208248161B8F}.Release|Any CPU.Build.0 = Release|Any CPU + {D20AC625-43A7-45A1-A111-81C3EDC7F6A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D20AC625-43A7-45A1-A111-81C3EDC7F6A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D20AC625-43A7-45A1-A111-81C3EDC7F6A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D20AC625-43A7-45A1-A111-81C3EDC7F6A5}.Release|Any CPU.Build.0 = Release|Any CPU + {909EE2D9-5B9E-444B-91DF-A8E35F4D1076}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {909EE2D9-5B9E-444B-91DF-A8E35F4D1076}.Debug|Any CPU.Build.0 = Debug|Any CPU + {909EE2D9-5B9E-444B-91DF-A8E35F4D1076}.Release|Any CPU.ActiveCfg = Release|Any CPU + {909EE2D9-5B9E-444B-91DF-A8E35F4D1076}.Release|Any CPU.Build.0 = Release|Any CPU + {7695B8A5-2737-444A-AC7B-09E43B09B9D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7695B8A5-2737-444A-AC7B-09E43B09B9D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7695B8A5-2737-444A-AC7B-09E43B09B9D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7695B8A5-2737-444A-AC7B-09E43B09B9D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {909EE2D9-5B9E-444B-91DF-A8E35F4D1076} = {9B98CFC6-581C-4006-ADB5-A757694915EF} + {7695B8A5-2737-444A-AC7B-09E43B09B9D9} = {9B98CFC6-581C-4006-ADB5-A757694915EF} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {35DA7CB4-3AB7-45FF-93D2-DBC4760221EF} EndGlobalSection diff --git a/src/PaySharp.Alipay/DI/PaySharpBuilderExtensions.cs b/src/PaySharp.Alipay/DI/PaySharpBuilderExtensions.cs new file mode 100644 index 0000000..f207e84 --- /dev/null +++ b/src/PaySharp.Alipay/DI/PaySharpBuilderExtensions.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PaySharp.Abstractions; +using PaySharp.Alipay.DI.fake; + +namespace PaySharp.Alipay +{ + public static class PaySharpBuilderExtensions + { + public static IPaySharpBuilder AddAlipay(this IPaySharpBuilder builder,Merchant option) + { + builder.AddOption(option); + builder.TryAddService(); + builder.TryAddService(); + builder.TryAddService(); + return builder; + } + } +} diff --git a/src/PaySharp.Alipay/DI/PaySharpProviderExtensions.cs b/src/PaySharp.Alipay/DI/PaySharpProviderExtensions.cs new file mode 100644 index 0000000..04fed5b --- /dev/null +++ b/src/PaySharp.Alipay/DI/PaySharpProviderExtensions.cs @@ -0,0 +1,29 @@ +using PaySharp.Abstractions; +using PaySharp.Alipay.DI.fake; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI +{ + public static class PaySharpProviderExtensions + { + public static IAlipayClient CreateAlipayClient(this IPaySharpProvider provider) + { + var option = provider.GetRequired(); + return CreateAlipayClient(provider,option); + } + public static IAlipayClient CreateAlipayClient(this IPaySharpProvider provider,Merchant merchant) + { + var factory = provider.GetRequired(); + return factory.CreateClient(merchant); + } + + public static IAlipayListener CreateAlipayListener(this IPaySharpProvider provider,Merchant merchant) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/PaySharp.Alipay/DI/fake/AlipayFactory.cs b/src/PaySharp.Alipay/DI/fake/AlipayFactory.cs new file mode 100644 index 0000000..b7b659e --- /dev/null +++ b/src/PaySharp.Alipay/DI/fake/AlipayFactory.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI.fake +{ + class AlipayFactory + { + public IAlipayClient CreateClient(Merchant merchant) + { + throw new NotImplementedException(); + } + public IAlipayListener CreateListener(Merchant merchant) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/PaySharp.Alipay/DI/fake/FakeAlipayClient.cs b/src/PaySharp.Alipay/DI/fake/FakeAlipayClient.cs new file mode 100644 index 0000000..62d56b0 --- /dev/null +++ b/src/PaySharp.Alipay/DI/fake/FakeAlipayClient.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI.fake +{ + class FakeAlipayClient:IAlipayClient + { + } +} diff --git a/src/PaySharp.Alipay/DI/fake/FakeAlipayListener.cs b/src/PaySharp.Alipay/DI/fake/FakeAlipayListener.cs new file mode 100644 index 0000000..e5fe250 --- /dev/null +++ b/src/PaySharp.Alipay/DI/fake/FakeAlipayListener.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI.fake +{ + class FakeAlipayListener:IAlipayListener + { + } +} diff --git a/src/PaySharp.Alipay/DI/fake/IAlipayClient.cs b/src/PaySharp.Alipay/DI/fake/IAlipayClient.cs new file mode 100644 index 0000000..2b627a1 --- /dev/null +++ b/src/PaySharp.Alipay/DI/fake/IAlipayClient.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI.fake +{ + public interface IAlipayClient + { + } +} diff --git a/src/PaySharp.Alipay/DI/fake/IAlipayListener.cs b/src/PaySharp.Alipay/DI/fake/IAlipayListener.cs new file mode 100644 index 0000000..2ee19b7 --- /dev/null +++ b/src/PaySharp.Alipay/DI/fake/IAlipayListener.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Alipay.DI.fake +{ + public interface IAlipayListener + { + } +} diff --git a/src/PaySharp.Alipay/Merchant.cs b/src/PaySharp.Alipay/Merchant.cs index 161f908..5ae2bd7 100644 --- a/src/PaySharp.Alipay/Merchant.cs +++ b/src/PaySharp.Alipay/Merchant.cs @@ -1,11 +1,17 @@ using PaySharp.Core; +using PaySharp.Abstractions; using System; using System.ComponentModel.DataAnnotations; namespace PaySharp.Alipay { - public class Merchant : IMerchant + public class Merchant : IMerchant,IPaySharpOption { + private string _name; + public string Name { + get => _name ?? AppId; + set => _name = value; + } #region 属性 /// diff --git a/src/PaySharp.AspNet/HttpContextKeyValueProvider.cs b/src/PaySharp.AspNet/HttpContextKeyValueProvider.cs new file mode 100644 index 0000000..7478d9c --- /dev/null +++ b/src/PaySharp.AspNet/HttpContextKeyValueProvider.cs @@ -0,0 +1,82 @@ +using PaySharp.Abstractions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Web; + +namespace PaySharp.AspNetCore +{ + /// + /// Asp.Net 的键值提供器 + /// + public class HttpContextKeyValueProvider : IKeyValueProvider + { + public HttpContextBase HttpContext { get; } + + public IEnumerable SupportedParts => _supportedParts; + + private IEnumerable _supportedParts = new[] { "QueryString", "Form" }; + + public HttpContextKeyValueProvider(HttpContextBase httpContext) + { + HttpContext = HttpContext; + } + + /// + public byte[] Get() + { + using (var ms = new MemoryStream()) + { + HttpContext.Request.GetBufferedInputStream().CopyTo(ms); + return ms.ToArray(); + } + + } + + /// + public IEnumerable GetKeys(string part = null) + { + var request = HttpContext.Request; + var result = new List(); + if (NullEq(part, "QueryString")) + { + result.AddRange(request.QueryString.AllKeys); + + } + if (NullEq(part, "Form")) + { + result.AddRange(request.Form.AllKeys); + } + + return result.Distinct(); + } + + /// + public string GetValue(string key, string part = null) + { + var request = HttpContext.Request; + if (NullEq(part, "QueryString")) + { + return request.QueryString[key]; + } + + if (NullEq(part, "Form")) + { + return request.Form[key]; + } + + return null; + } + + + private bool NullEq(string val, string compare) + { + return string.IsNullOrEmpty(val) || string.Equals(val, compare, StringComparison.OrdinalIgnoreCase); + } + private bool Eq(string str1, string str2) + { + return string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/src/PaySharp.AspNet/PaySharp.AspNet.csproj b/src/PaySharp.AspNet/PaySharp.AspNet.csproj new file mode 100644 index 0000000..c78cbcf --- /dev/null +++ b/src/PaySharp.AspNet/PaySharp.AspNet.csproj @@ -0,0 +1,15 @@ + + + + net45 + + + + + + + + + + + diff --git a/src/PaySharp.AspNetCore/HttpContextKeyValueProvider.cs b/src/PaySharp.AspNetCore/HttpContextKeyValueProvider.cs new file mode 100644 index 0000000..6283e35 --- /dev/null +++ b/src/PaySharp.AspNetCore/HttpContextKeyValueProvider.cs @@ -0,0 +1,101 @@ +using PaySharp.Abstractions; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace PaySharp.AspNetCore +{ + /// + /// Asp.Net-Core 的键值提供器 + /// + public class HttpContextKeyValueProvider : IKeyValueProvider + { + public HttpContext HttpContext { get; } + + public IEnumerable SupportedParts => _supportedParts; + + private IEnumerable _supportedParts = new[] { "QueryString", "Form" }; + + public HttpContextKeyValueProvider(IHttpContextAccessor httpContextAccessor) + { + HttpContext = httpContextAccessor.HttpContext; + } + + public HttpContextKeyValueProvider(HttpContext httpContext) + { + HttpContext = httpContext; + } + + /// + public byte[] Get() + { + using(var ms = new MemoryStream()) + { + HttpContext.Request.Body.CopyTo(ms); + return ms.ToArray(); + } + + } + + /// + public IEnumerable GetKeys(string part = null) + { + var request = HttpContext.Request; + var result = new List(); + if(NullEq(part,"QueryString")) + { + result.AddRange(request.Query.Keys); + + + } + if(NullEq(part, "Form")) + { + if (request.HasFormContentType && Eq("POST", request.Method)) + { + result.AddRange(request.Form.Keys); + } + } + + return result.Distinct(); + } + + /// + public string GetValue(string key, string part = null) + { + var request = HttpContext.Request; + if (NullEq(part, "QueryString")) + { + if (request.Query.ContainsKey(key)) + { + return request.Query[key]; + } + } + + if (NullEq(part, "Form")) + { + if (request.HasFormContentType && Eq("POST", request.Method)) + { + if (request.Form.ContainsKey(key)) + { + return request.Form[key]; + } + } + + } + + return null; + } + + + private bool NullEq(string val,string compare) + { + return string.IsNullOrEmpty(val) || string.Equals(val, compare, StringComparison.OrdinalIgnoreCase); + } + private bool Eq(string str1, string str2) + { + return string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/src/PaySharp.AspNetCore/Internal/PaySharpBuilder.cs b/src/PaySharp.AspNetCore/Internal/PaySharpBuilder.cs new file mode 100644 index 0000000..4657dbd --- /dev/null +++ b/src/PaySharp.AspNetCore/Internal/PaySharpBuilder.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using PaySharp.Abstractions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace PaySharp.AspNetCore.Internal +{ + public class PaySharpBuilder : IPaySharpBuilder + { + private readonly IServiceCollection _services; + + public PaySharpBuilder(IServiceCollection services) + { + _services = services; + } + + public void AddOption(T option) where T : class, IPaySharpOption + { + _services.AddScoped(s => option); + _services.AddScoped(s => option); + } + + + public void TryAddService(T service) where T : class + { + _services.TryAddScoped(s => service); + } + + public void TryAddService() where T:class where TImplementation :class, T + { + _services.TryAddScoped(); + } + } +} diff --git a/src/PaySharp.AspNetCore/Internal/PaySharpProvider.cs b/src/PaySharp.AspNetCore/Internal/PaySharpProvider.cs new file mode 100644 index 0000000..793e7fa --- /dev/null +++ b/src/PaySharp.AspNetCore/Internal/PaySharpProvider.cs @@ -0,0 +1,30 @@ +using PaySharp.Abstractions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace PaySharp.AspNetCore.Internal +{ + public class PaySharpProvider : IPaySharpProvider + { + public IEnumerable GetMutiple() where T : class + { + throw new NotImplementedException(); + } + + public T GetRequired() where T : class + { + throw new NotImplementedException(); + } + + T IPaySharpProvider.GetOption() + { + throw new NotImplementedException(); + } + + IEnumerable IPaySharpProvider.GetOptions() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/PaySharp.AspNetCore/PaySharp.AspNetCore.csproj b/src/PaySharp.AspNetCore/PaySharp.AspNetCore.csproj new file mode 100644 index 0000000..c24aa26 --- /dev/null +++ b/src/PaySharp.AspNetCore/PaySharp.AspNetCore.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/src/PaySharp.AspNetCore/ServiceCollectionExtensions.cs b/src/PaySharp.AspNetCore/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..30a25b0 --- /dev/null +++ b/src/PaySharp.AspNetCore/ServiceCollectionExtensions.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Collections.Generic; +using System.Text; +using PaySharp.Abstractions; +using System.ComponentModel; +using PaySharp.AspNetCore; +using PaySharp.AspNetCore.Internal; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// PaySharp 对 的扩展方法 + /// + public static class ServiceCollectionExtensions + { + + /// + /// 添加PaySharp相关服务 + /// + /// + /// + /// + public static IPaySharpBuilder AddPaySharp(this IServiceCollection services) + { + services.TryAddScoped(); + services.TryAddScoped(); + + + return new PaySharpBuilder(services); + } + } +} diff --git a/src/PaySharp.Core/Abstractions/HandlerResult.cs b/src/PaySharp.Core/Abstractions/HandlerResult.cs new file mode 100644 index 0000000..de72885 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/HandlerResult.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + public class HandlerResult + { + public HandlerResult(NotifyResponse response) + { + Response = response ?? throw new ArgumentNullException(nameof(response)); + } + public bool IsSuccess => Response.IsSuccess; + public HubOrder Data { get; set; } + + public NotifyResponse Response { get; set; } + } +} diff --git a/src/PaySharp.Core/Abstractions/HubOrder.cs b/src/PaySharp.Core/Abstractions/HubOrder.cs new file mode 100644 index 0000000..444c6b6 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/HubOrder.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + /// + /// 通用的处理数据 + /// + public class HubOrder + { + /// + /// 支付机构订单Id + /// + public virtual string GatewayOrderId { get; set; } + + /// + /// 业务逻辑的订单Id + /// + public virtual string BusinessOrderId { get; set; } + + /// + /// 支付机构此次处理的时间 + /// + public virtual DateTimeOffset ProcessTime { get; set; } + + /// + /// 支付处理器给的类型 + /// + /// 可以利用此值决定 的类型 + public virtual string GatewayType { get; set; } + + /// + /// 原本的数据 + /// + public virtual object RawData { get; set; } + + /// + /// 状态, 当为 null 时,为未知 + /// + public virtual HubHandlerDataStatus? Status { get; set; } + } + + /// + /// 支付数据状态 + /// + public enum HubHandlerDataStatus + { + /// + /// 支付成功 + /// + Success, + + /// + /// 支付失败 + /// + Fail + } +} diff --git a/src/PaySharp.Core/Abstractions/IKeyValueProvider.cs b/src/PaySharp.Core/Abstractions/IKeyValueProvider.cs new file mode 100644 index 0000000..a69f6e8 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IKeyValueProvider.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + /// + /// 键值提供器,用于从 HttpContext.Request 中提取数据。 + /// + /// 因为 HttpContext 在不同的框架中类不同,所以该接口用于协调这些专用类 + public interface IKeyValueProvider + { + /// + /// 获取 HttpContext.Request.Body 数据 + /// + /// Body的所有的字节 + byte[] Get(); + + /// + /// 获取所有的键 + /// + /// 该值指示从哪个部分中提取 比如:QueryString 或 Form , + /// 注意:该值为null时从所有的部分获取,而且应该忽略大小写 + /// + IEnumerable GetKeys(string part = null); + + /// + /// 通过提供键,获取值 + /// + /// 键 + /// 该值指示从哪个部分中提取 比如:QueryString 或 Form , + /// 注意:该值为null时从所有的部分获取,而且应该忽略大小写 + /// + string GetValue(string key, string part = null); + + IEnumerable SupportedParts { get; } + } +} diff --git a/src/PaySharp.Core/Abstractions/INotifyDataConverter.cs b/src/PaySharp.Core/Abstractions/INotifyDataConverter.cs new file mode 100644 index 0000000..a425ffa --- /dev/null +++ b/src/PaySharp.Core/Abstractions/INotifyDataConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + /// + /// 通知数据转换器, 他从HttpContext 转换为强类型数据 + /// + /// HttpContext在实现的类中采用构造函数注入, + [Obsolete("似乎没什么用",true)] + public interface INotifyDataConverter + { + Task ConvertDataAsync(); + } + + [Obsolete("似乎没什么用", true)] + public interface INotifyDataConverter : INotifyDataConverter + { + new Task ConvertDataAsync(); + } +} diff --git a/src/PaySharp.Core/Abstractions/INotifyHubHandler.cs b/src/PaySharp.Core/Abstractions/INotifyHubHandler.cs new file mode 100644 index 0000000..5ef2c40 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/INotifyHubHandler.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + /// + /// NotifyHub 处理器 + /// + public interface INotifyHubHandler + { + [Obsolete("似乎没什么用", true)] + INotifyDataConverter Converter { get; } + Task ProcessAsync(IKeyValueProvider valueProvider); + + /// + /// 获取失败的 + /// + /// + Task GetFailedResponseAsync(); + + } + +} diff --git a/src/PaySharp.Core/Abstractions/IPaySharpBuilder.cs b/src/PaySharp.Core/Abstractions/IPaySharpBuilder.cs new file mode 100644 index 0000000..5f4e52f --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IPaySharpBuilder.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PaySharp.Abstractions +{ + /// + /// 网关提供器的构造器 + /// + public interface IPaySharpBuilder + { + /// + /// 添加一个命名的网关 + /// + /// 网关的类型 + /// 网关的名字 + /// 网关 + /// + void TryAddService(T service) where T : class; + void TryAddService() where T:class where TImplementation :class, T; + void AddOption(T option) where T : class, IPaySharpOption; + + } +} diff --git a/src/PaySharp.Core/Abstractions/IPaySharpOption.cs b/src/PaySharp.Core/Abstractions/IPaySharpOption.cs new file mode 100644 index 0000000..615aed1 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IPaySharpOption.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + public interface IPaySharpOption + { + string Name { get; set; } + } +} diff --git a/src/PaySharp.Core/Abstractions/IPaySharpProvider.cs b/src/PaySharp.Core/Abstractions/IPaySharpProvider.cs new file mode 100644 index 0000000..7b4730a --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IPaySharpProvider.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PaySharp.Abstractions +{ + public interface IPaySharpProvider + { + T GetRequired() where T : class; + IEnumerable GetMutiple() where T : class; + + T GetOption() where T : class, IPaySharpOption; + + IEnumerable GetOptions() where T : class, IPaySharpOption; + } +} diff --git a/src/PaySharp.Core/Abstractions/IPaymentNotifyData.cs b/src/PaySharp.Core/Abstractions/IPaymentNotifyData.cs new file mode 100644 index 0000000..3c76b9f --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IPaymentNotifyData.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + public interface IPaymentNotifyData + { + + } +} diff --git a/src/PaySharp.Core/Abstractions/IUserHandler.cs b/src/PaySharp.Core/Abstractions/IUserHandler.cs new file mode 100644 index 0000000..894b451 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/IUserHandler.cs @@ -0,0 +1,26 @@ +using PaySharp.Abstractions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + /// + /// 用户逻辑处理器 + /// + public interface IUserHandler + { + + Task OnProcessingAsync(IKeyValueProvider keyValueProvider); + + Task OnProcessedAsync(HubOrder hubOrder, IKeyValueProvider valueProvider); + + Task OnSuccessedAsync(HubOrder hubOrder, IKeyValueProvider provider); + + Task OnFailedAsync(HubOrder hubOrder, IKeyValueProvider provider); + + Task OnExceptionAsync(Exception exception, IKeyValueProvider provider); + } +} diff --git a/src/PaySharp.Core/Abstractions/NotifyHub.cs b/src/PaySharp.Core/Abstractions/NotifyHub.cs new file mode 100644 index 0000000..933f515 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/NotifyHub.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + + /// + /// 通知适配器 + /// + public sealed class NotifyHub + { + private readonly INotifyHubHandler _hubHandler; + private Func _successHandler; + private Func _failHandler; + private Func _beforeProcessHandler; + private Func _afterProcessHandler; + private Func _exceptionHandler; + + /// + /// 通过一个 来实例化 该适配器 + /// + /// 要用来处理的通知处理器 + public NotifyHub(INotifyHubHandler hubHandler) + { + _hubHandler = hubHandler; + } + + /// + /// 一次性添加整个处理流程 + /// + /// 一个拥有所有处理流程的类的实例 + /// 返回配置的 + public NotifyHub UseUserHandler(IUserHandler handler) + { + _beforeProcessHandler = handler.OnProcessingAsync; + _successHandler = handler.OnSuccessedAsync; + _failHandler = handler.OnFailedAsync; + _exceptionHandler = handler.OnExceptionAsync; + _afterProcessHandler = handler.OnProcessedAsync; + return this; + } + + //[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public async Task ProcessAsync(IKeyValueProvider valueProvider) + { + // 首先检查, 成功和异常处理必须注册 + + if (_successHandler == null) + { + throw new InvalidOperationException("No Success delegate registed"); + } + if (_exceptionHandler == null) + { + throw new InvalidOperationException("No Exception delegate registed"); + } + + + + + try + { + // before + if (_beforeProcessHandler != null) + { + await _beforeProcessHandler(valueProvider); + } + // handing + var result = await _hubHandler.ProcessAsync(valueProvider); + if (result.IsSuccess) + { + await _successHandler(result.Data,valueProvider); + } + else + { + if (_failHandler != null) + { + await _failHandler(result.Data,valueProvider); + } + } + // after + if (_afterProcessHandler != null) + { + await _afterProcessHandler(result.Data,valueProvider); + } + return result.Response; + } + catch(Exception e) + { + await _exceptionHandler(e,valueProvider); + throw; + } + + } + } +} diff --git a/src/PaySharp.Core/Abstractions/NotifyResponse.cs b/src/PaySharp.Core/Abstractions/NotifyResponse.cs new file mode 100644 index 0000000..5c5f88d --- /dev/null +++ b/src/PaySharp.Core/Abstractions/NotifyResponse.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + public class NotifyResponse : IDisposable + { + public NotifyResponse(bool isSuccess) + { + IsSuccess = isSuccess; + } + + public virtual bool IsSuccess { get; private set; } + public virtual int StatusCode { get; private set; } + public virtual string ContentType { get; private set; } + public virtual IDictionary Headers { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + public virtual IDictionary Cookies { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public virtual Stream Body { get; private set; } = new MemoryStream(); + + public virtual NotifyResponse SetStatusCode(int code) + { + StatusCode = code; + return this; + } + public virtual NotifyResponse SetContentType(string type) + { + ContentType = type; + return this; + } + public virtual NotifyResponse AddHeader(Action> headerConfig) + { + headerConfig?.Invoke(Headers); + return this; + } + + public virtual NotifyResponse AddCookies(Action> cookiesConfig) + { + cookiesConfig?.Invoke(Cookies); + return this; + } + + public virtual async Task SetBodyAsync(Func bodyConfig) + { + if(bodyConfig != null) + { + await bodyConfig(Body); + } + Body.Seek(0, SeekOrigin.Begin); + return this; + } + public virtual NotifyResponse SetBody(Action bodyConfig) + { + bodyConfig?.Invoke(Body); + Body.Seek(0, SeekOrigin.Begin); + return this; + } + + #region IDisposable Support + private bool _isDisposed = false; // 要检测冗余调用 + + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Body?.Dispose(); + Headers?.Clear(); + Cookies?.Clear(); + } + + // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 + // TODO: 将大型字段设置为 null。 + Body = null; + Headers = null; + Cookies = null; + + _isDisposed = true; + } + } + + // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 + // ~NotifyResponse() { + // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + // Dispose(false); + // } + + // 添加此代码以正确实现可处置模式。 + public void Dispose() + { + // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + Dispose(true); + // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 + // GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/src/PaySharp.Core/Abstractions/ResponseResult.cs b/src/PaySharp.Core/Abstractions/ResponseResult.cs new file mode 100644 index 0000000..2410ee6 --- /dev/null +++ b/src/PaySharp.Core/Abstractions/ResponseResult.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PaySharp.Abstractions +{ + public class ResponseResult + { + public bool IsSuccess { get; set; } + + public NotifyResponse Response { get; set; } + } +} diff --git a/src/PaySharp.Core/Internal/GatewayBuilder.cs b/src/PaySharp.Core/Internal/GatewayBuilder.cs new file mode 100644 index 0000000..81e34f2 --- /dev/null +++ b/src/PaySharp.Core/Internal/GatewayBuilder.cs @@ -0,0 +1,61 @@ +//using System; +//using System.Collections.Generic; +//using System.Collections.Concurrent; +//using System.Text; +//using PaySharp.Abstractions; + +//namespace PaySharp.Internal +//{ +// /// +// public class GatewayBuilder : IPaySharpBuilder +// { +// private readonly IDictionary>> _store = new Dictionary>>(); + +// /// +// public bool TryAdd(string name, T gateway) where T : class +// { +// try +// { +// var t = typeof(T); +// if (_store.ContainsKey(t)) +// { +// var innerStore = _store[t]; +// innerStore[name] = new Lazy(() => gateway); +// return true; +// } +// else +// { +// var innerStore = new Dictionary>(StringComparer.OrdinalIgnoreCase) +// { +// [name] = new Lazy(() => gateway) +// }; +// _store.Add(t, innerStore); +// return true; +// } +// } +// catch +// { +// return false; +// } + + +// } + +// /// +// public IGatewayProvider Build() +// { +// return new GatewayProvider(_store); +// } + +// public bool TryAdd(string name, Func gateway) where T : class +// { +// throw new NotImplementedException(); +// } + +// private class GatewayStore +// { +// public string Name { get; set; } +// public object Gateway { get; set; } +// } +// } +//} diff --git a/src/PaySharp.Core/Internal/GatewayDefinition.cs b/src/PaySharp.Core/Internal/GatewayDefinition.cs new file mode 100644 index 0000000..f2bee9b --- /dev/null +++ b/src/PaySharp.Core/Internal/GatewayDefinition.cs @@ -0,0 +1,45 @@ +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; + +//namespace PaySharp.Core.Internal +//{ +// public class GatewayDefinition +// { +// public virtual string Name { get; set; } +// public IGatewayOption Option { get; set; } + +// public virtual Func Create { get; set; } +// } + +// public class GatewayDefinition :GatewayDefinition where T : IGatewayOption +// { +// public new T Option +// { +// get +// { +// if(base.Option is T t) +// { +// return t; +// } +// return default(T); +// } +// } + +// public new Func> Create +// { +// get +// { +// return base.Create as Func>; +// } +// set +// { +// base.Create = value; +// } +// } +// } + + +//} diff --git a/src/PaySharp.Core/Internal/GatewayProvider.cs b/src/PaySharp.Core/Internal/GatewayProvider.cs new file mode 100644 index 0000000..9603529 --- /dev/null +++ b/src/PaySharp.Core/Internal/GatewayProvider.cs @@ -0,0 +1,41 @@ +//using PaySharp.Abstractions; +//using System; +//using System.Collections.Generic; +//using System.Text; + +//namespace PaySharp.Internal +//{ +// /// +// public class GatewayProvider : IGatewayProvider +// { +// private readonly IDictionary> _store; + +// public GatewayProvider(IDictionary> store) +// { +// _store = store ?? throw new ArgumentNullException(nameof(store)); +// } + +// /// +// public T GetGateway() where T:class +// { +// return GetGateway(string.Empty); +// } + +// /// +// public T GetGateway(string gatewayName) where T:class +// { +// gatewayName = gatewayName ?? throw new ArgumentNullException(nameof(gatewayName), "Gateway name must not be null"); +// if (_store.TryGetValue(typeof(T), out var innerStore)) +// { +// if (innerStore.TryGetValue(gatewayName, out var gateway)) +// { +// if(gateway is T) +// { +// return (T)gateway; +// } +// } +// } +// return null; +// } +// } +//} diff --git a/test/PaySharp.AspNetCoreTest/DI/DIExtensionTest.cs b/test/PaySharp.AspNetCoreTest/DI/DIExtensionTest.cs new file mode 100644 index 0000000..c415769 --- /dev/null +++ b/test/PaySharp.AspNetCoreTest/DI/DIExtensionTest.cs @@ -0,0 +1,127 @@ +//using Microsoft.Extensions.DependencyInjection; +//using Microsoft.Extensions.DependencyInjection.Extensions; +//using PaySharp.Abstractions; +//using PaySharp.Internal; +//using System; +//using System.Collections.Generic; +//using Xunit; + +//namespace PaySharp.AspNetCoreTest +//{ +// public class DIExtensionTest +// { +// [Fact] +// public void ConfigDI_Repeate_Test() +// { +// var service = new ServiceCollection(); +// service.TryAddScoped(); +// service.AddPaySharp(builder => +// { +// builder.TryAdd("A", new XGateway()); +// }); + +// var provider = service.BuildServiceProvider(); + +// try +// { +// var gateway1 = GetGateway(provider); +// } +// catch (Exception e) +// { +// throw new Exception("第一次获取就出错了", e); +// } + + +// try +// { +// var gateway2 = GetGateway(provider); +// } +// catch (Exception e) +// { +// throw new Exception("第二次获取出错了", e); +// } +// } + +// [Fact] +// public void ConfigDI_Repeate_1scope_Test() +// { +// var service = new ServiceCollection(); +// service.TryAddScoped(); +// service.AddPaySharp(builder => +// { +// builder.TryAdd("A", new XGateway()); +// }); + +// var provider = service.BuildServiceProvider(); +// using (var scope = provider.CreateScope()) +// { +// var b = scope.ServiceProvider.GetRequiredService(); +// var gateway1 = b.GetGateway("A"); +// var b2 = scope.ServiceProvider.GetRequiredService(); +// var gateway2 = b2.GetGateway("A"); + +// } + + + +// } + +// private XGateway GetGateway(IServiceProvider servicProvider) +// { +// using (var provider = servicProvider.CreateScope()) +// { +// var gateWays = provider.ServiceProvider.GetRequiredService(); +// return gateWays.GetGateway("A"); +// } +// } + +// private class XGateway +// { +// public Guid Id { get; } = Guid.NewGuid(); +// } + + +// /// +// /// 采用Add 方法的Builder, 这将在重复添加的时候报错 +// /// +// private class TestGatewayBuilder : IPaySharpBuilder +// { +// private readonly IDictionary> _store = new Dictionary>(); + +// /// +// public bool TryAdd(string name, T gateway) where T : class +// { +// var t = typeof(T); +// if (_store.ContainsKey(t)) +// { +// var innerStore = _store[t]; +// innerStore.Add(name, gateway); +// return true; +// } +// else +// { +// var innerStore = new Dictionary(StringComparer.OrdinalIgnoreCase) +// { +// [name] = gateway +// }; +// _store.Add(t, innerStore); +// return true; +// } + +// } + +// /// +// public IGatewayProvider Build() +// { +// return new GatewayProvider(_store); +// } + + +// private class GatewayStore +// { +// public string Name { get; set; } +// public object Gateway { get; set; } +// } +// } +// } +//} diff --git a/test/PaySharp.AspNetCoreTest/PaySharp.AspNetCoreTest.csproj b/test/PaySharp.AspNetCoreTest/PaySharp.AspNetCoreTest.csproj new file mode 100644 index 0000000..d7efbef --- /dev/null +++ b/test/PaySharp.AspNetCoreTest/PaySharp.AspNetCoreTest.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.0 + + + + + + + + + + + + + + diff --git a/test/PaySharp.UnitTest/CodeWrite.cs b/test/PaySharp.UnitTest/CodeWrite.cs new file mode 100644 index 0000000..0bbb7f6 --- /dev/null +++ b/test/PaySharp.UnitTest/CodeWrite.cs @@ -0,0 +1,19 @@ +using ICanPay.Abstractions; +using ICanPay.AspNetCore; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ICanPay.UnitTest +{ + //class CodeWrite + //{ + // public void Write() + // { + // var provider = new HttpContextKeyValueProvider(new HttpContextAccessor()); + // var hub = new NotifyHub(null); + // hub. + // } + //} +} diff --git a/test/PaySharp.UnitTest/PaySharp.UnitTest.csproj b/test/PaySharp.UnitTest/PaySharp.UnitTest.csproj index 53fc0c5..c94b01c 100644 --- a/test/PaySharp.UnitTest/PaySharp.UnitTest.csproj +++ b/test/PaySharp.UnitTest/PaySharp.UnitTest.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.0 @@ -21,7 +21,8 @@ - + +