Create a web service with XML response - c#

What is the easiest way to create a web service with XML response?
Use WCF to create the web service? (seems really complicated)
If i want to use WCF to create my web service, where do I start?

In your case, I would definitely use WCF with the REST binding (webHttpBinding) - and I would disagree about it being complicated to learn.
Check out these resources to get started:
MSDN WCF REST developer center
DotNet Rocks TV Show #135: Keith Elder Demystifies WCF
DotNet Rocks TV Show #122: Miguel Castro on Extreme WCF

Few links are available in this article. Hope they will help you -
http://social.msdn.microsoft.com/Forums/en/wcf/thread/b082d6de-d1e9-4e51-a0ab-0fe98d7003e6

The easiest way to create a web service with an XML response is, no kidding, to put an XML file on a standard web server and serve it as a static file.
I'm guessing you want something more flexible than that, though...
You've got several options, and WCF is at the more complex (but flexible) end of the spectrum. First question: what's your client? Are you writing it? Do you want to write a web service that can be consumed by other clients?
Do you want to use REST -- i.e. plain-old-XML (POX) over plain-old-HTTP? XML-RPC? SOAP?
WCF supports all of these, so this really depends on which clients you want to support.
Update: If you want to support XML-RPC, you could do worse than start with this implementation of XML-RPC for WCF by Clemens Vasters. I asked a question about this here.

It's actually pretty easy to create a WCF service. There are plenty of tutorials online.
As for returning xml, there are a few ways.
You can do this with an 'old school' SOAP web service by converting the xml to a string in the service and then convert back in the client. It's not pretty but it works.
An alternative, and the way I'd do it, would be to use WCF and create a data contract that maps your xml.
You can do some pretty good stuff with data contracts, like pass round datasets and custom types but this can sometimes limit the binding types you can use.

I just made a web service.
PHP server side code:
<?php // instantiate SOAP server
function sendXmlMsg($msg){
return $msg;
}
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSD
$server = new SoapServer("mark.wsdl");
// Register exposed method
$server->addFunction('sendXmlMsg'); // generate captcha
//$server->addFunction('check_captcha'); // check captcha ID
$server->handle(); //?>
My WSDL file is
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='Msg91'
targetNamespace='http://localhost/webtest/test.wsdl'
xmlns:tns='http://localhost/webtest/test.wsdl'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
<message name='sendXmlMsgRequest'>
<part name='msg' type='xsd:string'/>
</message>
<message name='sendXmlMsgResponse'>
<part name='Result' type='xsd:string'/>
</message>
<portType name='Msg91PortType'>
<operation name='sendXmlMsg'>
<input message='tns:sendXmlMsgRequest'/>
<output message='tns:sendXmlMsgResponse'/>
</operation>
</portType>
<binding name='Msg91Binding' type='tns:Msg91PortType'>
<soap:binding style='rpc'
transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='sendXmlMsg'>
<soap:operation soapAction='urn:xmethods-delayed-quotes#sendXmlMsg'/>
<input>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
</binding>
<service name='Msg91Service'>
<port name='Msg91Port' binding='tns:Msg91Binding'>
<soap:address location='http://localhost/webtest/test.php'/>
</port>
</service>
</definitions>
Client side PHP file:
<?php
$client = new SoapClient("mark.wsdl");
$params= array('HiT');
echo $client->__soapCall( 'sendXmlMsg', $params );
?>
I hope this will help you.

Related

Wcf service server - authentication with usernametoken

