.Net Extension Methods – Extending ViewState With Generics

15. May 2010

I may be a little late to the party on mentioning how much extension methods have made my life easier. Extension methods tend to fill that gap between wanting to add an extra little tweak to an existing class without actually having to implement a customized inherited version. Previously whenever you wanted to use one extra tweak or feature you’d be responsible for making sure to replace all instances of the inherited class with your new version. That gets into supporting the new class when all you wanted to do was change or add one thing to an existing class!

In my case I just really wanted to stop having to check whether a ViewState value was null before trying to unbox the value into whatever value type or class I thought I stored in that key’s value field. In my case I really wanted to add generic typing support to the ViewState property of the page with as little work as possible. That is exactly where Extension methods come to the rescue.

For example normally one would see the following code to access a ViewState property:

   1:  private int GetGroupId()
   2:  {
   3:      int groupId = -1;
   4:   
   5:      if(ViewState["CurrentGroupId"] != null)
   6:      {
   7:          groupId = (int)ViewState["CurrentGroupId"];
   8:      }
   9:   
  10:      return groupId;
  11:  }

Ideally I would like to do the following:

   1:  private int GetGroupId()
   2:  {
   3:      return ViewState.Get<int>("CurrentGroupId", delegate { return -1; });
   4:  }

To do this I’d use a .Net extension method to extend the ViewState property through it’s StateBag class. Below you’ll find the ViewStateHelper class with all the required code to extend the StateBag class, thereby extending the ViewState property, and adding support for generic Get/Set functions. In order to use it just add the namespace where the static class is contained to the “usings” on the code-behind file of the page needing the ViewState extension support.

   1:      public static class ViewStateHelper
   2:      {
   3:          /// <summary>
   4:          /// Returns an object from view state
   5:          /// </summary>
   6:          /// <typeparam name="T">Type of object</typeparam>
   7:          /// <param name="key">View state key of object</param>
   8:          /// <param name="delegateDefault">If view state is empty, a delegate to return a value to put in view state.</param>
   9:          /// <returns></returns>
  10:          public static T Get<T>(this StateBag viewState, string key, DefaultMethod<T> delegateDefault)
  11:          {
  12:              T viewStateValue;
  13:              
  14:              if (viewState != null &&
  15:                  viewState[key] != null &&
  16:                  viewState[key].GetType() == typeof(T))
  17:              {
  18:                  viewStateValue = (T)viewState[key];
  19:              }
  20:              else
  21:              {
  22:                  viewStateValue = delegateDefault();
  23:                  viewState.Set<T>(key, viewStateValue);
  24:              }
  25:   
  26:              return viewStateValue;
  27:          }
  28:   
  29:          /// <summary>
  30:          /// Put an object in view state
  31:          /// </summary>
  32:          /// <typeparam name="T">Type of object to put in view state</typeparam>
  33:          /// <param name="key">Key of object to put in view state</param>
  34:          /// <param name="value">Object to put in view state</param>
  35:          public static void Set<T>(this StateBag viewState, string key, T value)
  36:          {
  37:              if (value != null)
  38:                  viewState[key] = value;
  39:              else
  40:                  viewState.Remove(key);
  41:          }        
  42:      }

.Net, ASP.Net, Programming

Telerik – RadControls or more appropriately BadControls…

24. March 2009
1331911801_6f960ea238_o

 

I’ve been a user of the Telerik RadControls for ASP.Net, RadControls for Winforms, and Reporting tools for the last few months. I’ve been using them since Q2 2008 to the latest release of Q3 2008.

In the last few months I can say this in no simpler terms that if you use any of the RadControls expect to be extremely irritated with the flat uselessness of these controls in any practical application scenario. Add a few multitudes of annoyance when you begin building composite control applications using RadControls as they do not interact well in abundance. I especially found the absolute worst case to be with the Telerik Reporting that is just not suitable for any reporting scenario inside of a corporate environment, let alone any business environment. Perhaps the reporting tools would be good for play toys by some stay at home moms to make flyers for the umpteen number of fundraisers that may happen in a child's life.

