問題描述
我需要讓非托管 Windows C++ 客戶端與 WCF 服務對話.C++ 客戶端可以在 Win2000 及更高版本上運行.我可以控制 WCF 服務和正在使用的 C++ API.由于它用于專有應用程序,因此最好盡可能使用 Microsoft 的東西,絕對不是 GNU 許可的 API.那些已經開始工作的人,你能分享一個如何讓它工作的分步過程嗎?
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 - 不好,不能在 Win 2000 客戶端上運行.
- ATL 服務器,使用 以下指南 作為參考.我遵循了概述的步驟(刪除策略引用并扁平化 WSDL),但是生成的 WSDL 仍然不能被 sproxy 使用
- 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:對于我可能感到困惑的任何人,我深表歉意:我正在尋找一種從沒有 .NET 的客戶端調用 WCF 服務的方法框架已安裝,因此不能使用基于 .NET 的幫助程序庫,它必須是純非托管 C++
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++
推薦答案
對于那些有興趣的人,我找到了一個半工作的 ATL Server 解決方案.以下是主機代碼,注意它使用的是 BasicHttpBinding,這是唯一一個與 ATL Server 一起工作的代碼:
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();
可以在此處找到 InlineXsdInWsdlBehavior 的代碼.需要對 InlineXsdInWsdlBehavior 進行一項重要更改,以便在涉及復雜類型時與 sproxy 一起正常工作.它是由 sproxy 中的錯誤引起的,它沒有正確確定名稱空間別名的范圍,因此 wsdl 不能有重復的名稱空間別名,否則 sproxy 會失敗.以下是需要更改的功能:
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);
}
}
}
}
下一步是生成C++頭文件:
Next step is to generate C++ header:
sproxy.exe /wsdl http://localhost:8200/Service1?wsdl
然后C++程序看起來像這樣:
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;
生成的 C++ 代碼可以很好地處理復雜類型,只是它不能將 NULL 分配給對象.
Resulting C++ code handles complex types pretty decently, except that it cannot assign NULL to the objects.
這篇關于為非托管 C++ 客戶端創建 WCF 服務的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!