4

在surging 微服务引擎下如何搭建webservice和身份验证 - fanly11

 1 year ago
source link: https://www.cnblogs.com/fanliang11/p/17226191.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在surging 微服务引擎下如何搭建webservice和身份验证

       现实生产中,有一些比较老的系统对外提供的接口都是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 的服务就已经添加成功。

192878-20230319205525174-1348634585.png

二、引用WebService

首先我们在创建好的控制台项目里面添加WebService的引用。

1、在依赖项上面右键,选择“添加服务引用”,选择wcf web service如图所示:

192878-20230316224025846-1366922422.png

 添加服务引用。如图所示:

192878-20230316224153910-1615642218.png

 配置完以后,点击“下一步”,去掉重新使用引用的程序集中的类型签名的复选框。

 

192878-20230316232014758-686995751.png

  直接点击“完成”按钮即可。慢慢等待配置完成:

192878-20230316224243613-27599211.png
192878-20230316224311814-2052308355.png

 配置完成界面如图所示:

 

192878-20230319210811790-1167272645.png

 下面就介绍如何在.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     }

程序输出结果:

192878-20230319213058591-2079282678.png

        surging 正在开发微服务平台(以处于调试阶段),形成独立的项目产品,抛弃之前的代码架构的形式,现如今已经攘括支持WEB, 物联网,流媒体等多种业务场景, 现在开发支持了外层协议有:MQTT,Grpc,, DNS,  TCP,UDP,restful,rtmp,httpflv,rtsp,websocket,webservice, 内部可以通过基于thrift 或者netty 做到可靠性的RPC调用,因为有服务治理,服务发现,并且支持了Apollo配置中心,skywalking 链路跟踪,并且支持JAVA和.NET主流开发语言,请大家多多留意surging 的微服务平台。或者你也可以加群联系到我:744677125(老群被封,这是新群)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK