Writing a simple webservice

  • Thread starter Thread starter Phillip Taylor
  • Start date Start date
P

Phillip Taylor

Hi guys, I'm looking to develop a simple web service in VB.NET but I'm
having some trivial issues. In Visual Studio I create a web services
project and change the asmx.vb file to this:

Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel

<System.Web.Services.WebService(Namespace:="http://
wwwpreview.#deleted#.co.uk/~ptaylor/Customer.wsdl")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)>
_
<ToolboxItem(False)> _
Public Class CustomerService
Inherits System.Web.Services.WebService

<WebMethod()> _
Public Function getCustomer() As TreeObject()

Dim t1 As New TreeObject
Dim t2 As New TreeObject
Dim t3 As New TreeObject

Dim arr(2) As TreeObject
arr(0) = t1
arr(1) = t2
arr(2) = t3

Return arr
End Function

End Class

As you can see my function returns an object of type "TreeObject" and
when you run this it works. the clients are clearly returned an array
3 TreeObjects objects. However I cannot actually invoke any functions
on these tree objects. This is the current definition of TreeObject:

Imports System.Web.Services

<System.Serializable()> _
Public Class TreeObject

Public Sub New()

End Sub

<WebMethod()> _
Public Sub setId(ByVal id As Int32)

End Sub

<WebMethod()> _
Public Function getId() As String
Return 1
End Function

<WebMethod()> _
Public Sub setName(ByVal value As String)
End Sub

<WebMethod()> _
Public Function getName() As String
Return "boo ya"
End Function

End Class

However the functions GetName, SetName, GetId, SetId do not appear in
the WSDL file and the functions are not accessable from the client. (I
think TreeObject has no functions other than those inherited from
Object)

How do I make those functions accessible please? Do I need to set up
another "service" or what?

Thanks

Phill
 
Hi guys, I'm looking to develop a simple web service in VB.NET but I'm
having some trivial issues. In Visual Studio I create a web services
project and change the asmx.vb file to this:

Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel

<System.Web.Services.WebService(Namespace:="http://
wwwpreview.#deleted#.co.uk/~ptaylor/Customer.wsdl")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)>
_
<ToolboxItem(False)> _
Public Class CustomerService
Inherits System.Web.Services.WebService

<WebMethod()> _
Public Function getCustomer() As TreeObject()

Dim t1 As New TreeObject
Dim t2 As New TreeObject
Dim t3 As New TreeObject

Dim arr(2) As TreeObject
arr(0) = t1
arr(1) = t2
arr(2) = t3

Return arr
End Function

End Class

As you can see my function returns an object of type "TreeObject" and
when you run this it works. the clients are clearly returned an array
3 TreeObjects objects. However I cannot actually invoke any functions
on these tree objects. This is the current definition of TreeObject:

Imports System.Web.Services

<System.Serializable()> _
Public Class TreeObject

Public Sub New()

End Sub

<WebMethod()> _
Public Sub setId(ByVal id As Int32)

End Sub

<WebMethod()> _
Public Function getId() As String
Return 1
End Function

<WebMethod()> _
Public Sub setName(ByVal value As String)
End Sub

<WebMethod()> _
Public Function getName() As String
Return "boo ya"
End Function

End Class

However the functions GetName, SetName, GetId, SetId do not appear in
the WSDL file and the functions are not accessable from the client. (I
think TreeObject has no functions other than those inherited from
Object)

How do I make those functions accessible please? Do I need to set up
another "service" or what?

Thanks

Phill

As I know, you need to public expose the methods in the .asmx.
 
As I know, you need to public expose the methods in the .asmx.

That's what I thought adding <WebMethod ()> _ to everything did, but
it doesn't seem to be enough on it's own.
 
When a WebService returns an Object to the calling program, it is sending the
data needed to create such an object. The data is being passed as XML. For the
calling program to use it, it must have the class definition of that object
available. It then creates a new instance of that class, and uses the data
received from the web service to initialize it. There is no sense in which you
are actually sending a functional object to the calling program.

Typically you would have a dll or similar that defines the class, with
properties identified as serializable, which is used by both the web service and
the calling program. When the web service is asked to return an instance of this
class, it returns as XML the values of the serializable properties. Then the
calling program creates an instance of the same class, and uses the serialized
XML data to make it the same as the one the web service used.

A good example is a Dataset, a class which both the web service and the calling
program can create. The web service can then be used to pass data serialized as
XML back and forth between a Dataset on the client and a Dataset on the server.

So essentially I have to mirror all the objects locally (with the
exception of the service itself)? They are not automatically generated
for me by the WSDL? On top of this, it must then reduce the entire
service to a single interface wall...effectively making SOAP identical
to XML-RPC with no benefits at all since I either break encapsulation,
moving entire objects and their contents to the client for processing,
or I have to pass the object data backwards and forwards like a C
style, completely un-object-oriented application?

Surely this is not correct is it?
 
So essentially I have to mirror all the objects locally (with the
exception of the service itself)? They are not automatically generated
for me by the WSDL? On top of this, it must then reduce the entire
service to a single interface wall...effectively making SOAP identical
to XML-RPC with no benefits at all since I either break encapsulation,
moving entire objects and their contents to the client for processing,
or I have to pass the object data backwards and forwards like a C
style, completely un-object-oriented application?

Surely this is not correct is it?

Unfortunately, you're trying to do something that is not possible with
web services. The purpose of a SOAP Web service (which is what
the .NET 2.0 Web services are) is to serve SOAP formatted XML, not
objects. They only pretend to be objects because Visual Studio / .NET
is "smart" enough to interpret SOAP formatted XML into proxy classes.
These proxy classes only contain property structures, not methods.

Basically, the normal flow for modifying object through a web service
is as follows:

1) User requests an item
2) Service handle requests, loads the item, and sends it to the user
3) User modifies properties of the item
4) User calls a Save web method and passes in the item
5) Service validates the property values and saves the item

As you see, the only time a user gets access to methods is through the
web service and not the object itself. It takes some getting used to,
but it isn't a very complicated concept, and is much, much more secure
than sending over your code. Just remember that the web service should
act as the presentation layer, and just call directly into your
business objects.

Thanks,

Seth Rowe [MVP]
 
Unfortunately, you're trying to do something that is not possible with
web services. The purpose of a SOAP Web service (which is what
the .NET 2.0 Web services are) is to serve SOAP formatted XML, not
objects. They only pretend to be objects because Visual Studio / .NET
is "smart" enough to interpret SOAP formatted XML into proxy classes.
These proxy classes only contain property structures, not methods.

Basically, the normal flow for modifying object through a web service
is as follows:

1) User requests an item
2) Service handle requests, loads the item, and sends it to the user
3) User modifies properties of the item
4) User calls a Save web method and passes in the item
5) Service validates the property values and saves the item

As you see, the only time a user gets access to methods is through the
web service and not the object itself. It takes some getting used to,
but it isn't a very complicated concept, and is much, much more secure
than sending over your code. Just remember that the web service should
act as the presentation layer, and just call directly into your
business objects.

Thanks,

Seth Rowe [MVP]

I don't want to come across as stupid by reiterating the question but
you are telling me that SOAP is nothing more than XML-RPC. That there
is a wall of functions (like a C style API) that return simple types
or structures and I still question this. I *believe* that with SOAP I
can return references to instance objects. I believe I can *somehow*
(possibly with the use of a proxy or a stub) invoke functions on the
client, which is wrapped up in a SOAP request and translated to an
actual invocation and running of the object instances method on the
server side. You are suggesting this is all that is possible:

SERVER SIDE

int CreateNewObject( ... ) //returns an ID
string GetName (int uniqueId)

CLIENT SIDE

int myObjectId = CreateNewObject ()
string name = GetName( myObjectId )

