Hosting webservice in service application

S

Stephan Steiner

I have to write a service application which needs two way
communication with a web service developed by another party. Making
calls to that third party server is not a problem, but I'm having some
trouble finding a suitable architecture for the reverse way.
The way the third party service talks to my application is as follows:
I have a WSDL file that I need to implement and the third party
service makes HTTP POSTs to an URL I give to it (by making a call to
the webservice that the third party software hosts). Creating a server
stub from the WSDL is no problem, neither is implementing that
interface in a webservice on its own. But that means the webservice
runs on IIS and that's where the problem starts.. now I have my
windows service that makes the first call to the third party service..
so my service needs to run first. If I host my own webservice on IIS,
that means I need to create a communication channel between the
webservice running on IIS and my windows service. In the past I used
to do it (with Java by the way) by either simply hosting the service
on the webserver (with the disadvantage that somebody has to make a
call to the webserver of initialize the whole thing), or by creating
an RMI communication channel between the part running on the
application server and the windows service (that alleviates the
problem of having to make a call to the webserver first.. but it means
I need to implement a remote interface which is additional work)..

In the case I'm looking at now, the windows service needs to run first
so running the whole thing on IIS is out, which leaves remoting (or
WCF).. but I have a bunch of different calls that the third party
server can make so the interface between the part running on IIS and
my windows service would be quite involved.

I looked a bit into http servers written in C#.. there are, but the
problem there is that while you get the HTTP POST, you need to either
parse it manually (ugh), or you need to find a way to turn the content
of the request into the object defined by the WSDL file. I'm
wondering.. is there a way to do that without manual parsing?
Alternatively, I found that it's possible to host my own asp.net
process within an application by using
ApplicationHost.CreateApplicationHost in the System.Web.Hosting
namespace. I got that working and it serves simple http pages I put in
the appropriate path.. but obviously Visual Studio won't even let me
create a web service within my service application, let alone deploy a
webservice in my hosted server. So, I'm wondering if there is a way to
get this working using this approach.. have everything in one
solution, have my webservice implementing the wsdl deploy it upon
runtime in my hosted asp.net process and have it forward all events to
my other code (so I can debug and whatnot).

Regards
Stephan
 
O

Ollis

In the case I'm looking at now, the windows service needs to run first
so running the whole thing on IIS is out, which leaves remoting (or
WCF).. but I have a bunch of different calls that the third party
server can make so the interface between the part running on IIS and
my windows service would be quite involved.

There is something else that you might consider with application
commnications called SQL Server 2005 Broker.

http://msdn.microsoft.com/en-us/library/ms345108.aspx
http://www.developer.com/db/article.php/3640771


1) The Service Broker can be a Web service client.
2) The Broker being a Web service client can place XML data into a SQL
server message queue.
3) Windows Service application can read a message from the message queue.
4) Windows Service can place a message in a queue to control the Broker.
5) Windows Service can place a message in a queue for outbound to a remote
site.

All the above I am doing with a project I am working on at this time.

It's not unlike WCF, but MS SQL server 2005 provides the plumbing.
And it can be debug in VS IDE.

This is a good book on it. isbn 978-1-59059-842-9
 
N

Nicholas Paldino [.NET/C# MVP]

Stephan,

The main mistake here is that you are assuming you can't host requests
in your service. You don't need IIS specifically (but if you are looking at
a high volume of calls, or want IIS's process management as well as
authentication/authorization, you are more than welcome to do so).

You could just as easily host the service that handles the requests from
the webservice using a ServiceHost instance in WCF and exposing the
contract.
 
S

Stephan Steiner

Nicholas

Sorry for the late reply.. Your message was just enough to get me
onto the proper path with this:
http://blogs.msdn.com/sonuarora/arc...-datacontractserializer-vs-xmlserializer.aspx.
I used svcutil to create the interface from my wsdl file (at the
bottom). Then I created the class implementing the interface and
hosted the whole thing and it runs. So far so good. Then I had the
third party software start sending events.. and I get at most one
event. Looking at the data exchange with Wireshark I noted that my
server would return HTTP 500 errors all the time - so I turned on
custom error messages.

