IndexOutOfBounds on databinding

G

Guest

I'm writing what should be a very simple app against an Oracle database. The
app has a number of user controls, any one of which is loaded into a main
display page using the loadControl method, depending on which menu item a
user selects. Each of these controls follows the same basic pattern: Get a
dataset from the database and then display the results using basic
databinding.

Everything works fine except that I'll occaisionally get an IndexOutOfBounds
exception on an actual databinding command in the .ascx page. Here's an
example of the exception message:

Index was outside the bounds of the array.
Description: An unhandled exception occurred during the execution of the
current web request. Please review the stack trace for more information about
the error and where it originated in the code.

Exception Details: System.IndexOutOfRangeException: Index was outside the
bounds of the array.

Source Error:


Line 21: </td>
Line 22: <td class="value">
Line 23: <%# CurrentRow["APPRV_COLLAT_VIN"] %>
Line 24: </td>
Line 25: <td class="label">


Source File: C:\inetpub\wwwroot\cart\Controls\CollateralAndFinanceData.ascx
Line: 23

Stack Trace:


[IndexOutOfRangeException: Index was outside the bounds of the array.]
System.Web.UI.DataBoundLiteralControl.SetDataBoundString(Int32 index,
String s) +14
ASP.CollateralAndFinanceData_ascx.__DataBind__control2(Object sender,
EventArgs e) in
C:\inetpub\wwwroot\cart\Controls\CollateralAndFinanceData.ascx:23
System.Web.UI.Control.OnDataBinding(EventArgs e) +66
System.Web.UI.Control.DataBind() +26
System.Web.UI.Control.DataBind() +86
CART.Controls.CollateralAndFinanceData.GetData() +130
CART.Controls.CollateralAndFinanceData.Page_Load(Object sender, EventArgs
e) +5
System.Web.UI.Control.OnLoad(EventArgs e) +67
System.Web.UI.Control.LoadRecursive() +35
System.Web.UI.Control.AddedControl(Control control, Int32 index) +307
System.Web.UI.ControlCollection.Add(Control child) +153
CART.ViewApplication.set_CurrentControlName(String value) +112
CART.NavigationLink.linkButton_Click(Object sender, EventArgs e) +34
System.Web.UI.WebControls.LinkButton.OnClick(EventArgs e) +108

System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler
sourceControl, String eventArgument) +18
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +138
System.Web.UI.Page.ProcessRequestMain() +1292


Notice that this is NOT the exception that's thrown if the field doesn't
exist in the row, nor the exception that would be raised if I was attempting
to access a row that doesn't exist. I've actually tried various ways of
getting to the field in the .cs code and writing the value to the trace. The
field is DEFINITELY there. The exception is actually on the
DataBoundLiteralControl.SetDataBoundString method.

What testing I've done seems to indicate that there's some sort of upper
limit to a page's (or other objects???) number of databound elements. I can
wrap various sections within panels, and this has often solved the problem.
That reinforces my theory that I'm running into a control's limitations --
each panel now has a fewer number of databound controls and the page now has
none itself.

Today I ran into the problem on yet another page, so I broke the page into
panels. What's interesting is that NOW I'm suddenly getting the error on yet
ANOTHER page (one that worked fine before), and it's on the 3rd databound
field. Now I'm thinking I'm running into some sort of limit on the total
number of databound fields available for the session, or some other sort of
limitation weirdness.

On another note (and possibly should be another thread) -- when I do break
one of these .ascx controls into panels, I've found the <asp:panel ... tag
can't be the first thing on the control, or I get a viewstate error.

Just as a sideline, I'm no newbie. I'm a senior developer and write this
kind of code day in and day out. This is the first app on which I've
encountered this kind of bizarre behaviour.



Some snippets from a standard control in my site:

