Delphi调用WCF异构编程

来源:互联网 发布:淘宝的店铺资质10000元 编辑:程序博客网 时间:2024/04/30 09:50

Delphi调用WCF异构编程

                   老帅

一、项目背景

      几年前,就开始使用Delphi进行分布式开发,最早用的方案是Delphi7+Webservice,在简单的应用场景下,也能够满足需求了。


      喜欢博主的博文,请投出您宝贵的一票,支持一下博主评选博客之星。

      http://vote.blog.csdn.net/blogstaritem/blogstar2013/shuaihj


 

      目前有一个项目,主要的需求点如下:

      1.   有N个系统

      2.   其中有一个系统A为基础数据平台,要为其他系统提供数据服务

      3.   这N个系统中,有用Java开发的Web,有用C#开发的Web,有用Delphi开发的桌面APP,还有用Android开发的手机APP,都要使用系统A提供的基础数据

      4.   系统A虽然要部署在internet上,但是为私有服务,要考虑其安全性。

      5.   系统A要接收多个系统发过来的数据,数据种类将来会有所增加,要保证其可用性和扩展性


      以前曾经测试过Delphi7+WCF的分布式开发架构,但那时Delphi7对WCF支持的不是很好,所以也就没有采用这个架构方案。目前来看如果只是使用Webservice的话,从需求和时间两个维度都不能满足项目的需求。就又想到了WCF,目前我们使用的Delphi版本是DelphiXE3,通过技术预研,我们发现DelphiXE3对WCF有了较好的支持。


二、开发过程

       关于WCF,网上已经有很多介绍的文章,这里就不再展开,直接进入主题,通过一个简单的调用案例,开始我们的Delphi+WCF编程之旅。

       开发环境:VS2013+DelphiXE3
1、为了提供服务,先用VS2013建立一个WCF服务库


1.1确认服务协定IWeatherService

