Javascript (or old asp 3) to WCF calls
I have been asked these days to find a solution of how to call WCF service from old asp 3 code , Not ASP.NET, but asp 3. you know: VBScript, option explicit, dim..... :-)
Apparently this is not trivial task at all. If you try to read about it on the net the following "buzzwords" will come up: Pox, REST, RestFull service, WebGet, WebInvoke....
In simple words, POX is a "plain old xml" meaning messages that consist solely of XML payloads without any enclosing SOAP envelope.We will use pox messages when there is no need for the advanced capablities of soap and WS-*, Like when using simple http GET or HTTP POST.
REST means "Representational State Transfer" or in simpler words: how do we use the http principles we already know to call WCF service operations.
This feature is supported only in .NET Framework 3.5, so use this WCF feature after installing the 3.5 version of the .NET Framework.
As you probably know, A WCF service can have many endpoint. Each endpoint has it's own binding. The addresses for these endpoint will be unique for each endpoint, like:
and so on. Each endpoint binding will describe the communication protocol this endpoint agrees on. So why do i need anything special to call this WCF service, why does the wshttpbinding or the basichttpbinding are not good enough?
Well , basically when we used HTTP GET or HTTP POST up until now , either when using web service nor when we used WCF service , the messages were SOAP messages.We can however send now "clean" xml messages, or simply using the query string to send the date to the WCF service operations.
Another term we need to realize is "Resource", a Resource is identified by URI and is used to uniquely identify an operation.When we used SOAP web services we used a single URI and we added an operation to this URI to specify which operation we wish to invoke. On the other hand "RESTful web service" uses a unique URI to reference every resource, and HTTP verbs to define actions on those resources.
OK, enough with that, lets show some simple WCF service and how we actually communicate with this service.
Here is my WCF Service code:
namespace DemoWCFService
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetsProperty1();
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "/Person")]
Person GetDTO();
/// <summary>
/// This is not working a real post. it still goes to the quesry string
/// </summary>
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped ,
UriTemplate = "Person2?Property1={sProperty1}&Property2={nProperty2}&Property3={bProperty3}")]
Person GetDTO2(string sProperty1, int nProperty2, bool bProperty3);
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "Person4?Property1={sProperty1}&Property2={nProperty2}&Property3={bProperty3}")]
Person GetDTO4(string sProperty1, int nProperty2, bool bProperty3);
[OperationContract]
[WebInvoke(Method="GET",
UriTemplate = "Person3?Property1={sProperty1}&Property2={nProperty2}&Property3={bProperty3}")]
int GetDTO3(string sProperty1, int nProperty2, bool bProperty3);
[OperationContract]
[WebInvoke(UriTemplate = "Person5")]
string GetDTO5(Customer c);
}
[DataContract]
public class Person
{
[DataMember]
public string sProperty1 = "123";
[DataMember]
public int nProperty2 = 123;
[DataMember]
public bool bProperty3 = true;
}
}
Note that i have created a WCF service with 5 operations, some of them will be used to explain this sample.
I also created a composite class named "Person" which contains some data members one is of type string, the second is of type int and the third is if type boolean. This will be the DTO(data transfer object) some some of the calls.
The most important code to notice is the WebInvoke attribute on the operations we declared.There is also a WebGet attribute that serve for the exact purpose only for HTTP GET requests, so no Method parameter should be specified there.
This attribute is applied to a service operation in addition to the OperationContractAttribute and associates the operation with a UriTemplate as well as an underlying transport verb that represents an invocation (for example, HTTP POST, PUT, or DELETE).
Notice also for the use of the UriTemplate which provides the mapping between a request URI and an OperationContract and it identifies the named values that are subsequently bound to matching OperationContract method parameters.
Now lets see the WCF service implementation, nothing special here:
namespace DemoWCFService
{
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class Service1 : IService1
{
private Person oPerson = new Person();
public string GetsProperty1()
{
return oPerson.sProperty1;
}
public Person GetDTO()
{
return this.oPerson;
}
public Person GetDTO2(string sProperty1, int nProperty2, bool bProperty3)
{
return this.oPerson;
}
public Person GetDTO4(string sProperty1, int nProperty2, bool bProperty3)
{
return this.oPerson;
}
public int GetDTO3(string sProperty1, int nProperty2, bool bProperty3)
{
return 590;
}
}
}
And finally , here is the asp 3 code (that can be easily be transformed
to JavaScript ajax calls)
<%
Set objXMLHTTP = Server.CreateObject("Microsoft.XMLHTTP")
'Set the name Person as it is in the WebInvoke attribute on the WCF service
dim sURL
sURL = "http://localhost./WCFService/Service.svc/pox/Person"
'Built the data object you wish to send
dim sBody
sBody = ""
objXMLHTTP.Open "POST", sURL, false
objXMLHTTP.setRequestHeader "Content-type", "application/xml; charset=utf-8"
objXMLHTTP.setRequestHeader "Content-type", "application/soap+xml; charset=utf-8"
objXMLHTTP.Send sBody
strXML = objXMLHTTP.ResponseText
Response.Write("RESPONSE STATUS: " & objXMLHTTP.status &
" RESPONSE STATUS TEXT: " & objXMLHTTP.statusText )
Response.Write("<br>" & Server.HTMLEncode(strXML))
Set objXMLHTTP = Nothing
Response.Write("<br><br>")
'Now calling another function on the WCF with parameters
Set objXMLHTTP2 = Server.CreateObject("Microsoft.XMLHTTP")
'Set the name Person as it is in the WebInvoke attribute on the WCF service
dim sURL2
sURL2 = "http://localhost./WCFService/Service.svc/pox/Person2"
sURL2 = sURL2 & "?Property1=somestring&Property2=5555555&Property3=True"
objXMLHTTP2.Open "POST", sURL2, false
objXMLHTTP2.setRequestHeader "Content-type", "application/xml; charset=utf-8"
objXMLHTTP2.setRequestHeader "Content-type", "application/soap+xml; charset=utf-8"
objXMLHTTP2.setRequestHeader "Content-type", "text/xml"
objXMLHTTP2.Send null
strXML2 = objXMLHTTP2.ResponseText
Response.Write("RESPONSE STATUS: " & objXMLHTTP2.status
& " RESPONSE STATUS TEXT: " & objXMLHTTP2.statusText )
Response.Write("<br>" & Server.HTMLEncode(strXML2))
Set objXMLHTTP2 = Nothing
Response.Write("<br><br>")
'Now calling another function on the WCF with parameters
Set objXMLHTTP3 = Server.CreateObject("Microsoft.XMLHTTP")
'Set the name Person as it is in the WebInvoke attribute on the WCF service
dim sURL3
sURL3 = "http://localhost./WCFService/Service.svc/pox/Person3"
sURL3 = sURL3 & "?Property1=somestring&Property2=123&Property3=true"
objXMLHTTP3.Open "GET", sURL3, false
objXMLHTTP3.setRequestHeader "Content-type", "application/xml; charset=utf-8"
objXMLHTTP3.setRequestHeader "Content-type", "application/soap+xml; charset=utf-8"
objXMLHTTP3.Send
strXML3 = objXMLHTTP3.ResponseText
Response.Write("RESPONSE STATUS: " & objXMLHTTP3.status
& " RESPONSE STATUS TEXT: " & objXMLHTTP3.statusText )
Response.Write("<br>" & Server.HTMLEncode(strXML3))
Set objXMLHTTP3 = Nothing
Response.Write("<br><br>")
'Now calling another function on the WCF with parameters
Set objXMLHTTP4 = Server.CreateObject("Microsoft.XMLHTTP")
'Set the name Person as it is in the WebInvoke attribute on the WCF service
dim sURL4
sURL4 = "http://localhost./WCFService/Service.svc/pox/Person4"
'Built the data object you wish to send
dim sBody4
sBody4 = "<Person4 sProperty1='somestring' nProperty2=123 nProperty2=true />"
objXMLHTTP4.Open "POST", sURL4, false
objXMLHTTP4.setRequestHeader "Content-type", "text/xml"
objXMLHTTP4.setRequestHeader "Content-type", "application/xml; charset=utf-8"
objXMLHTTP4.setRequestHeader "Content-type", "application/soap+xml; charset=utf-8"
objXMLHTTP4.Send sBody4
strXML4 = objXMLHTTP4.ResponseText
Response.Write("RESPONSE STATUS: " & objXMLHTTP4.status
& " RESPONSE STATUS TEXT: " & objXMLHTTP4.statusText )
Response.Write("<br>" & Server.HTMLEncode(strXML4))
Set objXMLHTTP4 = Nothing
Response.Write("<br><br>")'Now calling another function on the WCF with parameters
Set objXMLHTTP5 = Server.CreateObject("Microsoft.XMLHTTP")
'Set the name Person as it is in the WebInvoke attribute on the WCF service
dim sURL5
sURL5 = "http://localhost./WCFService/Service.svc/pox/Person5"
'Built the data object you wish to send
dim sBody5
sBody5 = "<Customer><ID>123</ID><Name>Demo User111121212</Name></Customer>"
objXMLHTTP5.Open "POST", sURL5, false
objXMLHTTP5.setRequestHeader "Content-type", "application/xml; charset=utf-8"
objXMLHTTP5.Send sBody5
strXML5 = objXMLHTTP5.ResponseText
Response.Write("RESPONSE STATUS: " & objXMLHTTP5.status & " RESPONSE STATUS TEXT: " & objXMLHTTP5.statusText )
Response.Write("<br>" & Server.HTMLEncode(strXML5))
Set objXMLHTTP5 = Nothing
Response.Write("<br><br>")
%>
Notes:
1. If you wish to watch the http requests using fiddler, just convert the code
portion you need to JavaScript. For proxy reasons fiddler will not show the http request
for you server side calls.
2. Notice the last call to the service, finding out how to invoke a POST request and
finding the xml format needed was hard.
Notice that the call for Person2 (which is mapped to GetDTO2) does a post request as well,
what looking at fiddler , the data is transmitted in the query string and not in the request
body, this is why i create the last call to Person4
3. You need to take special care on the order in wich you send the arguments to the WCF operations. You can use the Order property on the DataMember Attribute in the WCF composite type.
4. If you look at the following figure you will notice no soap is being send here.