ASP.Net

Having the Result Set of a Stored Proc Sent to You by RSS Feed.

by JBrooks 14. December 2010 12:44

I wanted to monitor one of my system from my desk top and from my phone.  I found a simple solution whereby I can subscribe to the result set of a stored proc by using RSS. So I can have this feed MS Outlook, my phone or my web browser.

First, Visual Studio 2010 makes creating an RSS feed a simple matter that is about 1 page of code.

I simply add an ASPX page to my project and remove most of the markup so it only has 2 lines:

 
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="rss.aspx.cs"  Inherits="RSS.rss"  %>
 
<%@ OutputCache Duration="60" VaryByParam="none" %>

Next the code behind simply calls the stored proc placing the results into a table and then loading up some of the RSS related collections VS2010 gives you. 

 
using System;
using System.Data;
using System.ServiceModel.Syndication;
using System.Web;
using System.Collections.Generic;
using System.Xml;
 
namespace RSS
{
public partial class rss : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
        string id = Request.QueryString["id"];
 
        // I don't want just anyone to subscribe, so you have to know the GUID.
        if (id== null || id != "23F14EA1-1B20-443B-9B94-92C4EA4A8099")
            throw new Exception("Guid not reconized");
 
 
        Response.ContentType = "application/atom+xml";
 
        // this gets the data from the database and populates a table.
        DataTable dt = cDB.getFeed();
        SyndicationFeed myFeed = new SyndicationFeed();
 
        myFeed.Title = TextSyndicationContent.CreatePlaintextContent("SampleApp Activity");
        myFeed.Description = TextSyndicationContent
            .CreatePlaintextContent(@"A syndication of the most recently 
                    SampleApp activity including exceptions.");
        myFeed.Links.Add(SyndicationLink.CreateAlternateLink(
            new Uri(GetFullyQualifiedUrl("/rss.aspx"))));
        myFeed.Links.Add(SyndicationLink.CreateSelfLink(
            new Uri(GetFullyQualifiedUrl(Request.RawUrl))));
        myFeed.Copyright = TextSyndicationContent
                        .CreatePlaintextContent("Copyright SampleApp");
        myFeed.Language = "en-us";
 
 
        List<SyndicationItem> feedItems = new List<SyndicationItem>();
        foreach (DataRow dr in dt.Rows)
        {
 
            SyndicationItem item = new SyndicationItem();
            item.Title = TextSyndicationContent.CreatePlaintextContent(dr["title"].ToString());
            SyndicationPerson authInfo = new SyndicationPerson();
            authInfo.Email = "SampleApp@YourDomain.com";
 
            item.Authors.Add(authInfo);
            // RSS feeds can only have one author.
 
            // The stored proc returns different categories of data that I am interested in.
            switch (dr["category"].ToString())
            {
                case "WindFarms":
                case "WindFarms ":
                    item.Links.Add(SyndicationLink.CreateAlternateLink(
                        new Uri(GetFullyQualifiedUrl("/WindFarms.aspx"))));
                    authInfo.Name = "SampleApp WindFarm";
                    break;
 
                case "Exceptions":
                    item.Links.Add(SyndicationLink.CreateAlternateLink(
                        new Uri(GetFullyQualifiedUrl("/ErrorLog.aspx"))));
                    authInfo.Name = "SampleApp Exception";
                    break;
 
                default:
                    authInfo.Name = "SampleApp";
                    break;
 
            }
            item.Summary = TextSyndicationContent.CreatePlaintextContent(
                dr["summary"].ToString());
 
            item.Categories.Add(new SyndicationCategory(dr["category"].ToString()));
            item.PublishDate = DateTime.Parse(dr["pubdate"].ToString());
            item.LastUpdatedTime = item.PublishDate;
            item.Id = item.PublishDate.ToString();
 
            // Add the item to the feed
            feedItems.Add(item);
        }
 
 
        myFeed.Items = feedItems;
 
 
        XmlWriter feedWriter = XmlWriter.Create(Response.OutputStream);
 
        // Use Atom 1.0 
        Atom10FeedFormatter atomFormatter = new Atom10FeedFormatter(myFeed);
        atomFormatter.WriteTo(feedWriter);
 
        feedWriter.Close();
 
    }
 
