Monday, March 26, 2012

DummyHtmlTextWriter Exception

Hi All,

I am getting the following exception using the April CTP:

System.Exception was unhandled by user code Message="An instance of 'Microsoft.Web.UI.DummyHtmlTextWriter' could not be used as an HtmlTextWriter. Make sure the specified class can be instantiated, extends System.Web.UI.HtmlTextWriter, and implements a constructor with a single parameter of type System.IO.TextWriter." Source="App_Web_sqmaviya" StackTrace: at Forms_Coordinators_AwardPoints.scriptManager_PageError(Object sender, PageErrorEventArgs e)in c:\Documents and Settings\jyoung\My Documents\Visual Studio 2005\WebSites\Pointfolio_v2\Forms\Coordinators\AwardPoints.aspx.cs:line 188 at Microsoft.Web.UI.ScriptManager.OnPageError(PageErrorEventArgs e) at Microsoft.Web.UI.ScriptManager.OnPageError(Exception ex) at Microsoft.Web.UI.ScriptManager.RenderPageCallback(HtmlTextWriter writer, Control pageControl) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) at System.Web.UI.Control.Render(HtmlTextWriter writer) at System.Web.UI.Page.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Control.RenderControl(HtmlTextWriter writer) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
This has proven to be very difficult to replicate as it seems completely random.
I have a web user control that contains a TreeView and 2 GridViews (available and selected).
Think file explorer with folders in the tree, files in one gridview and files that have been selected (via available) in the second gridview.
Both gridviews are wrapped in updatepanels with available triggering off the treeview and the selected triggering off the command of available.
The above exception gets thrown at random points when the triggers are fired.
I say random, because I can replicate the error, but not in an orderly fashion.
I go through selecting and deselecting and everything works fine and then boom exception.
Any help or insight would be greatly appreciated.

I tried the June CTP with the same issues.


In the hopes that this was an issue with the local dev server that is built into VS, I tried this under IIS6 with the same exception.

I am growing very discouraged by this. I ditched a custom built AJAX implementation in favor of Atlas and am now thinking that I have to ditch Atlas and go back to my implementation. I REALLY REALLY don't want to do this, but I don't know how to get around the exception.

I tried swallowing the exception but then I can an "Unknown Error" alert and then the whole thing blows up.

The aspx markup and codebehind is a bit long, but I can post it if you think it will help.

If this is an exception that I can do nothing about, is there anyway to swallow it and have it keep working without having to refresh the page?

I could really use the help on this one.

Thanks,

Joe


Hi,

two questions:

1) are you handling the PageError event of the ScriptManager?
2) are you using cache?

Hi, I am using the PageErrorEvent

protected void scriptManager_PageError(object sender, Microsoft.Web.UI.PageErrorEventArgs e) {throw new Exception(e.ErrorMessage); }
There is no caching at this page. There is some cache use in other parts of the application.

I take it there is some issue between Atlas and Output Caching and if we use one we can't use the other? What are the issues? Can you point me to a resource where there is more information?


I created a test project and was able to replicate the error.
It seems to have to due something with output caching. I added a webusercontrol and enabled output caching on it and got the error.
I can't upload my test solution so I will show all the code.

Web.Config
<configuration>
<!--
The configSections define a section for ASP.NET Atlas.
-->
<configSections>
<sectionGroup name="microsoft.web" type="Microsoft.Web.Configuration.MicrosoftWebSectionGroup">
<section name="converters" type="Microsoft.Web.Configuration.ConvertersSection" />
<section name="webServices" type="Microsoft.Web.Configuration.WebServicesSection" />
<section name="authenticationService" type="Microsoft.Web.Configuration.AuthenticationServiceSection" />
<section name="profileService" type="Microsoft.Web.Configuration.ProfileServiceSection" />
</sectionGroup>
</configSections
<!--
The microsoft.web section defines items required for the Atlas framework.
-->
<microsoft.web>
<converters>
<add type="Microsoft.Web.Script.Serialization.Converters.DataSetConverter"/>
<add type="Microsoft.Web.Script.Serialization.Converters.DataRowConverter"/>
<add type="Microsoft.Web.Script.Serialization.Converters.DataTableConverter"/>
</converters>
<webServices enableBrowserAccess="true" />
</microsoft.web>

<appSettings/>
<connectionStrings/>

<system.web>
<pages>
<controls>
<add namespace="Microsoft.Web.UI" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
<add namespace="Microsoft.Web.UI.Controls" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
</controls>
</pages>
<compilation debug="false">
<buildProviders>
<add extension=".asbx" type="Microsoft.Web.Services.BridgeBuildProvider" />
</buildProviders>
</compilation>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
<!--
The MultiRequestHandler enables multiple requests to be handled in one
roundtrip to the server. Its use requires Full Trust.
-->
<add verb="*" path="atlasbatchcall.axd" type="Microsoft.Web.Services.MultiRequestHandler" validate="false"/>
<add verb="*" path="atlasglob.axd" type="Microsoft.Web.Globalization.GlobalizationHandler" validate="false"/>
<!--
The IFrameHandler enables a limited form of cross-domain calls to 'Atlas' web services.
This should only be enabled if you need this functionality and you're willing to expose
the data publicly on the Internet.
To use it, you will also need to add the attribute [WebOperation(true, ResponseFormatMode.Json, true)]
on the methods that you want to be called cross-domain.
This attribute is by default on any DataService's GetData method.

