ASP.NET AJAX Advance Tips & Tricks (10) 解决使用AJAX Extender时的页面导出(Word/Excel)问题(Extender control 'XXX' is not a registered extender control)

前言:

有客户问到这么个问题:我们可以使用Response容易地将ASP.NET页面导出为Excel或Word。然而,如果有AJAX Control Toolkit的Extender在页面上的话,则会发生错误(Extender control 'XXX' is not a registered extender control)。我搜索了一下,ASP.NET forum里有很多这样的问题未能解决,故写了这个解决方案,与大家分享。

问题重现:

首先,使用Response将ASP.NET页面导出为Excel或Word,代码比较简单,如下所示:

    public void ExportControl(System.Web.UI.Control source, DocumentType type,string name)
    {
        
if (type == DocumentType.Excel)
        {
            
//Excel 
            Response.AppendHeader("Content-Disposition""attachment;filename="+name+".xls");
            Response.ContentType 
= "application/ms-excel";
        }
        
else if (type == DocumentType.Word)
        {
            
//Word 
            Response.AppendHeader("Content-Disposition""attachment;filename=" + name + ".doc");
            Response.ContentType 
= "application/ms-word";
        }
        Response.Charset 
= "UTF-8";
        Response.ContentEncoding 
= System.Text.Encoding.UTF8;

        source.Page.EnableViewState 
= false;

        System.IO.StringWriter writer 
= new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htmlWriter 
= new System.Web.UI.HtmlTextWriter(writer);
        source.RenderControl(htmlWriter);

        Response.Write(writer.ToString());
        Response.End();
    }

    
public enum DocumentType
    {
        Word,
        Excel
    }

 

然而,在下面的例子中,我们将会得到一个令人厌烦的错误:

<%@ Page Language="C#" EnableEventValidation = "false"  %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    protected 
void Button2_Click(object sender, EventArgs e)
    
{
        ExportControl(
this, DocumentType.Word, "ExportWord"); 
    }


    public override 
void VerifyRenderingInServerForm(Control control)
    
{

    }


    public 
void ExportControl(System.Web.UI.Control source, DocumentType type,string name)
    
{
        
if (type == DocumentType.Excel)
        
{
            
//Excel 
            Response.AppendHeader("Content-Disposition""attachment;filename="+name+".xls");
            Response.ContentType 
= "application/ms-excel";
        }

        
else if (type == DocumentType.Word)
        
{
            
//Word 
            Response.AppendHeader("Content-Disposition""attachment;filename=" + name + ".doc");
            Response.ContentType 
= "application/ms-word";
        }

        Response.Charset 
= "UTF-8";
        Response.ContentEncoding 
= System.Text.Encoding.UTF8;

        source.Page.EnableViewState 
= false;

        System.IO.StringWriter writer 
= new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htmlWriter 
= new System.Web.UI.HtmlTextWriter(writer);
        source.RenderControl(htmlWriter);

        Response.Write(writer.ToString());
        Response.End();
    }


    public enum DocumentType
    
{
        Word,
        Excel
    }


</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    
<title></title>
</head>
<body>
    
<form id="form1" runat="server">
    
<div>
        
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
    
</div>
    
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    
<ajaxToolkit:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" Enabled="True"
        TargetControlID
="TextBox1">
    
</ajaxToolkit:CalendarExtender>
    
<br />
    
<br />
    
<br />
    
<asp:Panel ID="Panel1" runat="server" Height="100px" Width="194px" BackColor="Chocolate">
    
</asp:Panel>
    
<ajaxToolkit:RoundedCornersExtender ID="Panel1_RoundedCornersExtender" runat="server"
        Enabled
="True" TargetControlID="Panel1">
    
</ajaxToolkit:RoundedCornersExtender>
    
<br />
    
</p>
    
<asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Download" />
    
</form>
</body>
</html>

 

错误信息如下:

Server Error in '/AjaxControlToolkitWebSite2' Application.
--------------------------------------------------------------------------------