I don’t say this lightly. I’ve garnered my fair share of ‘Telerik’ points, the points awarded for discovering (don’t let me make that sound like a challenge) problems or quirks that otherwise do not function as expected when using Telerik controls. The worse of all is the ease at which I've found these problems countered with the sheer number of man hours spent determining whether it was my own doing (because of course I wouldn’t expect such a highly regarded toolset as being so shoddy), but of course speaking with the Telerik’s support confirms my suspision that the tools just that bad. Don’t get me wrong Telerik’s support is fantastic for providing points quickly and effectively, and for the occasional gotty work-around to the problem that shouldn’t be there.

Telerik Reporting – Why you shouldn’t use it.

I’ll start with a simple example. If a developer were to use the Telerik Reporting don’t expect the reports to support out-of-process session state. This may not be a problem for some company/personal sites because of the lack for scalable websites, but becomes a deal breaker for any self respecting web architecture.

Why do they not support out-of-process?

Because of some serialization/deserialization problems that cause the Telerik reports to throw a nice reflection error on page rendering. The error itself isn’t a page level error but an error caught only by the Global.asax’s Application_Error event. The great thing about the exception is when a custom error page is used on the site that same custom error page will display within the report viewer where one would expect their report to be generated. The error itself is something very generic, if you handle the Server.GetLastError() in the Global.asax file, the description is something like “A list corresponding to the selected DataMember was not found.” Thanks captain obvious error I really can pin that down quickly.

I will give them this they made reports class objects instead of something like the typed XML format of RDLC, which leads way to more dynamic instantiation of custom report classes, but at the same time they’re not much in the current form.

Another funny thing about the RadReports is the fact that each report can be bound to a DataSet, but the report itself will only handle ONE DataTable from within the DataSet. At least RDLC you can just add a new panel/table and bind to X number of DataTables from within the bound DataSet datasource. Telerik on the other hand requires that you create a sub-report that you then bind to another DataSet, and again only one DataTable from that DataSet is allowed to be used to bind controls to. This becomes incredibly annoying when trying to create a simple order report with a ‘header data’ table, and an itemized ‘detail data’ table inside one report. Instead you have to create a master report for the header table, a sub-report for the itemized data, and mix in the lack of support for out-of-process its massive headache.

There is a work-around, not great, but i’ll touch on it here. After having bound the DataSet to the report, bound the textboxes/report controls, remove the DataMember property of the report settings, and then dynamically handle the on-demand datasource event of the report. The problem you get into in that situation is you then have to do the same for all the sub-reports by going through the same process, and then handling the data binding for the sub-report within the demand datasource of the master report. The end result is twice the data retrieval calls necessary to create a report that could be handled by support multiple DataTable bindings from a single bound DataSet to a report.

For any scenario used for generating business reports, reports with drill-through, or multi-table application just do yourself a favor and skip right over Telerik Reporting. Don’t believe me? Well check out the Telerik Reporting ‘forums/documentation’ on-line and find one sample or one thread talking about mulit-datasource reports. Find one that implements something other than a SqlDataSource page level datasource. Go ahead… i’ll wait. Back already?

Anyway, supposedly Telerik says the out-of-process problem will be resolved in Q1 2009 release, but we’ll see. It didn’t do us a lot of good at the time since it took about six days bouncing back and forth with support (gap over the weekend), creating test projects for them, and to finally discover they just don’t support out-of-process session data. When all was said and done we ditched Telerik Reporting for RDLC. RDLC may not be pretty, but at least it’s dependable.

Next Post – ASP.Net BadControls! Stay tuned…

I think I'll conclude part 1 of my Telerik experience post. I’ll follow up with my infamous experience using RadControls for ASP.Net! I can’t wait to share more about the RadMenu that touts templated items, multi-column menu, but none of that is supported with load-on-demand from web services. I’ll talk about the attributes that don’t carry over on RadMenu, the RadTreeView viewstate client disconnected bombs, RadSplitters looking like what President Obama would say ‘Special Olypmic's’ in non-IE browsers, and much much more.

