程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 我的WCF之旅(7) - Part II

我的WCF之旅(7) - Part II

編輯:關於.NET

我的WCF之旅(7):面向服務架構(SOA)和面向對象編程(OOP)的結合 - Part II

4.Host Service:http://localhost/Artech.InheritanceHierarchy

現在我們完成了Service的定義,現在我們來Host我們定義的Service,這次我們通過IIS的方式來host service。我們首先在該Website中引用Artech.InheritanceHierarchy.Service Project。然後為FullWhetherForecastService定義相應的.SVC文件(由於Service Contract的繼承關系構成了一種Service Contract的層次結構,從而導致所有定義的Operation都出現在最底層的Contract中,由於SimpleWhetherForecastService的Operation沒有被FullWhetherForecastServiceOverride,所以現在我們只需要Host FullWhetherForecastService就可以了)。

<%@ ServiceHost Service="Artech.InheritanceHierarchy.Service.FullWhetherForecastService,Artech.InheritanceHierarchy.Service" %>

接著我們在Web.config中為Service注冊Endpoint。

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
   <system.serviceModel>
    <services>
      <service name="Artech.InheritanceHierarchy.Service.FullWhetherForecastService" behaviorConfiguration="returnFaults">
        <endpoint contract="Artech.InheritanceHierarchy.Service.IFullWhetherForecast" binding="wsHttpBinding"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="returnFaults">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.web>
    <compilation debug="true">
      <assemblies>
        <add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="Microsoft.Transactions.Bridge, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="SMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.IdentityModel.Selectors, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="System.Web.RegularExpressions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies></compilation>
  </system.web>
</configuration>

5.定義Client:Artech.InheritanceHierarchy.Client

到現在為止,我們完成了Service的定義和Host的工作,換句話說現在我們定義的Whether

Forecast service已經可以訪問,並暴露在這樣的一個Address上:http://localhost/Artech.InheritanceHierarchy/FullWhetherForecastService.svc。現在我們來編寫我們Client來訪問這個Service。值得一說的是,現在這個Sample中,Client是一個獨立的Application,我們既沒有讓他引用我們定義的Artech.InheritanceHierarchy.BusinessEntity(在WCF中,這個相當於Data Contract),也沒有讓它和Service共享同一個Service Contract。這很類似於在純Web環境下調用Service。

我們通過添加Service reference的方式生成我們Client端的code, WCF中的添加Service reference同Web Service中的添加Web reference相識。通過添加Service reference,WCF會為我們生成基於Client的service contract,data contract,proxy,configuraiton,甚至為我們添加System.ServiceNModel dll的引用。下面就是我們生成的Code:

