2010-06-01 54 views
1

我正在努力从webservice/webclient体系结构迁移到WCF体系结构。这个对象非常复杂,有很多嵌套的xsd和不同的命名空间。代理类是通过将Web引用添加到具有30多个webmethods的原始wsdl并使用xsd.exe生成缺失的SOAPFault对象来生成的。我的试点WCF服务仅包含1个webmethod,它与原始方法之一的确切语法相匹配:1个对象作为参数,返回1个其他对象作为结果值。我使用这些代理类来创建WCF接口,使用以下属性:接口上的XMLSerializerFormat和ServiceContract,来自原始wsdl的OperationContract,指定Action,ReplyAction,全部使用正确的名称空间。我使用SoapUI创建传入的客户端消息;我从原始的WSDL文件生成了一个项目(导致SoapUI项目有30多个方法),并在一个实现的WebMethod中创建了一个新的请求,将url更改为我的wcf webservice并发送消息。由于OperationContractAttribute中指定的(Reply-)Action,消息实际上被接收并正确地反序列化为一个对象。为了实现这一目标(40个小时的谷歌搜索),很多挫折让我使用了一个自定义端点,其中WCF'包裹标签'被删除,嵌套类型的命名空间得到纠正,并且生成的wsdl get变平(为了更好与其他工具兼容,然后MS VisualStudio)。将webclient迁移到WCF; WCF客户端序列化方法的参数名称

界面代码是这样的:

[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document, SupportFaults = true)] 
[ServiceContract(Namespace = Constants.NamespaceStufZKN)] 
public interface IOntvangAsynchroon 
{ 

    [OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/zakLk01", Name = "zakLk01")] 
    [FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)] 
    Bv03Bericht zakLk01([XmlElement("zakLk01", Namespace = Constants.NamespaceStufZKN)] ZAKLk01 zakLk011); 

当我使用一个Web客户端的代码来发送消息,一切正常。我的问题是,当我使用WCF客户端。我使用ChannelFactory < IOntvangAsynchroon>发送消息。但生成的xml看起来不同:它包含方法的参数名称!我花了很多时间来弄清楚这一个,但这里会发生什么:

正确的XML(剥离SOAP信封):

<soap:Body> 
<zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310"> 
<stuurgegevens> 
<berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode> 
<zender xmlns="http://www.egem.nl/StUF/StUF0301"> 
<applicatie>ONBEKEND</applicatie> 
</zender> 
</stuurgegevens> 
<parameters> 
</parameters> 
</zakLk01> 
</soap:Body> 

错误的XML:

<soap:Body> 
<zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310"> 
<zakLk011> 
<stuurgegevens> 
<berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode> 
<zender xmlns="http://www.egem.nl/StUF/StUF0301"> 
<applicatie>ONBEKEND</applicatie> 
</zender> 
</stuurgegevens> 
<parameters> 
</parameters> 
</zakLk011> 
</zakLk01> 
</soap:Body> 

注意' zakLk011'元素?它是我的界面中方法的参数名称!所以现在它是zakLk011,但是当我的参数名称是'zakLk01'时,xml似乎包含了上面标签的一些魔术副本,但没有命名空间。当然,你可以想象在发现它是参数名称之前发生的事情我疯了!

我现在已经创建了一个WCF服务,我不能再使用WCF客户端发送消息。为了清楚起见:该方法在我的webservice上使用WCF客户端调用,但参数对象为空。因为我使用自定义端点来记录传入的xml,所以我可以看到收到的消息正常,但语法错误!

WCF客户端代码:

ZAKLk01 stufbericht = MessageFactory.CreateZAKLk01(); 
ChannelFactory<IOntvangAsynchroon> factory = new ChannelFactory<IOntvangAsynchroon>(new BasicHttpBinding(), new EndpointAddress("http://localhost:8193/Roxit/Link/zkn0310")); 
factory.Endpoint.Behaviors.Add(new LinkEndpointBehavior()); 
IOntvangAsynchroon client = factory.CreateChannel(); 
client.zakLk01(stufbericht); 

我不使用一个生成的客户端,我只是引用类似的我用于将web服务(共享库)。

编辑:当生成服务引用时,它会生成重复的类(不知道为什么..)。但是,当这些副本被删除时,客户端将使用正确的xml发送消息。但是我的架构需要共享库,所以这并不能帮助我。

任何人都可以帮我吗?我无法谷歌任何东西在这...

回答

0

建议:如果您刚刚开始使用WCF,那么先从“WCF方式”开始。一旦你知道如何正确地做到这一点,你就可以开始改变事情。现在,你不知道你的问题是由WCF引起的,还是由于你对WCF的经验不足造成的。

我建议你从零开始,而不是使用[XmlSerializerFormat]。只需创建一个ServiceContract与一个OperationContract。至少应包含一个FaultContract,以便您了解它的工作原理。

使用“添加服务引用”创建一个WCF客户端,并确保它的工作原理。

然后使用WCF服务(不是原始WSDL)中的WSDL创建一个SOAPUI项目。确保有效。

然后你就可以开始改变事物了。试试[XmlSerializerFormat]。尝试添加各种[Xml*]属性。慢慢开始改变事情,直到你看到什么时候休息。

0

好吧,我自己想清楚了。我已经创建了一个可以工作的WCF客户端(服务引用),并且仔细查看生成的代码,我找出了发生的事情。它必须处理WCF包装Webservice方法声明中所用的所有类的方法(所以方法提及的类的属性中使用的类不会被包装)。在我的例子中,ZAKLk01类的主体用XMLElement标签包装,使用parametername作为XMLElement-name。为了摆脱这种行为,我现在正在为我生成的代理类ZAKLk01和Bv03Bericht使用包装类,就像在我的新WCF客户端中生成的类的服务引用代理类一样。这些包装类用MessageContractAttributes装饰。

为了让这些包装类的一个示例:

[MessageContract(IsWrapped = false)] 
public partial class zakLk01Request 
{ 

    [MessageBodyMember(Namespace = Constants.NamespaceStufZKN, Order = 0)] 
    public ZAKLk01 zakLk01; 

    public zakLk01Request() 
    { 
    } 

    public zakLk01Request(ZAKLk01 zakLk01) 
    { 
     this.zakLk01 = zakLk01; 
    } 
} 

我的接口方法现在看起来是这样的:

[OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/Bv03Bericht")] 
[FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)] 
zakLk01Response zakLk01(zakLk01Request zakLk01); 

更清洁的没有的XMLElement标签,该标签功能(产生正确的XML )现在已被包装类取代。

我可以接收非包装xml的原因是我的自定义messageinspector包含一些代码,用于接受未包装的xml消息,而不必将MessageContract标签添加到所有现有类(或创建大量包装类)(用Google搜索它),它没有问题。代码片段:

MessageDescription.Body.WrapperName = null; 

但接收这是由我的(第一)WCF客户端仍然包裹类没有工作,关当然送包裹的消息...

我还是不明白这些Action属性是如何工作的:如果我不提供它们,我生成的wsdl不包含任何方法。那么,现在并不重要,因为我终于可以继续前进,并会在其他时间修改Action属性。