    private string GetFullyQualifiedUrl(string s)
    {
        Uri u = new Uri(HttpContext.Current.Request.Url, s);
        return u.ToString();
 
    }
 
}
}

 

To have this feed my Outlook RSS folder I just need to right click “RSS Feeds” and select “Add a New RSS Feed…”. 

AddFeedMenu

Then enter the URL of my RSS feed.   Don’t forget to add the GUID at the end with     ?id=23F14EA1-1B20-443B-9B94-92C4EA4A8099

AddFeed

If you site uses authentication in your site you will have to turn it off for the rss.aspx page.  To do this you would add an entry in your web config file:

 
<location path="rss.aspx">
    <system.web>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
</location>

You should now have a folder in Outlook that will get populated by the feed.

Tags:

ASP.Net | Development

Logging Exceptions and the Commands that Caused Them.

by jbrooks 14. December 2010 12:12

For a long time I’ve been logging all of my exceptions to a table that looks like:

ExceptionTable

Now for exceptions that were generated by the database I want to also log the exact database call that caused the exception.  It will make debugging go a lot faster.  For this I have a new table:

ExceptionCmdTable

This will get the exceptionId from the first table and the a string that caused the exception.  Something like:

saveSomething @id=100, @UserName='Jakey',  @IPAddress='100.100.100.100',  @editBy='JBrooks'

So the first part of logging the Exception is two methods on my base class.

 
public void LogException(Exception ex)
{
    LogException(ex, null);
}
 
 
public void LogExceptionx(Exception ex, SqlCommand objBadCmd)
{
    int id = 0;
 
    if (this._WritingErrorLog == true)
    {
        // don't want to get in an infinite loop.
        return;
    }
    else
    {
        this._WritingErrorLog = true;
    }
 
 
    try
    {
 
        SqlCommand objCmd = this.GetNewCmd("dbo.insertException");
 
        string message = "";
 
        // Get the userId of the user that got the error.
        if (System.Web.HttpContext.Current.Request.Cookies["UID"] != null)
            message = System.Web.HttpContext.Current.Request.Cookies["UID"].Value + "|";
 
        // Add the command that gave the error.
        if (objBadCmd != null && !string.IsNullOrEmpty(objBadCmd.CommandText))
            message += objBadCmd.CommandText + "|";
 
 
        message += ex.ToString();
 
        if (message.Length > 8000)
            message = message.Substring(0, 7999);
 
 
        objCmd.Parameters.Add("@Message", SqlDbType.VarChar, 8000).Value = message;
 
        objCmd.Parameters.Add("@StackTrace", SqlDbType.VarChar, 8000).Value =
            ((ex.StackTrace == null) ? "no stack trace." : ex.StackTrace);
 
        //insert the exception and get the new ID.
        id = this.ExecuteScalarInt(objCmd);
 
        if (id > 0 && objBadCmd != null)
            insertExceptionCmd(id, objBadCmd);
 
    }
    catch (Exception ExLogException)
    {
        this.LogExceptionToFile(ex);
        this.LogExceptionToFile(ExLogException);
    }
 
    this._WritingErrorLog = false;
 
}