we are trying to create server from given demo wsdl. Wsdl does not contains security but we need implement usernametoken where request header looks like this:
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:env="http://www.w3.org/2003/05/soap-envelope" env:mustUnderstand="true">
<wsse:UsernameToken wsu:Id="UsernameToken-7dd435a5-b8bb-4388-bba3-f77512a14351">
<wsse:Username>CES</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">e8I23Z92JGgSREAb=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">v21JzUcrKZiZ7MC==</wsse:Nonce>
<wsu:Created>2017-10-13T13:00:02.221Z</wsu:Created>
</wsse:UsernameToken>
<wsse:SecurityTokenReference>
<wsse:Embedded wsse:ValueType="http://www.asktirweb.org/security/authentication/username" wsu:Id="alex"/>
</wsse:SecurityTokenReference>
</wsse:Security>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://www.asktirweb.org/services/TIRAccountingService-1/sendInvoice</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:321a0dff-61a8-4eae-8934-7f06e8d87648</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">http://wiesbaden:8040/askdemo/hs/AskTirWebDemo/WsSecurityRequests</To>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
Any suggestions ?
Please try the below custom binding, it might be useful to you.
<customBinding>
<binding name="mybinding">
<textMessageEncoding messageVersion="Soap12WSAddressing10">
</textMessageEncoding>
<security authenticationMode="UserNameOverTransport" includeTimestamp="false" >
</security>
<httpsTransport></httpsTransport>
</binding>
</customBinding>
And the request body captured by Fiddle.
Besides, can we use the WSDL file to generate the client configuration, which has contained the essential binding type and security authentication mode? Like the below Tools.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/servicemodel-metadata-utility-tool-svcutil-exe
By default, it is a built-in tool in VS Developer Command Prompts.
svcutil https://vabqia969vm:21011
It will generate the output.config in the current directory, it contains the binding configuration to be used in WCF.
Feel free to let me know if there is anything I can help with.

C# Consuming XML API - No REST

I was wondering how to consume a XML Service, which states: "CarTrawler’s OTA Server does not expose a Web Services interface - i.e. no SOAP-discoverable WSDL. All messages are stateless and no session is maintained between calls.".
The service have targets URL’s defined in order to send the requests.
One possible request may be:
<?xml version="1.0" encoding="UTF-8"?>
<OTA_VehAvailRateRQ
xmlns="http://www.opentravel.org/OTA/2003/05"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opentravel.org/OTA/2003/05 OTA_VehAvailRateRQ.xsd"
Target="Test" Version="1.005">
<POS>
<Source ISOCurrency="EUR">
<RequestorID Type="16" ID="#####" ID_Context="####" />
</Source>
</POS>
<VehAvailRQCore Status="Available">
<VehRentalCore PickUpDateTime="2016-04-01T07:00:00" ReturnDateTime="2016-04-09T19:00:00">
<PickUpLocation CodeContext="####" LocationCode="71" />
<ReturnLocation CodeContext="####" LocationCode="71" />
</VehRentalCore>
<DriverType Age='30'/>
</VehAvailRQCore>
<VehAvailRQInfo PassengerQty='3'>
<Customer>
<Primary>
<CitizenCountryName Code='IE' />
</Primary>
</Customer>
<TPA_Extensions>
<ConsumerIP>999.999.999.999</ConsumerIP>
</TPA_Extensions>
</VehAvailRQInfo>
</OTA_VehAvailRateRQ>
Maybe using HttpClient?, as it has no WSDL and I guess the service isn't REST.
This is no problem. WSDL is just metadata to help you figure out the kind of data you should send or receive. It doesn't mean that the service is not RESTful.
There are many tools that you can use to call a RESTful service. This is my REST client:
https://bitbucket.org/MelbourneDeveloper/restclient-.net
NuGet: Install-Package RESTClient.NET
You should try just doing a simple GET as a string and see what gets returned. If you post the Url of the API, I will try it.

How to add custom security binding credentials to a web service reference?

I'm new to Service Reference stuff so I might need simple explanation.
I got a WSDL:
https://test.servicebench.com/servicebenchv5/services/CRMServiceOrderService?wsdl
I added the Service Reference in my project via MVS2013 without any problem.
Here's the autogenerated app.config file :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CRMServiceOrderBinding">
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint
address="https://test.servicebench.com/servicebenchv5/services/CRMServiceOrderService"
binding="customBinding"
bindingConfiguration="CRMServiceOrderBinding"
contract="ServiceBenchReference.CRMServiceOrderPortType"
name="CRMServiceOrderPort" />
</client>
</system.serviceModel>
</configuration>
Now, every requests I try to make to the server replies me : "Unauthorized".
I pretty sure it's because I didn't passed the required credentials in the SOAP request header.
I need to pass it 3 credentials (or info?) : ServiceBenchID, UserID and password.
I've tried using :
CRMServiceOrderPortTypeClient ServiceOrder = new CRMServiceOrderPortTypeClient();
ServiceOrder.ClientCredentials.UserName.UserName = myUserID;
ServiceOrder.ClientCredentials.UserName.password = myPassword;
but it didn't work. I checked the request via Fiddler and I didn't saw the credentials passed in the header.
So here's my question : How can I get these 3 custom credentials information to be passed in the header correctly ? (So I get a response from the server)
After searching a couple more hours, I manage to find a suitable solution !
Thanks to Thorarin for the piece of code,
How can I pass a username/password in the header to a SOAP WCF Service
It seems that having custom bindings in the app.config file is forcing you to add the security elements manually. I don't think its the best way to do it, but its working like this.

