Posts Tagged ‘asp.net’

Health Monitoring in ASP.NET

August 22nd, 2009

Unless your code is perfect, you’re bound to get runtime errors. Exceptions may not get caught, connections may not get closed off, and eventually, at some point, you’ll divide by 0. While you can’t prevent them, you can be aware of them using ASP.NET’s built in health monitoring provider. Health monitoring is configured in the web.config and can be set to use various types of logging, from writing to a SQL server instance or generating an email, for specific types of errors.

There are several pre-defined events, providers, and rules inside the root web.config file in the same directory as machine.config (not to be confused with the web.config in your application). In the healthMonitoring section you will see several groupings for providers, rules, profiles, and event mappings. For right now, we’ll focus on providers, rules, and eventMappings. I’ll discuss how these play into logging events.

Providers (<providers>) essentially tell where the log information is going. For example, the provider named EventLogProvider maps to the EventLogWebEventProvider class. As you’d expect, this provides all those error events you see in your Event Viewer. Similarly, the SqlWebEventProvider allows you to log events to the built in ASP.NET database (ASPNETDB.mdf in your app_data folder or your own SQL Server instance configured using aspnet_regsql.exe). Web can define a custom provider in your application web.config file (or in the root if you want to apply it to all your sites) to, for example, generate and send an email to a recipient containing logged event information. The SimpleMailWebEventProvider does just this. We will define this provider and use this provider in our example below.

Rules (<rules>) dictate which event type will use a provider. For example, you can have application errors write to the SQL provider or generate an email using your the email provider mentioned above. The eventName attribute, when adding a rule, specifies the name of the web event to use. Basically, for each rule, you specify the eventName and the provider. Simple as that.

Event Mappings (<eventMappings>) are used for mapping event names to provider classes. In the root web.config, you will notice several pre-defined provider names associated with event classes (the type attribute). If you are creating your own web event class (we’ll cover this in a later post), you may create a name for it and give it a type (your new class). By default, you can leave these alone, as the web events shipped with the framework cover most cases.

There are several event mappings listed, but there are usually one or two which, I feel, would be used in most conditions. First, the All Errors event mapping (using WebBaseErrorEvent) is used for all compilation, runtime, and configuration errors. I have found this to be the most handy. The second is the Failure Audits event (using the WebFailureAuditEvent class), which raises a an application page is accessed using improper credentials. By default, ASP.NET uses the NETWORK SERVICE account to access the file system, the registry, any databases, etc. If incorrect permissions are set in the file system, or malicious code is attempting to access the file system, this event will be raised. One other potentially useful web event is the Infrastructure Error mapping. This web event is raised only for compilation and configuration errors. However, I personally find it less useful, as the All Errors web event covers this.

In this post, I will create a basic health monitoring event handler using the SimpleMailWebEventProvider class to generate an email whenever any runtime error is found on the site. The email, by default, will provide all the information I need to diagnose the error and make corrections. You may customize this email template, but that is another topic.

First, since we’re using an email provider, we need to configure SMTP settings in the web.config. The SimpleMailWebEventProvider class will use these settings for sending the email. Configure your SMTP settings as follows:

<configuration>
    ...
    <system.net>
        <mailSettings>
            <smtp deliveryMethod="Network">
                <network host="SERVER" userName="USERNAME" password="PASSWORD" />
             </smtp>
        </mailSettings>
    </system.net>
    ...
</configuration>

Once that is entered, we can begin enabling the health monitoring features and chose our provider and rules. Again, the purpose is to create an email for all site errors and send them to my email address.

<system.web>
    ...
    <healthMonitoring enabled="true">
        <providers>
            <add name="EmailSiteErrors" type="System.Web.Management.SimpleMailWebEventProvider" to="ryan@marriedgeek.com" from="noreply@marriedgeek.com" buffer="false"/>
        </providers>
        <rules>
            <add name="Email Errors" eventName="All Errors" provider="EmailSiteErrors"/>
        </rules>
    </healthMonitoring>
    ...
</system.web>

That’s pretty much it. The ease of configuration and separation of providers and rules makes it a breeze to configure monitoring for your website. If you chose to use a SQL event provider, your logs will be written in the  provider database configured in your maching.config’s connection string. You may even have both or as many provider/rule sets as you like.

This is an overview of how to get started with using health monitoring in ASP.NET. To read more about health monitoring, check out the following links:

Create Custom Event Handlers & Arguments For Controls

July 28th, 2009