Now the part that generates the command string is another method that gets called be the method above:

 
private string getCmdString(SqlCommand objBadCmd)
{
 
    if (objBadCmd == null)
        return string.Empty;
 
    if (objBadCmd.Parameters == null || objBadCmd.Parameters.Count == 0)
        return objBadCmd.CommandText;
 
    StringBuilder sb = new StringBuilder();
 
    try
    {
        sb.Append(objBadCmd.CommandText+" ");
 
        for (int i = 0; i < objBadCmd.Parameters.Count; i++)
        {
            SqlParameter p = objBadCmd.Parameters[i];
 
            if (i > 0)
                sb.Append(", ");
 
            sb.Append(p.ParameterName + "=");
 
            if (p.Value == null)
                sb.Append("null");
            else
            {
                switch (objBadCmd.Parameters[i].SqlDbType)
                {
                    case SqlDbType.BigInt:
                    case SqlDbType.Int:
                    case SqlDbType.Float:
                    case SqlDbType.Decimal:
                    case SqlDbType.SmallInt:
                    case SqlDbType.Money:
                    case SqlDbType.Image:
                    case SqlDbType.Real:
                    case SqlDbType.SmallMoney:
                    case SqlDbType.TinyInt:
                    case SqlDbType.DateTimeOffset:
                        sb.Append(p.Value.ToString());
                        break;
 
                    default:
                        sb.Append("'" + p.Value.ToString() + "'");
                        break;
 
                }
            }
        }
    }
    catch (Exception ex)
    {
        return "getCmdString created its own error processing:  " + 
            sb.ToString() + "      +++++" + ex.ToString().Substring(0, 8000);
    }
 
    return sb.ToString();
}

So now I have a complete logging of exception in my applications and it is a simple matter to make a page where I can view them, or make an RSS feed where they are sent to me.

Tags:

Development | SQL | ASP.Net

Change Connection String Password Programmatically

by jbrooks 6. December 2010 13:07

On one of our projects we have a requirement that we have to change our passwords every 90 day.  So I created a page where I can just click a button and it will generate a password, change the password on the database for the user in the connection string and then change the password in the web.config.

The page just has a button that say “Change Password” and a label called lblMessage to show the results.

The code behind just calls the class that does all of the work and then shows a message:

 
 
const string CONNSTRINGNAME = "SampleAppConnString";
const string WEBCONFIGFILE = "~/Web.Config";
 
protected void btnChangePassword_Click(object sender, EventArgs e)
{
 
if (cConnStringPasswordChanger.ChangePassword(HttpContext.Current.Server.MapPath(WEBCONFIGFILE), 
        CONNSTRINGNAME))
    this.lblMessage.Text = "Password has been changed";
else
    this.lblMessage.Text = "Password has NOT been changed";
 
}

Now for the class that does all of the work:

 
public static class cConnStringPasswordChanger
{
 
    public static bool ChangePassword(string webConfig, string ConnStringName)
    {
        return ChangePassword(webConfig, ConnStringName, 
                Guid.NewGuid().ToString().Replace("-", "").Substring(0, 9));
    }
 
 
    // 1. Open the web.config.
    // 2. Change the connString to have the new password.
    // 3. Change the password on the database.
    // 4. Commit the web.config change.
    public static bool ChangePassword(string webConfig, string ConnStringName, 
        string newPassword)
    {
 
        bool changed = false;
        string oldConnString;
 
        FileInfo fi = new FileInfo(webConfig);
 
        if (fi.IsReadOnly)
        {
            File.SetAttributes(webConfig, FileAttributes.Normal);
        }
 
        fi = null;
 
        XmlDocument cfgDoc = new XmlDocument();
        cfgDoc.Load(webConfig);
 
        XmlNode connNode = cfgDoc.SelectSingleNode("//connectionStrings");
 
        XmlNode myNode = connNode.SelectSingleNode("//add[@name='" + ConnStringName + "']");
        oldConnString = myNode.Attributes["connectionString"].Value;
 
        string oldPassword = getValue(oldConnString, "Password");
 
        string newConnString = oldConnString.Replace(oldPassword, newPassword);
 
        myNode.Attributes["connectionString"].Value = newConnString;
 
        string userId = getValue(newConnString, "User Id");
 
        XmlTextWriter writer = new XmlTextWriter(webConfig, null);
        writer.Formatting = Formatting.Indented;
 
        // last possible second change it on the database.
        changePassword(oldConnString, userId, oldPassword, newPassword);
        try
        {
            cfgDoc.WriteTo(writer);
            writer.Flush();
            writer.Close();
            changed = true;
        }
        catch (Exception ex)
        {
            // error saving web.config change, so change it back on the database.
            changePassword(newConnString, userId, newPassword, oldPassword);
            throw;
        }
 
        writer = null;
        cfgDoc = null;
 
        return changed;
    }
 