No for instance for an onLineState message, the error my app returns
is
Cannot assign object of type System.Xml.XmlNode[] to an object of type
LineState
The error is similar for all the other operations that do not work
(the only one that works is onPhoneSetStaticState).. it's always the
object that's part of the call that cannot be deserialized.

And here's the wireshark dump of the message:

POST /XMLPhoneEvents HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related,
text/*
User-Agent: Axis/1.4
Host: 10.145.18.29
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: "onLineState"
Content-Length: 505

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://
www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:blush:nLineState
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://xmlapi.alcatel.com/phone"><sessionId
xsi:type="xsd:string">3453</sessionId><state
xsi:type="ns1:LineState">IN_SERVICE</state></ns1:blush:nLineState></
soapenv:Body></soapenv:Envelope>

Is there a way to modify the WSDL / an option in svcutil that would
generate a stub that works with the following WSDL file for all the
calls?

Regards
Stephan

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://xmlapi.alcatel.com/phone"
xmlns:impl="http://xmlapi.alcatel.com/phone"
xmlns:tns1="http://xmlapi.alcatel.com/phone/types"
xmlns:tns2="http://xmlapi.alcatel.com/phonesetprogramming/types"
xmlns:intf="http://xmlapi.alcatel.com/phone"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">


<wsdl:types>

<schema
targetNamespace="http://xmlapi.alcatel.com/phone"
xmlns="http://www.w3.org/2001/XMLSchema">

<import namespace="http://xmlapi.alcatel.com/phone/types"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

<complexType name="ArrayOf_tns1_Call">
<complexContent>
</restriction>
</complexContent>
</complexType>

</schema>

<schema
targetNamespace="http://xmlapi.alcatel.com/phone/types"
xmlns="http://www.w3.org/2001/XMLSchema">

<import namespace="http://xmlapi.alcatel.com/phone"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

<simpleType name="CallState">
<restriction base="xsd:string">
<enumeration value="init"/>
<enumeration value="ringingIncoming"/>
<enumeration value="ringingOutgoing"/>
<enumeration value="active"/>
<enumeration value="held"/>
<enumeration value="conferenced"/>
<enumeration value="recording"/>
<enumeration value="waiting"/>
<enumeration value="dialing"/>
<enumeration value="releasing"/>
<enumeration value="unreacheable"/>
<enumeration value="busytone"/>
<enumeration value="opereserved"/>
<enumeration value="paging"/>
<enumeration value="unknown"/>
</restriction>
</simpleType>

<simpleType name="MessageType">
<restriction base="xsd:string">
<enumeration value="apology"/>
<enumeration value="unknown"/>
</restriction>
</simpleType>

<complexType name="Call">
<sequence>
<element name="callRef" type="xsd:long"/>
<element name="correlator" nillable="true" type="xsd:hexBinary"/>
<element name="message" nillable="true" type="xsd:string"/>
<element name="msgtype" nillable="true" type="tns1:MessageType"/>
<element name="name" nillable="true" type="xsd:string"/>
<element name="number" nillable="true" type="xsd:string"/>
<element name="state" nillable="true" type="tns1:CallState"/>
</sequence>
</complexType>

<simpleType name="NomadMode">
<restriction base="xsd:string">
<enumeration value="privatePhone"/>
<enumeration value="local"/>
<enumeration value="voip"/>
</restriction>
</simpleType>

<simpleType name="LineState">
<restriction base="xsd:string">
<enumeration value="IN_SERVICE"/>
<enumeration value="OUT_OF_SERVICE"/>
<enumeration value="UNKNOWN"/>
</restriction>
</simpleType>

</schema>

<schema
targetNamespace="http://xmlapi.alcatel.com/phonesetprogramming/
types"
xmlns="http://www.w3.org/2001/XMLSchema">

<import namespace="http://xmlapi.alcatel.com/phonesetprogramming"/>
<import namespace="http://xmlapi.alcatel.com/common"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

<simpleType name="AlcForwardTargetType">
<restriction base="xsd:string">
<enumeration value="NONE"/>
<enumeration value="NUMBER"/>
<enumeration value="VOICE_MAIL"/>
<enumeration value="ROUTING_SERVICE"/>
</restriction>
</simpleType>

<simpleType name="AlcForwardType">
<restriction base="xsd:string">
<enumeration value="NO_FORWARD"/>
<enumeration value="IMMEDIATE"/>
<enumeration value="ON_BUSY"/>
<enumeration value="ON_NO_ANSWER"/>
<enumeration value="ON_BUSY_OR_NO_ANSWER"/>
</restriction>
</simpleType>

<complexType name="AlcForwardState">
<sequence>
<element name="firstName" nillable="true" type="xsd:string"/>
<element name="name" nillable="true" type="xsd:string"/>
<element name="targetNumber" nillable="true" type="xsd:string"/>
<element name="targetType" nillable="true"
type="tns2:AlcForwardTargetType"/>
<element name="type" nillable="true" type="tns2:AlcForwardType"/>
</sequence>
</complexType>

<simpleType name="AlcOverflowType">
<restriction base="xsd:string">
<enumeration value="NO_OVERFLOW"/>
<enumeration value="ON_BUSY"/>
<enumeration value="ON_NO_ANSWER"/>
<enumeration value="ON_BUSY_OR_NO_ANSWER"/>
</restriction>
</simpleType>

<complexType name="AlcStaticState">
<sequence>
<element name="associate" nillable="true" type="xsd:string"/>
<element name="campOnActivated" type="xsd:boolean"/>
<element name="doNotDisturbActivated" type="xsd:boolean"/>
<element name="forwardState" nillable="true"
type="tns2:AlcForwardState"/>
<element name="locked" type="xsd:boolean"/>
<element name="overflowType" nillable="true"
type="tns2:AlcOverflowType"/>
</sequence>
</complexType>

</schema>

</wsdl:types>

<wsdl:message name="onSessionClosed">
<wsdl:part name="sessionId" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="onSessionClosedResponse">
</wsdl:message>

<wsdl:message name="onCallState">
<wsdl:part name="sessionId" type="xsd:string"/>
<wsdl:part name="calls" type="impl:ArrayOf_tns1_Call"/>
</wsdl:message>
<wsdl:message name="onCallStateResponse">
</wsdl:message>

<wsdl:message name="onNewSession">
<wsdl:part name="sessionId" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="onNewSessionResponse">
</wsdl:message>

<wsdl:message name="onConnectionDown">
</wsdl:message>
<wsdl:message name="onConnectionDownResponse">
</wsdl:message>

<wsdl:message name="onPhoneSetStaticState">
<wsdl:part name="sessionId" type="xsd:string"/>
<wsdl:part name="state" type="tns2:AlcStaticState"/>
</wsdl:message>
<wsdl:message name="onPhoneSetStaticStateResponse">
</wsdl:message>

<wsdl:message name="onUnansweredCall">
<wsdl:part name="sessionId" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="onUnansweredCallResponse">
</wsdl:message>

<wsdl:message name="onNomadState">
<wsdl:part name="sessionId" type="xsd:string"/>
<wsdl:part name="mode" type="tns1:NomadMode"/>
<wsdl:part name="homeNumber" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="onNomadStateResponse">
</wsdl:message>

<wsdl:message name="onLineState">
<wsdl:part name="sessionId" type="xsd:string"/>
<wsdl:part name="state" type="tns1:LineState"/>
</wsdl:message>
<wsdl:message name="onLineStateResponse">
</wsdl:message>







<wsdl:portType name="XmlPhoneEvents">

<wsdl:blush:peration name="onCallState" parameterOrder="sessionId calls">
<documentation>This notification is sent each time a call's state
has changed.</documentation>
<wsdl:input name="onCallState" message="impl:blush:nCallState"/>
<wsdl:blush:utput name="onCallStateResponse"
message="impl:blush:nCallStateResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onNewSession" parameterOrder="sessionId">
<documentation>This notification is sent when another XmlPhone
session has been opened for the same user.</documentation>
<wsdl:input name="onNewSession" message="impl:blush:nNewSession"/>
<wsdl:blush:utput name="onNewSessionResponse"
message="impl:blush:nNewSessionResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onSessionClosed" parameterOrder="sessionId">
<documentation>This notification is sent when the XmlPhone session
has been closed after a timeout.</documentation>
<wsdl:input name="onSessionClosed" message="impl:blush:nSessionClosed"/>
<wsdl:blush:utput name="onSessionClosedResponse"
message="impl:blush:nSessionClosedResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onConnectionDown">
<documentation>This notification is sent when the event connection
<wsdl:blush:utput name="onConnectionDownResponse"
message="impl:blush:nConnectionDownResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onPhoneSetStaticState"
parameterOrder="sessionId state">
<documentation>This notification is sent each time the static state
of the phone set changes.</documentation>
<wsdl:input name="onPhoneSetStaticState"
message="impl:blush:nPhoneSetStaticState"/>
<wsdl:blush:utput name="onPhoneSetStaticStateResponse"
message="impl:blush:nPhoneSetStaticStateResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onUnansweredCall" parameterOrder="sessionId">
<documentation>This notification is sent each time a new incoming
<wsdl:blush:utput name="onUnansweredCallResponse"
message="impl:blush:nUnansweredCallResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onNomadState" parameterOrder="sessionId mode
homeNumber">
<documentation>This notification is sent each time the nomadic
state has changed.</documentation>
<wsdl:input name="onNomadState" message="impl:blush:nNomadState"/>
<wsdl:blush:utput name="onNomadStateResponse"
message="impl:blush:nNomadStateResponse"/>
</wsdl:blush:peration>

<wsdl:blush:peration name="onLineState" parameterOrder="sessionId state">
<documentation>This notification is sent each time the line state
has changed.</documentation>
<wsdl:input name="onLineState" message="impl:blush:nLineState"/>
<wsdl:blush:utput name="onLineStateResponse"
message="impl:blush:nLineStateResponse"/>
</wsdl:blush:peration>

</wsdl:portType>







<wsdl:binding name="XmlPhoneEventsSoapBinding"
type="impl:XmlPhoneEvents">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/
soap/http"/>

<wsdl:blush:peration name="onCallState">
<wsdlsoap:blush:peration soapAction="onCallState"/>
<wsdl:input name="onCallState">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onCallStateResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onNewSession">
<wsdlsoap:blush:peration soapAction="onNewSession"/>
<wsdl:input name="onNewSession">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onNewSessionResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onSessionClosed">
<wsdlsoap:blush:peration soapAction="onSessionClosed"/>
<wsdl:input name="onSessionClosed">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onSessionClosedResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onConnectionDown">
<wsdlsoap:blush:peration soapAction="onConnectionDown"/>
<wsdl:input name="onConnectionDown">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onConnectionDownResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onPhoneSetStaticState">
<wsdlsoap:blush:peration soapAction="onPhoneSetStaticState"/>
<wsdl:input name="onPhoneSetStaticState">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onPhoneSetStaticStateResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onUnansweredCall">
<wsdlsoap:blush:peration soapAction="onUnansweredCall"/>
<wsdl:input name="onUnansweredCall">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onUnansweredCallResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onNomadState">
<wsdlsoap:blush:peration soapAction="onNomadState"/>
<wsdl:input name="onNomadState">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onNomadStateResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

<wsdl:blush:peration name="onLineState">
<wsdlsoap:blush:peration soapAction="onLineState"/>
<wsdl:input name="onLineState">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:input>
<wsdl:blush:utput name="onLineStateResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://
schemas.xmlsoap.org/soap/encoding/" namespace="http://
xmlapi.alcatel.com/phone"/>
</wsdl:blush:utput>
</wsdl:blush:peration>

</wsdl:binding>

<wsdl:service name="XmlPhoneEventsService">
<wsdl:port name="XmlPhoneEvents"
binding="impl:XmlPhoneEventsSoapBinding">
<wsdlsoap:address location="http://localhost/XMLPhoneEvents"/>
</wsdl:port>
</wsdl:service>

</wsdl:definitions>
 
S

Stephan Steiner

Scratch that.. I figure out what's wrong by looking at the messages
going over the line. It seems the namespace used in the messages that
cannot be deserialized do not correspond to the namespace of the
corresponding messages in the WSDL. Once I corrected that in the stub,
I no longer have any errors.

Regards
Stephan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top