English 中文(简体)
Creating and showing dynamic error messages (Not working inside UpdatePanel)
原标题:

My web forms inherits a class called MyPageMain, which inhertis System.Web.UI.Page and is located on the App_Code folder.

In this MyPageMain class I created this method, to record and output Exceptions (error messages):

public string Error(Exception pException, string pFriendlyMessage)
{
    using (BusError erro = new BusError())
    {
        int? errorId = //HERE Routine to log the error;

        StringWriter stringWriter = new StringWriter();

        using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
        {

            writer.AddAttribute(HtmlTextWriterAttribute.Class, "erroMain");
            writer.RenderBeginTag(HtmlTextWriterTag.Div); //<div>

            writer.RenderBeginTag(HtmlTextWriterTag.P); //<p>
            writer.Write(pFriendlyMessage);
            writer.RenderEndTag(); // </p>
            writer.RenderBeginTag(HtmlTextWriterTag.Small); 
            writer.Write("Event tracker:");
            writer.Write(errorId);
            writer.RenderEndTag(); 

            writer.RenderEndTag(); // </div>
            Console.WriteLine(stringWriter.ToString());
        }

    }
}

Then, when there is some exception on the page, I call it, like this:

    Protected void btnLoad_Click(object sender, EventArgs e)
    {
         LoadData();
    }        

    private void LoadData()
    {
        try
        {
             //Loading some data here.
        }
        catch (Exception ex)
        {
             Error(ex, "Unexpected error trying to load data.");
        }
    }

This is bulding OK, but doesn t work... I think that one of the reasons may be the fact that the whole thing is inside an UpdatePanel. Any suggestions on how to make this work?

Is this Console.Writeline suitable for what i m trying to do? Is this going to work on UpdatePanels?

Already Tried with Response.Write(...) and it does work. But not inside an UpdatePanel

最佳回答

When you use an UpdatePanel, you can only update content within the panel during an async postback triggered from that panel, so your error message will have to appear somewhere within the UpdatePanel. (That is, unless you set UpdateMode="Always" on one of your UpdatePanels, then its content is updated on every async and full postback. But that doesn t help you here unless you put your error message in its own UpdatePanel with UpdateMode="Always", which would require you to add said UpdatePanel to every page. I understand this is not what you want to do.)

The following example will work to add the error message at the top of the UpdatePanel.

You will need to add a Control errorParent parameter to your Error method, so it can add the error message as child control to that parent control.

In your catch block, just pass in whatever container control where you want the error message to appear. That control must be a container to accept child controls, so it has to be something that renders as a <div> or <span> tag, like an asp:Panel or asp:UpdatePanel.

In the example below, you could use errorParent.Controls.Add(errorControl) to show the error message at the bottom of the UpdatePanel, or use AddAt() with a different index. Just be sure that index will always work on every page.

Take a parent control and add a new Literal child control:

public string Error(Exception pException, string pFriendlyMessage, Control errorParent)
{
    using (BusError erro = new BusError())
    {
        int? errorId = //HERE Routine to log the error;

        Literal errorControl = new Literal();
        errorControl.Text = String.Format("<div class="errorMain"><p>{0}</p><small>Event Tracker: {1}</small></div>", pFriendlyMessage, errorId);
        errorParent.Controls.AddAt(0, errorControl);
    }
}

Pass in the parent control:

private void LoadData()
{
    try
    {
         //Loading some data here.
    }
    catch (Exception ex)
    {
         Error(ex, "Unexpected error trying to load data.", MyUpdatePanel.ContentTemplateContainer);
    }
}
问题回答

Since your Error method returns string, you can return error message and display it.

Place Literal in your UpdatePanel (maybe in MasterPage, so you do not have to write it for all 40 or more pages). When exception is thrown, handle it with your Error method and set returned message to Literal.

Console.WriteLine is not usable in ASP.NET. Use Debug.WriteLine instead. It will write to Output window in VisualStudio.

Many of the answers are dancing around the issue. Console.WriteLine is a command used to output a line of text for a Console application (command-line). This is a Web app. So, you either use Response.Write to spit a string out to the Response stream or set the text of a Literal control that is already on the page and set it to be visible (default hidden).

Since I myself completely missed the UpdatePanel detail, here s an alternate solution to make up for it. My example uses a hidden div and some jQuery through the usage of the ScriptManager control to inject text into a div that is outside the UpdatePanel. Based on the conditions of the go_Click handler method of the button, it ll show or hide an error message using jQuery that gets injected into the Page server-side at the time of the UpdatePanel s update.

Note that it is critically important to use the ScriptManager s functions to register JavaScript rather than Page.ClientScript when using AJAX. Using the latter won t add the JS to the page.

Page markup

<div id="errorMessagePlaceHolder" class="error" style="display:none;">
</div>
<asp:UpdatePanel ID="myPanel" runat="server">
    <ContentTemplate>
        <asp:TextBox ID="myText" runat="server" />
        <asp:Button ID="go" Text="GO" runat="server" OnClick="go_Click" />
    </ContentTemplate>
</asp:UpdatePanel>

Page code-behind