( A C style wall of functions. The server needs to take the unique Id
and find the real object and invoke the function on it manually).

I actually believe this is possible with SOAP

SERVER SIDE

Object CreateNewObject (...)

CLIENT SIDE

Object o = new Object
string name = o.GetName() //Get name runs on the server, and the
result is specific to the instance in question.

--

Am I delusional? Can't this be done? I would appreciate it if a few
people could confirm or deny this. I'm sorry to ask after I already
got a reply but I'm still not sure how SOAP Servers are developed and
I would like this issue cleared up. Is what I have described possible
or not?
 
I don't want to come across as stupid by reiterating the question but
you are telling me that SOAP is nothing more than XML-RPC.

Yes, SOAP is the successor to XML-RPC, and like XML-RPC it returns
simple objects which are nothing more than a set of properties (no
methods).
That there
is a wall of functions (like a C style API) that return simple types
or structures

If by "simple types or structures" you mean objects with only
properties than you are correct.
and I still question this.

Which is fine, I'll try to explain as best I can.
I *believe* that with SOAP I
can return references to instance objects.

AFAIK, you cannot return references to server side objects through
the .NET 2.0 SOAP Web Services.
I believe I can *somehow*
(possibly with the use of a proxy or a stub) invoke functions on the
client, which is wrapped up in a SOAP request and translated to an
actual invocation and running of the object instances method on the
server side.

The only way to invoke functions is to call them through the web
service using a SOAP formatted request. There is no "magic"
translation that happens that gives the client the ability to invoke
methods on the object. If I confused you by talking about proxy
classes earlier than let me rephrase - proxy classes are just very
simple objects (properties only) that .NET creates for you to give you
compile time support. All that happens is that the framework reads the
WSDL, pulls out the property structure and does a simple code gen to
create the classes. You'll notice that you'll also lose any
functionality in the properties (such as validation code), they become
simple get..set.. pairs.
You are suggesting this is all that is possible:

Nope. I'm saying if you want to invoke functions on a web service you
must call them through the web service, not the objects served by the
web service.

Take a look at this simple, pseudocode, example on how to use a
service.

Here's the Web Service code:

////////////////
<WebMethod()> _
Public Function GetProgrammerByBadgeId(badgeId as integer) As
Programmer
Return New Programmer(badgeId)
End Function

<WebMethod()> _
Public Sub SaveProgrammer(programmer as Programmer)
'// We get the Programmer's methods back
programmer.Save()
End Sub
///////////////

And the code for the programmer class:

//////////////
Public Class Programmer

Public Sub New()

End Sub

Public Sub New(badgeId as Integer)
Me.New()

Me.BadgeId = badgeId
Me.Load()
End Sub

'// I'm too lazy to type these out, they are standard properties
Public Property BadgeId As Integer()
Public Property Name As String()
Public Property FavoriteLanguage As String()

Private Sub Load()
'// Load the object from the data access layer
DALC.Load(Me, badgeId)
End Sub

Private Sub Save()
'// Save the object through the data access layer
DALC.Save(Me)
End Sub

End Class
/////////////

This is the client side code:

///////////////
'// Instantiate a new web service
Using service As New ProgrammersService()
Dim programmer As ProgrammersService.Programmer =
service.GetProgrammerByBadgeId(999)

Console.WriteLine("The Programmer's Name is {0}", programmer.Name)
'// Prints "Seth Rowe"
Console.WriteLine("The Programmer's preferred language is {0}",
programmer.PreferredLanguage) '// Prints C#

'// Since C# isn't my favorite language, we need to update the
database
programmer.PreferredLanguage = "VB.NET"

'// That call only sets the client side property value, we now
need to save the object back
service.SaveProgrammer(programmer)
End Using
///////////////

Hopefully that makes a little more sense on how you should be using
web services. Basically you just get the object, do any client side
processing with the properties, and then save the object back to the
web service. If you're really, really stuck and can't figure out how
to implement this pattern with your CustomerService object, let me
know and I'll try to help.