From the .cs code behind:
...
public class ApplicantData : System.Web.UI.UserControl
{

private DataSet _data;

private void Page_Load(object sender, System.EventArgs e)
{
GetData();
}

private void GetData()
{
DataBase db = new DataBase();
_data = db.GetData("GetApplicantData");

this.DataBind();
}

public DataRow CurrentRow
{
get
{
DataRow returnRow = null;
if (_data == null)
{
GetData();
}

if (_data.Tables.Count > 0 && _data.Tables[0].Rows.Count > 0)
{
returnRow = _data.Tables[0].Rows[0];
}

return returnRow;
}
}
...

From the .ascx page:

<%@ Control Language="c#" AutoEventWireup="false"
Codebehind="ApplicantData.ascx.cs" Inherits="CART.Controls.ApplicantData"
TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<h2>Personal</h2>
<table class="dataTable" cellspacing="0">
<tr>
<td class="label">
First Name
</td>
<td class="value">
<%# CurrentRow["APLNT_FIRST_NM"] %>
</td>
<td class="label">
SSN
</td>
<td class="value">
<%# CurrentRow["APLNT_SSN"] %>
</td>
</tr>
<td class="label">
Middle Initial
</td>
<td class="value">
<%# CurrentRow["APLNT_MIDL_NM"] %>
</td>
<td class="label">
DOB
</td>
<td class="value">
<%# String.Format("{0:d}", CurrentRow["APLNT_BIRTH_DT"]) %>
</td>
<tr>
<td class="label">
Last Name
</td>
<td class="value">
<%# CurrentRow["APLNT_LAST_NM"] %>
</td>
<td class="label">
Age
</td>
<td class="value">
<%# CurrentRow["APLNT_AGE"] %>
</td>
</tr>
<tr>
<td class="label">
Suffix
</td>
<td class="value">
<%# CurrentRow["APLNT_SUFFX_NM"] %>
</td>
<td class="label">
Marital Status
</td>
<td class="value">
<%# CurrentRow["APLNT_MARITAL_STATUS_CD"] %>
</td>
</tr>
</table>
 
S

Steven Cheng[MSFT]

Hi kevin,

Welcome to ASP.NET newsgroup.
From your description and the code snippet you provided, you've expose an
DataRow property on a ascx UserControl which is used to perform databinding
to some inline <%# .. %> blocks and you perform the databinding in the
Usercontrol's Page_Load event. However, you're encountering occasional
"IndexOutOfRangeException" when you dynamically add this Usercontrol on
asp.net page,yes?

From my opinion , the problems is still likely something incorrect with the
DataSource (you expose through the CurrentRow). At least there won't have
limit on the total number of databound fields available per page or
Session. How many UserControl or DtaBinding fields are there on your
UserControl?

Since we can't get any further info through the exception and callstack, I
suggest you turn on your web application's Trace (in the <trace> element
in web.config).

And put Trace.Write statement during your UserControl's databinding code,
such as GetData()
CurrentRow's Get method .... You can check the _data or the DataRow or
event all those fields in the row to see what happend actually.

BTW, from the code you provided , your data access logic seems like:

===================
private void Page_Load(object sender, System.EventArgs e)
{
GetData();
}

private void GetData()
{
DataBase db = new DataBase();
_data = db.GetData("GetApplicantData");

this.DataBind();
}

