65.9K
CodeProject 正在变化。 阅读更多。
Home

通过 C# 库(.NET 互操作)从 C 语言引用 WebService

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6投票s)

2005年5月5日

5分钟阅读

viewsIcon

63073

提供了从 C 项目通过 C# 库访问 WebService 的分步指南。

引言

在本篇文章中(这是对我上一篇已发布文章的修改!),我将举例说明如何使用 C# 库从 C 项目访问 WebService。此外,WebService 的 URL 也可以从 C 项目中的初始化文件(.ini)动态读取。

因此,这是一个典型的 .NET 互操作场景。C 项目将与 C# 库通信,C# 库再访问 WebService,并将必要的数据检索到 C# 库中。反过来,C# 库应解析返回的 XML,然后将返回的数据序列化为相应的结构,以便 C 项目可以使用它。

解决方案

首先,这是完成此任务的分步指南。

  1. 创建一个新的 C# 库 解决方案资源管理器 -> 添加 -> 添加新项目 -> Visual C# -> 类库。为项目命名(我们称之为 Library)。
  2. 添加对 WebService 的引用,解决方案资源管理器 -> C# 类库的添加引用 -> 添加 Web 引用,然后输入公开的 WebService 的 URL(例如:https://:8080/axis/service1/GmsWs?wsdl)并点击“转到”。一旦 WSDL 显示出来,为 WebService 指定一个描述性名称,然后点击“添加引用”。(我们称此引用为 WebService。)
  3. 现在,已添加 WebService,并创建了一个包装类来与服务交互。右键单击服务的 Web 引用,将 URL 行为从静态更改为动态,因为我们的程序将从初始化文件中动态读取服务 URL,并且构造函数也必须进行修改,使其接受一个字符串(WebService 的 URL)。
  4. 点击解决方案资源管理器选项卡上的“显示所有文件”图标,然后导航到服务引用部分下的 Reference.cs 文件,用自定义构造函数替换 WebService 的构造函数,该构造函数旨在动态读取 URL 并创建包装器。
    [System.Web.Services.WebServiceBindingAttribute(Name="WsSoapBinding",
     Namespace="urn:GmsWs")]
    public class WsAPIService : System.Web.Services.Protocols.
      SoapHttpClientProtocol {
    /// <REMARKS />
    
    /*public WsAPIService() {
    string urlSetting = 
    System.Configuration.ConfigurationSettings.AppSettings
     ["Library.WebService.WsAPIService"];
    if ((urlSetting !=null)) {
        this.Url = string.Concat(urlSetting, "");
    }
    else {
        this.Url = https://:8080/axis/services/GmsWs;
    } */
    //For generating dynamic wrapper classes based on the supplied URL
    
    public WsAPIService(string szURL)   {
        this.Url = szURL; 
    }
  5. 接下来,勾画 C# 库以调用 WebService,在访问方法之前创建 WebService 实例。
    Library.WebService.WsAPIService myService = 
            new Library.WebService.WsAPIService(URL);

    Library 是我们的 C# 库的名称,WebService 是我们引用的 Web Service 的名称。WsAPIService 是服务器端 WebService 的名称。这可以在 WebService 生成的 WSDL 文件的 wsdl:service name =" " 标签中找到。此外,在实例化 WebService 时,必须将其 URL 传递给构造函数,因为我们已将其定义为动态的。

  6. 请记住为需要从 C DLL 访问的所有函数编写接口,因为它将仅通过创建的接口引用 C# 库的方法。
    //Creating interfaces to the C# Library functions which 
    
    //inturn access the webservice 
    
    public interface IMyInterface 
        {
            int LfindName2(string name, string URL);
            string LgetStandardName(string name,string URL);
        }
  7. 此外,在执行 .NET 互操作时,我们必须为创建的接口和类提供 GUID,因为 COM 依赖于注册表。我们必须为公开的接口和类提供唯一的 GUID。这相当于注册组件时生成的 CLSID。工具 -> 创建 GUID -> 注册表格式,这将生成可以合并到代码中的唯一 GUID。现在点击“复制”,然后将其粘贴到接口和其他类声明的上方。
    Guid("876B4EAD-C5C2-4bd2-86C5-E132B1320006")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IMyInterface 
    {..;
    .. }
  8. 还要记住创建与 COM 兼容的数据结构(参考Microsoft 开发人员网络库)。
  9. 在类中编写用于访问 WebService 的函数,请记住为类添加 GUID。
    [Guid("59B6BA59-A296-4b38-AD6E-D0896C5D3FE8")]
    [ClassInterface(ClassInterfaceType.None)]
    public class LibraryImplementation : IMyInterface
    {    
       public int LfindName2(string name, string URL)
        {
            try
            {
                 //access webservice from here
    
            }
            catch
            { ...
            
            }
        }
    }
  10. 一旦 C# 库被勾画并成功编译,将其注册到 GAC,同时将其转换为类型库供 C DLL 导入。
    regasm Library.dll /tlb Library.tlb

    Library 是我们 C# 库的名称;此命令可以放在 Visual Studio IDE 的生成后选项中。)

  11. 请记住程序集的强命名,是的,如果您需要进行 .NET 互操作,则必须这样做,所以请执行
    sn -k Library.snk

    这将生成一个密钥,您需要将其添加到您的项目中。

  12. 转到 assembly.cs 文件并填写标题、描述、公司、产品等。最重要的是,为程序集指定一个特定的版本号,而不是默认的 1.1.*.*,否则每次在进行小型更改后编译 DLL 时,修订号都会递增并在注册表中注册为新库。因此,指定一个像 1.1.1.1 这样的数字将停止不必要地填充注册表。在 assembly.cs 文件中也进行这些更改,将生成的强命名密钥添加到 AssemblyKeyFile
    [assembly: AssemblyDelaySign(false)]
    [assembly: AssemblyKeyFile("Library.snk")]
    [assembly: AssemblyKeyName("")]
  13. 将生成的 Library.tlb 文件导入到 C 项目的头文件中,并创建对 C# 库中声明的托管接口的引用。
    /////////////////////////////////////////////////////
    
    // .NET Specific Header which is included in the C Project
    
    //////////////////////////////////////////////////////////
    
    #pragma warning (disable: 4278)
    #include <string.h>
    
    #import <mscorlib.tlb> raw_interfaces_only
    
    // Ignoring the server namespace and using named guids:
    
    #if defined (USINGPROJECTSYSTEM)
    #import "..\Library\Library.tlb" no_namespace named_guids
    #else  // Compiling from the command line, all files in the same directory
    
    #import "Library.tlb" no_namespace named_guids
    #endif  
    
    using namespace std;
    
    ///////////////////////////////////////////////////////////////
    
    // End .NET Specific Header, #include this header to the C Main 
    
    ///////////////////////////////////////////////////////////////
  14. C 代码只能通过托管接口访问 C# 库。
    IMyInterface *test = NULL;
    CoInitialize(NULL); //Enter Single Threaded Apartment (STA)-STA Thread
    
    //Instantiate the COM object in the appropriate apartment
    
    HRESULT hr = 
    CoCreateInstance(CLSID_LibraryImplementation,NULL,CLSCTX_INPROC_SERVER, 
      IID_IManagedInterface,reinterpret_cast
    (&test)); 
    if (FAILED(hr))
    {
        MessageBox(NULL,"Couldn't create the instance!","C# Library",MB_OK);
    }
  15. 通过创建的托管指针访问相应的 C# 库函数。
    string str;
    //getName is a function in the C# Library which inturn calls an exposed 
    
    //function on the web service
    
    str = test->LfindName2(szSearchName,szURL);
  16. 在函数中使用托管接口后,我们必须清理 COM 以释放内存。
    CoUninitialize();
    test->Release();
  17. 好了,在那之前,我将告诉您如何从 C 中的 .INI 文件读取 WebService 的 URL。
    //Reading the .INI file and getting the url of the webservice
    
    //ini file contains URL=https://:8080/axis/service/GmsWs?wsdl
    
    void CheckWebService(LPCSTR szIniFile)
    {
        CHAR wsURL[128];
        GetPrivateProfileString("Central GMS","URL","",
                              wsURL,sizeof(wsURL),szIniFile);
        if(strcmp(wsURL,"") != 0)   
        {    
            szURL = (_bstr_t) wsURL;    
        }  
        else
        {    
           //default webservice running on localhost
    
           szURL = 
             (_bstr_t) "https://:8080/axis/services/GmsWs?wsdl";    
        }
    }
  18. 最后,处理抛出或接收的错误和异常以及两个库之间的通信。
  19. 将 C# 库转换为类型库也可以通过命令实现
    tlbexp Library.dll /out:Library.tlb

在客户端 PC 上安装生成的 DLL。

最后一步是在目标 PC 上安装生成的 DLL。这可以通过将生成的 C DLL 和 C# 库(Library.dll)复制到目标 PC 的应用程序目录,然后执行以下命令来实现:

regasm Library.dll /tlb:Library.tlb
gacutil /I Library.dll

目标 PC 所需的软件

目标 PC 应安装 .NET Framework 可再发行组件包。您可以从 Microsoft 网站下载。

摘要

本文介绍了一种通过创建 C# 库来在 WebService 和 C 项目之间进行接口,从而从 C 语言访问 WebService 的方法。如需进一步澄清,请给我发送电子邮件。

使用的命名空间

using System;
using System.Runtime.InteropServices; // for interop services

using System.IO;
using System.Xml; //for parsing the xml

using System.Collections; // in case you are using collection to hold data

using System.ComponentModel;
using System.Text;
using System.Data;
© . All rights reserved.