DataTable from an array of objects returned from a webservice

K

Kevin Schneider

I have the "simple" problem of wanting to take an array of objects I
get from a webservice and turning them into a DataTable. The following
is my solution and I'm looking for a critique of what I am doing. The
names in the code below have been changed to "protect the company",
but the spirit remains. I've posted it as if you would call
getAndFillDT(). Thanks

using System;
using System.Data;
using System.Reflection;

namespace Testing
{

public class DTfromWS
{
public DTfromWS()
{
}


private DataTable getAndFillDT ()
{
MyWebService.VO vo = new MyWebService.VO();
Array mvo = taiws.findAllVOs(vo);

DataTable dt = makeDataTable(new MyWebService.VO());


foreach (MyWebServiceVO voi in mvo)
{
System.Type mt= voi.GetType();
System.Reflection.FieldInfo[] fia =
mt.GetFields(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.DeclaredOnly);

DataRow dr = dt.NewRow();
foreach (System.Reflection.FieldInfo fi in fia)
{
try
{
dr[fi.Name] = mt.InvokeMember(
fi.Name,
System.Reflection.BindingFlags.GetField
| BindingFlags.Instance
| BindingFlags.Public
| System.Reflection.BindingFlags.DeclaredOnly,
null,
voi,
null);
}
catch (Exception ex)
{
throw new Exception(fi.Name + " current field name", ex);
}

}
dt.Rows.Add(dr);
}
}

public DataTable makeDataTable(object VO)
{
DataTable dt = new DataTable();
DataRow dr = dt.NewRow();

System.Type mt= VO.GetType();
System.Reflection.FieldInfo[] fia =
mt.GetFields(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.DeclaredOnly);

foreach (System.Reflection.FieldInfo fi in fia)
{
dt.Columns.Add(fi.Name,fi.FieldType);
}

return dt;
}

}
}
 
D

Dino Chiesa [Microsoft]

Looks reasonable. It's a general solution. You may pay a perf penalty for
reflection at runtime.
If you know the types of the objects, then you could optimize it by
hand-coding the construction of a DataTable from an array of strongly-typed
objects. You'd have to benchmark it to know if it is worth it.

----
If you stick with reflection, and if the objects are all of the same type,
you should factor out this bit:

System.Type mt= voi.GetType();
System.Reflection.FieldInfo[] fia = mt.GetFields(...);

from the loop. You need to do this once for each type of object, not once
for each object.

If you are real picky about unnecessary object creation and optimization,
you can change this:
DataTable dt = makeDataTable(new MyWebService.VO());

to this:
System.Type mt= voi.GetType(); // factored out of the loop
System.Reflection.FieldInfo[] fia = mt.GetFields(...); // factored out
of the loop
DataTable dt = makeDataTable(fia);

and then modify makeDataTable to accept a FieldInfo[]. But then
makeDataTable is reduced to

DataTable dt = new DataTable();
foreach (System.Reflection.FieldInfo fi in fia)
dt.Columns.Add(fi.Name,fi.FieldType);

It's so simple, you may want to eliminate it as a separate function.


-D

Kevin Schneider said:
I have the "simple" problem of wanting to take an array of objects I
get from a webservice and turning them into a DataTable. The following
is my solution and I'm looking for a critique of what I am doing. The
names in the code below have been changed to "protect the company",
but the spirit remains. I've posted it as if you would call
getAndFillDT(). Thanks

using System;
using System.Data;
using System.Reflection;

namespace Testing
{

public class DTfromWS
{
public DTfromWS()
{
}


private DataTable getAndFillDT ()
{
MyWebService.VO vo = new MyWebService.VO();
Array mvo = taiws.findAllVOs(vo);

DataTable dt = makeDataTable(new MyWebService.VO());


foreach (MyWebServiceVO voi in mvo)
{
System.Type mt= voi.GetType();
System.Reflection.FieldInfo[] fia =
mt.GetFields(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.DeclaredOnly);

DataRow dr = dt.NewRow();
foreach (System.Reflection.FieldInfo fi in fia)
{
try
{
dr[fi.Name] = mt.InvokeMember(
fi.Name,
System.Reflection.BindingFlags.GetField
| BindingFlags.Instance
| BindingFlags.Public
| System.Reflection.BindingFlags.DeclaredOnly,
null,
voi,
null);
}
catch (Exception ex)
{
throw new Exception(fi.Name + " current field name", ex);
}

}
dt.Rows.Add(dr);
}
}

public DataTable makeDataTable(object VO)
{
DataTable dt = new DataTable();
DataRow dr = dt.NewRow();

System.Type mt= VO.GetType();
System.Reflection.FieldInfo[] fia =
mt.GetFields(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.DeclaredOnly);

foreach (System.Reflection.FieldInfo fi in fia)
{
dt.Columns.Add(fi.Name,fi.FieldType);
}

return dt;
}

}
}
 
K

Kevin Schneider

Thanks for taking the time to give it a look. I think I work in some
of your suggestions.

As a point of reference, I did some benchmarking after I posted this
and found that it doesn't affect the speed at all. I ran it so that
the web service returned the biggest set of objects I can get (approx.
20,000, each object had 8 fields) and processing the whole array into
a datatable took less than a second. The real bottleneck is actually
passing the entire object array across the wire, which takes about 10
seconds. Unfortunatley (or fortunatley) I can't control the web
service in this case.
 

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,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top