Extender control 'TextBox1_CalendarExtender' is not a registered extender control. Extender controls must be registered using RegisterExtenderControl() before calling RegisterScriptDescriptors().
Parameter name: extenderControl

分析:

显然,问题是出现在AJAX Extender上,如果把页面上的AJAX Extender全部删除,则工作正常。

有此,该问题的解决思路为“在导出之前移除页面上所有的Extender

 

解决方案:

使用递归方式,在导出之前移除所有AJAX Extenders:

 

    private void DisableAJAXExtenders(Control parent)
    {
        
for (int i = 0; i < parent.Controls.Count; i++)
        {
            
if (parent.Controls[i].GetType().ToString().IndexOf("Extender"!= -1 && parent.Controls[i].ID != null)
            {
                parent.Controls.RemoveAt(i);
                parent.Controls[i].Dispose();
            }
            
if (parent.Controls[i].Controls.Count > 0)
            {
                DisableAJAXExtenders(parent.Controls[i]);
            }
        }
    }

 

如下例所示,页面可成功导出为Word/Excel:

 

<%@ Page Language="C#" EnableEventValidation = "false"  %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    protected 
void Button2_Click(object sender, EventArgs e)
    {
        
//DisableAJAXExtenders(this);
        ExportControl(this, DocumentType.Word, "ExportWord"); 
    }

    private 
void DisableAJAXExtenders(Control parent)
    {
        
for (int i = 0; i < parent.Controls.Count; i++)
        {
            
if (parent.Controls[i].GetType().ToString().IndexOf("Extender"!= -1 && parent.Controls[i].ID != null)
            {
                parent.Controls.RemoveAt(i);
                parent.Controls[i].Dispose();
            }
            
if (parent.Controls[i].Controls.Count > 0)
            {
                DisableAJAXExtenders(parent.Controls[i]);
            }
        }
    }

    public override 
void VerifyRenderingInServerForm(Control control)
    {

    }

    public 
void ExportControl(System.Web.UI.Control source, DocumentType type,string name)
    {
        
if (type == DocumentType.Excel)
        {
            
//Excel 
            Response.AppendHeader("Content-Disposition""attachment;filename="+name+".xls");
            Response.ContentType 
= "application/ms-excel";
        }
        
else if (type == DocumentType.Word)
        {
            
//Word 
            Response.AppendHeader("Content-Disposition""attachment;filename=" + name + ".doc");
            Response.ContentType 
= "application/ms-word";
        }
        Response.Charset 
= "UTF-8";
        Response.ContentEncoding 
= System.Text.Encoding.UTF8;

        source.Page.EnableViewState 
= false;

        System.IO.StringWriter writer 
= new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htmlWriter 
= new System.Web.UI.HtmlTextWriter(writer);
        source.RenderControl(htmlWriter);

        Response.Write(writer.ToString());
        Response.End();
    }

    public enum DocumentType
    {
        Word,
        Excel
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    
<title></title>
</head>
<body>
    
<form id="form1" runat="server">
    
<div>
        
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
    
</div>
    
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    
<ajaxToolkit:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" Enabled="True"
        TargetControlID
="TextBox1">
    
</ajaxToolkit:CalendarExtender>
    
<br />
    
<br />
    
<br />
    
<asp:Panel ID="Panel1" runat="server" Height="100px" Width="194px" BackColor="Chocolate">
    
</asp:Panel>
    
<ajaxToolkit:RoundedCornersExtender ID="Panel1_RoundedCornersExtender" runat="server"
        Enabled
="True" TargetControlID="Panel1">
    
</ajaxToolkit:RoundedCornersExtender>
    
<br />
    
<br />
    
<asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Download" />
    
</form>
</body>
</html>

 

PS:

一般情况下,如果想要移除页面上的所有AJAX Extender,也可以采用JavaScript的方式:

 

Code

 

相关Case:

http://forums.asp.net/t/1405746.aspx

http://forums.asp.net/p/1078866/2082230.aspx

http://forums.asp.net/p/1242924/2275572.aspx

 

 

 

 

posted @ 2009-04-09 15:31 LanceZhang 阅读(...) 评论(...) 编辑 收藏