我需要让非托管的Windows C ++客户端与WCF服务进行通信。 C ++客户端可以在Win2000及更高版本上运行。我可以控制WCF服务和正在使用的C ++ API。由于它是专有应用程序,因此最好尽可能使用Microsoft的东西,绝对不是GNU许可的API。那些有它工作的人,你能分享一个循序渐进的过程如何让它发挥作用吗?
到目前为止,我已经研究了以下选项:
还有什么想法吗?只有在你真正让自己工作的时候才能回答。
Edit1 :我为任何可能感到困惑的人道歉:我正在寻找的是一种从没有.NET的客户端调用WCF服务的方法框架是安装的,所以使用基于.NET的帮助程序库不是一个选项,它必须是纯粹的非托管C ++
答案 0 :(得分:58)
答案 1 :(得分:12)
对于那些感兴趣的人,我找到了一个半工作的ATL服务器解决方案。以下是主机代码,注意它使用BasicHttpBinding,它是唯一一个与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();
可以找到InlineXsdInWsdlBehavior的代码here。需要对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)
{
//
// 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);
}
}
}
}
下一步是生成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。
答案 2 :(得分:2)
我将创建一个C#托管类来执行WCF工作,并将该类作为COM对象公开给C ++客户端。
答案 3 :(得分:1)
您可以使用已弃用的MS Soap Toolkit轻松实现SOAP客户端。不幸的是,除了迁移到.NET之外,似乎没有替代它。
答案 4 :(得分:0)
您是否可以发布REST Web服务并使用MSXML COM库 - 应该已经安装,具有XML解析器和HTTP库。