Reputation: 1279
I'm trying to call a WCF service.
However, I have the request body as an XML document.
So for instance, instead of this
ListProductsRequest request = new ListProductsRequest();
request.Query = new RootQuery();
request.Query.Product = "milk";
request.Query.Group = "dairy";
ListProductsPortType client = new ListProductsPortTypeClient();
ListProductsResponse response = client.ListProducts(request);
I wanna do this:
String xml = "<Root xmlns=\"urn:ns\"><Query><Group>dairy</Group><Product>milk</Product></Query></Root>";
var request = // read in to XmlReader or XmlDocument or whatever
ListProductsPortType client = new ListProductsPortTypeClient();
var response = client.ListProducts(request);
Is there a way to use the generated proxy, with the advantage of having the data layer security and transport handled for me, but without using the proxy objects?
Thanks, Brecht
Upvotes: 4
Views: 4477
Reputation: 1279
I got this far, thanks to 2GDev's comment. Code without handling exceptions or abnormal situations properly.
This way I can use the generated stub's endpoint (and thus reuse the config etc.)
public void CallWs()
{
WsdlRDListProductsPortTypeClient client = new WsdlRDListProductsPortTypeClient();
String req = "<Root xmlns=\"urn:ns\"><Query><Group>TV</Group><Product>TV</Product></Query></Root>";
CallWs(client.Endpoint, "ListProducts", GetRequestXml(req));
}
public XmlElement CallWs(ServiceEndpoint endpoint, String operation, XmlElement request)
{
String soapAction = GetSoapAction(endpoint, operation);
IChannelFactory<IRequestChannel> factory = null;
try
{
factory = endpoint.Binding.BuildChannelFactory<IRequestChannel>();
factory.Open();
IRequestChannel channel = null;
try
{
channel = factory.CreateChannel(endpoint.Address);
channel.Open();
Message requestMsg = Message.CreateMessage(endpoint.Binding.MessageVersion, soapAction, request);
Message response = channel.Request(requestMsg);
return response.GetBody<XmlElement>();
}
finally
{
if (channel != null)
channel.Close();
}
}
finally
{
if (factory != null)
factory.Close();
}
}
private String GetSoapAction(ServiceEndpoint endpoint, String operation)
{
foreach (OperationDescription opD in endpoint.Contract.Operations)
{
if (opD.Name == operation)
{
foreach (MessageDescription msgD in opD.Messages)
if (msgD.Direction == MessageDirection.Input)
{
return msgD.Action;
}
}
}
return null;
}
When I try this with the basic ICalculator sample from msdn http://msdn.microsoft.com/en-us/library/ms734712.aspx
Which is secured with SPNego, I have to change this a bit, because then we need an IRequestSessionChannel instead of an IRequestChannel.
public XmlElement CallWs(ServiceEndpoint endpoint, String operation, XmlElement request)
{
String soapAction = GetSoapAction(endpoint, operation);
IChannelFactory<IRequestSessionChannel> factory = null;
try
{
factory = endpoint.Binding.BuildChannelFactory<IRequestSessionChannel>();
factory.Open();
IRequestSessionChannel channel = null;
try
{
channel = factory.CreateChannel(endpoint.Address);
channel.Open();
Message requestMsg = Message.CreateMessage(endpoint.Binding.MessageVersion, soapAction, request);
Message response = channel.Request(requestMsg);
return response.GetBody<XmlElement>();
}
finally
{
if (channel != null)
channel.Close();
}
}
finally
{
if (factory != null)
factory.Close();
}
}
It does do the negotiation, and a message seems to be sent, but unfortunately I now get the following error message:
No signature message parts were specified for messages with the 'http://Microsoft.ServiceModel.Samples/ICalculator/Add' action.
Upvotes: 1
Reputation: 2158
I think you could use
ListProductsRequest request = (ListProductsRequest) new XmlSerializer(
typeof(ListProductsRequest)).Deserialize();
to create the corresponding object...
Upvotes: 0
Reputation: 2466
I don't think you can call a WCF service and passing what you want.
The method ListProducts only accept a ListProductsRequest object. So you have to create this kind of object.
String xml = "<Root xmlns=\"urn:ns\"><Query><Group>dairy</Group><Product>milk</Product></Query></Root>";
ListProductsRequest request = MappingObject(xml);
ListProductsPortType client = new ListProductsPortTypeClient();
var response = client.ListProducts(request);
And in the Mapping method you can work with your XML to create an ListproductRequest.
I don't know if there is another way to do this.
Upvotes: 1