为非托管C ++客户端创建WCF服务 [英] Create WCF service for unmanaged C++ clients

查看:180
本文介绍了为非托管C ++客户端创建WCF服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要让非托管的Windows C ++客户端与WCF服务交谈。 C ++客户端可以在Win2000及更高版本上运行。我有一个控制WCF服务和使用哪个C ++ API。因为它是一个专有应用程序,最好是尽可能使用Microsoft的东西,绝对不是GNU许可的API。



我已经研究了以下选项:




  • WWSAPI - 不好,不能在Win 2000客户端上使用。

  • ATL服务器, =http://icoder.wordpress.com/2007/07/25/consuming-a-wcf-service-with-an-unmanaged-c-client-with-credential-passing/>以下指南作为参考。我按照概述的步骤(删除策略引用和展平WSDL),但是生成的WSDL仍然不能由sproxy使用



:对于我可能有的任何人,我们深表歉意。困惑:我正在寻找的是一种从客户端调用WCF服务的方法,其中没有安装.NET框架,所以使用基于.NET的助手库不是一个选项,它必须是纯非托管C ++

解决方案

对于那些有兴趣的人,我发现了一个半工作的ATL服务器解决方案。下面是主机代码,注意它是使用BasicHttpBinding,它是唯一一个与ATL服务器工作:

  var svc = new Service1(); 
Uri uri = new Uri(http:// localhost:8200 / Service1);
ServiceHost host = new ServiceHost(typeof(Service1),uri);

var binding = new BasicHttpBinding();
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService1),binding,uri);
endpoint.Behaviors.Add(new InlineXsdInWsdlBehavior());

host.Description.Behaviors.Add(new ServiceMetadataBehavior(){HttpGetEnabled = true});
var mex = host.AddServiceEndpoint(typeof(IMetadataExchange),MetadataExchangeBindings.CreateMexHttpBinding(),mex);
host.Open();

Console.ReadLine();

代码InlineXsdInWsdlBehavior可以找到这里。需要对InlineXsdInWsdlBehavior执行一个重要的更改,以便在涉及复杂类型时使用sproxy正常工作。它是由sproxy中的错误引起的,它不适当地限定命名空间别名,所以wsdl不能有重复的命名空间别名,或者sproxy将会崩溃。以下是需要更改的函数:

  public void ExportEndpoint(WsdlExporter exporter,WsdlEndpointConversionContext context)
{
int tnsCount = 0;

XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas;

foreach(WsdlDescription wsdl in exporter.GeneratedWsdlDocuments)
{
//
//递归找到由此wsdl
//导入的所有模式,然后添加它们。在此过程中,删除任何
//< xsd:imported />
//
List< XmlSchema> importsList = new List< XmlSchema>();
foreach(wsdl.Types.Schemas中的XmlSchema模式)
{
AddImportedSchemas(schema,schemaSet,importsList,ref tnsCount);
}
wsdl.Types.Schemas.Clear();
foreach(importsList中的XmlSchema模式)
{
RemoveXsdImports(schema);
wsdl.Types.Schemas.Add(schema);
}
}
}


private void AddImportedSchemas(XmlSchema schema,XmlSchemaSet schemaSet,List< XmlSchema> importsList,ref int tnsCount)
{
foreach(XmlSchemaImport import in schema.Includes)
{
ICollection realSchemas = schemaSet.Schemas(import.Namespace);
foreach(realSchemas中的XmlSchema ixsd)
{
if(!importsList.Contains(ixsd))
{
var new_namespaces = new XmlSerializerNamespaces
foreach(ixsd.Namespaces.ToArray()中的var ns)
{
var new_pfx =(ns.Name ==tns)? String.Format(tns {0},tnsCount ++):ns.Name;
new_namespaces.Add(new_pfx,ns.Namespace);
}

ixsd.Namespaces = new_namespaces;
importsList.Add(ixsd);
AddImportedSchemas(ixsd,schemaSet,importsList,ref tnsCount);
}
}
}
}


$ b 步骤是生成C ++头文件:

  sproxy.exe / wsdl http:// localhost:8200 / Service1?wsdl 

,然后C ++程序如下所示:

  using namespace Service1; 

CoInitializeEx(NULL,COINIT_MULTITHREADED);