public DataRow CurrentRow
{
get
{
DataRow returnRow = null;
if (_data == null)
{
GetData();
}
.................

}
=================

I don't think we should put "this.DataBind();" in "GetData" function since
it will make all the databinding statement be fired again. Maybe we can
change it to:

=================
private void Page_Load(object sender, System.EventArgs e)
{
this.DataBind();
}

private void GetData()
{
DataBase db = new DataBase();
_data = db.GetData("GetApplicantData");

}

public DataRow CurrentRow
{
get
{
DataRow returnRow = null;
if (_data == null)
{
GetData();
}
.................

}

=================

HTH. Thanks,


Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
G

Guest

Steven,

Thanks for your response!
Since we can't get any further info through the exception and callstack, I
suggest you turn on your web application's Trace (in the <trace> element
in web.config).

And put Trace.Write statement during your UserControl's databinding code,
such as GetData()
CurrentRow's Get method .... You can check the _data or the DataRow or
event all those fields in the row to see what happend actually.

I did something somewhat similar to this. In my trace, I actually looped
through the dataset independently of the databinding and writing out the
values of the fields. All the fields traced out correctly and there were no
errors, but the same error occurred in the inline code. As an act of
desperation, I then went through all of the databinding code and replaced the
simple <%# %> blocks with literal controls:

old:
<td>
<%# CurrentRow["APLNT_LAST_NM"] %>
</td>

new:

<td>
<asp:Literal runat="server" id="lastNameLiteral" text='<%#
CurrentRow["APLNT_LAST_NM"] %>'></asp:Literal>
</td>

That completely solved my problem. On the one hand, that means I'm cool now
and no longer in need of assistance. On the other hand, I think that
reinforces the theory that there is something amiss behind the scenes when
binding directly to a user control or aspx page. I only insist in this
because it might be helpful for others who experience the same issue, even if
it's released as some sort of best practice or guideline.

For example, when I first encountered the issue, I solved the issue on one
page SIMPLY by wrapping two tables like this one:

<table>
<tr>
<td>Last Name:</td>
<td>
<%# CurrentRow["APLNT_LAST_NM"] %>
</td>
</tr>
<!-- several more rows with other fields -->
</table>

In their own panel controls, like this:

<asp:panel runat="server" id="tableOnePanel">
<table>
<tr>
<td>Last Name:</td>
<td>
<%# CurrentRow["APLNT_LAST_NM"] %>
</td>
</tr>
<!-- several more rows with other fields -->
</table>
</asp:panel>

This solved the problem on that page immediately, but then I would run into
the same issue on another page with another field. As in the process that
finally resolved my issue completely (using literal controls instead of
binding directly to the page), the name of the fields never changed. In one
case I cut-and-pasted, and in the other case I never even touched the field
names -- I simply added the panel tags before and after the existing table.

One thing to keep in mind is the somewhat non-traditional architecture of
this specific application. It's writen almost like a Java-bean app, with one
main .aspx page that contains a single place holder control. The various
"pages" are all .asCx user controls just like the one we've been describing.
A navigation control contains link buttons. The onClick event of each link
button (on the server side) creates the specific ascx control via
LoadControl, and then adds the control to the place holder. So in the
original load of the page, the last control is added behind the scenes so
that the engine can handle events. Then on the post-back, the new control is
added to the place holder. So I guess in actuallity, the page now contains
direct binding to all the fields on both pages. My only conclusion is that
at some point I'm simply exceeding some kind of limit to the number of
databound elements the page can handle as direct child controls.

Any other thoughts are more than welcome! Again, I have definitely solved my
issue, and dont' require assistance, but I'd be more than happy to contine
disussing the underlying issue.

Thanks again,

Kevin
 
S

Steven Cheng[MSFT]

Thanks for your detailed response and description Kevin,

AS you said that the problem went away when you use Literal Control instead
of directly inject databinding expression. I'm also feeling very strange.
From my research, the ASP.NET will actually use DataBoundLiteralControl to
display datas we bind directly with <%# %> expression. Those dynamic
generated controls are in the dynamic compiled page class (in the tempoaray
asp.net folder) so we have no idea of them generally. The code will be
something like:

private Control __BuildControl__control2()
{
DataBoundLiteralControl control1 = new DataBoundLiteralControl(8, 7);
this.__control2 = control1;
control1.SetStaticString(0, "\r\n<h2>Personal Info</h2>\r\n<table
class=\"dataTable\" cellspacing=\"0\">\r\n\t<tr>\r\n\t\t<td
class=\"label\">\r\n\t\t\tFirst Name\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(1,
"\r\n\t\t</td>\r\n\t</tr>\r\n\t<TR>\r\n\t\t<td
class=\"label\">\r\n\t\t\tMiddle Initial\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(2,
"\r\n\t\t</td>\r\n\t</TR>\r\n\t<tr>\r\n\t\t<td
class=\"label\">\r\n\t\t\tLast Name\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(3, "\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(4, "\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(5,
"\r\n\t\t</td>\r\n\t</tr>\r\n\t\r\n\t<TR>\r\n\t\t<td
class=\"label\">\r\n\t\t\tMiddle Initial\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(6,
"\r\n\t\t</td>\r\n\t</TR>\r\n\t<TR>\r\n\t\t<td
class=\"label\">\r\n\t\t\tMiddle Initial\r\n\t\t</td>\r\n\t\t<td
class=\"value\">\r\n\t\t\t");
control1.SetStaticString(7,
"\r\n\t\t</td>\r\n\t</TR>\r\n</table>\r\n");
control1.DataBinding += new EventHandler(this.__DataBind__control2);
return control1;
}

public void __DataBind__control2(object sender, EventArgs e)
{
DataBoundLiteralControl control2 = (DataBoundLiteralControl) sender;
Control control1 = control2.BindingContainer;
control2.SetDataBoundString(0,
Convert.ToString(base.get_CurrentRow()["APLNT_FIRST_NM"]));
control2.SetDataBoundString(1,
Convert.ToString(base.get_CurrentRow()["APLNT_MIDL_NM"]));
control2.SetDataBoundString(2,
Convert.ToString(base.get_CurrentRow()["APLNT_LAST_NM"]));
control2.SetDataBoundString(3,
Convert.ToString(base.get_CurrentRow()["APLNT_LAST_NM"]));
control2.SetDataBoundString(4,
Convert.ToString(base.get_CurrentRow()["APLNT_LAST_NM"]));
control2.SetDataBoundString(5,
Convert.ToString(base.get_CurrentRow()["APLNT_MIDL_NM"]));
control2.SetDataBoundString(6,
Convert.ToString(base.get_CurrentRow()["APLNT_MIDL_NM"]));
}

We can use the reflector tool to lookup the dynamic generated page in the
assemblies
(in %SYSTEM%\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\
....)

So I think the indexOutOfRange exception just occur at the above step. One
thing we can do curently is try building a simple test page to repro the
problem. Would you try creating a simple asp.net page or ascx control which
just add some <%# %> blocks and use some test datas( generate on the fly
rather than from database) bind with those expression. If the error occurs,
you can have a look at the dyanmic page (or UserControl) class's code to
see whether it is incorrectly generated. If there does exists some
problems with the dynamic generated file, you can send me the repro page so
that I can send it to our dev guys for some further research.

Thanks,

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 

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,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top