    // This function is passed a connection string like:
    // "data source=.\SQLEXPRESS;Initial Catalog=MyDb;User Id=McUser;Password=c99c0472e;"
    // and a partName like "User Id" or "Password".
    // it returns the value for that partName.
    private static string getValue(string connString, string partName)
    {
        int partStart = connString.ToLower().IndexOf(partName.ToLower());
        int partEndSemi; 
        int partEndQuote;
            
 
        if (partStart > -1)
            partStart += partName.Length + 1;
        else
            throw new Exception(partName + " not found in connection string");
 
        partEndSemi = connString.Substring(partStart).IndexOf(";");
        partEndQuote = connString.Substring(partStart).IndexOf("\"");
            
 
        if (partEndQuote == -1)
            partEndQuote = connString.Length - partStart - 1;
 
        if (partEndSemi == -1)
            partEndSemi = connString.Length - partStart - 1;
                        
        return connString.Substring(partStart, Math.Min(partEndQuote, partEndSemi));
    }
 
    // Call the database to change the password.
    private static bool changePassword(string connString, string loginName, 
        string oldPassword, string newPassword)
    {
        bool changed = false;
 
        using (SqlConnection connection = new SqlConnection(connString))
        {
            SqlCommand command = new SqlCommand("dbo.sp_password", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add("@loginame", SqlDbType.NVarChar, 128).Value = loginName;
            command.Parameters.Add("@old", SqlDbType.NVarChar, 128).Value = oldPassword;
            command.Parameters.Add("@new", SqlDbType.NVarChar, 128).Value = newPassword;
            command.Connection.Open();
            command.ExecuteNonQuery();
            changed = true;
        }
 
 
        return changed;
 
    }
}
 

Tags:

ASP.Net | Development | SQL

Stripping Out Passwords

by jbrooks 19. November 2010 07:44

I have a page in my ASP.Net application where I show all of my AppSettings, connection strings, etc.  But I didn’t want to show the passwords.  I wanted something like:

server=MyServer;uid=MyUserId;pwd=*******;database=MyDatabase;

So here is the code to strip out the password:

 
 