//------------------------------------------------------------------------------
// <auto-generated>
//   This code was generated by a tool.
//   Runtime Version:2.0.50727.312
//
//   Changes to this file may cause incorrect behavior and will be lost if
//   the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Artech.InheritanceHierarchy.Client.WhetherForecastService
{
  using System.Runtime.Serialization;
  using System;

  
  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  [System.SerializableAttribute()]
  public partial class BasicWhetherInfo : object, System.Runtime.Serialization.IExtensibleDataObject
  {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions ConditionField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private double TemperatureField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
      get
      {
        return this.extensionDataField;
      }
      set
      {
        this.extensionDataField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions Condition
    {
      get
      {
        return this.ConditionField;
      }
      set
      {
        this.ConditionField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public double Temperature
    {
      get
      {
        return this.TemperatureField;
      }
      set
      {
        this.TemperatureField = value;
      }
    }
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  public enum WhetherConditions : int
  {

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Clear = 0,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Cloudy = 1,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Overcost = 2,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Rainy = 3,
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  [System.SerializableAttribute()]
  public partial class WindInfo : object, System.Runtime.Serialization.IExtensibleDataObject
  {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection DirectionField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private string SpeedField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
      get
      {
        return this.extensionDataField;
      }
      set
      {
        this.extensionDataField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection Direction
    {
      get
      {
        return this.DirectionField;
      }
      set
      {
        this.DirectionField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public string Speed
    {
      get
      {
        return this.SpeedField;
      }
      set
      {
        this.SpeedField = value;
      }
    }
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  public enum WindDirection : int
  {

    [System.Runtime.Serialization.EnumMemberAttribute()]
    East = 0,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    South = 1,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    West = 2,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    North = 3,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Northeast = 4,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    SouthEast = 5,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Northwest = 6,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Southwest = 7,
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast")]
  public interface IFullWhetherForecast
  {

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfo", ReplyAction="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfoResponse")]
     Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode);

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFullWhetherForecast/GetWindInfo", ReplyAction="http://tempuri.org/IFullWhetherForecast/GetWindInfoResponse")]
     Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode);
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public interface IFullWhetherForecastChannel : Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast, System.ServiceModel.IClientChannel
  {
  }

  [System.Diagnostics.DebuggerStepThroughAttribute()]
  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public partial class FullWhetherForecastClient : System.ServiceModel.ClientBase<Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast>, Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast
  {

    public FullWhetherForecastClient()
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName, string remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public FullWhetherForecastClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    {
    }

    public Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
    {
      return base.Channel.GetBasicWhetherInfo(postalcode);
    }

    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode)
    {
      return base.Channel.GetWindInfo(postalcode);
    }
  }
}

Code比較長,我們現在一部分一部分地來分析。

Part I:Data Contract

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  [System.SerializableAttribute()]
  public partial class BasicWhetherInfo : object, System.Runtime.Serialization.IExtensibleDataObject
  {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions ConditionField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private double TemperatureField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
      get
      {
        return this.extensionDataField;
      }
      set
      {
        this.extensionDataField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions Condition
    {
      get
      {
        return this.ConditionField;
      }
      set
      {
        this.ConditionField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public double Temperature
    {
      get
      {
        return this.TemperatureField;
      }
      set
      {
        this.TemperatureField = value;
      }
    }
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  public enum WhetherConditions : int
  {

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Clear = 0,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Cloudy = 1,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Overcost = 2,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Rainy = 3,
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  [System.SerializableAttribute()]
  public partial class WindInfo : object, System.Runtime.Serialization.IExtensibleDataObject
  {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection DirectionField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private string SpeedField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
      get
      {
        return this.extensionDataField;
      }
      set
      {
        this.extensionDataField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection Direction
    {
      get
      {
        return this.DirectionField;
      }
      set
      {
        this.DirectionField = value;
      }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public string Speed
    {
      get
      {
        return this.SpeedField;
      }
      set
      {
        this.SpeedField = value;
      }
    }
  }

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
     "y")]
  public enum WindDirection : int
  {

    [System.Runtime.Serialization.EnumMemberAttribute()]
    East = 0,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    South = 1,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    West = 2,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    North = 3,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Northeast = 4,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    SouthEast = 5,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Northwest = 6,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Southwest = 7,
}

把這段代碼基本上對應的我們在Artech.InheritanceHierarchy.BusinessEntity定義的Data Contract:兩個Class:BasicWhetherInfo& WindInfo和連個Enum:WindDirection& WhetherConditions。不過有一點我覺得奇怪的是我們原來的BasicWhetherInfo& WindInfo的定義中,我Override了ToString方法,但是在生成的Class中,卻沒有相應的Code。我不清楚Microsoft對此事作怎麼樣的考慮,還是忽略了這一點。

Part II Service Contract

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]  [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast")]
  public interface IFullWhetherForecast
  {
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfo", ReplyAction="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfoResponse")]
     Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode);

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFullWhetherForecast/GetWindInfo", ReplyAction="http://tempuri.org/IFullWhetherForecast/GetWindInfoResponse")]
     Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode);
  }

在Service端,我們通過運用繼承定義了一套Service contract的層次結構,並為處於最底層的Contract公開了一個Endpoint。在Client端,我們通過添加Service reference的方式生成了Client的Service contract的結構。不過Client的Service contract的結構是一種扁平的結構:通過一個Contract定義所有的Operation。

Part III Proxy

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public interface IFullWhetherForecastChannel : Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast, System.ServiceModel.IClientChannel
  {
  }

  [System.Diagnostics.DebuggerStepThroughAttribute()]
  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public partial class FullWhetherForecastClient : System.ServiceModel.ClientBase<Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast>, Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast
  {

    public FullWhetherForecastClient()
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName, string remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public FullWhetherForecastClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public FullWhetherForecastClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    {
    }

    public Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
    {
      return base.Channel.GetBasicWhetherInfo(postalcode);
    }

    public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode)
    {
      return base.Channel.GetWindInfo(postalcode);
    }
}

現在我們可以通過FullWhetherForecastClient這個Proxy Class來訪問Service了。雖然能完成我們的所有操作,但是這樣的代碼總覺得很別扭。我們希望的是以Service端定義結構進行Service的調用:Client具有兩個Proxy:SimpleWhetherForecastClient和FullWhetherForecastClient。FullWhetherForecastClient繼承自SimpleWhetherForecastClient。我們先刪除我們生成的Code,按照以下的步驟來實現這樣功能。

Step 1:定義Client端的Service Contract

ISimpleWhetherForecast

using System;
using System.Collections.Generic;
using System.Text;

using Artech.InheritanceHierarchy.BusinessEntity;
using System.ServiceModel;

namespace Artech.InheritanceHierarchy.Client
{
  [ServiceContract]
  public interface ISimpleWhetherForecast
  {
    [OperationContract]
    BasicWhetherInfo GetBasicWhetherInfo(string postalcode);
  }
}

IFullWhetherForecast.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using Artech.InheritanceHierarchy.BusinessEntity;

namespace Artech.InheritanceHierarchy. Client
{
  [ServiceContract]
  public interface IFullWhetherForecast:ISimpleWhetherForecast
  {
    [OperationContract]
    WindInfo GetWindInfo(string postalcode);
  }
}

除了namespace,和Service端的contract沒有什麼區別。

Step2:引用Artech.InheritanceHierarchy.BusinessEntity

Step3:  配置Endpoint

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="http://localhost/Artech.InheritanceHierarchy/FullWhetherForecastService.svc"
        binding="wsHttpBinding" bindingConfiguration="" contract="Artech.InheritanceHierarchy.Client.IFullWhetherForecast"/>
    </client>
  </system.serviceModel>
</configuration>

因為Service端的Endpoint對應的Contract是Artech.InheritanceHierarchy.Service IFullWhetherForecast,所以我們適應對應的Client端的Contract:Artech.InheritanceHierarchy.Client.IFullWhetherForecast

Step 4:建立Proxy

SimpleWhetherForecastClient.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using Artech.InheritanceHierarchy.BusinessEntity;

namespace Artech.InheritanceHierarchy.Client
{
  public class SimpleWhetherForecastClient:ClientBase<IFullWhetherForecast>,ISimpleWhetherForecast
  {
    ISimpleWhetherForecast Members#region ISimpleWhetherForecast Members

    public BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
    {
      return this.Channel.GetBasicWhetherInfo(postalcode);
    }

    #endregion
  }
}

FullWhetherForecastClient.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Artech.InheritanceHierarchy.Client
{
  public class FullWhetherForecastClient:SimpleWhetherForecastClient,IFullWhetherForecast
  {

    IFullWhetherForecast Members#region IFullWhetherForecast Members

    public Artech.InheritanceHierarchy.BusinessEntity.WindInfo GetWindInfo(string postalcode)
    {
      return this.Channel.GetWindInfo(postalcode);
    }

    #endregion
  }
}

現在通過SimpleWhetherForecastClient和FullWhetherForecastClient完全以OO的方式優雅地調用Whether forecast service。

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