I was hoping to get this post up earlier, but got distracted by a couple of things. First, I jacked up my hand trying to separate my dogs from fighting to the point I couldn’t even move my ring finger (long story about the dogs, but I love ‘em). Second, I started a new job at Groove Commerce on Monday. So far, so good. I feel it’ll keep me on my game and give me some nice challenges ahead.

A few entries ago we talked about custom server controls and mentioned how to structure a composite control to allow the ViewState to “pick up” on it’s post back content so that data isn’t re-binded with every call. It was a very basic composite control, but it showed how to add native WebControl objects to the Controls tree to create a basic layout without using a .ASCX design file. This type of control can be added to your app_code directory or manually compiled as an assembly and placed into your bin directory. The advantage of the latter is to feasibly add it to your Visual Studio toolbar by loading the assembly. This time, we’ll add a custom event to our control using a delegate for an event, as well as a custom event argument class to pass along with it.

We’ll take the code from last time, but add several things which are highlighted in green.

  • A line to declare our event delegate variable and the delegate itself.
  • A class which will be used for our arguments.
  • A binded event for the button Click.
  • A line in the button Click handler to invoke the event delegate.
using System;
using System.Web;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace RyanControls
{
    public class MyCompositeControl : CompositeControl
    {
        public MyCompositeControl() { }

        // Declare the Updating event of delegate type CustomControlUpdateHandler
        public event CustomControlUpdateHandler Updating;

        protected override void CreateChildControls()
        {
            TextBox txtMyData = new TextBox();
            DropDownList drpMyList = new DropDownList();
            Button btnUpdate = new Button() { Text = "Update!" };

            Controls.Add(drpMyList);
            Controls.Add(txtMyData);
            Controls.Add(btnUpdate);

            if (!Page.IsPostBack)
            {
                drpMyList.Items.Add(new ListItem("item 1"));
                drpMyList.Items.Add(new ListItem("item 2"));
                drpMyList.Items.Add(new ListItem("item 3"));
            }

            // Add a handler for the button click to launch the Updating event
            btnUpdate.Click += new EventHandler(FireEvent);
        }

        // The method that handles the Click event from the button
        // and triggers the Updating event by calling the delegate
        protected void FireEvent(Object s, EventArgs e)
        {
            Updating(s, new CustomControlUpdateEventArgs() { SomeData = "The control was updated!" });
        }
    }

    // Our custom event class that inherits EventArgs. You may use
    // EventArgs as the class if you don't have additional data to pass
    public class CustomControlUpdateEventArgs : EventArgs
    {
        public CustomControlUpdateEventArgs() { }
        public String SomeData;
    }

    // The delegate declaration (or template, as I call it) for the handler
    public delegate void CustomControlUpdateHandler(Object s, CustomControlUpdateEventArgs e);
}

There you have it. If you place this code into a .CS file inside your app_code directory, you’ll be able to include the control on your pages. If you compiled it into an assembly, toss it into your bin directory and feel free to add it to your toolbar in VS or VWD.

<asp:MyCompositeControl runat="server" ID="cntMyControl" OnUpdating="DisplayUpdate" />

By assigning an event handler for the Updating event (the page automatically prepends the “On” for “OnUpdating”) to call a method to handle the update, you can use data contained in the CustomControlUpdateEventArgs object. In this case, there’s only a public string called SomeData.

protected void DisplayUpdate(Object s, RyanControls.CustomControlUpdateEventArgs e)
{
    Response.Write(String.Format("<div>From the event handler: {0}</div>", e.SomeData));
}

When you run the code and click the button, the method will be invoked and the message displayed. Similarly, you can bind the handler programmatically by adding cntMyControl.Updating += new RyanControls.CustomControlUpdateHandler(DisplayUpdate) in your code-behind.

custom_event

So again, while the code isn’t really useful, it shows how to create your own event handlers and custom argument class(es) for a composite server control. The point is to be able to create one or more event handlers, as well as combine those with one or more types of event argument classes. The fields of that particular argument class should be specific to that type of event and it is best not to use one custom event args class to satisfy many types of event argsuments, unless the data being passed into your hander functions generic enough to do so.

Happy coding!

Composite controls and maintaining ViewState in ASP.NET.

July 17th, 2009

One day you’ll find that you’ve outgrown the native web controls in .NET, or find yourself using a set of controls in a lot of your projects, and feel the urge to implement something….custom. We’ve discussed extending a single, preexisting control to add extra functionality (such as a DropDownList pre-binded with gender data for a form), but what if you want to combine multiple controls, something similar to a user control, and want it to be easily deployable – such as dropping an assembly into your bin directory?