        private string stripPassword(string connString)
        {
            if (string.IsNullOrEmpty(connString))
                return connString;
 
            int pos = connString.ToLower().IndexOf("pwd");
            if (pos > -1)
                pos += 4;
            else
            {
                pos = connString.ToLower().IndexOf("password");
                if (pos > -1)
                    pos += 9;
                else
                    return connString;
            }
 
            return connString.Substring(0, pos) + "*******" + 
                connString.Substring(pos + connString.Substring(pos).IndexOf(";"));
        }
 

Tags:

ASP.Net | Development

Grid within a GridView Cell

by JBrooks 8. November 2010 11:04

GridInGrid

I needed to display some parent data with it’s child data on the same row like shown in the image above. I happen to be combining a few tables together into a new table (called dtPlan) and then binding the GridView to that new table.  So this was my approach while moving the data into the dtPlan table.  dtRampRates is the child table to the data in dtResults.

 
DataView dvRampRates = new DataView(dtRampRates);
dvRampRates.Sort = "parentId, id";
StringBuilder sb = new StringBuilder();
 
for (int indexRow = 0; indexRow < dtResults.Rows.Count; indexRow++)
{
    DataRow drPlan = dtPlan.NewRow();
    drPlan["c0"] = planHour;
    drPlan["c1"] = dtResults.Rows[indexRow]["ResourceStatus"].ToString();
    drPlan["c2"] = dtResults.Rows[indexRow]["MinEconomicMW"].ToString();
    drPlan["c3"] = dtResults.Rows[indexRow]["MaxEconomicMW"].ToString();
 
    dvRampRates.RowFilter = "parentId=" + dtResults.Rows[indexRow]["id"].ToString();
    sb.Length = 0;
    sb.Append("<table cellspacing='0' class='RampRate'>");
 
    if (indexRow == 0)
        sb.Append("<tr><td>Limit</td><td>Up</td><td>Down</td></tr>");
 
 
    for (int i = 0; i < dvRampRates.Count; i++)
    {
        sb.Append("<tr><td>");
        sb.Append(dvRampRates[i]["breakpointLimit"].ToString());
        sb.Append("</td>");
 
        sb.Append("<td>");
        sb.Append(dvRampRates[i]["rampRateUp"].ToString());
        sb.Append("</td>");
 
 
        sb.Append("<td>");
        sb.Append(dvRampRates[i]["rampRateDown"].ToString());
        sb.Append("</td></tr>");
    }
    sb.Append("</table>");
 
    drPlan["c4"] = sb.ToString();
    dtPlan.Rows.Add(drPlan);
}
 
gvPlan.DataSource = dtPlan;
gvPlan.DataBind();

The child grid is made in the “for” loop.  Normally you would have this loop in the RowDataBound event for the GridView.  With that approach it is easy to see how most of the code would be the same.

Tags:

ASP.Net | GridView | Development

Using the Ajax Tabs Control as a Menu

by JBrooks 24. October 2010 10:53

I have a regular menu for my site and I wanted to use the Ajax Tabs Control as a submenu when the user was doing point-of-sale (ordering cards that describe the wine).  So when the user was on POS  on the main menu (black background) they would see the submenu as shown below.

Menu

To make this, the first thing I did was create a new web user control and add the Ajax Tabs Control.  This user control is called wcPOSMenu and will be place on each of the 3 ASP.Net pages involved. You can see there isn’t much to the markup below.

 
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="wcPOSMenu.ascx.cs" 
Inherits="ToutonWeb.wcPOSMenu" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<asp:TabContainer ID="TabContainerPOS" runat="server" AutoPostBack="true" BorderWidth="0px"
    Width="926px" Height="12px" CssClass="ajax__tab_xp" ActiveTabIndex="0" 
    OnActiveTabChanged="TabContainerPOS_ActiveTabChanged">
    <asp:TabPanel ID="tpSelect" runat="server" HeaderText="Select POS" BorderWidth="0px">
        <ContentTemplate>
            Enter Description or ItemNo to Search for and Hit Enter. Click a Column Heading
            to Sort by That Column.
        </ContentTemplate>
    </asp:TabPanel>
    <asp:TabPanel ID="tpEdit" runat="server" HeaderText="Edit SKUs" BorderWidth="0px">
        <ContentTemplate>
            Enter a SKU to Add or Edit.
        </ContentTemplate>
    </asp:TabPanel>
    <asp:TabPanel ID="tpSend" runat="server" HeaderText="Send POS" BorderWidth="0px">
        <ContentTemplate>
            Send POS.
        </ContentTemplate>
    </asp:TabPanel>
</asp:TabContainer>

One thing to note is that I couldn’t quickly figure out how to eliminate the tab’s containers border so I just made it a height of 12px and used that area as a subtitle to the rest of the content.

Below is the code behind, there isn’t much to this either.  First you have a user control’s property TabIndex that can be set on each of the parent pages.  So for my example the page for “Edit SKUs” will have this user control on it and it’s TabIndex property will be set to the value of 1. 

The page Page_Load event just uses that property to set the current tab.

The TabContainerPOS_ActiveTabChanged just redirects the user to the correct page whenever they change the tab.  To the user is appears they are selecting a menu option, but to the tab control they are actually changing the active tab.

 

 
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace ToutonWeb
{
    public partial class wcPOSMenu : System.Web.UI.UserControl
    {
        private int _tabIndex;
        public int TabIndex
        {
            get { return _tabIndex; }
            set { _tabIndex = value; }
        }
 
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
                this.TabContainerPOS.ActiveTabIndex = _tabIndex;
        
        }
 
 
        protected void TabContainerPOS_ActiveTabChanged(object sender, EventArgs e)
        {
            switch (TabContainerPOS.ActiveTabIndex)
            {
                case 0:
                    Response.Redirect("~/frmPOS.aspx");
                    break;
                case 1:
                    Response.Redirect("~/frmPOSEdit.aspx");
                    break;
 
                case 2:
                    Response.Redirect("~/frmPOSSend.aspx");
                    break;
 
            }
 
        }
    }
}