using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace WeatherWcfServiceLibrary{    [ServiceContract]    public interface IWeatherService    {        // 测试返回简单数据类型        [OperationContract]        string GetWeatherDescription(int day);        // 测试返回复杂数据类型(一定要注意,如果返回的是List,List中不能嵌套List,否则客户端无法识别)        [OperationContract]        WeatherData GetWeather(int day);        // 测试参数回传(一定要注意,回传参数不用用out,否则客户端无法识别)        [OperationContract]        void FindWeather(ref WeatherData data);    }        [DataContract]    public class WeatherData    {        string description = " ";        [DataMember]        public string Description        {            get { return description; }            set { description = value; }        }    }}

 

1.2实现WeatherService服务类

using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace WeatherWcfServiceLibrary{    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service1”。    public class WeatherService : IWeatherService    {        public string GetWeatherDescription(int day)        {            return "第" + day.ToString() + "天的天气尚无预测!";        }        public WeatherData GetWeather(int day)        {            WeatherData weatherData = new WeatherData();            weatherData.Description = "预告:第" + day.ToString() + "天的天气万里无云!";            return weatherData;        }        public void FindWeather(ref WeatherData data)        {            data.Description = "先生:正像你告诉我的,今天的天气真不错!";        }    }}
 

2、为了使用上面的服务类库,需要使用VS2013建立一个WCF宿主程序

 

2.1引用上面的服务类库和必要类库System.ServiceModel


2.2在App.config文件中配置服务

<?xml version="1.0" encoding="utf-8" ?><configuration>    <startup>         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />    </startup>  <system.serviceModel>    <!--定制服务行为,服务将使用这种行为-->    <behaviors>      <serviceBehaviors>        <behavior name="Laoshuai.WeatherBehavior">          <!--允许外部获取元数据-->          <serviceMetadata httpGetEnabled="true"/>          <!--不包含详细错误信息-->          <serviceDebug includeExceptionDetailInFaults="false"/>        </behavior>      </serviceBehaviors>    </behaviors>        <!--定制服务-->    <services>      <!--定制服务名称、行为(使用上面定制的行为)-->      <service name="WeatherWcfServiceLibrary.WeatherService" behaviorConfiguration="Laoshuai.WeatherBehavior">        <!--定制服务基地址-->        <host>          <baseAddresses>            <add baseAddress="http://localhost:8801/WeatherService"/>          </baseAddresses>        </host>                <!--定制服务地址(为空则使用上面的基地址)、绑定类型、服务协定-->        <endpoint address="" binding="basicHttpBinding" contract="WeatherWcfServiceLibrary.IWeatherService"/>                <!--定制原数据,对外提供服务查找和引用-->        <endpoint address="mex" binding="basicHttpBinding" contract="IMetadataExchange"/>              </service>         </services>  </system.serviceModel></configuration>

2.3启动服务,准备对外提供服务


using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.ServiceModel;namespace WeatherWcfServiceApplication{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            // 创建一个宿主对象,使服务能运行在这个宿主中            ServiceHost host = new ServiceHost(typeof(WeatherWcfServiceLibrary.WeatherService));            // 打开服务            if (host.State != CommunicationState.Opening)            {                host.Open();                this.Text = "服务状态:" + host.State;            }        }    }}
 

2.4程序启动起来以后,测试一下效果


使用浏览器访问:http://localhost:8801/WeatherService


使用浏览器访问:http://localhost:8801/WeatherService?wsdl

将看到以前直接调用WebService时,一样的XML页面

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://tempuri.org/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" name="WeatherService" targetNamespace="http://tempuri.org/"><wsdl:types><xsd:schema targetNamespace="http://tempuri.org/Imports"><xsd:import schemaLocation="http://localhost:8801/WeatherService?xsd=xsd0" namespace="http://tempuri.org/"/><xsd:import schemaLocation="http://localhost:8801/WeatherService?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/><xsd:import schemaLocation="http://localhost:8801/WeatherService?xsd=xsd2" namespace="http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary"/></xsd:schema></wsdl:types><wsdl:message name="IWeatherService_GetWeatherDescription_InputMessage"><wsdl:part name="parameters" element="tns:GetWeatherDescription"/></wsdl:message><wsdl:message name="IWeatherService_GetWeatherDescription_OutputMessage"><wsdl:part name="parameters" element="tns:GetWeatherDescriptionResponse"/></wsdl:message><wsdl:message name="IWeatherService_GetWeather_InputMessage"><wsdl:part name="parameters" element="tns:GetWeather"/></wsdl:message><wsdl:message name="IWeatherService_GetWeather_OutputMessage"><wsdl:part name="parameters" element="tns:GetWeatherResponse"/></wsdl:message><wsdl:message name="IWeatherService_FindWeather_InputMessage"><wsdl:part name="parameters" element="tns:FindWeather"/></wsdl:message><wsdl:message name="IWeatherService_FindWeather_OutputMessage"><wsdl:part name="parameters" element="tns:FindWeatherResponse"/></wsdl:message><wsdl:portType name="IWeatherService"><wsdl:operation name="GetWeatherDescription"><wsdl:input wsaw:Action="http://tempuri.org/IWeatherService/GetWeatherDescription" message="tns:IWeatherService_GetWeatherDescription_InputMessage"/><wsdl:output wsaw:Action="http://tempuri.org/IWeatherService/GetWeatherDescriptionResponse" message="tns:IWeatherService_GetWeatherDescription_OutputMessage"/></wsdl:operation><wsdl:operation name="GetWeather"><wsdl:input wsaw:Action="http://tempuri.org/IWeatherService/GetWeather" message="tns:IWeatherService_GetWeather_InputMessage"/><wsdl:output wsaw:Action="http://tempuri.org/IWeatherService/GetWeatherResponse" message="tns:IWeatherService_GetWeather_OutputMessage"/></wsdl:operation><wsdl:operation name="FindWeather"><wsdl:input wsaw:Action="http://tempuri.org/IWeatherService/FindWeather" message="tns:IWeatherService_FindWeather_InputMessage"/><wsdl:output wsaw:Action="http://tempuri.org/IWeatherService/FindWeatherResponse" message="tns:IWeatherService_FindWeather_OutputMessage"/></wsdl:operation></wsdl:portType><wsdl:binding name="BasicHttpBinding_IWeatherService" type="tns:IWeatherService"><soap:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="GetWeatherDescription"><soap:operation soapAction="http://tempuri.org/IWeatherService/GetWeatherDescription" style="document"/><wsdl:input><soap:body use="literal"/></wsdl:input><wsdl:output><soap:body use="literal"/></wsdl:output></wsdl:operation><wsdl:operation name="GetWeather"><soap:operation soapAction="http://tempuri.org/IWeatherService/GetWeather" style="document"/><wsdl:input><soap:body use="literal"/></wsdl:input><wsdl:output><soap:body use="literal"/></wsdl:output></wsdl:operation><wsdl:operation name="FindWeather"><soap:operation soapAction="http://tempuri.org/IWeatherService/FindWeather" style="document"/><wsdl:input><soap:body use="literal"/></wsdl:input><wsdl:output><soap:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:service name="WeatherService"><wsdl:port name="BasicHttpBinding_IWeatherService" binding="tns:BasicHttpBinding_IWeatherService"><soap:address location="http://localhost:8801/WeatherService"/></wsdl:port></wsdl:service></wsdl:definitions>


3.使用DelphiXE3调用这个WCF服务

3.1建立一个WinForm程序,引用前面提供的服务



将生成一个服务调用的代理文件WeatherService.pas,源码如下

// ************************************************************************ //// The types declared in this file were generated from data read from the// WSDL File described below:// WSDL     : http://localhost:8801/WeatherService?wsdl//  >Import : http://localhost:8801/WeatherService?wsdl>0//  >Import : http://localhost:8801/WeatherService?xsd=xsd0//  >Import : http://localhost:8801/WeatherService?xsd=xsd2//  >Import : http://localhost:8801/WeatherService?xsd=xsd1// Encoding : utf-8// Version  : 1.0// (2014-01-08 11:40:10 - - $Rev: 52705 $)// ************************************************************************ //unit WeatherService;interfaceuses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;const  IS_OPTN = $0001;  IS_NLBL = $0004;  IS_REF  = $0080;type  // ************************************************************************ //  // The following types, referred to in the WSDL document are not being represented  // in this file. They are either aliases[@] of other types represented or were referred  // to but never[!] declared in the document. The types from the latter category  // typically map to predefined/known XML or Embarcadero types; however, they could also   // indicate incorrect WSDL documents that failed to declare or import a schema type.  // ************************************************************************ //  // !:string          - "http://www.w3.org/2001/XMLSchema"[Gbl]  // !:int             - "http://www.w3.org/2001/XMLSchema"[Gbl]  WeatherData2         = class;                 { "http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary"[GblCplx] }  WeatherData          = class;                 { "http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary"[GblElm] }  // ************************************************************************ //  // XML       : WeatherData, global, <complexType>  // Namespace : http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary  // ************************************************************************ //  WeatherData2 = class(TRemotable)  private    FDescription: string;    FDescription_Specified: boolean;    procedure SetDescription(Index: Integer; const Astring: string);    function  Description_Specified(Index: Integer): boolean;  published    property Description: string  Index (IS_OPTN or IS_NLBL) read FDescription write SetDescription stored Description_Specified;  end;  // ************************************************************************ //  // XML       : WeatherData, global, <element>  // Namespace : http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary  // ************************************************************************ //  WeatherData = class(WeatherData2)  private  published  end;  // ************************************************************************ //  // Namespace : http://tempuri.org/  // soapAction: http://tempuri.org/IWeatherService/%operationName%  // transport : http://schemas.xmlsoap.org/soap/http  // style     : document  // use       : literal  // binding   : BasicHttpBinding_IWeatherService  // service   : WeatherService  // port      : BasicHttpBinding_IWeatherService  // URL       : http://localhost:8801/WeatherService  // ************************************************************************ //  IWeatherService = interface(IInvokable)  ['{791CBBA3-0C97-0B5E-6A23-77A0CBF082AF}']    function  GetWeatherDescription(const day: Integer): string; stdcall;    function  GetWeather(const day: Integer): WeatherData2; stdcall;    procedure FindWeather(const data: WeatherData2); stdcall;  end;function GetIWeatherService(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): IWeatherService;implementation  uses SysUtils;function GetIWeatherService(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): IWeatherService;const  defWSDL = 'http://localhost:8801/WeatherService?wsdl';  defURL  = 'http://localhost:8801/WeatherService';  defSvc  = 'WeatherService';  defPrt  = 'BasicHttpBinding_IWeatherService';var  RIO: THTTPRIO;begin  Result := nil;  if (Addr = '') then  begin    if UseWSDL then      Addr := defWSDL    else      Addr := defURL;  end;  if HTTPRIO = nil then    RIO := THTTPRIO.Create(nil)  else    RIO := HTTPRIO;  try    Result := (RIO as IWeatherService);    if UseWSDL then    begin      RIO.WSDLLocation := Addr;      RIO.Service := defSvc;      RIO.Port := defPrt;    end else      RIO.URL := Addr;  finally    if (Result = nil) and (HTTPRIO = nil) then      RIO.Free;  end;end;procedure WeatherData2.SetDescription(Index: Integer; const Astring: string);begin  FDescription := Astring;  FDescription_Specified := True;end;function WeatherData2.Description_Specified(Index: Integer): boolean;begin  Result := FDescription_Specified;end;initialization  { IWeatherService }  InvRegistry.RegisterInterface(TypeInfo(IWeatherService), 'http://tempuri.org/', 'utf-8');  InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IWeatherService), 'http://tempuri.org/IWeatherService/%operationName%');  InvRegistry.RegisterInvokeOptions(TypeInfo(IWeatherService), ioDocument);  { IWeatherService.GetWeatherDescription }  InvRegistry.RegisterMethodInfo(TypeInfo(IWeatherService), 'GetWeatherDescription', '',                                 '[ReturnName="GetWeatherDescriptionResult"]', IS_OPTN or IS_NLBL);  InvRegistry.RegisterParamInfo(TypeInfo(IWeatherService), 'GetWeatherDescription', 'GetWeatherDescriptionResult', '',                                '', IS_NLBL);  { IWeatherService.GetWeather }  InvRegistry.RegisterMethodInfo(TypeInfo(IWeatherService), 'GetWeather', '',                                 '[ReturnName="GetWeatherResult"]', IS_OPTN or IS_NLBL);  InvRegistry.RegisterParamInfo(TypeInfo(IWeatherService), 'GetWeather', 'GetWeatherResult', '',                                '[Namespace="http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary"]', IS_NLBL);  { IWeatherService.FindWeather }  InvRegistry.RegisterParamInfo(TypeInfo(IWeatherService), 'FindWeather', 'data', '',                                '[Namespace="http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary"]', IS_NLBL);  RemClassRegistry.RegisterXSClass(WeatherData2, 'http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary', 'WeatherData2', 'WeatherData');  RemClassRegistry.RegisterXSClass(WeatherData, 'http://schemas.datacontract.org/2004/07/WeatherWcfServiceLibrary', 'WeatherData');end.


3.2引用并调用服务

unit FormWeatherClient;interfaceuses  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, WeatherService;type  TFrmWeatherClient = class(TForm)    btn1: TButton;    edt1: TEdit;    btn2: TButton;    edt2: TEdit;    btn3: TButton;    edt3: TEdit;    procedure btn1Click(Sender: TObject);    procedure btn2Click(Sender: TObject);    procedure btn3Click(Sender: TObject);  private    { Private declarations }    FWeatherService: IWeatherService;    function GetWeatherService: IWeatherService;  public    { Public declarations }  end;var  FrmWeatherClient: TFrmWeatherClient;implementation{$R *.dfm}procedure TFrmWeatherClient.btn1Click(Sender: TObject);begin  edt1.Text := GetWeatherService.GetWeatherDescription(2);end;procedure TFrmWeatherClient.btn2Click(Sender: TObject);var  data: WeatherData2;begin  data := GetWeatherService.GetWeather(2);  edt2.Text := data.Description;  data.Free;end;procedure TFrmWeatherClient.btn3Click(Sender: TObject);var  data: WeatherData2;begin  data := WeatherData2.Create;  GetWeatherService.FindWeather(data);  edt3.Text := data.Description;end;function TFrmWeatherClient.GetWeatherService: IWeatherService;begin  if not Assigned(FWeatherService) then    FWeatherService := WeatherService.GetIWeatherService();  Result := FWeatherService;end;end.

至此,一个DelphiXE3+WCF异构编程的流程就完成了。


源码下载:http://download.csdn.net/detail/shuaihj/6823535


喜欢博主的博文,请投出您宝贵的一票,支持一下博主评选博客之星。

http://vote.blog.csdn.net/blogstaritem/blogstar2013/shuaihj

4 1
原创粉丝点击