navigation
 Monday, February 25, 2008
With new technology making the web a viable option for more and more applications, we are now seeing the web browser take over for the traditional desktop. Developers making this transition, quickly learn about some of the key differences between the two paradigms. One of the issues they are often forced to deal with is Session expiration. Out of the box, ASP.NET and IIS typically allow only 20 minutes of idle time before the session expires. This can be configured, but knowing that the session expired, or redirecting to a particular page often comes in handy. One way to do this is to add a cookie during the Session_Start method of the global.ascx.cs file, and then check for that same cookie the next time a session is created. If the cookie is there, the session either timed out, or was reset.
posted on February 25, 2008  #    by Mike Dugan  Comments [0]
 Friday, September 28, 2007

I got up at 5 in the morning and jumped on a plane to meet the rest of the Falafels at headquarters. It was a long day. The airline had lost my luggage and I had been up for 8 hours before even getting to the office. We worked all day and headed out for dinner after that. I was exhausted. That all changed when I realized how I was going to get back to my hotel. I was going to take the company car:

posted on September 28, 2007  #    by Mike Dugan  Comments [1]
 Thursday, April 12, 2007

Ever need to show something in a databound gridview that isn't in your datasource? Don't worry, relax, forget about that datasource. Just create that extra row dynamically.

Lets assume I have a GridView with 2 columns. The first column shows the items on an order,  the second column shows the price of that item and the footer shows the order total.  How would I inject a row that shows the tax?

Something like this in the RowDataBound EventHandler would do the trick:

decimal orderTotal = 0.0m;
decimal tax = 0.0m;
protected void gvOrderDetail_RowDataBound(object sender, GridViewRowEventArgs e)
{
    //TODO: Calculate the orderTotal and the tax when RowType = DataRow
    if (e.Row.RowType == DataControlRowType.Footer)
    {
        //Create the Row
        GridViewRow row = new GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal);
        //Add the two Columns
        row.Cells.AddRange(CreateCells());
        //get a reference to the table that holds this row
        Table tbl = (e.Row.Parent as Table);
        //Add the row at the end of the list, but before the footer.
        tbl.Rows.AddAt(gvOrderDetail.Rows.Count + 1, row);

        //Don't forget to account for any changes in the footer. Since we added a row to show the tax,
        //that tax must also be accounted for in our footer. Calculating the orderTotal and the tax
        //is an exercise for the reader.
        Label lbl;
        lbl = (Label)e.Row.FindControl("lblTotal");
        lbl.Text = String.Format("{0:C}", (orderTotal + tax));
    }
}

private TableCell[] CreateCells()
{

    TableCell[] cells = new TableCell[2];
    TableCell cell;
    Label lbl;

    //The order item column
    cell = new TableCell();
    lbl = new Label();
    lbl.Text = "Sales Tax";
    cell.Controls.Add(lbl);
    cells[0] = cell;

    //The price column
    cell = new TableCell();
    lbl = new Label();
    lbl.Font.Bold = true;
    lbl.Text = tax.ToString("C");
    cell.HorizontalAlign = HorizontalAlign.Right;
    cell.Controls.Add(lbl);
    cells[1] = cell;

    return cells;
}

posted on April 12, 2007  #    by Mike Dugan  Comments [0]
 Thursday, September 28, 2006

Many companies are moving away from constantly building applications from scratch, and instead focusing their development on  building a reusable and testable framework to encapsulate their business rules.  Their frameworks are then used to quickly produce custom apps, webservices, components, etc. It is sort of like building a house. First they build a solid foundation, and then build on top of that foundation whatever structure they may need. If you are part of a team about to head down this path, I would strongly recommend a few of my favorite resources, to make sure you get the foundation right the first time.

Early in 2005, Brad Abrams had a 15 part webcast on "Designing .NET Class Libraries". Its now archived on MSDN, but I dug up the link so you don't have to: https://msdn.microsoft.com/netframework/programming/classlibraries/

Soon after the series was complete, he and Krzysztof Cwalina released a book called "Framework Design Guidelines". The book sums up what you might see in the webcast, and if you decide to take a stab at building your own framework, I would consider it required to have on hand.

posted on September 28, 2006  #    by Mike Dugan  Comments [0]
 Saturday, September 16, 2006

If you have a BoundField in a GridView that displays a datetime, but you only want to display the date, how would you go about doing that?

Set the DataFormatString to "{0:d}" ?

That is what I thought too. Turns out, this doesn't always work.
That is because by default the value is extracted from the data store, HtmlEncoded, and then the format string is applied. After HtmlEncoding,  the format string won't do anything. The fix in most cases, is usually pretty simple. Just turn off HtmlEncoding for that field by setting HtmlEncode="false".
If you can't turn off HtmlEncoding, it looks like there is some custom formating in your future.

posted on September 16, 2006  #    by Mike Dugan  Comments [0]
 Wednesday, August 16, 2006

If you add an item using the indexer, like this:

Cache["TestItem"] = value;

The item is added to the cache with no expiration policy and a normal priority. As a result, the item will stick around indefinitely.
We can help the cache decide which items to toss out of memory by specifying an expiration policy and/or a priority:

Cache.Insert("TestItem", value, null, Cache.NoAbsoluteExpiration,
  TimeSpan.FromMinutes(20), CacheItemPriority.Normal, null)

Above, I gave the item a 20 minute sliding expiration. This means each time the item is accessed, its 20 minute lease on life is renewed.
I could have told it to expire after exactly 20 mins, no matter how many times it is accessed by setting an absolute expiration instead:

Cache.Insert("TestItem", value, null, DateTime.Now.AddMinutes(20),
  Cache.NoSlidingExpiration, CacheItemPriority.Normal, null)

And to really take control of the scavenging mechanism, you can change the priority of items added to the cache. Lower priority, means it is removed first when system resources are running low. The values range from "Low" to "NotRemovable". See the CacheItemPriority type's documentation for all of the values.

You will also notice that the Cache has an "Add" method. If you choose to use the Add method, adding a key that already exists in the cache will result in an exception, while doing the same with the Insert method will overwrite it. Setting a value using the indexer is equivalent to this call:

Cache.Insert("TestItem", value, null, Cache.NoAbsoluteExpiration,
  Cache.NoSlidingExpiration, CacheItemPriority.Normal, null)

posted on August 16, 2006  #    by Mike Dugan  Comments [0]
 Wednesday, May 31, 2006

There is a cool new feature in ASP.NET 2.0 that allows you to embed resources into your server side assemblies and have your web controls request these resources automatically. This is especially handy when you want to deploy a new control. No longer do you have to find just the right spot to place the JavaScript and image files that your control depends on. 

Microsoft already uses this technique with its validators. The JavaScript needed for client side validation is embedded in one of the .NET assemblies on the server. If you were to view the source of any web page that uses a validator in ASP.NET 2.0, you might see something like this:

<script src="/MyWebSite/WebResource.axd?d=68d8KT0ikvX6J4c8Z8zwvfZXzPdyyYYY8TuccizWlCePFWz&t=632847500868593750" type="text/javascript"></script>

This is a request to a new HttpHandler, WebResources.axd, for the necessary JavaScript. The first parameter, ‘d’ is an encrypted identifier telling the handler which resource it needs. The ‘t’ parameter is an encrypted timestamp, used to determine if the resource has changed.

Looks pretty simple right?