On each of the parent pages I just need to add 2 lines.  The first is to register the user control,  line 5 below. The second is line 9 below.  Note the TabIndex property of the user control being set in line 9.

   1: <%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true"
   2:     CodeBehind="frmPOSEdit.aspx.cs" Inherits="ToutonWeb.frmPOSEdit" %>
   3:  
   4: <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp"%>
   5: <%@ Register Src="wcPOSMenu.ascx" TagName="wcPOSMenu" TagPrefix="uc1" %>
   6: <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
   7: </asp:Content>
   8: <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
   9:     <uc1:wcPOSMenu ID="wcPOSMenu1" runat="server" TabIndex="1" />

That is it.

Tags:

ASP.Net | Development

Changing HTML Attributes on ASP.NET Pages in the Code Behind

by JBrooks 24. September 2010 11:40

Not many developers realize that you can change a plain HTML object’s attributes in the code behind without having to convert it into an ASP.Net control.

So if I have a checkbox like this:

<input type="checkbox" id="cbShowDef" name="cbShowDef"  onclick="javascript: show()" />

I can hide this in the code behind with:

((System.Web.UI.HtmlControls.HtmlInputCheckBox) Form.FindControl("cbShowDef")).Style.Add("display","none");

Tags:

ASP.Net | Development

Displaying a Long Description Column in a GridView

by JBrooks 6. July 2010 20:05

A lot of times you have something like a description column and you want to display it in a GridView.  But since for some of the rows the description column can be very long, it doesn’t always work very well. One solution is where you set the TD’s attribute NOWRAP, then the column runs off to the right for as long as is needed.  The solution I sometimes employ is the following: 

First, here is my sample table:

CREATE TABLE Categories
(CategoryName varchar(20),
Description varchar(1000))
 
And here is the SQL that is going to bind to my GridView:
 
SELECT c.CategoryName,
CASE WHEN LEN(c.Description) > 30
THEN SUBSTRING(c.Description,1,27)+'...'
ELSE c.Description END AS LineDescription,
c.Description AS FullDescription
FROM dbo.Categories c
ORDER BY c.CategoryName

Notice that the Description column is in there twice. Once where it maxes out at 30 characters (the LineDescription column), and the second one that contains the full text (the FullDescription column.) This brings back a table that looks like the following:

CategoryName LineDescription FullDescription
Beverages Soft drinks, coffees, teas,... Soft drinks, coffees, teas, beers, and ales
Condiments Sweet and savory sauces, re... Sweet and savory sauces, relishes, spreads, and seasonings
Confections Desserts, candies, and swee... Desserts, candies, and sweet breads
Dairy Products Cheeses Cheeses
Grains/Cereals Breads, crackers, pasta, an... Breads, crackers, pasta, and cereal
Meat/Poultry Prepared meats Prepared meats
Produce Dried fruit and bean curd Dried fruit and bean curd
Seafood Seaweed and fish Seaweed and fish

 