How to set up a schema to use for generating proxy classes

I'm consuming a WSDL and in this WSDL there're some methods and types defined.
Here's an example of the XML in the WSDL:
<operation name="GETSTUFF">
<wsdlsoap:operation soapAction="GETSTUFF"/>
<input name="GETSTUFFSRequest">
<wsdlsoap:body use="literal"/>
</input>
<output name="GETSTUFFSResponse">
<wsdlsoap:body use="literal"/>
</output>
</operation>
The generated method looks like this client.GETSTUFF() which is not that pretty.
The same goes for the complex types defined in the WSDL and the corresponding proxy classes generated when adding a service reference from Visual Studio.
So how do I control how the generated proxy classes and methods are named?
This is really more of a question for the people who wrote the service. If their operation is named GETSTUFF, then your proxy operation will be named GETSTUFF.
If you import the WSDL using wsdl.exe, you can use the /parameters command line parameter to pass an XML file with parameters.
That XML file can reference a SchemaImporterExtension class. You can write a SchemaImporterExtension to format the generated code according to your wishes.
See http://msdn.microsoft.com/en-us/library/system.xml.serialization.advanced.schemaimporterextension.aspx for the SchemaImporterExtension class you must inherit your implementation from, and http://msdn.microsoft.com/en-us/library/w46ccb0h.aspx for a sample program.

C# .NET 4.0 WCF MessageSecurityException, "Security header is empty." when consuming a service

When using WCF and C# in a project I get an exception, MesssageSecurityException, with the message "Security header is empty.". Here follows the response (according to MS Service Trace Viewer):
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="true"></wsse:Security>
<wsa:Action>_WHAT_I_DID_</wsa:Action>
<wsa:RelatesTo>_MSG_ID_OF_REQUEST_</wsa:RelatesTo>
</soapenv:Header>
<soapenv:Body>
_CORRECT_BODY_
</soapenv:Body>
</soapenv:Envelope>
Indeed, the security header is "empty", but it is still correct accprding to the security header definition as far as I can tell.
I've also tried editing the bindings, but that doesn't seem to help as well. I also found a similar problem where enabling EnableUnsecuredResponse would help, but it doesn't here.
Here is the response according to SoapUI:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/>
<wsa:Action>_WHAT_I_DID_</wsa:Action>
<wsa:RelatesTo>_REQ_MSG_ID_</wsa:RelatesTo>
</soapenv:Header>
<soapenv:Body>
_CORRECT_BODY_
</soapenv:Body>
</soapenv:Envelope>
They are almost identical, except for how they close the security header. Which is interesting, but should not raise the exception?
I also found a similar problem where the solution was to create a custom message encoder and strip the entire security header, although this would work it is an extra unneeded step. Is that the only way to do it with .Net and WCF? Can't WCF handle security headers without content?
EDIT:
Clarification of the issue, is writing an encoder which drops the security header the only way to recieve and parse SOAP-messages with empty security headers using WCF?
EDIT2: Adding part of conf:
<binding name="NinjaBinding">
<security allowSerializedSigningTokenOnReply="true" enableUnsecuredResponse="true"
authenticationMode="UserNameOverTransport" requireDerivedKeys="false"
securityHeaderLayout="Lax" includeTimestamp="false" allowInsecureTransport="true"
keyEntropyMode="ClientEntropy"
messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="false">
<localServiceSettings detectReplays="false" />
<secureConversationBootstrap _IDENTICAL_TO_ABOVE_
</secureConversationBootstrap>
</security>
<textMessageEncoding />
<httpsTransport />
</binding>
As far as I know, its configure to allow practically everything?
(Now I'm answering my own question since I've been able to elicit some kind of answer)
In short, no you cannot use WCF "out of the box" (ie through *.config) with application servers which provide empty security headers in responses. You have to implement an encoder which modifies messages to a format acceptable by the WCF-framework.
For more information read this blog which contains a quite good walkthrough of the encoder and its applications. This blog (another blog) also provides a code snippet capable of solving my issue, ie modifying the security header.
I wonder why MS and Oracle products never can co-exist peacefully :D

Categories