Well, lets see how easy it is for you to use this technique. Lets try to create a control that has its JavaScript embedded as a resource. For this example, I am going to use a useful script that buffers key presses and matches an entire word in a dropdownlist instead of just the first character. (Thanks to Jonathan Cogley at ASP Alliance for the original script: http://authors.aspalliance.com/thycotic/articles/view.aspx?id=3)

First, lets open up or create a new web site in Visual Studio 2005 and then add a new Web Control Library project to it. After adding the project, remember to add a reference to it from our web site.  This new assembly will contain all of the elements of our control and our web site has to know about it to use it.

Next, lets add a new class that inherits from DropDownList:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;


 

namespace WebControlLibrary1
{
    public class KeyedDropDownList : DropDownList
{
        private bool _caseSensitive = false;

        public KeyedDropDownList(){}

    
     public bool CaseSensitive
     {
     get
     {
     return _caseSensitive;
     }
     set
     {
     _caseSensitive = value;
     }
     }
    }
}

I have also added a property “CaseSensitive” which will be passed to the script to allow us to turn on and off case sensitivity when matching strings in our list.

Now add a new a JScript file and examine the properties. To embed this file as a resource the Build Action must be set to 'Embedded Resource'.  After setting the build action,  feel free to copy this code into the file or substitute JavaScript of your own:

function KeyedDropDownList_onkeypress(dropdownlist,caseSensitive) 
{
// check the keypressBuffer attribute is defined on the dropdownlist
var undefined;
if (dropdownlist.keypressBuffer == undefined)
   {
dropdownlist.keypressBuffer = '';
}
   // get the key that was pressed
var key = String.fromCharCode(window.event.keyCode);
dropdownlist.keypressBuffer += key;
  if (!caseSensitive)
   {
// convert buffer to lowercase
dropdownlist.keypressBuffer = dropdownlist.keypressBuffer.toLowerCase();
}
  // find if it is the start of any of the options
var optionsLength = dropdownlist.options.length;
for (var n=0; n < optionsLength; n++)
{
var optionText = dropdownlist.options[n].text;
if (!caseSensitive)
     {
optionText = optionText.toLowerCase();
  }
if (optionText.indexOf(dropdownlist.keypressBuffer,0) == 0)
     {
dropdownlist.selectedIndex = n;
return false; // cancel the default behavior since
// we have selected our own value
     }
}
// reset initial key to be inline with default behavior
dropdownlist.keypressBuffer = key;
return true; // give default behavior
}

Next,  you must add an attribute to the assemblyinfo.cs file to reference the embedded resource:

[assembly: System.Web.UI.WebResource("WebControlLibrary1.JScript1.js", 
"text/javascript")]

You will notice that the reference to the JScript file is fully qualified. You must do this using the project's default namespace, not just any old namespace in the assembly. You can see this  by right clicking on the project and viewing the properties. I should also mention that we intentionally left out an optional boolean parameter named 'PerformSubstitution'. By default 'PerformSubstitution' is off, and you should turn it on if the referenced resource accesses other embedded resources. An embedded style sheet that defines some style using an embedded image is a good example of when to set PerformSubstitution to true.

Now, instead of registering the script block with the necessary JavaScript ourselves, we will register a request to get the script block from our  assembly.  Thanks to the new ClientScriptManager in ASP.NET 2.0, this is  very easy.  We will first override the OnInit method of our KeyedDropDownList class and then  get a reference to this manager to do most of our work.

protected override void OnInit(EventArgs e)    
{
base.OnInit(e);
ClientScriptManager cs = Page.ClientScript;
Type rsType = this.GetType();
cs.RegisterClientScriptInclude("MyScript",
cs.GetWebResourceUrl(rsType,"WebControlLibrary1.JScript1.js"));
}

The last piece of coding is very simple.  Just attach  the onkeypress event of our control to our custom JavaScript function.  Although in this example we have not used the ViewState to track our lone property,  we might want to do that or add more properties that can be passed to the JavaScript function.  So here I overrode the OnLoad method to add the attribute to our webcontrol. By the time the OnLoad event is fired, the ViewState will have been  loaded.

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Attributes.Add("onkeypress",
"return KeyedDropDownList_onkeypress(this," +
_caseSensitive.ToString().ToLower() + ")");
}

If all goes well, we should be able to now use this control on any form in our web app and the necessary JavaScript will automatically accompany it wherever it goes. I should also point out that when debugging, the JavaScript is not cached, it is downloaded each time. When debugging is off, the JavaScript is cached on the client automatically. 

I have  included the markup for the test page that registers and uses this new control below.