<add verb="*" path="iframecall.axd" type="Microsoft.Web.Services.IFrameHandler" validate="false"/>
-->
<add verb="*" path="*.asbx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
</httpHandlers>
<httpModules>
<add name="ScriptModule" type="Microsoft.Web.Services.ScriptModule"/>
<add name="BridgeModule" type="Microsoft.Web.Services.BridgeModule"/>
<add name="WebResourceCompression" type="Microsoft.Web.Services.WebResourceCompressionModule"/>
</httpModules>
<authentication mode="Windows" />
</system.web>
</configuration>

ASPX Page
<%@. Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AtlasTest._Default" %
<%@. register src="http://pics.10026.com/?src=WebUserControl1.ascx" tagname="WebUserControl1" tagprefix="uc1" %>

<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<atlas:scriptmanager id="scriptManager" runat="server" enablepartialrendering="true" onpageerror="scriptManager_PageError"></atlas:scriptmanager>
<asp:treeview id="TreeView1" runat="server" onselectednodechanged="TreeView1_SelectedNodeChanged">
</asp:treeview>
<atlas:updatepanel id="updatePanel1" runat="server" mode="Conditional">
<contenttemplate>
<asp:gridview id="GridView1" runat="server" backcolor="White" bordercolor="#CC9966" borderstyle="None" borderwidth="1px" cellpadding="4" autogeneratecolumns="False" autogenerateselectbutton="True" onselectedindexchanged="GridView1_SelectedIndexChanged">
<footerstyle backcolor="#FFFFCC" forecolor="#330099" />
<rowstyle backcolor="White" forecolor="#330099" />
<selectedrowstyle backcolor="#FFCC66" font-bold="True" forecolor="#663399" />
<pagerstyle backcolor="#FFFFCC" forecolor="#330099" horizontalalign="Center" />
<headerstyle backcolor="#990000" font-bold="True" forecolor="#FFFFCC" />
<columns>
<asp:boundfield headertext="Id" datafield="Id" />
<asp:boundfield headertext="Name" datafield="Name" />
</columns>
</asp:gridview>
</contenttemplate>
<triggers>
<atlas:controleventtrigger controlid="TreeView1" eventname="SelectedNodeChanged" /></triggers>
</atlas:updatepanel>
</div>
<uc1:webusercontrol1 id="WebUserControl1_1" runat="server" />
</form>
</body>
</html>

Code Behind
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace AtlasTest
{
public partialclass _Default : System.Web.UI.Page
{
private Dictionary<int, Group> groupDictionary;

protected void Page_Load(object sender, EventArgs e)
{
CreateGroups();

if (!Page.IsPostBack)
{
BindGroupTree(groupDictionary[1],null);
}
}

private void CreateGroups()
{

groupDictionary =new Dictionary<int, Group>();

Group root =new Group(1,"Root");
Group child1 =new Group(2,"Child1");
Group child2 =new Group(3,"Child2");
Group child11 =new Group(4,"Child11");
Group child12 =new Group(5,"Child12");
Group child21 =new Group(6,"Child21");
Group child22 =new Group(7,"Child22");

groupDictionary.Add(root.Id, root);
groupDictionary.Add(child1.Id, child1);
groupDictionary.Add(child2.Id, child2);
groupDictionary.Add(child11.Id, child11);
groupDictionary.Add(child12.Id, child12);
groupDictionary.Add(child21.Id, child21);
groupDictionary.Add(child22.Id, child22);

// Build the tree
root.Children.Add(child1.Id, child1);
root.Children.Add(child2.Id, child2);

child1.Children.Add(child11.Id, child11);
child1.Children.Add(child12.Id, child12);

child2.Children.Add(child21.Id, child21);
child2.Children.Add(child22.Id, child22);

child1.Users.Add(new User(11,"Test 11"));
child1.Users.Add(new User(12,"Test 12"));
child1.Users.Add(new User(13,"Test 13"));
child1.Users.Add(new User(14,"Test 14"));
child1.Users.Add(new User(15,"Test 15"));

child2.Users.Add(new User(21,"Test 21"));
child2.Users.Add(new User(22,"Test 22"));
child2.Users.Add(new User(23,"Test 23"));
child2.Users.Add(new User(24,"Test 24"));
child2.Users.Add(new User(25,"Test 25"));

child11.Users.Add(new User(111,"Test 111"));
child11.Users.Add(new User(112,"Test 112"));
child11.Users.Add(new User(113,"Test 113"));
child11.Users.Add(new User(114,"Test 114"));
child11.Users.Add(new User(115,"Test 115"));

child12.Users.Add(new User(121,"Test 121"));
child12.Users.Add(new User(122,"Test 122"));
child12.Users.Add(new User(123,"Test 123"));
child12.Users.Add(new User(124,"Test 124"));
child12.Users.Add(new User(125,"Test 125"));

child21.Users.Add(new User(211,"Test 211"));
child21.Users.Add(new User(212,"Test 212"));
child21.Users.Add(new User(213,"Test 213"));
child21.Users.Add(new User(214,"Test 214"));
child21.Users.Add(new User(215,"Test 215"));

child22.Users.Add(new User(221,"Test 221"));
child22.Users.Add(new User(222,"Test 222"));
child22.Users.Add(new User(223,"Test 223"));
child22.Users.Add(new User(224,"Test 224"));
child22.Users.Add(new User(225,"Test 225"));
}

private void BindGroupTree(Group group, TreeNode parent)
{
if (group.Children ==null) {return; }

foreach (KeyValuePair<int, Group> kvpin group.Children)
{
TreeNode treeNode =new TreeNode();
treeNode.Value = kvp.Key.ToString();
treeNode.Text = kvp.Value.Name;

if (parent ==null)
{
TreeView1.Nodes.Add(treeNode);
}
else
{
parent.ChildNodes.Add(treeNode);
}

BindGroupTree(kvp.Value, treeNode);
}
}

protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
int selectedIndex = System.Convert.ToInt32(TreeView1.SelectedValue);

List users = groupDictionary[selectedIndex].Users;

GridView1.DataSource = users;
GridView1.DataBind();
}

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{

}

protected void scriptManager_PageError(object sender, Microsoft.Web.UI.PageErrorEventArgs e)
{
throw new Exception(e.ErrorMessage);
}
}
}

Data
using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace AtlasTest
{
public class Group
{
private int id;
private string name;
private Dictionary<int, Group> children;
private List users;

public int Id
{
get {return this.id; }
set {this.id =value; }
}

public string Name
{
get {return this.name; }
set {this.name =value; }
}

public Dictionary<int, Group> Children
{
get {return this.children; }
}

public List Users
{
get {return this.users; }
}

public Group(int id,string name)
{
this.id = id;
this.name = name;
this.children =new Dictionary<int, Group>();
this.users =new List();
}
}

public class User
{
private int id;
private string name;

public int Id
{
get {return this.id; }
set {this.id =value; }
}

public string Name
{
get {return this.name; }
set {this.name =value; }
}

public User(int id,string name)
{
this.id = id;
this.name = name;
}
}
}

WebUserControl
<%@. Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="AtlasTest.WebUserControl1" %>
<%@. outputcache duration="5" varybyparam="none" %>
<asp:datalist id="DataList1" runat="server" onitemdatabound="DataList1_ItemDataBound">
<itemtemplate>
<asp:label id="lblTest" runat="server" text="Label"></asp:label>
</itemtemplate>
</asp:datalist>

WebUserControl CodeBehind
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace AtlasTest
{
public partialclass WebUserControl1 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
BindData();
}
}

private void BindData()
{
List<string> testList =new List<string>();
testList.Add("One");
testList.Add("Two");
testList.Add("Three");
testList.Add("Four");
testList.Add("Five");

DataList1.DataSource = testList;
DataList1.DataBind();
}

protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
string test = e.Item.DataItemas string;

Label lblTest = e.Item.FindControl("lblTest")as Label;

lblTest.Text = test;
}
}
}
}

It seems like there are some severe issues with Atlas and Caching. Is the Atlas team aware of this? If so is there a fix coming soon or a work around?

Thanks,

Joe


Hi,

is there any user control with cache enabled, in your page? What I suggest is, if you have user controls in your page, to remove each one and see if the problem persists. Specifically, look for controls or user controls that are *outside* an UpdatePanel.

Yeah, there was one usercontrol that used cache. It happens to be the only place where caching is used. I disabled the cache and have yet to encounter the exception. Is there a way to use both atlas and caching that I am not aware of? Is this behavior expected to be fixed in the final release. I will keep caching disabled for the time being as we cannot have random exceptions being thrown about,Big Smile but I would really like to use both.

Joe


Hi,

yes, there is an issue with the UpdatePanel and Output caching, at least in the April CTP:

http://forums.asp.net/thread/1318184.aspx

I don't know if it has been fixed in the current CTP (June), you can try to switch to the June CTP and see if it works, otherwise I'll do a test later. Let me know how it goes.

Thanks for the post about the issue, i have been looking everywhere (or so I thought) trying to find some more info.

I updated to the June CTP hoping that it was indeed fixed, but the same exception is still being thrown. I did not see error being fixed in the release notes as well, so I am assuming that it is not fixed. Hopefully it will be soon.Big Smile

Really appreciate the help and info.

Many Thanks,

Joe


I'm also encountering the same issue with the July CTP. I'm just hoping this will be fixed in whatever the next release is, as output caching is such a huge performance benefit.

Mark

No comments:

Post a Comment