Thanks,

Seth Rowe [MVP]
 
Yes, SOAP is the successor to XML-RPC, and like XML-RPC it returns
simple objects which are nothing more than a set of properties (no
methods).


If by "simple types or structures" you mean objects with only
properties than you are correct.


Which is fine, I'll try to explain as best I can.


AFAIK, you cannot return references to server side objects through
the .NET 2.0 SOAP Web Services.


The only way to invoke functions is to call them through the web
service using a SOAP formatted request. There is no "magic"
translation that happens that gives the client the ability to invoke
methods on the object. If I confused you by talking about proxy
classes earlier than let me rephrase - proxy classes are just very
simple objects (properties only) that .NET creates for you to give you
compile time support. All that happens is that the framework reads the
WSDL, pulls out the property structure and does a simple code gen to
create the classes. You'll notice that you'll also lose any
functionality in the properties (such as validation code), they become
simple get..set.. pairs.


Nope. I'm saying if you want to invoke functions on a web service you
must call them through the web service, not the objects served by the
web service.

Take a look at this simple, pseudocode, example on how to use a
service.

Here's the Web Service code:

////////////////
<WebMethod()> _
Public Function GetProgrammerByBadgeId(badgeId as integer) As
Programmer
Return New Programmer(badgeId)
End Function

<WebMethod()> _
Public Sub SaveProgrammer(programmer as Programmer)
'// We get the Programmer's methods back
programmer.Save()
End Sub
///////////////

And the code for the programmer class:

//////////////
Public Class Programmer

Public Sub New()

End Sub

Public Sub New(badgeId as Integer)
Me.New()

Me.BadgeId = badgeId
Me.Load()
End Sub

'// I'm too lazy to type these out, they are standard properties
Public Property BadgeId As Integer()
Public Property Name As String()
Public Property FavoriteLanguage As String()

Private Sub Load()
'// Load the object from the data access layer
DALC.Load(Me, badgeId)
End Sub

Private Sub Save()
'// Save the object through the data access layer
DALC.Save(Me)
End Sub

End Class
/////////////

This is the client side code:

///////////////
'// Instantiate a new web service
Using service As New ProgrammersService()
Dim programmer As ProgrammersService.Programmer =
service.GetProgrammerByBadgeId(999)

Console.WriteLine("The Programmer's Name is {0}", programmer.Name)
'// Prints "Seth Rowe"
Console.WriteLine("The Programmer's preferred language is {0}",
programmer.PreferredLanguage) '// Prints C#

'// Since C# isn't my favorite language, we need to update the
database
programmer.PreferredLanguage = "VB.NET"

'// That call only sets the client side property value, we now
need to save the object back
service.SaveProgrammer(programmer)
End Using
///////////////

Hopefully that makes a little more sense on how you should be using
web services. Basically you just get the object, do any client side
processing with the properties, and then save the object back to the
web service. If you're really, really stuck and can't figure out how
to implement this pattern with your CustomerService object, let me
know and I'll try to help.

Thanks,

Seth Rowe [MVP]

Thank you for taking the time out to reply. I really mean that. What
you saying makes complete sense. I got the impression that if I passed
an object back from a web service, that it became a webservice itself
- hense I could suddenly call member methods on it - with the real
logic on the server side... but forget it... I was clearly confused
and completely delusional. I think I have better understanding of what
SOAP is now.

Thank you for clearing this up.
 
Thank you for taking the time out to reply. I really mean that. What
you saying makes complete sense. I got the impression that if I passed
an object back from a web service, that it became a webservice itself
- hense I could suddenly call member methods on it - with the real
logic on the server side... but forget it... I was clearly confused
and completely delusional. I think I have better understanding of what
SOAP is now.

Thank you for clearing this up.

No problem - I take pride in my ability to get people to say they are
delusional.

:-)

Seriously though, I'm glad I helped you out.

Thanks,

Seth Rowe [MVP]
 
Back
Top