<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%@ Register Assembly="WebControlLibrary1"
Namespace="WebControlLibrary1" TagPrefix="wcl" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Test Page</title>
</head>
<body>
<form id="form1" runat="server">
<wcl:KeyedDropDownList id="ddlTest" runat="server">
<asp:ListItem Value="1">Calendar</asp:ListItem>
<asp:ListItem Value="2">Can</asp:ListItem>
<asp:ListItem Value="3">Candle</asp:ListItem>
<asp:ListItem Value="4">Canary</asp:ListItem>
<asp:ListItem Value="5">Card</asp:ListItem>
<asp:ListItem Value="6">Cat</asp:ListItem>
<asp:ListItem Value="7">Cow</asp:ListItem>
</wcl:KeyedDropDownList>
</form>
</body>
</html>
posted on May 31, 2006  #    by Mike Dugan  Comments [0]
 Friday, March 31, 2006

When paging just won't cut it, scrollbars come in handy. Fortunately, it is quite easy to add scrolling support to just about anything. All you need to do is wrap any of your controls in an HTML DIV tag.

The key to the code below is to set the DIV style to "OVERFLOW: auto;" and specify a size. When overflow is set to auto, scrollbars will automatically appear if  the control size exceeds the DIV's dimensions. The code below binds a datagird to the Order table in the Northwind database. This would normally produces a pretty large datagrid, but thanks to our DIV, we will only see a subsection of the data.

<DIV style="OVERFLOW: auto; WIDTH: 550px; HEIGHT: 200px">
<asp:datagrid id=DataGrid1 runat="server" DataSource="<%# dataView1 %>"
AutoGenerateColumns="False" ShowHeader="False">
<Columns>
<asp:BoundColumn DataField="OrderID"></asp:BoundColumn>
<asp:BoundColumn DataField="ShippedDate"></asp:BoundColumn>
<asp:BoundColumn DataField="ShipName"></asp:BoundColumn>
<asp:BoundColumn DataField="ShipCity"></asp:BoundColumn>
</Columns>
</asp:datagrid>
</DIV>
posted on March 31, 2006  #    by Mike Dugan  Comments [0]
 Saturday, February 18, 2006

Krugle is a search engine for source code that is supposed to make life easier for us developers. You can sign up for the Beta on their website and try it out sometime next month.  http://www.krugle.com/

posted on February 18, 2006  #    by Mike Dugan  Comments [0]
 Friday, January 27, 2006

The MSDN Library says this about the DataGrid.Items property:

"Only items bound to the data source are contained in the Items collection. The header, footer, and separator are not included in the collection."

So how do we get to these other items? Most people handle the ItemCommandEvent for the grid, but there is a way to access them directly.

If these items are not in the DataGrid.Items collection, then where are they? To find out, turn on tracing for your ASP.NET webpage. You will see that the grid is rendered something like this:

DataGrid
   DataGridTable
      DataGridItem
         TableCell
         TableCell
      DataGridItem
         TableCell
         LiteralControl
         Label
      DataGridItem
      ...

What we are seeing is that the first object in the DataGrid's Control hierarchy is a DataGridTable. That DataGridTable contains ALL of the DataGridItems, including the header and footer. To get these DataGridItems we just need to grab the first or last control out of the DataGridTable's control collection.

So to get a DataGrid's footer, this code will do this trick:

//First get the DataGridTable (the first control in DataGrid's control collection.)
//Then grab the last control in the DataTable's Collection
DataGridItem footer = 
    DataGrid1.Controls[0].Controls[DataGrid1.Controls[0].Controls.Count -1] as DataGridItem;
posted on January 27, 2006  #    by Mike Dugan  Comments [0]
 Friday, January 06, 2006

Add vertical guidelines to Visual Studio by adding a simple registry key to this location:

[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\Text Editor]

Now, add a string value named "Guides".

Set its value to something like RGB(128,0,0) 80, 100

The setting above will draw a Red guideline in Visual Studio at column 80 and 100. You can  have up to 13 guidelines. Adjust the values as you see fit.

Giving credit where credit is due, I believe Sara Ford first blogged about this about a year ago.

posted on January 6, 2006  #    by Mike Dugan  Comments [0]