The answer is creating a composite control. A composite control is exactly what it sounds like – it’s a set of controls, added using the Controls.Add(…) method as child controls to the object. You lose out on design-time aspects you would otherwise get by using a user control (using a .ASCX file and inheriting from UserControl), but you gain the ability to compile one or more controls into a single assembly for easy redistribution. You may even add these to your Visual Studio toolbar.

As mentioned earlier, the Controls.Add(…) method is used to add child controls to the control “tree” inside your control. This method is available at any point in the state of your control but you should try to construct your control tree inside the CreateChildControls() method for one major reason – ViewState. If you build your controls inside of Render(), your controls will still load, but during a PostBack, you will lose your ViewState.

This behavior is related to the Page lifecycle and the order in which events fire. During a PostBack, the CreateChildControls() method is fired BEFORE the page’s PreLoad event, which is the event that loads up the ViewState from your last PostBack. The reason this is important is because, when you invoke Controls.Add(…) inside of that method, a special method called TrackViewState() is invoked on your composite control. Once this is called, any binded data will be added to the ViewState. Once it is added to the ViewState, the Page’s PreLoad method can load up the ViewState on a PostBack. This order is very important in maintaining the state of your composite control during PostBack.

Lets play with some code. The following code builds a very, very simple (pretty much useless) composite control. The point is to really show the basic structure and to demonstrate how it relates to maintaining the ViewState for TextBox and DropDownList controls. This control is inheriting from the CompositeControl class, which implements the INamingContainer interface. This marker interface gives the control’s child elements a unique ID (in reference to the parent control’s ID). You could also inherit from WebControl and implement the INamingContainer (System.Web.UI) interface yourself.

using System;
using System.Web;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace RyanControls
{
    public class MyCompositeControl : CompositeControl
    {
        public MyCompositeControl() { }

        protected override void CreateChildControls()
        {
            TextBox txtMyData = new TextBox();
            DropDownList drpMyList = new DropDownList();
            Button btnUpdate = new Button() { Text = "Update!" };

            Controls.Add(drpMyList);
            Controls.Add(txtMyData);
            Controls.Add(btnUpdate);

            if (!Page.IsPostBack)
            {
                drpMyList.Items.Add(new ListItem("item 1"));
                drpMyList.Items.Add(new ListItem("item 2"));
                drpMyList.Items.Add(new ListItem("item 3"));
            }
        }
    }
}

Notice that I’m adding ListItem elements AFTER I added the DropDownList to the Controls list. This is an important step. If I had not done this, while I would be able to add items for this first instance of the control, they would be added BEFORE the TrackViewState method was invoked by performing Controls.Add(…). Because of this, they would not added to the ViewState and not be available during PostBack. If I had removed the IF-statement for checking IsPostBack and added items before the Controls.Add(…) method, it would still essentially work during a PostBack – the items would still appear and the selected index would still be correct (the ViewState is maintained for the controls themselves, but not their child controls in this case). However, this is adding the items for each and every time it’s called. If you were grabbing this data from, say, a database, you’re not going to want to perform this overhead each time. This is why we checked for a PostBack (which is what you should be doing anyway when binding unchanging data) so that we will only have to bind once and not each time. With that said, adding the items, or performing data binding, after the controls has been added will add it to the ViewState.

So, that’s pretty much it. If you were to run this code by loading it onto your page, you’ll see the three controls laid out side-by-side. If you change the DropDownList selection, type some text into the TextBox, and click “Update!”, you’ll notice that the ViewState is maintained, and no subsequent trips to the database or use of other binding methods are required.

Next time I’ll add onto this control by making use of delegates for adding custom event handlers (even with a custom event argument class)!

Extending A Native Web Control

July 9th, 2009

Some may not know the difference but user controls are different from server controls. User controls inherit from the UserControl class while server controls can inherit from, say, the Button, DropDownList, GridView, or, well, any Control or WebControl object. Using a server control is faster than using a user control since there is no designer UI to be compiled.

The main drawback from creating a server control versus a user control is the lack of building a rich UI in most respects. Because there isn’t a .ascx page to load existing controls onto, you don’t have this ability as easily as you do with a server control (unless you programmatically add controls to a placeholder object in a composite control).

The main difference is that your control must inherit from an existing Control or WebControl object, or one that inherits from these, such as a Button.

Here’s a quick example of a DropDownList that is pre-populated with data essential to determining sex – “Male” and “Female”. You can save this as a .CS file into your app_code directory. In this example, we are essentially extending the existing DropDownList control to add additional functionality.

using System;
using System.Web;
using System.Web.UI.WebControls;
using System.Data;