So to bind this to the GridView we bind the first two columns only.  The first GridView column is bound to the CategoryName data column and the second one is bound to the LineDescription data column with the heading title of “Description”.  On the second GridView column we also click the “Convert this field into a TemplateField” as shown below.

GridViewColumns

 

We save this and then edit the templates for the GridView columns.  For the Description column we edit the ItemTemplate and we bind the ToolTip to the FullDescription data column.

ToolTipBinding

 

Now we have the GridView column that is titled “Description” bound to the LineDescription data column and the tooltip is bound to the FullDescription data column.  We can run this and  see how it works:

GridViewWithToolTip

So now we have a short description in our grid, but the user can easily see the full description in the ToolTip.

Tags:

ASP.Net | GridView | Development

Unhide Exceptions Hidden By AJAX

by JBrooks 3. February 2010 09:35

If you work with AJAX for any length of time you will find that no matter what the exception thrown in the code behind the message displayed to the user is “Exception has been thrown by the target of an invocation.”  Not very useful.

image

My approach to debugging the exception had been to comment out the UpdatePanel, recreate the exception and see the real error.  But this doesn’t work at all when the code is deployed to the end-user.

So the solution is to capture the AsyncPostBackError event of the ScriptManager as shown here:

image

Then in the  code for this event (code behind) we can change the AsyncPostBackErrorMessage to the actual error message in the exception.

protected void ScriptManager1_AsyncPostBackError(object sender,AsyncPostBackErrorEventArgs e)
{
    if (e.Exception != null && e.Exception.InnerException != null)
    {
        ScriptManager1.AsyncPostBackErrorMessage = e.Exception.InnerException.Message;
        cApp.LogExceptionNoThrow(e.Exception.InnerException);
    }
}

Note that I also log the exception which includes the stack trace so I can later research the problem. 

One further enhancement would be to replace the alert box with a label on the page.  To do this I first wire up an event in JavaScript to capture the return from an Ajax call.  So here I am registering the JavaScript function “endRequest” to be called at the end of an AJAX request.

function pageLoad(sender, args) {
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
}

And in my endRequest function I set the label and turns off the alert box.

function endRequest(sender, args) {

    if (args.get_error() != undefined) {

        var lbl = $get('<%= this.lblMessage.ClientID %>');
        lbl.innerHTML = args.get_error().message;
        lbl.style.color = 'Red'

        // This will stop the alert box from displaying.
        args.set_errorHandled(true);

        // go to the top so they can see the error message.
        window.scroll(0, 0);

    }
}

Note that the lblMessage label control needs to be inside the UpdatePanel so that it is cleared on the next PostBack. 

So now when I get an exception it displays the real error to the user in a label with red text, something like below. 

image 

And the details are logged in my exceptions table.

image

Much better than the default.

Tags:

ASP.Net

Select One Row From a GridView

by JBrooks 5. August 2009 16:53

 

I have a page where the user can select which users are active (using CheckBoxes), and also select one (only one) to be the administrator.  I put together this sample to show how I did it.  The sample uses technologies instead of user.  The picture below gives you an idea.  I didn't want to use the GridView "selected row" functionality because I didn't want to do a PostBack and I have another project where the user has to select 1 row per day where a day can take up 3 to 10 rows and there were many days in the grid.

 
PickOne

 

 

using System;