PS. Needless to say if you want to save yourself time try Infragistics, been a few years since i last used them, but at least they weren’t as bad as Telerik has been. It could be just me, but i doubt it. Hopefully Q1 2009 brings much needed improvement.

ASP.Net, Third Party Controls, Programming

cXML and ASP.NET

12. March 2009

What is cXML? Commerce XML referred to as cXML is actually a protocol created by Ariba to carry out interactions between procurement companies to supply something of an updated EDI process to better support e-commerce systems of suppliers. That of course was the idea in 1999 when it was created and (un)fortunately it has been used up until the present to conduct business to business interactions through a PunchOut request/response process.

I have been (un)fortunate enough to be tapped to lead the integration of a cXML based PunchOut system for a client I've been working with in order to integrate into something called ACES. ACES is a e-commerce solution by a company called American Solutions for Business. While during the initial conversations were centered about a messaging mechanism to request and respond with messages I was not initially familiar with the cXML standard. I was at least with its older competitor EDI. So this began my quest to better understand, design, and develop an support system on the client system for implementing the protocol.

I began initially with scouring the forums, Google, Live.com, and other assorted search engines for exactly what others were doing to integrate cXML into ASP.Net systems. That is when I discovered that aside from www.cXML.org there is actually very little material on the subject at all let alone regarding using it with ASP.NET in any fashion. Besides bizTalk and a few forums about validating a received cXML document against the cXML DTD available from cXML.org the protocol is a ghost.

To top the fact that the protocol is essentially never mentioned except in a few out of publishing books available on Amazon.com on B2B based messaging architectures even the Ariba website lacks any samples available for ASP.NET developers. I was excited on further searching to find a link to the classic ASP example project available on the site but my enthusiasm was shortly lived. All links to the contents were to a page that informs the user that the content has been expired from the site permanently.

So now what. Well thankfully after digging through umpteen number of websites I managed to scarf up a few PDF files of cXML solutions guides, and the cXML version 1.2 that the procurement company current users. After reading through the documents one can see quickly how reliant cXML is to the protocol standard enforcing company Ariba. The protocol relies heavily on a Ariba supplier ID and (Dun & Bradstreet) DUN numbers available from www.dnb.com.

Within the solution guide I also managed to round up the only ASP related material showing snippets of messaging decoding performed with classic ASP. It was at least enough to get me started building out my cXML support framework which essentially consists of multiple synchronous XML GET/POST to continue the interaction. By doing so an outside site can direct users from the outside customers site to display your supplier site inline the users browser experience to configure the product/service as the user would like. The request of course is posted to your domain, handled by the request object to receive the XML input stream, cXML request is parsed, and then a response posted back to the calling page from a URL identified via the response cXML document. Based on identifying whether a shared key is correct the cXML request can be processed, and the user redirected to begin product configuration seamlessly believing they’re interacting with the external site never realizing they’re working on a external supplier site.

I guess on the plus side I could qualify myself as a cXML knowledgeable company capable of being sourced to integrate the standard in other company e-commerce solutions. I don’t think I'll throw my hat in that ring just yet it’s been a big pain to integrate this standard into a modern ASP.NET based e-commerce system considering that the only documentation of the protocol was updated on classic ASP I assume that this standard was meant to be let alone for modern systems. Of course compared to EDI it’s night and day more robust.

When my project is complete I'll take the time to post a good how-to on implementing the request response mechanism in a modern web language. Heaven knows I'd have appreciated finding one myself when i started to learn this system!

ASP.Net, Programming, .Net

ASP.Net 3.5 ListView Control – Using DataPager

2. March 2009

I was working on a new project recently and unlike many of the older projects i’ve been working on this new project was built on the .Net 3.5 framework. Meaning now, should i choose, i could use LINQ, or any other number of ‘new’ features available to me. I decided to start with a few basic updates to the project the first of which was to add a ‘paging’ ability to a data listing that previously had a screen limitation of 22 items max per group otherwise the items would not display in the visible screen area.

