程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF服務中元數據的地址問題

WCF服務中元數據的地址問題

編輯:關於.NET

初用WCF的朋友可能會遇到這樣的問題,就是在使用svcutil.exe生成proxy和config的時候,或者利用add service reference添加引用的時候,部署的WCF服務到底它的metadata是什麼。或者換句話說,svcutil的URL參數,以及添加服務引用時候的那個Address,到底應該填什麼。

在這裡我用兩個最常用的Binding方式,WSHttpBinding和NetTcpBinding,分別以實際的例子來進行說明。

建立服務契約

在這裡就從MSDN上抄一個四則運算的服務來作為我們的素材。建立一個控制台程序,添加System.ServiceModel引用,然後添加下面兩個文件:

ICalculatorService.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
  
namespace Nocturne.Learning.WcfAddressDemo
{
  [ServiceContract]
  public interface ICalculatorService
  {
    [OperationContract]
    double Add(double n1, double n2);
    [OperationContract]
    double Subtract(double n1, double n2);
    [OperationContract]
    double Multiply(double n1, double n2);
    [OperationContract]
    double Divide(double n1, double n2);
  
  }
}

CalculatorService.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
  
namespace Nocturne.Learning.WcfAddressDemo
{
  public class CalculatorService : ICalculatorService
  {
    public double Add(double n1, double n2)
    {
      double result = n1 + n2;
      Console.WriteLine("Received Add({0},{1})", n1, n2);
      Console.WriteLine("Return: {0}", result);
      return result;
    }
  
    public double Subtract(double n1, double n2)
    {
      double result = n1 - n2;
      Console.WriteLine("Received Subtract({0},{1})", n1, n2);
      Console.WriteLine("Return: {0}", result);
      return result;
    }
  
    public double Multiply(double n1, double n2)
    {
      double result = n1 * n2;
      Console.WriteLine("Received Multiply({0},{1})", n1, n2);
      Console.WriteLine("Return: {0}", result);
      return result;
    }
  
    public double Divide(double n1, double n2)
    {
      double result = n1 / n2;
      Console.WriteLine("Received Divide({0},{1})", n1, n2);
      Console.WriteLine("Return: {0}", result);
      return result;
    }
  }
}

下面我們就分別來看看怎樣HOST這個服務,怎樣獲取它的元數據。

WSHttpBind方式

這種方式下,元數據可以直接從http地址中獲得。先看看下面這段啟動服務的代碼(注意,我只使用code方式啟動,如果存在app.config,請將其刪除)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
  
namespace Nocturne.Learning.WcfAddressDemo
{
  class Program
  {
    static void Main(string[] args)
    {
      Uri baseAddress=new Uri("http://localhost:8009/MyService");
      ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress);
      
      ServiceMetadataBehavior smb = new ServiceMetadataBehavior()
      {
        HttpGetEnabled = true
      };
      
      host.Description.Behaviors.Add(smb);
  
      host.AddServiceEndpoint(typeof(ICalculatorService), new WSHttpBinding(), baseAddress);
  
      host.Open();
  
      Console.WriteLine("The service is ready.");
      Console.WriteLine("Press <ENTER> to terminate service.");
      Console.WriteLine();
      Console.ReadLine();
  
    }
  }
}

啟動該工程,這時候就可以訪問這個服務了。注意這裡的baseAddress,決定了該host是采用基地址訪問,而這個“訪問”,僅僅是針對endpoint的位置來說的,理解這個概念非常重要。如果我們在將host.AddServiceEndpoint()的最後一個參數改為一個string,比如"CalculatorService“,影響的只是該服務的endpoint地址,對元數據沒有影響。

這個時候,我們就可以通過svcutil來生成輔助文件了,命令如下:

D:\Program\temp>svcutil http://localhost:8009/MyService /language:cs /out:Proxy.cs /config:app.config
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation. All rights reserved.
Attempting to download metadata from 'http://localhost:8009/MyService' using WS-Metadata Exchange or DISCO.
Generating files...
D:\Program\temp\Proxy.cs
D:\Program\temp\app.config

其中的URL參數,就是代碼中寫到的baseAddress,在後面添加endpoint的時候不管最後那個參數寫的是啥,這個命令都這麼寫,因為metadata是屬於一個host的,並不屬於一個endpoint。

如果是通過給工程添加Service Reference,也是在Address裡填入這個baseAddress。如圖所示:

之後該怎麼玩就悉聽尊便了。

NetTcpBinding方式

由於在這種方式下,服務本身是通過NetTcp方式來與客戶端應答的,元數據就得另開一個mex的endpoint,來專門提供。看下面的代碼:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
  
namespace Nocturne.Learning.WcfAddressDemo
{
  class Program
  {
    static void Main(string[] args)
    {
      Uri baseAddress = new Uri("net.tcp://localhost:8009/MyService");
      ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress);
  
      ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
  
      host.Description.Behaviors.Add(smb);
  
      host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
      host.AddServiceEndpoint(typeof(ICalculatorService), new NetTcpBinding(), baseAddress);
  
      host.Open();
  
      Console.WriteLine("The service is ready.");
      Console.WriteLine("Press <ENTER> to terminate service.");
      Console.WriteLine();
      Console.ReadLine();
    }
  }
}

與前面建立WSHttpBinding的代碼有兩個不同的地方。首先是smb裡取消了HttpGetEnabled=true的屬性設置,這是由於我們的基地址不是HTTP地址,會引發異常,錯誤信息是:The HttpGetEnabled property of ServiceMetadataBehavior is set to true and the HttpGetUrl property is a relative address, but there is no http base address. Either supply an http base address or set HttpGetUrl to an absolute address。第二點就是最關鍵的元數據地址,添加了一個MexTcpBinding綁定類型的endpoint,它就承擔為整個service對外提供元數據的任務。元數據的地址就是在基址後面加了“mex”的形式,在這裡就是net.tcp://localhost:8009/MyService/mex。在實際應用中,這個“mex”可以省略,即只用net.tcp://localhost:8009/MyService,系統會自動去尋找mex,而如果在前面建立endpoint的時候,用的是其它的名稱(比如mex1),那就不能省略了。建議使用完整路徑。

D:\Program\temp>svcutil net.tcp://localhost:8009/MyService/mex /language:cs /out:Proxy.cs /config:app.config
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation. All rights reserved.
Attempting to download metadata from 'net.tcp://localhost:8009/MyService' using WS-Metadata Exchange. This URL does not support DISCO.
Generating files...
D:\Program\temp\Proxy.cs
D:\Program\temp\app.config

Add Service Reference的操作類同。

小結

Address和元數據,是部署WCF服務時最最基本的概念,有必要非常熟練地掌握,筆者也只是對常用的兩種綁定方式做了一個討論,更多的內容還有待發掘。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved