Transferring data to heterogeneous clients

R

Robert Scheer

Hi.

I have an asp.net application that needs to serve some data to
heterogeneous clients (some Java applications, one PHP application and
other .NET applications).

I am considering to create a Web Service to allow my clients to
consume my data, but I am in doubt on how to do this. A simple dataset
can be used to transfer this information to all these clients? I read
about DTO but how do I implement it?

Thanks,
Robert Scheer
 
J

John Saunders [MVP]

Robert Scheer said:
Hi.

I have an asp.net application that needs to serve some data to
heterogeneous clients (some Java applications, one PHP application and
other .NET applications).

I am considering to create a Web Service to allow my clients to
consume my data, but I am in doubt on how to do this. A simple dataset
can be used to transfer this information to all these clients? I read
about DTO but how do I implement it?

Robert, a DTO is just a simple object for transferring data. Simple meaning
simpler than a DataSet. For instance, instead of a DataSet with two tables,
you might have:

public class DtoTable1
{
public int Table1Column1 {get;}
public int Table1Column2 {get;}
// ... etc.
public DtoTable1(DataSet ds)
{
_table1Column1 = (int) ds.Tables[0]["Column1"];
_table1Column2 = (string) ds.Tables[0]["Column2"];
}
}

public class DtoTable2
{
public int Table2Column1 {get;}
public int Table2Column2 {get;}
// ... etc.
public DtoTable2(DataSet ds)
{
_table2Column1 = (int) ds.Tables[1]["Column1"];
_table2Column2 = (string) ds.Tables[1]["Column2"];
}
}

public class Dto
{
public DtoTable1 Table1 {get;}
public DtoTable2 Table2 {get;}
public Dto(DataSet ds)
{
_dtoTable1 = new DtoTable1(ds);
_dtoTable2 = new DtoTable2(ds);
}
}


Then return an object of type Dto in your web service. It will contain all
of the data from the DataSet, but none of the platform-specific complexity.
 
R

Robert Scheer

I have an asp.net application that needs to serve some data to
heterogeneous clients (some Java applications, one PHP application and
other .NET applications).
I am considering to create a Web Service to allow my clients to
consume my data, but I am in doubt on how to do this. A simple dataset
can be used to transfer this information to all these clients? I read
about DTO but how do I implement it?

Robert, a DTO is just a simple object for transferring data. Simple meaning
simpler than a DataSet. For instance, instead of a DataSet with two tables,
you might have:

public class DtoTable1
{
public int Table1Column1 {get;}
public int Table1Column2 {get;}
// ... etc.
public DtoTable1(DataSet ds)
{
_table1Column1 = (int) ds.Tables[0]["Column1"];
_table1Column2 = (string) ds.Tables[0]["Column2"];
}

}

public class DtoTable2
{
public int Table2Column1 {get;}
public int Table2Column2 {get;}
// ... etc.
public DtoTable2(DataSet ds)
{
_table2Column1 = (int) ds.Tables[1]["Column1"];
_table2Column2 = (string) ds.Tables[1]["Column2"];
}

}

public class Dto
{
public DtoTable1 Table1 {get;}
public DtoTable2 Table2 {get;}
public Dto(DataSet ds)
{
_dtoTable1 = new DtoTable1(ds);
_dtoTable2 = new DtoTable2(ds);
}

}

Then return an object of type Dto in your web service. It will contain all
of the data from the DataSet, but none of the platform-specific complexity.

Hi John,

I see what you mean and it is really simple. Is a DTO the preferred
way to transfer data through these applications or should I consider
other ways?

Thanks for your help.

Robert Scheer
 
J

John Saunders [MVP]

Robert Scheer said:
I have an asp.net application that needs to serve some data to
heterogeneous clients (some Java applications, one PHP application and
other .NET applications).
I am considering to create a Web Service to allow my clients to
consume my data, but I am in doubt on how to do this. A simple dataset
can be used to transfer this information to all these clients? I read
about DTO but how do I implement it?

Robert, a DTO is just a simple object for transferring data. Simple
meaning
simpler than a DataSet. For instance, instead of a DataSet with two
tables,
you might have:

public class DtoTable1
{
public int Table1Column1 {get;}
public int Table1Column2 {get;}
// ... etc.
public DtoTable1(DataSet ds)
{
_table1Column1 = (int) ds.Tables[0]["Column1"];
_table1Column2 = (string) ds.Tables[0]["Column2"];
}

}

public class DtoTable2
{
public int Table2Column1 {get;}
public int Table2Column2 {get;}
// ... etc.
public DtoTable2(DataSet ds)
{
_table2Column1 = (int) ds.Tables[1]["Column1"];
_table2Column2 = (string) ds.Tables[1]["Column2"];
}

}

public class Dto
{
public DtoTable1 Table1 {get;}
public DtoTable2 Table2 {get;}
public Dto(DataSet ds)
{
_dtoTable1 = new DtoTable1(ds);
_dtoTable2 = new DtoTable2(ds);
}

}

Then return an object of type Dto in your web service. It will contain
all
of the data from the DataSet, but none of the platform-specific
complexity.

Hi John,

I see what you mean and it is really simple. Is a DTO the preferred
way to transfer data through these applications or should I consider
other ways?


A DTO is _a_ preferred way. I prefer it when platform-independence is an
issue.

And, BTW, I prefer to _assume_ that a Web Service should be
platform-independent, so I prefer either to use a DTO, or to structure the
Web Service around platform-independent representations of the domain
objects that the service is about.
 
M

mojeza

John,

I wonder if there is a way to create some sort of generic DtoTable
object at run-time so it could be use for with any ADO.NET DataTable.
I have to develop Web Service which will be consumed by Adobe Flex 2
client and it would be nice to have a generic function for returning
results of all SELECT queries. Is there a way to do something like
that? I'm new to VS2005 and .NET so foregive me if my question is
realy stupid.
 
J

John Saunders [MVP]

mojeza said:
John,

I wonder if there is a way to create some sort of generic DtoTable
object at run-time so it could be use for with any ADO.NET DataTable.
I have to develop Web Service which will be consumed by Adobe Flex 2
client and it would be nice to have a generic function for returning
results of all SELECT queries. Is there a way to do something like
that? I'm new to VS2005 and .NET so foregive me if my question is
realy stupid.

That's what a DataSet is!

You wouldn't realize this if you stuck to the new, cool mechanism in Visual
Studio 2005. But you can still do this the old fashioned way:

DataSet ds = new DataSet("Data");
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("SELECT * FROM MY_TABLE", conn);
SqlDataAdapter da = new SqlDataAdapter();
....
da.Fill(ds);

(error handling, using blocks, etc. left out of the above)


..NET will create a table corresponding to the data you read in with the
SELECT. It will have as column names the names in the query (or their alias
if you use "AS 'Column Name'".
 
M

mojeza

That's what a DataSet is!
.NET will create a table corresponding to the data you read in with the
SELECT. It will have as column names the names in the query (or their alias
if you use "AS 'Column Name'".

Thank you John.

I wish it would be so easy and I could serialize Dataset or DataTable
back to client written in Adobe Flex 2.
Datasets are not supported, DataTables are working but with a lot of
problems and 'side effects'. The only way it works fast and reliable
is when I use array of objects, something like this:

<WebMethod(Description:="Returns ArrayList", EnableSession:=True)> _
Public Function GetParticipants_Array(ByVal vTop As String) As
Participant()
Dim connection As SqlConnection = New SqlConnection("Data
Source=XZP650;Initial Catalog=rk;Persist Security Info=True;User
ID=xxxx;Password=xxxxx")
Dim vQuery As String = "SELECT TOP " & vTop & " ParticipantID,
LastName, FirstName, SSNumber, Phone, BirthDate, Eligible FROM
tblParticipants ORDER BY ParticipantID DESC"
Dim adapter As SqlDataAdapter = New SqlDataAdapter(vQuery,
connection)
Dim arrList As New ArrayList

Dim custDS As DataSet = New DataSet()
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
adapter.Fill(custDS, "myData")

For Each Row As DataRow In custDS.Tables("myData").Rows
Dim myParticipant As New Participant

With myParticipant
.ParticipantID = Row("ParticipantID")
.LastName = Row("LastName").ToString
.FirstName = Row("FirstName").ToString
.BirthDate = Row("BirthDate").ToString
.SSNumber = Row("SSNumber").ToString
.Phone = Row("Phone").ToString
.Eligible = Row("Eligible")
End With
arrList.Add(myParticipant)
Next

Dim arrParticipant As Participant() =
arrList.ToArray(GetType(Participant))
Return arrParticipant
End Function

Public Class Participant
Public ParticipantID As Int64
Public LastName As String
Public FirstName As String
Public SSNumber As String
Public Phone As String
Public BirthDate As Date
Public Eligible As Boolean
End Class

Flex is able to deserialize this to ArrayCollection and data could be
bound to grids, lists, etc. Would be nice if I could create
Participant class at runtime based on column structure of a DataTable.
 
J

John Saunders [MVP]

mojeza said:
....
Public Class Participant
Public ParticipantID As Int64
Public LastName As String
Public FirstName As String
Public SSNumber As String
Public Phone As String
Public BirthDate As Date
Public Eligible As Boolean
End Class

Flex is able to deserialize this to ArrayCollection and data could be
bound to grids, lists, etc. Would be nice if I could create
Participant class at runtime based on column structure of a DataTable.

Well, you _could_ if you **really** want to. With .NET, you can create and
execute code on the fly. This is exactly what .NET does during XML
serialization. You could read the structure of the datatable and use it to
create fields in your struct or class.

See the System.CodeDom namespace.
 
M

mojeza

John,

I wonder if you could help me again. I follow your advice and
implemented System.CodeDom
namespace funtionality in my web service. It works very good, I am
able to step through
all code when debugging but at the time when web service try to
serialize response object
I get this exception:

System.InvalidOperationException: There was an error generating the
XML document. ---> System.InvalidOperationException: The type
GenericTable[] may not be used in this context.
at
System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String
name, String ns, Object o, Boolean xsiType)
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write1_Object(String
n, String ns, Object o, Boolean isNullable, Boolean needType)
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_anyType(Object
o)
at
Microsoft.Xml.Serialization.GeneratedAssembly.ObjectSerializer.Serialize(Object
objectToSerialize, XmlSerializationWriter writer)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter
xmlWriter, Object o, XmlSerializerNamespaces namespaces, String
encodingStyle, String id)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter
xmlWriter, Object o, XmlSerializerNamespaces namespaces, String
encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter
textWriter, Object o)
at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse
response, Stream outputStream, Object returnValue)
at
System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[]
returnValues, Stream outputStream)
at
System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[]
returnValues)
at System.Web.Services.Protocols.WebServiceHandler.Invoke()

My web service function look like this:

<WebMethod(Description:="Returns array of objects using System.CodeDom
namespace", EnableSession:=True)> _
Public Function GetData_CodeDom(ByVal queryString As String) As Object
Dim connection As SqlConnection = New SqlConnection("Data
Source=P6;Initial Catalog=RK;Persist Security Info=True;User
ID=xxx;Password=xxxxxx")
Dim adapter As SqlDataAdapter = New SqlDataAdapter(QueryString,
connection)

Dim custDS As DataSet = New DataSet()
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
adapter.Fill(custDS, "myTable")

Dim classCodeDome As New clsCodeDom
Dim myObject As Object =
classCodeDome.GetCustomObject(custDS.Tables("myTable"))

Return myObject
End Function

The queryString parameter is populated whith this SELECT statement:
SELECT TOP 2 ParticipantID, LastName, FirstName, BirthDate, Eligible
FROM tblParticipants ORDER BY ParticipantID DESC

classCodeDom GetCustomObject function builds a following code at
runtime:

Imports System
Imports System.Data
Imports System.Xml
Imports System.Collections

Public Class Sample
Public Shared Function SampleFunction(dt as DataTable) As
GenericTable()
Dim arrList As New ArrayList
For Each Row As DataRow In dt.Rows
Dim oGenericTable As New GenericTable
With oGenericTable
.ParticipantID = Row("ParticipantID").ToString
.LastName = Row("LastName").ToString
.FirstName = Row("FirstName").ToString
.BirthDate = Row("BirthDate").ToString
.Eligible = Row("Eligible").ToString
End With
arrList.Add(oGenericTable)
Next
Dim arrObject As Object() = arrList.ToArray(GetType(GenericTable))
Return arrObject
End Function
End Class

Public Class GenericTable
Public ParticipantID As String
Public LastName As String
Public FirstName As String
Public BirthDate As String
Public Eligible As String
End Classble As String
End Class

This code is compiled and then executed, all works fine, I am able to
see array of objects populated
with data from the database when inspecting myObject properties. Once
code execution exit GetData_CodeDom
function the exception listed above is poped up in a browser window.

Any idea what I'm doing wrong? I appreciate your help and any advice,
stack on this since last night and
have no idea how to solve this problem.

Thank you,
John
 
J

John Saunders [MVP]

mojeza said:
John,

I wonder if you could help me again. I follow your advice and
implemented System.CodeDom
namespace funtionality in my web service. It works very good, I am
able to step through
all code when debugging but at the time when web service try to
serialize response object
I get this exception:

System.InvalidOperationException: There was an error generating the
XML document. ---> System.InvalidOperationException: The type
GenericTable[] may not be used in this context.

This is probably telling you the truth. It doesn't like you trying to return
an array of GenericTable objects.

I don't know why not offhand, but for one thing, please try defining your
webmethod as returning GenericTable() instead of returning Object. Try that
and get back to us.
 
M

mojeza

I don't know why not offhand, but for one thing, please try defining your
webmethod as returning GenericTable() instead of returning Object. Try that
and get back to us.

I wish I could. GenericTable class is built, compiled and run
(InvokeMember) at runtime by CodeDom based on DataTable return from
database. So if you have following query:
SELECT SomeID, SomeName FROM SomeTable

the GenericTable class will look like:
Public Class GenericTable
Public SomeID As String
Public SomeName As String
End Class

Entire purpose of this approach was to dynamically generate class,
compile and generate a ArrayList of objects for a Flex 2 client.

John, thank so much for help me, I hope you have some additional ideas
how to handle this issue.

Thank you,
John
 
J

John Saunders [MVP]

mojeza said:
I wish I could. GenericTable class is built, compiled and run
(InvokeMember) at runtime by CodeDom based on DataTable return from
database. So if you have following query:
SELECT SomeID, SomeName FROM SomeTable

the GenericTable class will look like:
Public Class GenericTable
Public SomeID As String
Public SomeName As String
End Class

Entire purpose of this approach was to dynamically generate class,
compile and generate a ArrayList of objects for a Flex 2 client.

John, thank so much for help me, I hope you have some additional ideas
how to handle this issue.

Your WebMethod was returning Object, wasn't it? Instead, is should return
GenericTable() (which is "Array of GenericTable"). Why does it need to
return Object?
 
M

mojeza

Your WebMethod was returning Object, wasn't it? Instead, is should return
GenericTable() (which is "Array of GenericTable"). Why does it need to
return Object?

I posted a replay on May 4th but I cannot see it so I will try to
posted again.

I cannot cast my WebMethod as array of GenericTable class because this
class doesn't exist at design time. If I try I get error which say:
Type 'GenericTable' is not defined'.

Looks like I wonn't be able to create generic functionality unless I
define generic class with predefined number of public members and use
this class no for every request which will return result of the SELECT
statement. Class may look like:

Public Class GenericTable
Public Col1 As String
Public Col2 As String
...
Public Col25 As String
End Class

The problem with this aproach is that I won't be able to return result
sets with number of columns bigger than the number of public memebers
of GenericTable class. Additionally it seams like not very economical
solution since every return set will have the same number of columns
even if SELECT statement would return only 2 columns.
 

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

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,816
Latest member
nipsseyhussle

Latest Threads

Top