DCSIMG
Javascript (or old asp 3) to WCF calls - Pini Dayan

Pini Dayan

The best thing about a boolean is even if you are wrong, you are only off by a bit.

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.

image

 
Posted: Dec 07 2008, 05:23 AM by Pini Dayan | with 7 comment(s) |
תגים:,

Comments

Jonathan Wax said:

Hi Pini,

Thank you, this was the information I was looking for. One wonders how this is not part of the samples in .NET 3.5 SDK since RESTful APIS are the most popular in this day and age for internet facing APIs.

Thx

Jonathan.

# January 6, 2009 6:32 AM

Pini Dayan said:

Yes you are right

it took me some time to find how it is being done

# January 8, 2009 11:31 AM

Aparna said:

I have a set of WCF services which need to be exposed to both ASP2.0, ASP.NET clients. Is it mandatory that the WCF services be restful for being callable by ASP2.0 ?

Thanks.

# February 19, 2009 5:10 PM

Pini Dayan said:

Hi, It depend on if you want to call the WCF service from your code behind or from your client side.

What is the scanerio in your case?

# February 20, 2009 5:59 PM

Mekala said:

Hi,

I tried the given sample and I am getting the following error:

msxml3.dll error '80072f78'

The server returned an invalid or unrecognized response

Any suggestion on this please?

# June 23, 2009 2:38 PM

Patrick Elmer said:

Hi,

And How do I call WCF service with WsHttpBinding from old asp 3 ?

Any suggestion?

Thanx

# October 14, 2009 12:33 PM

Pini Dayan said:

Have you tried my samples with this binding?

# October 14, 2009 1:50 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: