一、前言
现实生产中,有一些比较老的系统对外提供的接口都是WebService,尤其是比较老的系统都是围绕ESB进行搭建,而对外提供就需要WebService ,为了更好完善其解决方案,故集成了webservice 协议组件和身份验证,现把它上传至github, 而这篇文章就是讲述如何构建WebService,创建的接口IWebServiceService代码如下:
using Surging.Core.CPlatform.Ioc; using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; using Surging.IModuleServices.Common.Models; using System.ServiceModel; using System.Threading.Tasks; namespace Surging.IModuleServices.Common { [ServiceBundle("api/{Service}/{Method}")] [ServiceContract] public interface IWebServiceService : IServiceKey { [OperationContract] Task<string> SayHello(string name); [OperationContract] Task<string> Authentication(AuthenticationRequestData requestData); } }
AuthenticationRequestData 代码如下:
using ProtoBuf; using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; namespace Surging.IModuleServices.Common.Models { [ProtoContract] [DataContract] public class AuthenticationRequestData { [ProtoMember(1)] [DataMember] public string UserName { get; set; } [ProtoMember(2)] [DataMember] public string Password { get; set; } } }
从以上代码来看,除了需要符合引擎代码规则外,还需要添加[ServiceContract]和[OperationContract] 特性, 如果参数是实体的话,需要添加在实体模型上加[DataContract]和 属性上加[DataMember]
那么创建的业务服务WebServiceService代码如下:
using Surging.Core.ApiGateWay.OAuth; using Surging.Core.Protocol.WebService.Runtime; using Surging.IModuleServices.Common; using Surging.IModuleServices.Common.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Surging.Modules.Common.Domain { public class WebServiceService : WebServiceBehavior, IWebServiceService { private readonly IAuthorizationServerProvider _authorizationServerProvider; public WebServiceService(IAuthorizationServerProvider authorizationServerProvider) { _authorizationServerProvider = authorizationServerProvider; } public async Task<string> SayHello(string name) { var token = this.HeaderValue.Token; if (await _authorizationServerProvider.ValidateClientAuthentication(token)) return $"Hello,{name}"; else return " Please leave, stranger"; } public async Task<string> Authentication(AuthenticationRequestData requestData) { var param = new Dictionary<string, object>(); param.Add("requestData", requestData); var result= await _authorizationServerProvider.GenerateTokenCredential(param); return result; } } }
通过以上代码,首先需要继承IWebServiceService和WebServiceBehavior,然后通过IAuthorizationServerProvider 去生成Token 和验证Token, 或者也可以脱离引擎的身份鉴权,通过传递的this.HeaderValue.Token 进行验证。
通过访问127.0.0.1:289/api/webservice/sayhello.asmx,显示以下界面,说明基于webservice 的服务就已经添加成功。
二、引用WebService
首先我们在创建好的控制台项目里面添加WebService的引用。
1、在依赖项上面右键,选择“添加服务引用”,选择wcf web service如图所示:
添加服务引用。如图所示:
配置完以后,点击“下一步”,去掉重新使用引用的程序集中的类型签名的复选框。
直接点击“完成”按钮即可。慢慢等待配置完成:
配置完成界面如图所示:
下面就介绍如何在.net 6.0下调用webservice
三、调用WebService
在Program类文件中,调用webservice 提供的sayhello,在调用前需要生成token, 通过token才能正确访问结果,以下是基于.net 6.0,代码如下:
1 // See https://aka.ms/new-console-template for more information 2 using ConsoleApp7; 3 using ServiceReference1; 4 using System.ServiceModel; 5 6 try 7 { 8 9 10 WebServiceServiceClient client = new WebServiceServiceClient(); 11 using (var scope = new FlowingOperationContextScope(client.InnerChannel)) 12 { 13 var authenticationResponse = await client.AuthenticationAsync(new AuthenticationRequestData 14 { 15 UserName = "admin", 16 Password = "admin" 17 }).ContinueOnScope(scope); 18 var authenticationResult = authenticationResponse.Body.AuthenticationResult; 19 if (authenticationResponse.Body.AuthenticationResult != null) 20 { 21 var header1 = System.ServiceModel.Channels.MessageHeader.CreateHeader("headerValue", "http://tempuri.org/", new HeaderValue 22 { 23 Token = authenticationResult 24 }); 25 OperationContext.Current.OutgoingMessageHeaders.Add(header1); 26 var sayHelloResponse =await client.SayHelloAsync("fanly").ContinueOnScope(scope); 27 Console.WriteLine(sayHelloResponse.Body.SayHelloResult); 28 Console.ReadLine(); 29 } 30 31 } 32 33 } 34 catch (Exception ex) 35 { 36 Console.WriteLine(ex.Message); 37 }
以下是基于.net framework 调用webservice 的代码:
1 internal class Program 2 { 3 static async Task Main(string[] args) 4 { 5 try 6 { 7 8 WebServiceServiceClient client = new WebServiceServiceClient(); 9 using (var scope = new OperationContextScope(client.InnerChannel)) 10 { 11 var authenticationResponse = client.Authentication(new AuthenticationRequestData 12 { 13 UserName = "admin", 14 Password = "admin" 15 }); 16 if (authenticationResponse != null) 17 { 18 var header1 = System.ServiceModel.Channels.MessageHeader.CreateHeader("headerValue", "http://tempuri.org/", new HeaderValue 19 { 20 Token = authenticationResponse 21 }); 22 OperationContext.Current.OutgoingMessageHeaders.Add(header1); 23 var sayHelloResponse = client.SayHello("fanly"); 24 Console.WriteLine(sayHelloResponse); 25 Console.ReadLine(); 26 } 27 28 } 29 30 } 31 catch (Exception ex) 32 { 33 Console.WriteLine(ex.Message); 34 } 35 } 36 }
HeaderValue 代码如下:
namespace ConsoleApp7 { public class HeaderValue { public string Token { get; set; } } }
因为.net 6.0 生成的代码是异步,所以就要修改OperationContextScope 以支持异步,代码如下:
1 public sealed class FlowingOperationContextScope : IDisposable 2 { 3 bool _inflight = false; 4 bool _disposed; 5 OperationContext _thisContext = null; 6 OperationContext _originalContext = null; 7 8 public FlowingOperationContextScope(IContextChannel channel): 9 this(new OperationContext(channel)) 10 { 11 } 12 13 public FlowingOperationContextScope(OperationContext context) 14 { 15 _originalContext = OperationContext.Current; 16 OperationContext.Current = _thisContext = context; 17 } 18 19 public void Dispose() 20 { 21 if (!_disposed) 22 { 23 if (_inflight || OperationContext.Current != _thisContext) 24 throw new InvalidOperationException(); 25 _disposed = true; 26 OperationContext.Current = _originalContext; 27 _thisContext = null; 28 _originalContext = null; 29 } 30 } 31 32 internal void BeforeAwait() 33 { 34 if (_inflight) 35 return; 36 _inflight = true; 37 } 38 39 internal void AfterAwait() 40 { 41 if (!_inflight) 42 throw new InvalidOperationException(); 43 _inflight = false; 44 OperationContext.Current = _thisContext; 45 } 46 } 47 48 public static class TaskExt 49 { 50 public static SimpleAwaiter<TResult> ContinueOnScope<TResult>(this Task<TResult> @this, FlowingOperationContextScope scope) 51 { 52 return new SimpleAwaiter<TResult>(@this, scope.BeforeAwait, scope.AfterAwait); 53 } 54 55 public class SimpleAwaiter<TResult> : 56 System.Runtime.CompilerServices.INotifyCompletion 57 { 58 readonly Task<TResult> _task; 59 60 readonly Action _beforeAwait; 61 readonly Action _afterAwait; 62 63 public SimpleAwaiter(Task<TResult> task, Action beforeAwait, Action afterAwait) 64 { 65 _task = task; 66 _beforeAwait = beforeAwait; 67 _afterAwait = afterAwait; 68 } 69 70 public SimpleAwaiter<TResult> GetAwaiter() 71 { 72 return this; 73 } 74 75 public bool IsCompleted 76 { 77 get 78 { 79 if (_task.IsCompleted) 80 return true; 81 _beforeAwait(); 82 return false; 83 } 84 85 } 86 87 public TResult GetResult() 88 { 89 return _task.Result; 90 } 91 92 // INotifyCompletion 93 public void OnCompleted(Action continuation) 94 { 95 _task.ContinueWith(task => 96 { 97 _afterAwait(); 98 continuation(); 99 }, 100 CancellationToken.None, 101 TaskContinuationOptions.ExecuteSynchronously, 102 SynchronizationContext.Current != null ? 103 TaskScheduler.FromCurrentSynchronizationContext() : 104 TaskScheduler.Current); 105 } 106 } 107 }
程序输出结果:
四、结尾
surging 正在开发微服务平台(以处于调试阶段),形成独立的项目产品,抛弃之前的代码架构的形式,现如今已经攘括支持WEB, 物联网,流媒体等多种业务场景, 现在开发支持了外层协议有:MQTT,Grpc,, DNS, TCP,UDP,restful,rtmp,httpflv,rtsp,websocket,webservice, 内部可以通过基于thrift 或者netty 做到可靠性的RPC调用,因为有服务治理,服务发现,并且支持了Apollo配置中心,skywalking 链路跟踪,并且支持JAVA和.NET主流开发语言,请大家多多留意surging 的微服务平台。或者你也可以加群联系到我:744677125(老群被封,这是新群)
标签:OperationContext,webservice,System,身份验证,surging,new,var,using,public From: https://www.cnblogs.com/fanliang11/p/17226191.html