So the first thing that I decided to do was check out the ASP.Net 3.5 ListView control. For the longest time to create any number of data lists I've used a conjunction of data-bound readers with template fields or DataGrid lists. Going in using the ListView i was sold on two points, the first is the ability to create both a layout template, and the ability to great a group item template. For added icing there was also the ability to assign a DataPager to the ListView right out of the box, what fun!

What I ideally wanted to create was a data listing that had a previous, next, first, and last buttons on both the top and bottom of the data list. Along with this i wanted to be able to display the current row position, and have the movement controls show/hide based on the current index without having to implement my own data paging logic. Trust me i’ve had to create my own paging logic way more times than i can count, and have plenty of ‘code snippets’ to paste into place to provide it. The major draw to ListView was the data pager, and template support.

After looking around for a way to create the pager style i was looking for i came back highly dissatisfied. All i found was the same out-of-box Microsoft snippets displayed on the umpteen number of blog sites with wordy diatribes that only sufficed to say the same verbiage found on the Microsoft site with a few ‘neat’ and ‘look at what i did’ comments. So needless to say i had to pretty much just default to the plug and play method to make out what i wanted.

So after a number of hours reading, prodding, and poking here is what I came up with:

<asp:ListView ID="lvCartUsers" ItemPlaceholderID="itemPlaceholder" runat="server"
            OnPreRender="lvCartUsers_PreRender">
            <LayoutTemplate>
                <div class="cartUserNavControls">
                    <asp:DataPager runat="server" ID="dpProductTopPager" PagedControlID="lvCartUsers"
                        PageSize="5">
                        <Fields>
                            <asp:TemplatePagerField OnPagerCommand="cartUsers_OnPagerCommand">
                                <PagerTemplate>
                                    <div class="navMoveFirst">
                                        <asp:ImageButton CommandName="First" ID="ibFirst" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && (((Container.StartRowIndex / Container.PageSize) + 1) > 1) %>'
                                            ImageUrl='<%# GetFirstImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMovePrevious">
                                        <asp:ImageButton CommandName="Previous" ID="ibPrevious" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && (((Container.StartRowIndex / Container.PageSize) + 1) > 1) %>'
                                            ImageUrl='<%# GetPreviousImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMoveLast">
                                        <asp:ImageButton CommandName="Last" ID="ibLast" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && ((Container.StartRowIndex + Container.PageSize) < Container.TotalRowCount) %>'
                                            ImageUrl='<%# GetLastImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMoveNext">
                                        <asp:ImageButton CommandName="Next" ID="ibNext" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && ((Container.StartRowIndex + Container.PageSize) < Container.TotalRowCount) %>'
                                            ImageUrl='<%# GetNextImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navPagerCount">
                                        Displaying Records
                                        <asp:Label runat="server" ID="CurrentPageLabel" Text="<%# Container.StartRowIndex %>" />
                                        -
                                        <asp:Label runat="server" ID="TotalPagesLabel" Text="<%# Container.StartRowIndex+Container.PageSize %>" />
                                        ( of
                                        <asp:Label runat="server" ID="TotalItemsLabel" Text="<%# Container.TotalRowCount%>" />
                                        records.)
                                    </div>
                                </PagerTemplate>
                            </asp:TemplatePagerField>
                        </Fields>
                    </asp:DataPager>
                </div>
                <div id="cartGrid">
                    <div id="cartListHeader">
                        <div id="headerFistName">
                            <asp:Literal ID="lblFirstHeader" runat="server" Text="First" />
                        </div>
                        <div id="headerLastName">
                            <asp:Literal ID="lblLastHeader" runat="server" Text="Last" />
                        </div>
                        <div id="headerCartNumber">
                            <asp:Literal ID="lblCartNumberHeader" runat="server" Text="Cart #" />
                        </div>
                        <div id="headerCartStatus">
                            <asp:Literal ID="lblCartStatusHeader" runat="server" Text="Status" />
                        </div>
                    </div>
                    <div runat="server" id="itemPlaceHolder">
                    </div>
                </div>
                <br style="clear: both;" />
                <div class="cartUserNavControls">
                    <asp:DataPager runat="server" ID="dpProductBottomPager" PagedControlID="lvCartUsers"
                        PageSize="5">
                        <Fields>
                            <asp:TemplatePagerField OnPagerCommand="cartUsers_OnPagerCommand">
                                <PagerTemplate>
                                    <div class="navMoveFirst">
                                        <asp:ImageButton CommandName="First" ID="ibFirst" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && (((Container.StartRowIndex / Container.PageSize) + 1) > 1) %>'
                                            ImageUrl='<%# GetFirstImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMovePrevious">
                                        <asp:ImageButton CommandName="Previous" ID="ibPrevious" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && (((Container.StartRowIndex / Container.PageSize) + 1) > 1) %>'
                                            ImageUrl='<%# GetPreviousImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMoveLast">
                                        <asp:ImageButton CommandName="Last" ID="ibLast" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && ((Container.StartRowIndex + Container.PageSize) < Container.TotalRowCount) %>'
                                            ImageUrl='<%# GetLastImagePath() %>' runat="server" />
                                    </div>
                                    <div class="navMoveNext">
                                        <asp:ImageButton CommandName="Next" ID="ibNext" Visible='<%# (Math.Ceiling(System.Convert.ToDouble(Container.TotalRowCount) / Container.PageSize) > 1) && ((Container.StartRowIndex + Container.PageSize) < Container.TotalRowCount) %>'
                                            ImageUrl='<%# GetNextImagePath() %>' runat="server" />
                                    </div>
                                </PagerTemplate>
                            </asp:TemplatePagerField>
                        </Fields>
                    </asp:DataPager>
                </div>
            </LayoutTemplate>
            <EmptyDataTemplate>
                <asp:Label ID="lblNoItems" runat="server" />
            </EmptyDataTemplate>
            <ItemTemplate>
                <div class="cartListRow">
                    <div class="rowFistName">
                        <asp:Literal ID="lblFirstName" runat="server" Text='<%# Eval("FirstName") %>' />
                    </div>
                    <div class="rowLastName">
                        <asp:Literal ID="lblLastName" runat="server" Text='<%# Eval("LastName") %>' />
                    </div>
                    <div class="rowCartNumber">
                        <a class="cartListRowCartNumber" href='<%# Request.Path + "?CartId=" + Eval("CartId") %>'>
                            <%# Eval("CartId") %></a>
                    </div>
                    <div class="rowCartStatus">
                        <asp:Literal ID="lblStatus" runat="server" Text='<%# Eval("Status") %>' />
                    </div>
                </div>
            </ItemTemplate>
        </asp:ListView>

Code-behind:

public partial class CartUserList : System.Web.UI.UserControl
    {
        #region Properties
 
        private int _pageSize = 5;
 
        public int PageSize
        {
            get { return _pageSize; }
            set { _pageSize = value; }
        }
 
        private DataSet CartDataSet
        {
            get
            {
                DataSet dsCarts = null;
 
                if (ViewState["DataSet"] != null)
                {
                    dsCarts = (DataSet)ViewState["DataSet"];
                }
 
                return dsCarts;
            }
            set { ViewState["DataSet"] = value; }
        }
 
        #endregion // </Properties>
 
        #region Events
 
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (!IsPostBack)
                {
                    <Call RebindCartList here>
                }
            }
            catch (Exception ex)
            {
            }
        }
 
        protected void cartUsers_OnPagerCommand(object sender, DataPagerCommandEventArgs e)
        {
            try
            {
                int position = e.Item.Pager.StartRowIndex + e.Item.Pager.PageSize;
 
                switch (e.CommandName)
                {
                    case "First":
                        e.NewStartRowIndex = 0;
                        e.NewMaximumRows = e.Item.Pager.MaximumRows;
                        break;
                    case "Last":
                        e.NewStartRowIndex = (e.TotalRowCount - e.Item.Pager.PageSize);
                        e.NewMaximumRows = e.Item.Pager.MaximumRows;
                        break;
                    case "Next":
                        if (position <= e.TotalRowCount)
                        {
                            e.NewStartRowIndex = position;
                            e.NewMaximumRows = e.Item.Pager.MaximumRows;
                        }
                        break;
                    case "Previous":
                        e.NewStartRowIndex = e.Item.Pager.StartRowIndex - e.Item.Pager.PageSize;
                        e.NewMaximumRows = e.Item.Pager.MaximumRows;
                        break;
                }
            }
            catch (Exception ex)
            {
            }
        }
 
        protected void lvCartUsers_PreRender(object sender, EventArgs e)
        {
            if (IsPostBack)
            {
                    <Call RebindCartList here>
            }
        }
 
        #endregion //</Events>
 
        #region Functions
 
        private void RebindCartList(int customerID, int userID)
        {
            try
            {
                DataTable tblCarts = null;
 
                if (CartDataSet == null)
                {
                    CartDataSet = <BLL get DataSet>
 
                    if (CartDataSet.Tables.Count > 0)
                    {
                        tblCarts = CartDataSet.Tables[0];
                    }
                }
 
                lvCartUsers.DataSource = tblCarts;
                lvCartUsers.DataBind();
            }
            catch (Exception ex)
            {
            }
        }
 
        #endregion //</Functions>