namespace CustomControls
{
    public class GenderList : DropDownList
    {
        public GenderList()
        {
            System.Collections.Generic.Dictionary<String, String> dctGender = new System.Collections.Generic.Dictionary<String, String>();

            dctGender.Add("MALE", "Male");
            dctGender.Add("FEMALE", "Female");
            dctGender.Add("NA", "No response");

            base.DataSource = dctGender;
            base.DataTextField = "value";
            base.DataValueField = "key";
            base.DataBind();
        }

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);
        }
    }
}

Now, to use it on your page, you’ll need to either Register the control using the <%@ Register %> declaration or add a reference in the <pages><controls> … </controls></pages> section of your web.config.

<%@ Register TagPrefix="asp" Namespace="CustomControls" %>

…or in your web.config…

<pages>
    <controls>
        ....
        <add tagPrefix="asp" namespace="CustomControls"/>
    </controls>
</pages>

Notice we did not include the assembly. This is because it was not compiled into a .dll. If it is compiled into a .dll, you must include the Assembly name.

genderlist

After that, if you don’t feel like waiting for your intellisense to update, you can simply insert the control onto your page. The only difference is, you do not need to include the src attribute, since the control will be compiled (just the TagPrefix, and Namespace).

The class above is very simple. It inherits from DropDownList, so it has all the functionality of the native DropDownList class, but binds some data in the constructor. Pretty simple, but will save a lot of time when working with forms. If this seem a bit boring, another idea could be to have a StateList control that is populated with states from an XML file. Or, perhaps you find yourself always setting default attributes in your GridViews, such as GridLines=”none” or AutoGenerateColumns=”false”. Make your own and have these defaults set for you.

Add some jQuery animation to UpdatePanel postbacks

July 4th, 2009

Here’s a little eye-candy trick if you’re one of those using UpdatePanel  in ASP.NET (and not caring about performance, ahem) that will allow for a quick animation (e.g., fade, slide) on any data getting refreshed from the server. The method uses jQuery to handle the animation and a few lines of JavaScript to inject the animation into the “click” event of a button (or any other element!).

A neat use of this would be for, say, a GridView of data. You may have a series of filters for that data and instead of having that data (asynchronously) refresh with little notice from the user, you add a slideIn()/slideOut() animation so that the user can visually see exactly what is being refreshed.

The process involves 1) grabbing whatever the current onclick handler is for each element, 2) initializing the new “click” handlers for the buttons incorporating the new fadeOut or slideUp effect, and 3) binding your final effect for when the AJAX response is received.

The following code will invoke a function, InitBrowseButtons(), when the DOM is ready when the page is initially loaded (if your buttons invoking the “asynchronicity” are inside the update panel, you’ll need to do run ScriptManager.RegisterStartupScript(…) to re-bind the handlers). For this code, I bound a checkbox control that updates the data in the UpdatePanel when checked or unchecked. This can easily be substituted for a button or other element by changing the jQuery selector.

$(document).ready(function()
{
    InitBrowseButtons();
});

// round up the elements using jQuery selectors, grab the current onclick and insert your own
function InitBrowseButtons()
{
    $("input[type='checkbox'][name$='chkBrowseAll']").each(function()
    {
        var currAction = $(this).attr("onclick");

        $(this).attr("onclick", "").click(function()
        {
            $("div[id$='upMessages']").slideUp(500, function() { currAction(); });
        });
    });
}

This function will cycle through all the elements grabbed by the selector (only one in this case) and, for each, save the current onclick handler to a variable. It will then reassign a click event to that element, in thise case, a jQuery animation to slideUp an UpdatePanel named upMessages. On the callback event for the animation, it will then invoke the previous click handler (the parenthesis will invoke the variable as a function).

This function will handle the slideUp and the subsequent postback event, but what about when the data is posted back? The following function is invoked by static method ScriptManager.RegisterStartupScript(…) from the code-behind file. This will invoke a script each time a postback is complete.

The C# script (I called it from Page_Load, but adjust as necessary)…

ScriptManager.RegisterStartupScript(Page, Page.GetType(), "InitFadeData", "InitFadeData();", true);

… will invoke the following JavaScript…

// function called when post back is completed
function InitFadeData()
{
    $("div[id$='upMessages']").slideDown(500);
}

This script grabs the same UpdatePanel (which is just a DIV) and slides the content open once it is repopulated with server-side data.

A demo can be found here. Source code here. All scripts were inline for the purposes of viewing.

And just to note about the performance of UpdatePanels; yes, they’re great for quick-and-dirty partial updates, but should mainly be used for low traffic sites or for administratitive sites (CMSes and other private web sites). Otherwise, use the built-in page methods or use jQuery’s AJAX methods and render your own UIs.