I am trying to invoke WCF service dynamically. I am able connect to the service and invoke methods that do not require any parameters.
ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(this.ServiceBinding, this.EndPoint.Address);
IRequestChannel channel = factory.CreateChannel();
However, I am unable to invoke Operation Contracts that require composite Entity as a parameter.
The following code is used to instantiate the request Message:
Message requestMessage = Message.CreateMessage(this.ServiceBinding.MessageVersion, contractNameSpace, new SimpleMessageBody(value));
The value used in SimpleMessageBody class is serialized value of the entity using DataContractSerializer.
<Person xmlns="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>John Smith</Name></Person>
Operation Contract
public string GetData(Person value)
{
using (MemoryStream ms = new MemoryStream())
{
value = new Person { Name = "John Smith" };
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
ser.WriteObject(ms, value);
var result = UnicodeEncoding.UTF8.GetString(ms.ToArray());
}
return string.Format("You entered: {0}", value.Name);
}
Entity
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
}
The following SOAP message is generated from the above createmessage code:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService1/G开发者_运维技巧etData</a:Action>
<a:MessageID>urn:uuid:cf78d5b7-333b-40eb-a71c-d81cb9c37b5d</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost:52724/Service1.svc</a:To>
</s:Header>
<s:Body><Person xmlns="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>John Smith</Name></Person></s:Body>
</s:Envelope>
However, in order for the Person entity to be populated and the correct operation contract to be executed the SOAP has to be as follows:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService1/GetData</a:Action>
<a:MessageID>urn:uuid:d49bd525-0f30-46fe-94fb-0248c2cb1ea2</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
<s:Body>
<GetData xmlns="http://tempuri.org/">
<value xmlns:d4p1="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:Name>John Smith</d4p1:Name>
</value>
</GetData>
</s:Body>
</s:Envelope>
Please NOTE the message body.
Thanks
I don't know why are you doing it this hard way but if you want to call the method expecting SOAP request you shown you must first provide message contract to your client:
[MessageContract(WrapperName="GetName")]
public class MessageContract
{
[MessageBodyMember(Name="value")]
public Person Person { get; set; }
}
And you will also need similar contract for response.
Default serialization uses wrappers inferred from operation contract names but because you are not providing service contract your serializer doesn't know about existing wrappers because of that you have to provide this additional knowledge manually or redefine your service so that it doesn't expect wrappers elements (it is also done with message contracts and setting their IsWrapped
properties to false
).
精彩评论