xml data connection in Web Services

  • Thread starter Thread starter Brock
  • Start date Start date
B

Brock

I'm trying to develop a web service to expose an XML file for product
manufacturers for a client application to consume and populate a
datagrid on the consuming end.

I have successfully tested the web service with simple mathematic
returns like:


<%@ WebService Language="VB" Class="aWebService" %>
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
<WebService(Namespace := "http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
Public Class aWebService
Inherits System.Web.Services.WebService


<System.Web.Services.WebMethod()> _
Public Function SquareRootTimesSide(ByVal Diagonal As Double) _
As Double
Return (Diagonal * System.Math.Sqrt(2))
End Function


End Class


So I thought I'd try exposing structured data. I use mostly XML files
for my datasources so I'd like to stick with that.


I have successfully implemented reading the XML file into a
local .aspx page with this code:


<script runat="server">
Private Function MakeDataView() as DataView
Dim myDataSet As New DataSet()
myDataSet.ReadXml(Server.MapPath("Manufacturers.xml"))
Dim view As DataView = New DataView(myDataSet.Tables(0))
view.AllowDelete = False
view.AllowEdit = False
view.AllowNew = False
view.Sort = "name ASC"
Return view
End Function


Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim view as DataView = MakeDataView()
dgManufacturers.DataSource = view
dgManufacturers.AllowSorting = True
dgManufacturers.DataBind()
End Sub
</script>


How can I write the server-side code as a web method?


Many thanks!!
Brock
 
Brock said:
How can I write the server-side code as a web method?

You don't. Your web service code will be concerned with web service things.
Not DataView or DataSet.

Code your webmethod as a function returning type System.Xml.XmlDocument.
Then do something like this:

Dim doc As New XmlDocument
doc.Load(Server.MapPath("Manufacturers.xml"))
Return doc
 
In your line: "Dim doc As New XmlDocument" "XmlDocument" is not
being accepted... should this be "XmlDataSource"?

In "doc.Load(Server.MapPath("Manufacturers.xml"))' I get "'Public
Event Load(sender As Object, e As System.EventArgs)' is an event, and
cannot be called directly. Use a 'RaiseEvent' statement to raise an
event."

I tried this with no luck:

<System.Web.Services.WebMethod()> _
Private Function GetManufacturers(ByVal sender As Object, ByVal e
As System.EventArgs) Handles GetManufacturers
Dim doc As New XmlDataSource
doc.Load(Server.MapPath("Manufacturers.xml"))
Return doc
End Function
 
Brock said:
In your line: "Dim doc As New XmlDocument" "XmlDocument" is not
being accepted... should this be "XmlDataSource"?

In "doc.Load(Server.MapPath("Manufacturers.xml"))' I get "'Public
Event Load(sender As Object, e As System.EventArgs)' is an event, and
cannot be called directly. Use a 'RaiseEvent' statement to raise an
event."

I tried this with no luck:

Sorry. Try System.Xml.XmlDocument. You may need to reference the System.Xml
assembly.
 
that worked (Dim doc As New System.Xml.XmlDocument), but I'm still
struggling with this line:

"Private Function GetBlogEntries(ByVal sender As Object, ByVal e
As System.EventArgs) As ????"

I may have this one all wrong
 
Brock said:
that worked (Dim doc As New System.Xml.XmlDocument), but I'm still
struggling with this line:

"Private Function GetBlogEntries(ByVal sender As Object, ByVal e
As System.EventArgs) As ????"

I may have this one all wrong

That should probably be a Private Sub, not a function.
 
OK this went fine with no problems in the .asmx:

<System.Web.Services.WebMethod()> _
Private Sub GetBlogEntries(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim doc As New System.Xml.XmlDocument
doc.Load(Server.MapPath("blog.xml"))
End Sub

However, even after refreshing the web references I cannot see
anything in the WSDL referencing the above (?)

Ultimately what I'm trying to do is have a datagrid in an .aspx that
calls the web service in its code behind... something like:

Imports System.Data

Partial Class webServiceDG
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim wsConvert As New com.widgets.aWebService2
Dim view As DataView = MakeDataView()
dgEntries.DataSource = View
dgEntries.AllowSorting = True
dgEntries.DataBind()
End Sub

End Class
 
Brock said:
OK this went fine with no problems in the .asmx:

<System.Web.Services.WebMethod()> _
Private Sub GetBlogEntries(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim doc As New System.Xml.XmlDocument
doc.Load(Server.MapPath("blog.xml"))
End Sub

However, even after refreshing the web references I cannot see
anything in the WSDL referencing the above (?)

Ok, I'm sorry; I'm confused. Why do you want GetBlogEntries to be a Web
Method? Do you want it to return doc? If so, then it needs to be like this:

<System.Web.Services.WebMethod()> _
Public Function GetBlogEntries() As System.Xml.XmlDocument
Dim doc as New System.Xml.XmlDocument
doc.Load(Server.MapPath("blog.xml"))
Return doc
End Function
 
Using function instead of method makes sense. Now my WSDL looks like I
would expect and no errors on the .asmx side. On my client .aspx I'm
using (with errors):

Imports System.Data
Partial Class webServiceDG
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim wsConvert As New com.juggernautical.aWebService2
Dim view As DataView = ?????
dgEntries.DataSource = View
dgEntries.AllowSorting = True
dgEntries.DataBind()
End Sub
End Class

the line: "Dim view As DataView = XmlDataSourceView" appears to be the
problem. I've tried several posibilities plugged in here but I'm lost
at this point.
 
Brock said:
Using function instead of method makes sense. Now my WSDL looks like I
would expect and no errors on the .asmx side. On my client .aspx I'm
using (with errors):

Imports System.Data
Partial Class webServiceDG
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim wsConvert As New com.juggernautical.aWebService2
Dim view As DataView = ?????
dgEntries.DataSource = View
dgEntries.AllowSorting = True
dgEntries.DataBind()
End Sub
End Class

the line: "Dim view As DataView = XmlDataSourceView" appears to be the
problem. I've tried several posibilities plugged in here but I'm lost
at this point.

I'm lost too. Where is the call to GetBlogEntries?
 
On my client I can reference the GetBlogEntries by:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim GetBlogEntries As New com.juggernautical.aWebService2
End Sub

Correct?

which compiles but I need to expose that to more code to popluate my
datagrid
 
Brock said:
On my client I can reference the GetBlogEntries by:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim GetBlogEntries As New com.juggernautical.aWebService2
End Sub

Correct?

No.

In the service, didn't we define GetBlogEntries as a Function? It's a
function on the client, as well.

If you use:

Dim wsConvert As New com.juggernautical.aWebService2
Dim elem As XmlElement = wsConvert.GetBlogEntries()

Then I believe you'll get an XmlElement back containing the data you loaded
into the XmlDocument back on the service.

On the other hand, I see that you are trying to use a DataView on the
client. Yet, you loaded the blog entries into an XmlDocument on the service.
But, XmlDocument and XmlElement have nothing to do with a DataView, so this
isn't going to help you at all.

I strongly suggest that you start from the very beginning. I have been
assuming that your code was mostly correct and that you needed a little help
with the syntax. I no longer believe that. I do not thing that the path
we've been on is going to lead to you having working code, so I think we'd
better start from the beginning.

If I understand at all what you're trying to accomplish, you have some blog
entries in an XML file on the server. You want a web service to send those
blog entries to the client, where you'll display them in a DataGrid. Is that
correct?

If this is correct, then please remind me what version of Visual Studio you
are running. Also, are you running the Express edition, Professional
edition, or which other one? Finally, are your web service and web
application created by using File->New Project, or are they created by using
File->New Web Site?

Thanks,
John
 
Yes starting over would help. First thanks so much for your help. This
is actually just a learning exercize for me, not job related or class-
room stuff. I have a personal 'lab' website that when I want a really
lightweight and quick data storage I just create an XML file. If it is
something heavier I use MS-Access.

So a while back I put together a couple of .aspx's and was able to
display an XML file on a datagrid with no problem (see code below).

I had done some web service studying a year ago but the need for a
good understanding of that technology has just now become aparent as I
have seen the real-world practical uses I might find along the way
(even distributed desktop apps needing data from a web service).

So just for the challenge of it more than anything else, I decided to
study a little more on my own and thought why not take the datagrid
that is working well on my aspx and populate it with a reference to
an .asmx? The XML file is simple, just one 'field' really.

Here's what I have that is working to populate the datagrid on
my .aspx (and I simply want to learn how to do the same by using a web
service and I have the .asmx side put together):

<script runat="server">
Private Function MakeDataView() as DataView
Dim myDataSet As New DataSet()
myDataSet.ReadXml(Server.MapPath("Manufacturers.xml"))
Dim view As DataView = New DataView(myDataSet.Tables(0))
view.AllowDelete = False
view.AllowEdit = False
view.AllowNew = False
view.Sort = "name ASC"
Return view
End Function


Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim view as DataView = MakeDataView()
dgManufacturers.DataSource = view
dgManufacturers.AllowSorting = True
dgManufacturers.DataBind()
End Sub
</script>
 
Brock said:
Yes starting over would help. ....

<script runat="server">
Private Function MakeDataView() as DataView

Ok, step 1, please learn how to use codebehind. In fact, I recommend you
learn to create both your web applications and web services by using
File->New Project. Try not to use File->New Web Site for web applications,
and _never_ use it for web services.

Next, I think that our server-side code for GetBlogPosts was ok when it was
returning an XmlDocument:

<WebMethod()> _
Public Function GetBlogPosts() As XmlDocument
Dim doc As New XmlDocument
doc.Load(Server.MapPath("file.xml"))
Return doc
End Function

-----

The client code needs to be a little different:

Private Function MakeDataView() as DataView
Dim myDataSet As New DataSet()
Using svc As wsConvert As New com.juggernautical.aWebService2
myDataSet.ReadXml(New
System.Xml.XmlNodeReader(wsConvert.GetBlogPosts()))
End Using
Dim view As DataView = New DataView(myDataSet.Tables(0))

etc.

The difference is that GetBlogPosts returns an XmlElement (yeah, I know we
returned XmlDocument, but it will be XmlElement on the client). There is no
direct way to read an XmlElement into a DataSet, but there _is_ a way to use
an XmlReader to read into a DataSet. The XmlNodeReader type is an XmlReader
that can read from an existing XmlNode, and XmlElement is a kind of XmlNode,
so we should be all set.
 
What I currently have on the .asmx side is:

<System.Web.Services.WebMethod()> _
Public Function GetBlogEntries() As System.Xml.XmlDocument
Dim doc As New System.Xml.XmlDocument
doc.Load(Server.MapPath("blog.xml"))
Return doc
End Function

I'm assuming this is OK (?)... if I get rid of the "System.Xml." I get
errors... so I guess leave this alone (?)...

In my code behind for the client (I was using scripting only in the
original .aspx tool, though it should have been "code-behind" also..
my bad habit!), if I use:

Private Function MakeDataView() as DataView 'of course it looks
like I would call this function from "Sub Page_Load"**
Dim myDataSet As New DataSet()
Using svc As wsConvert As New com.juggernautical.aWebService2
myDataSet.ReadXml(New
System.Xml.XmlNodeReader(wsConvert.GetBlogEntries()))
End Using
Dim view As DataView = New DataView(myDataSet.Tables(0))
End Function

In the above "svc As wsConvert As New com.juggernautical.aWebService2"
errors with a 'Using resource needs explicit initialization',
'wsConvert not defined', 'End of statement expected'


** Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
MakeDataView()
End Sub
 
Brock said:
What I currently have on the .asmx side is:

<System.Web.Services.WebMethod()> _
Public Function GetBlogEntries() As System.Xml.XmlDocument
Dim doc As New System.Xml.XmlDocument
doc.Load(Server.MapPath("blog.xml"))
Return doc
End Function

I'm assuming this is OK (?).

Yes. That's ok.
Using svc As wsConvert As New com.juggernautical.aWebService2
myDataSet.ReadXml(New
System.Xml.XmlNodeReader(wsConvert.GetBlogEntries()))
End Using
Dim view As DataView = New DataView(myDataSet.Tables(0))
End Function

My VB is rusty. The message is correct. It needs to be

Using wsConvert As com.juggernautical.aWebService2 = New
com.juggernautical.aWebService2
....
End Using
 
Everything compiles now except the page does not render anything.
I did notice that "End Function" does have a warning:
Function 'MakeDataView' doesn't return a value on all code paths. A
null reference exception could occur at run time when the result is
used.

So I tried adding source and binding for the datagrid in the code-
behind:

Private Function MakeDataView() As DataView
Dim myDataSet As New DataSet()
Using wsConvert As com.juggernautical.aWebService2 = New
com.juggernautical.aWebService2
myDataSet.ReadXml(New
System.Xml.XmlNodeReader(wsConvert.GetBlogEntries()))
End Using
Dim view As DataView = New DataView(myDataSet.Tables(0))
dgBlog.DataSource = view
dgBlog.AllowSorting = True
dgBlog.DataBind()
End Function

But still no rendering of anything on the page.
Here's my HTML of the .aspx

<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="WebServiceDG.aspx.vb" Inherits="_Default" %>
<%@import Namespace="System.Data"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>History</title>
</head>
<body>
<form id="form1" runat="server">
<asp:datagrid id="dgBlog"
runat="server"
AutoGenerateColumns="False"
Font-Name="Verdana"
Font-Size="X-Small"
HorizontalAlign="Center"
ItemStyle-BackColor="#C0FFC0"
AlternatingItemStyle-BackColor="White"
Width="412px"
Height="128px"
AllowSorting="True"
BorderColor="PeachPuff"
BorderStyle="Outset"
BorderWidth="10px" CellSpacing="2" CellPadding="15"
Font-Names="Verdana" ShowHeader="False">
<HeaderStyle BackColor="DarkGreen"
HorizontalAlign="Center"
ForeColor="White"
Font-Bold="True" />
<Columns>
<asp:BoundColumn HeaderText="Blog Entry" DataField="entry" />
</Columns>
<AlternatingItemStyle BackColor="White" />
<ItemStyle BackColor="#C0FFC0" HorizontalAlign="Left" />
</asp:datagrid>
</form>
</body>
</html>
 
I've tried debugging but remote debugging is not allowed. Anyone any
ideas on how I can find out if the web service is returning any
consumable values?
 
Back
Top