{
CService1T< CSoapWininetClient> cli;
cli.SetUrl(_T(http:// localhost:8200 / Service1));

HRESULT hr = cli.HelloWorld(); // todo:analyze hr
}

CoUninitialize();
return 0;

结果的C ++代码非常地处理复杂类型,除了它不能将NULL赋给对象。 p>

I need to get unmanaged Windows C++ clients to talk to a WCF service. C++ clients could be running on Win2000 and later. I have a control over both WCF service and which C++ API is being used. Since it's for a proprietary application, it is preferable to use Microsoft stuff where possible, definitely not GNU licensed APIs. Those of you who have it working, can you share a step-by-step process how to make it working?

I have researched following options so far:

  • WWSAPI - not good, will not work on Win 2000 clients.
  • ATL Server, used following guide as a reference. I followed the steps outlined (remove policy refs and flatten WSDL), however the resulting WSDL is still not usable by sproxy

Any more ideas? Please answer only if you actually have it working yourself.

Edit1: I apologize for anyone who I might have confused: what I was looking for was a way to call WCF service from client(s) where no .NET framework is installed, so using .NET-based helper library is not an option, it must be pure unmanaged C++

解决方案

For those who are interested, I found one semi-working ATL Server solution. Following is the host code, notice it is using BasicHttpBinding, it's the only one which works with ATL Server:

        var svc =  new Service1();
        Uri uri = new Uri("http://localhost:8200/Service1");
        ServiceHost host = new ServiceHost(typeof(Service1), uri);

        var binding = new BasicHttpBinding();
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService1), binding, uri);
        endpoint.Behaviors.Add(new InlineXsdInWsdlBehavior());

        host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });
        var mex = host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
        host.Open();

        Console.ReadLine();

code for InlineXsdInWsdlBehavior could be found here . One important change needs to be done to the InlineXsdInWsdlBehavior in order for it to work properly with sproxy when complex types are involved. It is caused by the bug in sproxy, which does not properly scope the namespace aliases, so wsdl cannot have repeating namespace aliases or sproxy will crap out. Here's the functions which needs to change:

    public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
    {
        int tnsCount = 0;

        XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas;

        foreach (WsdlDescription wsdl in exporter.GeneratedWsdlDocuments)
        {
            //
            // Recursively find all schemas imported by this wsdl
            // and then add them. In the process, remove any
            // <xsd:imports/>
            //
            List<XmlSchema> importsList = new List<XmlSchema>();
            foreach (XmlSchema schema in wsdl.Types.Schemas)
            {
                AddImportedSchemas(schema, schemaSet, importsList, ref tnsCount);
            }
            wsdl.Types.Schemas.Clear();
            foreach (XmlSchema schema in importsList)
            {
                RemoveXsdImports(schema);
                wsdl.Types.Schemas.Add(schema);
            }
        }
    }


    private void AddImportedSchemas(XmlSchema schema, XmlSchemaSet schemaSet, List<XmlSchema> importsList, ref int tnsCount)
    {
        foreach (XmlSchemaImport import in schema.Includes)
        {
            ICollection realSchemas = schemaSet.Schemas(import.Namespace);
            foreach (XmlSchema ixsd in realSchemas)
            {
                if (!importsList.Contains(ixsd))
                {
                    var new_namespaces = new XmlSerializerNamespaces();
                    foreach (var ns in ixsd.Namespaces.ToArray())
                    {
                        var new_pfx = (ns.Name == "tns") ? string.Format("tns{0}", tnsCount++) : ns.Name;
                        new_namespaces.Add(new_pfx, ns.Namespace);
                    }

                    ixsd.Namespaces = new_namespaces;
                    importsList.Add(ixsd);
                    AddImportedSchemas(ixsd, schemaSet, importsList, ref tnsCount);
                }
            }
        }
    }

Next step is to generate C++ header:

sproxy.exe /wsdl http://localhost:8200/Service1?wsdl

and then C++ program looks like this:

using namespace Service1;

CoInitializeEx( NULL, COINIT_MULTITHREADED  );

{
	CService1T<CSoapWininetClient> cli;
	cli.SetUrl( _T("http://localhost:8200/Service1") );

	HRESULT hr = cli.HelloWorld(); //todo: analyze hr
}

CoUninitialize();
return 0;

Resulting C++ code handles complex types pretty decently, except that it cannot assign NULL to the objects.

这篇关于为非托管C ++客户端创建WCF服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