public partial class _Default : Page {
    protected void go_Click(object sender, EventArgs e) {
        try {
            // Do something that can throw an exception

            // Hide the error if we reach the end as we may have triggered
            // it in a prior update and no longer want it to display.
            HideError();
        } catch (Exception) {
            ShowError("myText is empty!");
        }
    }

    #region Move to a base page or a helper class if it helps reduce duplication

    private void HideError() {
        ScriptManager.RegisterStartupScript(Page, GetType(), "HideErrorMessageScript", HideErrorMessageScript(), true);
    }

    private void ShowError(string errorMessage) {
        ScriptManager.RegisterStartupScript(Page, GetType(), "ErrorMessageScript", ErrorMessageScript(errorMessage), true);
    }

    private static string HideErrorMessageScript() {
        return @"
$(document).ready(function() {
    $( #errorMessagePlaceHolder ).hide();
});
";
    }

    private static string ErrorMessageScript(string errorMessage) {
        return
            string.Format(
                @"
$(document).ready(function() {{
    $( #errorMessagePlaceHolder ).html( {0} );
    $( #errorMessagePlaceHolder ).show();
}});
",
                errorMessage);
    }

    #endregion

}

I feel like nobody has actually answered the entire question yet, so let me try.

Is this Console.Writeline suitable for what i m trying to do?

Probably not, unless you just want debug information to appear in the output window while debugging. Some people like to keep outputting info to the Console, even in a release build and so if you want to do that with your errors, it s a valid choice, but you should also be showing a friendly error message to the user and/or logging the error to some kind of persistence (eg. log file). All of the answers above are suggesting ways for you to show some notification of the error to the user.

Is this going to work on UpdatePanels?

There is NO reason why it shouldn t if your triggers and the like are set up properly (and we know they are because you said that you re able to hit the Console.WriteLine breakpoint). I wonder if your Console output is working fine but you re looking for it in the wrong place? In the typical configuration for a web application, it should appear in the Output window of the Visual Studio instance you re using to Debug.


As to a suggestion for what I think you re asking, which is "how do I get my error message to appear in the update panel if there s an error loading the content for that update panel?"...

I would suggest an approach similar to nekno s proposal above. You can either dynamically add a control whose text you can set to be the error string during update panel request processing or you can even have an initially hidden/collapsed control on the page, which is only set to be visible in the case of an error. I d prefer the latter approach because it s more maintainable. You can completely control the look and feel of the error label from the markup/display views of your ASPX page.

Are you calling .update() on your UpdatePanel after your LoadData() method runs? I think the UpdatePanel won t automatically fire unless the postback originates from inside it.

Ex:

Protected void btnLoad_Click(object sender, EventArgs e)
{
    LoadData();
    MyUpdatePanel.Update(); 
} 

Update: I was able to get Response.Write() to work in an UpdatePanel by registering a trigger like this <Triggers><asp:PostBackTrigger ControlID="btn1" /></Triggers> for the button that will create the error.

Are you trying to log errors or display them? If you are trying to display them, you should:

On your masterpage, create a spot where your errors will be displayed (maybe below your navigation bar or near the bottom:

<asp:ContentPlaceHolder id= cphError ></asp:ContentPlaceHolder>

Everytime you get an error, you can call your error function as is, but instead of writing out the text with Response.Write() or Console.WriteLine(), you can add a label in there:

Label lError = new Label();
lError.CssClass =  .. ;
lError.Text =  .. ;
cphError.Controls.Add(lError);

This will help you out with displaying the error, but AJAX will still be a problem. At this point, you have two options:

  1. Since update panels update other update panels, you can wrap an update panel around cphError, this way your AJAX calls will still update that area

  2. OR: You can can use ClientScript.RegisterStartupScript to create the error label. (This method is only preferable if you do not have a static error message spot)

Place a Panel on the master, extend it with the modalpopupextender in the AjaxToolKit. When the error is raised, write the contents of string writer to a label in the panel E.g. Label lbl = (Label)Master.FindControl() lbl.text = StringWriter.ToString();

// Now access the modal popup AjaxControlToolkit.ModalPopupExtender MPE = (AjaxControlToolkit.ModalPopupExtender)Master.findControl(""); // and show it MPE.Show();

The Modal will need a hidden button to use as it s target control, but it will not require a user s input. I accomplish this on the page with the following code:

            <asp:Button ID="btnDummyOK" runat="server" Style="display: none;" />
        <asp:ModalPopupExtender ID="mpePnlErrors" runat="server" TargetControlID="btnDummyButton" PopupControlID="pnlErrirs" BackgroundCssClass="modalBackground" CancelControlID="btnCancel" OkControlID="btnOK" />

Good luck

I think Console.WriteLine don t work on asp.net application and i think inside an update panel you can simple fire the throw New Exception( the friendly error message) and it will appear in an alert box.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Transaction handling with TransactionScope

I am implementing Transaction using TransactionScope with the help this MSDN article http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx I just want to confirm that is ...

System.Web.Mvc.Controller Initialize

i have the following base controller... public class BaseController : Controller { protected override void Initialize(System.Web.Routing.RequestContext requestContext) { if (...

Microsoft.Contracts namespace

For what it is necessary Microsoft.Contracts namespace in asp.net? I mean, in what cases I could write using Microsoft.Contracts;?

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!

热门标签