Lee Z
Lee Z

Reputation: 964

c# xslt transform on large xml string causes aspx timeout

I am working on an older project using .NET framework 4.5. There is an aspx page with an OnSelectedIndexChanged event that completes via a server side call. The server side call uses a stored proc that returns xml and then uses a transformation to convert the xml into html. The issue is that when the xml is large (currently testing with 10k records in xml format from the stored proc though the expectation is 100k records in production), then the aspx page times out. I am not sure what the best way to fix this issue is since the web.config settings for executionTimeout is set very high and debug is set to false.

Web.Config

<httpRuntime maxRequestLength="102400" executionTimeout="20000"/>

ASPX Page

<asp:DropDownList ID="ddlViews" runat="server" AutoPostBack="true" style="height:25px;min-width:150px;"  
    OnSelectedIndexChanged="ddlViews_SelectedIndexChanged">
</asp:DropDownList>

. . .

<asp:UpdatePanel ID="updPnl" runat="server">
    <Triggers> 
        <asp:AsyncPostBackTrigger ControlID="ddlViews" EventName="SelectedIndexChanged" />
     </Triggers>
    <ContentTemplate>
        <asp:Literal ID="litData" runat="server"></asp:Literal>
    </ContentTemplate>
</asp:UpdatePanel>

ASPX Code Behind

protected void ddlViews_SelectedIndexChanged(object sender, EventArgs e)
{
    if (ddlViews.Items.Count > 0 && ddlViews.SelectedValue != "-1")
    {
        System.Threading.Thread.Sleep(3000);
        ShowView();
    }
}

private void ShowView()
{
    if (ddlViews.Items.Count > 0)
    {
        string inputXml = GetXml();
        strData = Utils.ApplyXslt(inputXml);

        litData.Text = strData;
    }
}

public static string ApplyXslt(string xml)
{
    try
    {
        string xsltUri = GetXslPath();
        XsltArgumentList xslArg = new XsltArgumentList();
        xslArg.AddExtensionObject("urn:string-plus", new XslStringPlus());
        var xdoc = new XmlDocument();
        xdoc.LoadXml(xml);
        var xslt = new System.Xml.Xsl.XslCompiledTransform();

        using (var mStream = new System.IO.MemoryStream())
        {
            xslt.Load(xsltUri);
            xslt.Transform(xdoc, xslArg, mStream);
            mStream.Position = 3;
            var sr = new System.IO.StreamReader(mStream);
            return sr.ReadToEnd();
        }
    }
    catch (Exception e){
        throw new Exception(String.Format("Error Applying Xslt from path '{0}'to xml value '{1}'", xsltUri, xml) + " | " + e.StackTrace);
    }
}

The Transform is taking close to 3 minutes to complete for 10k records. It would be great to be able to drastically reduce that time if possible. The page is timing out after 1.5 minutes and I cannot find anything that works to increase that.

XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xslplus="urn:string-plus">
    <xsl:output method="html" />
    <xsl:template match="/">
        <table  id="tblLoanQuery" class="tableStyle">
            <tr>
                <xsl:for-each select="ROOT/Fields/child::*">
          <xsl:variable name="h" select="." />
                    <th><xsl:value-of select="xslplus:FormatLabel($h)" /></th>
                </xsl:for-each>
            </tr>
            <xsl:for-each select="ROOT/LoanNumbers/child::*">
                <xsl:variable name="loanId" select="." />
                <tr>
                    <xsl:for-each select="//ROOT/Fields/Field">
                        <xsl:variable name="fullFieldName" select="." />
                        <xsl:variable name="field" select="substring-after($fullFieldName,'.')" />
            <xsl:variable name="FieldValue" select="//ROOT/ROWS/row[@lqKey=$loanId]/@*[name(.)= xslplus:ConvertSpace($field)]/." />
            <td>
              <xsl:value-of select="xslplus:FormatValue($FieldValue)"/>              
            </td>
                    </xsl:for-each>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 306

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167571

In terms of XSLT it appears that //ROOT/ROWS/row[@lqKey=$loanId] suggests you want to use a key <xsl:key name="row-ref" match="ROOT/ROWS/row" use="@lqKey"/> and use key('row-ref', $loanId) instead of //ROOT/ROWS/row[@lqKey=$loanId]. The use of a key might improve run-time performance.

Upvotes: 1

Related Questions