using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
public partial class SelectOne : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ViewState["selectedBest"] = "ASP.Net";
 
            bind();
        }
    }
 
    protected void bind()
    {
        DataTable dt = new DataTable();
 
        dt.Columns.Add("Include", typeof(Boolean));
        dt.Columns.Add("Name", typeof(String));
        dt.Rows.Add(new Object[] { false, "C#" });
        dt.Rows.Add(new Object[] { false, "ASP.Net" });
        dt.Rows.Add(new Object[] { false, "SQL Server" });
        dt.Rows.Add(new Object[] { false, "VB.Net" });
 
        GridView1.DataSource = dt;
        GridView1.DataBind();
 
    }
 
 
    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType != DataControlRowType.DataRow)
            return;
 
        // See if this matches our saved selection.
        if (e.Row.Cells[1].Text.Equals(ViewState["selectedBest"].ToString()))
            e.Row.Cells[2].Text = e.Row.Cells[2].Text.Replace("value", "checked value");
 
        // Set the value to the RowIndex so it is unique.
        e.Row.Cells[2].Text = e.Row.Cells[2].Text.Replace("{0}", e.Row.RowIndex.ToString());
 
    }
 
    protected void btnSave_Click(object sender, EventArgs e)
    {
        int total = 0;
 
        //Count of the number that our checked.
        foreach (GridViewRow gvr in this.GridView1.Rows)
        {
            if (gvr.RowType != DataControlRowType.DataRow)
                continue;
 
            if (((CheckBox)gvr.Cells[0].FindControl("cbSelected")).Checked)
                total++;
 
        }
 
        //Save the selected Best.
        ViewState["selectedBest"] = 
            this.GridView1.Rows[Convert.ToInt32(Request.Form["RBBest"])].Cells[1].Text;
 
        //Normally you would be saving to the database here.
        this.lblMessage.Text = "You selected " + total.ToString() 
            + " with " + ViewState["selectedBest"].ToString() + " as the best.";
 
        bind();
 
    }
 
}
 
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SelectOne.aspx.cs" 
Inherits="SelectOne"%>
 
<!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>Test check all CheckBoxes</title>
 
    <script type="text/javascript" src="jquery-1[1].3.2.min.js"></script>
 
    <script type="text/javascript" language="javascript">
 
        function changeAllCheckBoxes(sender) {
            var gridViewRows = GetParentElementByTagName(sender, "TABLE").rows;
            for (var i = 1; i < gridViewRows.length; ++i) {
                gridViewRows[i].cells[0].childNodes[0].checked = sender.checked;
                //gridViewRows[i].cells[0].childNodes[1].style.display = 'none';
            }
            return false;
        }
 
 
        function GetParentElementByTagName(element, tagName) {
            var element = element;
            while (element.tagName != tagName)
                element = element.parentNode;
            return element;
        }
    </script>
 
</head>
<body>
    <form id="form1" runat="server">
    <div id="divp" style="text-align: left">
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
        Caption="Pick Some Technologies"
            BackColor="White" BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px"
            CellPadding="4" onrowdatabound="GridView1_RowDataBound">
            <Columns>
                <asp:TemplateField HeaderText="Include" SortExpression="Include">
                    <HeaderTemplate>
                        <asp:CheckBox ID="CheckBox1" runat="server" 
                        onclick="changeAllCheckBoxes(this)" />
                    </HeaderTemplate>
                    <ItemTemplate>
                        <asp:CheckBox ID="cbSelected" runat="server" />
                    </ItemTemplate>
                    <ItemStyle HorizontalAlign="Center" />
                </asp:TemplateField>
                <asp:BoundField DataField="Name" HeaderText="Technology" />
                <asp:TemplateField HeaderText="Best">
                    <ItemTemplate>
                        <input id="RBBest" type="radio" name="RBBest" value="{0}" />
                    </ItemTemplate>
                    <ItemStyle HorizontalAlign="Center" />
                </asp:TemplateField>
            </Columns>
            <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="#FFFFCC" />
        </asp:GridView>
    </div>
    <br />
    <div>
        <asp:Button ID="btnSave" runat="server" Text="Save" OnClick="btnSave_Click" />
    </div>
    <br />
    <asp:Label ID="lblMessage" runat="server" Text="Make selections and then click Save">
    </asp:Label>
 
    </form>
</body>
</html>

Tags:

ASP.Net | GridView | Development

One Script

OneScript Continuous Integration for you database Scripts in version control are automatically combined into a release script.

RecentPosts