The first thing you’ll see is the LayoutTemplate. This is the core to the ListView control as the entire structure of the ‘list’ is formatted within this template area. If one was building a HTML table the beginning tag for <table> and end tag </table> would be contained within this template. Unlike many other controls there is no header template and footer template instead what represents the header and footer of the template is defined within the LayoutTemplate. However, the actual data being repeated, ie the body of the data, is defined in the ItemTemplate.

Since I wanted the DataPager to appear above and below the list of data I have to create the two new DataPager controls above and below my ItemTemplate area so that they again appear above and below the data being paged. In order to get the look that I was going for I also had to implement my own TemplatePagerFields with the PagerTemplate set to display my custom ASP.Net ImageButtons with the selected first, next, previous, and last images to display instead of text. This is another benefit to using the TemplatePagerFields is that instead of having to use the built in text or button movement controls I can create my own by simply providing my own ASP.Net ImageButton controls with a custom CommandName. By using a custom command name I can just handle the event for OnPagerCommand to set the pagers index position based on the control clicked by the user. The code-behind snippet will show the OnPagerCommand being used to page the data. The thing to note here, as I saw in many blogs about paging problems, is that after a paging action is performed the data has to be rebound. It seems like out of the box the control should hold a temporary cache/session data when paging, but it doesn’t. That’s why on my example i handle the OnPreRender of the ListView control to re-bind the data when IsPostBack.

Getting back to the ItemTemplate that is sandwiched between the two DataPager controls. Within the ItemTemplate the bound data can be formatted as this will be the template repeated for each row of data found within the DataSource used to bind with the ListView. Here is where using Eval() the fields can be formatted for display applying any HTML elements or ASP.Net controls within the ItemTemplate area.

So from our perspective the layout looks much like this:

<LayoutTemplate>
<DataPager />
<ItemTemplate>
</ItemTemplate>
<DataPager/>
</LayoutTemplate>

The best part is that by setting the PagedControlID of the DataPager controls to the ListView control I can simply add a few functions to check whether to display the paging controls based on the current PagerSize of the DataPager and I no longer need to handle calculating when to display the controls on the code-behind. You can see the functions for this on the Visible property of the DataPager’s PagerTemplate controls.

All in all not bad. The control is easy enough to use, but when searching for how to use the ListView i did come across many blogs where users couldn’t figure out why after a paging action occurred the ListView was empty. Easy enough, when it posts back the user still is responsible for rebinding the control with the data source. If a SqlDataSource control is used then a user can take advantage of the caching ability of the SqlDataSource otherwise on the post back the ListView must be re-bound with data. Keep that in mind and this is one sweet control.

There is one thing I've used but didn’t touch on and that's the GroupTemplate. The GroupTemplate sits within the LayoutTemplate where ItemTemplate would be displayed in my hierarchy above, but now the GroupTemplate itself contains a definition of the ItemTemplate within it. So what you’d get is the ability to span items, using <div> tags with float set, across columns, essentially creating a table arrangement across columns instead of just rows. Below is a rough hierarchy of how the GroupTemplate becomes involved. There is actually a great article here detailing how to use the ListView with a great snippet on setting up a GroupTemplate here http://msdn.microsoft.com/en-us/library/bb398790.aspx.

<LayoutTemplate>
<DataPager />
<GroupTemplate>
<ItemTemplate>
</ItemTemplate>
</GroupTemplate>
<DataPager/>
</LayoutTemplate>

For now I’ve just started using the control and I'm sure I'll find all kinds of nifty little tricks to perform this that and the other. Either way it goes I've found my new favorite control for quickly creating both grouped and lists of bound data in a way i can quickly put together using CSS to create quick lists of data that is both paging and dynamically syllable.

ASP.Net, Programming, .Net

Subfolder Web.config Overriding Parent (Root) Web.config

21. January 2009

I was setting up a BlogEngine.Net for a local plumbing business and came across an annoying quirk. Adding the blog engine should have been pretty straight forward, drop in the blog engine folder into a website root folder, convert the folder to an application in IIS, change the virtual directory path setting in the web.config in the blog engine folder, and then the plumbing company could start blogging away.

Of course nothing is ever that easy. An error kept showing up that the theme specified within the <Pages> section ‘Theme’ property was not found from the root folders web.config settings. This error showed that the blog engine was trying to load the root folders web.config before loading the blog engine folder, which is expected even though the blog engine folder was set as a .Net 2.0 application through IIS. At that point one would wonder, how do i override or avoid loading the parent web.config settings?

Simple, surround the <system.web> setting of the blog engine folder’s web.config with a <Location> tag. Using the ‘Path’ property simply enter the name of the folder the blog engine is currently residing, and then the blog engine will automatically use only the <system.web> of the web.config found within the blog engine folder. There is also something to be said about ensuring the application pool is set to the classic setting, but that is a whole other conversation.

ASP.Net, Programming

Passing and Accessing DataBinder Container DataItems

6. January 2009

When fielding a few questions on the ASP.Net Forums I ran across a question that I’d recently read about going through the ASP.Net 2.0 Wrox book. The question was how do I access the row values from a databound grid without having access to the original data source. The person then went on to ask whether they’d be able to pass the DataBinder class object to the code behind to have access to the static Eval() method for the entire row of data.

Normally in the markup you see most of the databound code examples will have a function that accepts an input value that is called from the markup, passed to the code-behind, and then the code behind will output a formatted value back to the markup. It works well for situations where you need to calculate values quickly without the original data source, or to quickly format values for display purposes on databinding the control to a datasource.

 

Passing a Single Eval DataItem

ASPX

<%# GetTotalValue(Eval("ColumnName")) %>

CS

protected int GetTotalValue(object total)
{
int value = 0;
int.TryParse(Convert.ToString(total), out value);
return value;
}
 

In cases where multiple row values need to be accessible without having to pass each value directly one could simply access the databound row from the code-behind during the binding of the data control. In this case we still have the markup call to the code-behind as seen in the ASPX section below. This time we’re not passing any value(s), but instead we’ll just call them as we need them on the code-behind. Yes, it’s that simple. As you can see below we simply call to the DataBinder.Eval static function, pass in the data container (exposed by the Page,) and then simply supply the name of the column from the datasource we want. This is not limited to a single column, but only to a single row of data at a time.

 

Accessing Multiple DataItems 

ASPX

<%# GetTotalValue() %>

CS

protected int GetTotalValue()
{
int value = 0;
int.TryParse(Convert.ToString(DataBinder.Eval(Page.GetDataItem(), "ColumnName")), out value);
return value;
}
 

The reason this is limited to a single row is that we’re only able to access these values during data binding event, which is indcated per the ‘<%#’ on the markup side indicating that this function will only be called when the form is binding. Each row will call the same function outputting the unique formatting of the columns or calculations being performed on the code-behind calls. There is no need to try to pass the DataBinder, pass the datacontainer, or anything of the sort because it’s already available to us. Now keep in mind that you can’t call the GetTotalValue() anytime you’d like as this function will only work during the the databound event of the control.

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

ASP.Net, Programming

Microsoft JScript runtime error: 'document.body' is null or not an object

20. November 2008

I was working on a project recently working on the master page of a .Net 2.0 Web Application and I encountered the most ambiguous error message. I was removing style sheet controls that were going to be added to a dynamic Page style mechanism when I first ran into the error. I had been going through the tags removing the trailing ASP control tags with the /> tag to end the control markup.

I did this on a JavaScript tag changing from this:

<script type="text/javascript" language="javascript" src="../scripts/vkboards.js”></script>

To this:

<script type="text/javascript" language="javascript" src="../scripts/vkboards.js"/>

Everything compiled fine but when I ran the project I kept getting this error message:

Microsoft JScript runtime error: 'document.body' is null or not an object.

Code Segment:

var _b=document.createElement("div");

var _c=document.createElement("div");

_b.style.visibility="hidden";

_b.style.position="absolute";

_b.style.fontSize="1px";

_c.style.height="0px";

_c.style.overflow="hidden";

document.body.appendChild(_b).appendChild(_c);

It was really strange and i took a look again at my code and the only thing I could think was that all the JavaScript included file gets inserted on the page rendering in-between where the beginning script markup and the end tag markup is located. I didn’t see this happening on the page markup when the exception was thrown, but that’s my best guess for now. If you’ve run into this error it’s easy enough to fix just add an ending tag, </script> in this case, and the exception will be diverted.

ASP.Net, Programming

ASP.Net Gridview using JavaScript Confirm("") dialog

15. October 2008

I inherited an ASP.Net 2.0 web application project that was in desperate need of repair. One thing I quickly noticed was the amount of JavaScript scripts that were added on the Page_Load to the click event of LinkButton controls within a template column in a GridView control.

The scripts would add the JavaScript Confirm(“”) function to the click event of each control to prompt a user with a hard-coded message on whether to continue the action or cancel. The problem with this approach was that on clicking cancel the post-back would still occur and as a result the delete/edit/insert action would be performed. After spending what seemed like days trying to find the cause of the post-back and why even though the JavaScript function returned the value to the client click it would still carry on it’s server side action.

I searched and searched on the cause of this problem and found everything from creating a page level script to change the 0 and 1 to the respective true and false values that get returned from the JavaScript call. This did the exact same thing as just returning 1 or 0 based on the Ok or Cancel button selection. Nothing seemed to work and the grid wasn’t setup in any special way. That was until I found the ConfirmButtonExtender control as part of the AJAXToolkit.

After including a ConfirmButtonExtender within the template column with the control to validate set to my LinkButton did the JavaScript confirm dialog actually do what it was supposed to. Now when clicking on a LinkButton the confirm dialog appears, displays my ConfirmText property, and then based on the user action of clicking Ok or Cancel will actually stop the post-back from happening. Fantastic, the exact fix I was looking for, and it had the added advantage of exposing a control on the code-behind that could have the displayed confirmation text easily changed without having to consciously worry about JavaScript hooks to the client click event.

Now all I have to do is add my ConfirmButtonExtender to my TemplateField as such:

<asp:TemplateField HeaderText="Delete">
<ItemTemplate>                           
<asp:LinkButton ID="lbtndelete" runat="server" CommandName="Delete" Text="Delete" />
                           
<ajaxToolKit:ConfirmButtonExtender ID="cbeDelete" runat="server" TargetControlID="lbtndelete" />
                       
</ItemTemplate>
</asp:TemplateField>

On the GridView I can simply add an event handler for the OnRowDataBound event to programmatically assign my ConfirmText from say a Resource file or possibly other mechanism.

OnRowDataBound="GrvAdmin_RowDataBound"

protected void GrvAdmin_RowDataBound(object sender, GridViewRowEventArgs e)       
{
           
((AjaxControlToolkit.ConfirmButtonExtender)e.Row.FindControl("cbeDelete")).ConfirmText = Resources.Resource.CONFIRM_DELETE_USER;
}

ASP.Net, Programming