在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 的服務就已經添加成功。

 

 

 

二、引用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(老羣被封,這是新羣)

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章