diff --git a/Falcon.SugarApi.WebService/Falcon.SugarApi.WebService.csproj b/Falcon.SugarApi.WebService/Falcon.SugarApi.WebService.csproj new file mode 100644 index 0000000..0e981d0 --- /dev/null +++ b/Falcon.SugarApi.WebService/Falcon.SugarApi.WebService.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + enable + enable + + + + + + diff --git a/Falcon.SugarApi.WebService/Readme.md b/Falcon.SugarApi.WebService/Readme.md new file mode 100644 index 0000000..000c24d --- /dev/null +++ b/Falcon.SugarApi.WebService/Readme.md @@ -0,0 +1,65 @@ +## WebService服务器帮助 + +### 服务端 + +1. 首先使用IServiceCollection.AddWebServices注册服务及其实现。 +2. 使用IApplicationBuilder.UseRouting()应用路由中间价。 +3. 调用IApplicationBuilder.UseWebServiceEndpoint方法应用中间件。 + +### 客户端 + +1. 调用WebServiceClient.CreateWebServiceClient方法创建客户端。T为服务端应以的协议接口,返回T协议对应的通信实现。 + + +### 实例 + +服务端: +~~~c# + /// + /// Web服务协议 + /// + [ServiceContract] + public interface IWebSvc + { + [OperationContract] + public string HellowWorld(string name); + } + + public class WebSvc:IWebSvc + { + public string HellowWorld(string name) { + return $"Hellow world {name}!"; + } + } + + using Falcon.SugarApi.WebService; + using Server; + + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddWebService(); + + var app = builder.Build(); + app.UseRouting(); + app.UseWebServiceEndpoint("/WebService.asmx"); + + app.Run(); + +~~~ + +客户端: +~~~c# + + using System.ServiceModel; + [ServiceContractAttribute(ConfigurationName = "Service.IWebSvc")] + internal interface IWebSvc + { + [OperationContractAttribute(Action = "http://tempuri.org/IWebSvc/HellowWorld",ReplyAction = "http://tempuri.org/IWebSvc/HellowWorldResponse")] + Task HellowWorldAsync(string name); + } + + using Falcon.SugarApi.WebService; + + var svc = WebServiceClient.CreateWebServiceClient("http://localhost:5000/WebService.asmx"); + var result=await svc.HellowWorldAsync("Jeck"); + +~~~ \ No newline at end of file diff --git a/Falcon.SugarApi.WebService/WebServiceClient.cs b/Falcon.SugarApi.WebService/WebServiceClient.cs new file mode 100644 index 0000000..3063663 --- /dev/null +++ b/Falcon.SugarApi.WebService/WebServiceClient.cs @@ -0,0 +1,31 @@ +using System.ServiceModel; + +namespace Falcon.SugarApi.WebService +{ + /// + /// WebService客户端 + /// + public static class WebServiceClient + { + /// + /// 创建一个符合协议的WebService客户端 + /// + /// 协议 + /// 服务端地址 + /// 创建器 + /// 实例化的协议通信客户端 + /// + public static T CreateWebServiceClient(string url,Action? builder = null) { + url=url??throw new ArgumentNullException("url must is not null."); + var bind = new BasicHttpBinding { + MaxBufferSize=int.MaxValue, + ReaderQuotas=System.Xml.XmlDictionaryReaderQuotas.Max, + MaxReceivedMessageSize=int.MaxValue, + AllowCookies=true, + }; + var option = new WebServiceClientOption { Address=url,Binding=bind }; + builder?.Invoke(option); + return (new ChannelFactory(option.Binding,new EndpointAddress(option.Address))).CreateChannel(); + } + } +} diff --git a/Falcon.SugarApi.WebService/WebServiceClientOption.cs b/Falcon.SugarApi.WebService/WebServiceClientOption.cs new file mode 100644 index 0000000..02aeef4 --- /dev/null +++ b/Falcon.SugarApi.WebService/WebServiceClientOption.cs @@ -0,0 +1,20 @@ +using System.ServiceModel.Channels; + +namespace Falcon.SugarApi.WebService +{ + /// + /// WebService客户端配置 + /// + public class WebServiceClientOption + { + /// + /// 绑定 + /// + public Binding? Binding { get; set; } + /// + /// 服务端地址 + /// + public string? Address { get; set; } + + } +} diff --git a/Falcon.SugarApi.WebService/WebServiceExtend.cs b/Falcon.SugarApi.WebService/WebServiceExtend.cs new file mode 100644 index 0000000..31bcaa1 --- /dev/null +++ b/Falcon.SugarApi.WebService/WebServiceExtend.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using SoapCore; +using System.Xml; + +namespace Falcon.SugarApi.WebService +{ + /// + /// 扩展服务集合和应用程序,支持WebService + /// + public static class WebServiceExtend + { + /// + /// 添加基于Soap协议的WebService服务 + /// + /// 服务类型 + /// 实现类 + /// 服务集合 + /// 服务集合 + public static IServiceCollection AddWebService(this IServiceCollection services) + where Tservice : class where TImplementation : class, Tservice { + services.AddSoapCore(); + services.TryAddSingleton(); + return services; + } + /// + /// 添加基于Soap协议的WebService服务组 + /// + /// 服务集合 + /// 要添加的WebService服务说明 + /// 服务集合 + public static IServiceCollection AddWebServices(this IServiceCollection services,params ServiceDescriptor[] descriptors) { + services.AddSoapCore(); + if(descriptors==null||descriptors.Length==0) { + return services; + } + foreach(var des in descriptors.Where(d => d!=null)) { + services.TryAddSingleton(des); + } + return services; + } + + /// + /// 增加WebService终结点。在此之前必须首先UseRouting()。 + /// + /// 终结点服务 + /// 应用创建器 + /// 终结点url + /// 终结点服务 + public static IApplicationBuilder UseWebServiceEndpoint(this IApplicationBuilder application,string url="/WebSvc.asmx") { + var xnm = new XmlNamespaceManager(new NameTable()); + xnm.AddNamespace("soap","http://schemas.xmlsoap.org/soap/envelope/"); + xnm.AddNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance"); + xnm.AddNamespace("xsd","http://www.w3.org/2001/XMLSchema"); + application.UseEndpoints(endpoints => { + endpoints.UseSoapEndpoint(url, + new SoapEncoderOptions() { XmlNamespaceOverrides=xnm }, + SoapSerializer.DataContractSerializer, + omitXmlDeclaration: false, + indentXml: false); + }); + return application; + } + } +} diff --git a/Falcon.SugarApi.sln b/Falcon.SugarApi.sln index cb4c5fc..b2e30e7 100644 --- a/Falcon.SugarApi.sln +++ b/Falcon.SugarApi.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Falcon.SugarApi.WebService", "Falcon.SugarApi.WebService\Falcon.SugarApi.WebService.csproj", "{A02586C2-B485-47C3-988B-AC050BD2286C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {EADC8D8F-449C-4C4C-8168-0075B333494B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EADC8D8F-449C-4C4C-8168-0075B333494B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EADC8D8F-449C-4C4C-8168-0075B333494B}.Release|Any CPU.Build.0 = Release|Any CPU + {A02586C2-B485-47C3-988B-AC050BD2286C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A02586C2-B485-47C3-988B-AC050BD2286C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A02586C2-B485-47C3-988B-AC050BD2286C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A02586C2-B485-47C3-988B-AC050BD2286C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE