To get things working you will need to:

Strong name sign the assembly

image

Allow Partially Trusted Callers

In the AssemblyInfo.cs file you will need to add the assembly attribute for “AllowPartiallyTrustedCallers”

image

You should now be able to get NLog working as part of a partial trust installation, except that the File target won’t work. Other targets will still work (database for example)

 

Changing BaseFileAppender.cs to get file logging to work

In the directory \Internal\FileAppenders there is a file called “BaseFileAppender.cs”.

Make a change to the function call “TryCreateFileStream()”. The error occurs here:

image

Change the function call to be:

        private FileStream TryCreateFileStream(bool allowConcurrentWrite)
        {
            FileShare fileShare = FileShare.Read;

            if (allowConcurrentWrite)
                fileShare = FileShare.ReadWrite;

#if DOTNET_2_0
            if (_createParameters.EnableFileDelete && PlatformDetector.GetCurrentRuntimeOS() != RuntimeOS.Windows)
            {
                fileShare |= FileShare.Delete;
            }
#endif

#if !NETCF
            try
            {
                if (PlatformDetector.IsCurrentOSCompatibleWith(RuntimeOS.WindowsNT) ||
                        PlatformDetector.IsCurrentOSCompatibleWith(RuntimeOS.Windows))
                {
                    return WindowsCreateFile(FileName, allowConcurrentWrite);
                }
            }
            catch (System.Security.SecurityException secExc)
            {
                InternalLogger.Error("Security Exception Caught in WindowsCreateFile. {0}", secExc.Message);
            }
#endif

            return new FileStream(FileName, 
                FileMode.Append, 
                FileAccess.Write, 
                fileShare, 
                _createParameters.BufferSize);
        }

 

Basically we wrap the call in a try..catch. If we catch a SecurityException when trying to create the FileStream using WindowsCreateFile(), we just swallow the exception and use the native System.Io.FileStream instead.

This is an extremely short post, buy hopefully it will help others in the situation. (Also if I need to find it again I know where to look)

We have recently completed a project using DotNetNuke as our base. The project was for a B2B portal using Microsoft Dynamics NAV as our back-end. We had a requirement where we wanted to change the title of a Module on the fly. This ended up being pretty easy from our module.

In our Page_Load event all we had to do was the following.

Control ctl = DotNetNuke.Common.Globals.FindControlRecursiveDown(this.ContainerControl, "lblTitle");
if ((ctl != null))
{
    ((Label)ctl).Text += "- Text Added";
}

Thats it. All we do it go up 1 control (this.ContainerControl) and look for the Label called "lblTitle". We then append text to the existing Module title.

I've recently started using LinqToSql for some of newer projects. The reason its been such a long time before I've started using LinqToSql is because all our websites get hosted on WebCentral. WebCentral has only offered .NET 3.5 in the last couple of months. We have a policy on not using new technologies until they are offered as an option on our hosting partner.

Anyway... as I said, I've just started using LinqToSql. Recently I was trying to save some data to the database, and getting a very strange error returned. For me to debug the error I needed to know what the query was that was being run on my SQL box. A quick bit of googling led me to an article by Kris Vandermotten on how to send LinqToSql log output to the debug window in Visual Studio. From here I made a few quick changes, and got the output going to a Logger.

Setting up my DataContext

I use a singleton object in my business logic layer to control all access to my DataContext object. This means that all properties (for example logging) are maintained in one place, and I don't have lots of calls to "new DataContext()" throughout my ASP.NET code.

public class DataProvider
 {
     private NorthwindDataContext _context = null;
     public NorthwindDataContext DataContext
     {
         get
         {
             if (_context == null)
             {
                 _context = new NorthwindDataContext (System.Configuration.ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString);

                 _context.Log = new NLogTextWriter();
             }

             return _context;
         }
     }


     public static DataProvider Instance
     {
         get
         {
             if (System.Web.HttpContext.Current.Items["NorthwindDataProvider"] == null)
             {
                 DataProvider dp = new DataProvider();
                 System.Web.HttpContext.Current.Items.Add("NorthwindDataProvider", dp);
             }

             return System.Web.HttpContext.Current.Items["NorthwindDataProvider"] as DataProvider;
         }
     }
 }

In my ASP.NET code, I can then get access to my datacontext as follows:


DataProvider
.Instance.DataContext.Table.First(ii => ii.Id == Request.QueryString["id"]);

 

Logging the output of LinqToSql to a Log File

We use NLog as a logging mechanism. In the example below you could equally use Log4Net, ELMAH, Microsoft Enterprise Library, text files.... whatever you want.

public class NLogTextWriter : System.IO.TextWriter
 {
     private readonly static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

     public NLogTextWriter()
     {

     }

     public override void Write(string value)
     {
         logger.Trace("SQL: {0}", value);
     }

     public override void Write(char[] buffer, int index, int count)
     {
         logger.Trace("SQL: {0}", new string(buffer, index, count));
     }


     public override Encoding Encoding
     {
         get
         {
             return System.Text.Encoding.UTF8;
         }
     }
 }

You will notice in my DataContext code, that _context.Log gets set to a new instance on NLogTextWriter. What happens now, is all logging gets pushed to my log provider.

Credits

Credit to Kris Vandermotten for his article on sending the Log output to the DEBUG window as a start for this article. You can read his article here

A comment was recently left on a previous post of mine asking how to go about adding a button to a wizard and handling the click. I thought I'd answer the question with another post as there is usually more you'd like to do than just adding a button (we certainly do!!!!)

Adding a button to the Wizard and handling the onclick event

Adding a button to the ASP.NET wizard is pretty simple and pretty easy to manage. You just have to define the StartNavigationTemplate, StepNavigationTemplate and FinishNavigationTemplate. These are what define the rendering of the buttons at the bottom of the wizard.

<asp:Wizard ID="wzd" runat="Server" Width="100%" DisplaySideBar="false">
     <WizardSteps>
         <asp:WizardStep ID="step1" runat="server" StepType="Start">
             ... omitted ...
         </asp:WizardStep>
         <asp:WizardStep ID="step2" runat="server" StepType="Step">
             ... omitted ...
         </asp:WizardStep>
         <asp:WizardStep ID="step3" runat="server" StepType="Finish">
             ... omitted ...
         </asp:WizardStep>
     </WizardSteps>
     <StartNavigationTemplate>
         <table cellpadding="3" cellspacing="3">
             <tr>
                 <td>
                     <asp:Button ID="btnCancel" runat="server" Text="Cancel"
                         CausesValidation="false" 
                         OnClientClick="return confirm('Are you sure you want to cancel');" 
                         OnClick="btnCancel_Click" 
                      />
                 </td>
                 <td>
                     <asp:Button ID="btnNext" runat="server" Text="Next >>"
                         CausesValidation="true" 
                         CommandName="MoveNext" 
                      />
                 </td>
             </tr>
         </table>
     </StartNavigationTemplate>
     <StepNavigationTemplate>
         <table cellpadding="3" cellspacing="3">
             <tr>
                 <td>
                     <asp:Button ID="btnCancel" runat="server" Text="Cancel"
                         CausesValidation="false" 
                         OnClientClick="return confirm('Are you sure you want to cancel');" 
                         OnClick="btnCancel_Click" 
                      />
                 </td>
                 <td>
                     <asp:Button ID="btnPrevious" runat="server" Text="<< Previous"
                         CausesValidation="false" 
                         CommandName="MovePrevious" 
                      />
                      <asp:Button ID="btnNext" runat="server" Text="Next >>"
                         CausesValidation="true" 
                         CommandName="MoveNext" 
                      />
                 </td>
             </tr>
         </table>
     </StepNavigationTemplate>
     <FinishNavigationTemplate>
         <table cellpadding="3" cellspacing="3">
             <tr>
                 <td>
                     <asp:Button ID="btnCancel" runat="server" Text="Cancel"
                         CausesValidation="false" 
                         OnClientClick="return confirm('Are you sure you want to cancel');" 
                         OnClick="btnCancel_Click" 
                      />
                 </td>
                 <td>
                      <asp:Button ID="btnFinish" runat="server" Text="Finish"
                         CausesValidation="true" 
                         CommandName="MoveComplete" 
                      />
                 </td>
             </tr>
         </table>
     </FinishNavigationTemplate>
 </asp:Wizard>
In the ASP.NET code above, I've added 3 steps to my wizard, each with a different StepType. The StepType is what defines which NavigationTemplate the ASP.NET wizard uses.
In the example above:
  • Step 1 will use the "StartNavigationTemplate"
  • Step 2 will use the "StepNavigationTemplate"
  • Step 3 will use the "FinishNavigationTemplate"

The trick with making your own NavigationTemplates is to make sure you use the "CommandNames" that the ASP.NET wizard requires. You can see on the "Next", "Previous" and "Complete" buttons that there are no "OnClick" handlers, rather we have used "MoveNext", "MovePrevious" and "MoveComplete" as the CommandNames on the buttons. These CommandNames are what the wizard uses to fire the appropriate event.

In all the cases above, I've added a button that allows the user to "Cancel". When the user clicks on "Cancel", it fires a quick javascript confirm. If the user presses "OK", then the normal code-behind button event handler is raised.

image

protected void btnCancel_Click(object sender, EventArgs e)
{
    // Do something with the click ...
    Response.Redirect("home.aspx");
}

Finding a button in a NavigationTemplate

Sometimes we want (or need) to hide a button on one of the wizard steps for whatever reason.
For example, if you are using a wizard for an e-commerce checkout, you might disable the Next button on the first step if there are no items in your shopping basket.

This code below is from someone else, so I can't take credit for it.... I'm not sure where we got it from, but it works.

public enum WizardNavigationTempContainer
{
    StartNavigationTemplateContainerID = 1,
    StepNavigationTemplateContainerID = 2,
    FinishNavigationTemplateContainerID = 3
}

private Control GetControlFromWizard(Wizard wizard, WizardNavigationTempContainer wzdTemplate, string controlName)
{
    System.Text.StringBuilder strCtrl = new System.Text.StringBuilder();
    strCtrl.Append(wzdTemplate);
    strCtrl.Append("$");
    strCtrl.Append(controlName);

    return wizard.FindControl(strCtrl.ToString());
}

The ASP.NET wizard does some weird stuff with naming, and you can't use the standard FindControl() to find the control. If you're using .NET 3.5, you could probably implement the above "GetControlFromWizard" as an Extension Method.

Hiding the button

Now that we know how to find the button in the wizard step, we can hide/disable... do anything we want to the button.

protected void Page_Load(object sender, EventArgs e)
{
    if (Page.User.Identity.IsAuthenticated == true)
    {
        Button btnNext = GetControlFromWizard(wzd, WizardNavigationTempContainer.StartNavigationTemplateContainerID, "btnNext") as Button;
        btnNext.Enabled = false;
    }
}

In the code above, I'm checking if a user is Authenticated.. and if they are, then I hide the button. As I said before, you could implement what condition you wanted to do here.

Putting it all together

Using the techniques I've used here, and the techniques described in my previous post, you can actually make some pretty nice looking wizards using the ASP.NET Wizard control. We use the methods I've shown here, and the methods in my previous post together and we've produced some pretty user-friendly wizards.

Recently I was asked by a friend of mine to screen scrape a website. What he wanted was the results of a form submission. There were a number of fields on the form (mostly dropdowns), and he wanted me to run every possible permutation of these dropdown lists. All up, this resulted in just over 8,000 pieces of data.

It ended up being REALLY easy (a bit easier than I thought). So I thought I'd share how I went about doing it. Most of these methods were gleaned from other peoples posts, then tailored to my specific needs.

My approach was to tackle this in 2 separate parts:

  1. Make the requests to the remote server, and save all the possible permutations to disk
  2. Load up and then scrape the files to extract the data I needed.

Where to Start

I start by firing up Fiddler and make a request to the server just using the browser.

From this I can get the following information:

  • The URL I need to send the request to
  • All the form fields I need to send with the request

image

In my case, the server wasn't an ASP.NET server, so I didn't have to worry about VIEWSTATE at all.

Making the request through code

This is one place where I was surprised how EASY it was to make the request. The last time I had to do this was back in the .NET 1.1 days, and it was a little bit harder.

private void SendRequest()
{
    try
    {
        WebClient webClient = new WebClient();

        // Create a new NameValueCollection instance to hold some custom parameters to be posted to the URL.
        NameValueCollection vars = new NameValueCollection();

        // Add necessary parameter/value pairs to the name/value container.
        vars.Add("ddlGender", "male");
        vars.Add("ddlAge", ">30");

        // Upload the NameValueCollection.
        byte[] responseArray = webClient.UploadValues(URL, "POST", vars);

        // Save the response.
        string fileName = "webRequest.html";

        System.IO.File.WriteAllBytes(System.IO.Path.Combine(filePath, fileName), responseArray);

    }
    catch (Exception ee)
    {
        // Log error (omitted for brevity)
    }

}

In my case above, the variables "URL" and "filePath" are set in the constructor of the class.

You will note in the example above that in my case I am using POST to get the data from the server. This can easily be changed to GET (or whatever HTTP method you need).

I save all the response data to a file (which I then parse to get the data I want)

Parsing the HTML files

To parse the files also ended up being extremely easy for me. In the past I've tried to use regular expressions to extract the data from files, but plain and simple... I DO NOT understand regular expressions. I've tried, and where I need to I can get them to work, but my poor little brain doesn't have enough room to remember regular expressions.

This time I used the HTML Agility Pack available through CodePlex. It rocks... Coming from a .NET world, I can understand and use this easily, and its pretty fast as well. For those who haven't heard of the HTML Agility Pack here is an excerpt from their CodePlex homepage.

This is an agile HTML parser that builds a read/write DOM and supports plain XPATH or XSLT (you actually don't HAVE to understand XPATH nor XSLT to use it, don't worry...). It is a .NET code library that allows you to parse "out of the web" HTML files. The parser is very tolerant with "real world" malformed HTML. The object model is very similar to what proposes System.Xml, but for HTML documents (or streams).

private void ParseFile(string fileName)
{
    if (!System.IO.File.Exists(System.IO.Path.Combine(filePath, fileName)))
    {
        return;
    }

    HtmlDocument doc = new HtmlDocument();

    doc.Load(System.IO.Path.Combine(filePath, fileName));

    HtmlNode greenBlockContainer = doc.DocumentNode.SelectSingleNode("//div[@class=\"green-block-container\"]");

    HtmlNodeCollection greenBlocks = greenBlockContainer.SelectNodes("//div[@class=\"green-block\"]");

    string s1 = greenBlocks[0].SelectNodes("//div[@class=\"result-block-left\"]")[0].InnerText;
    string s2 = greenBlocks[0].SelectNodes("//div[@class=\"result-block-right\"]")[0].InnerText;
    // etc...
    
    // Do something with the data... omitted.
    
}

Here is what the code above does:

  1. Checks whether the file exists... if not returns
  2. Creates a HtmlDocument (from the HtmlAgilityPack)
  3. Load the html file (fileName) into the HtmlDocument
  4. Extract the nodes we are looking for. Here we can use XPath type queries to get elements
  5. Use the "InnerText" property to get the value of the node and assign it to a string (I then used this string to populate a DataTable)

The default style of the ASP.NET Wizard control is not the best. For the sidebar to work, and display all the wizard steps in a wizard requires quite a bit of space. And in all the wizards we end up creating, we don't want the user to jump from one step to the next using the sidebar. We make the user click from step to step linearly.

We've spent a little time lately changing the way the wizard looks and have come up with the following look and feel.

wizardDetails

The top HeaderTemplate contains the current step the user is on (derived from the WizardStep Title) and an indication of the total number of step (we use three different classes in indicate the current step, completed step and incomplete step). The "steps" also have tooltips added to let the user know what steps are coming. (See image below)

 Tooltip when Mouse hovers over the step number

The WizardStep in the image above is all the information regarding "Billing and Shipping" details (this is just standard Wizard Step stuff)

How its done

The markup for the wizard aspx code is as follows:

<asp:Wizard ID="wzd" runat="Server" Width="100%" DisplaySideBar="false">
    <HeaderTemplate>
        <table style="width: 100%" cellpadding="0" cellspacing="0">
            <tr>
                <td class="wizardTitle">
                    <%= wzd.ActiveStep.Title%>
                </td>
                <td>
                    <table style="width: 100%; border-collapse: collapse;">
                        <tr>
                            <td style="text-align: right">
                                <span class="wizardProgress">Steps:</span>
                            </td>
                            <asp:Repeater ID="SideBarList" runat="server">
                                <ItemTemplate>
                                    <td class="stepBreak">&nbsp;</td>
                                    <td class="<%# GetClassForWizardStep(Container.DataItem) %>" title="<%# DataBinder.Eval(Container, "DataItem.Name")%>">
                                        <%# wzd.WizardSteps.IndexOf(Container.DataItem as WizardStep) + 1 %>
                                    </td>
                                </ItemTemplate>
                            </asp:Repeater>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    </HeaderTemplate>
    <SideBarTemplate>
    </SideBarTemplate>
    <WizardSteps> ... removed... </WizardSteps>
</asp:Wizard>

We add the following event handler to Page_Load in our code-behind

protected void Page_Load(object sender, EventArgs e)
{
    wzd.PreRender += new EventHandler(wzd_PreRender);
}

And have the following methods in the code-behind

protected void wzd_PreRender(object sender, EventArgs e)
{
    Repeater SideBarList = wzd.FindControl("HeaderContainer").FindControl("SideBarList") as Repeater;

    SideBarList.DataSource = wzd.WizardSteps;
    SideBarList.DataBind();

}

public string GetClassForWizardStep(object wizardStep)
{
    WizardStep step = wizardStep as WizardStep;

    if (step == null)
    {
        return "";
    }

    int stepIndex = wzd.WizardSteps.IndexOf(step);

    if (stepIndex < wzd.ActiveStepIndex)
    {
        return "stepCompleted";
    }
    else if (stepIndex > wzd.ActiveStepIndex)
    {
        return "stepNotCompleted";
    }
    else
    {
        return "stepCurrent";
    }
}

Explanation of the code above

When the wizard goes into PreRender, we bind the collection of WizardSteps to the Repeater in our HeaderTemplate

The "GetClassForWizardStep" is a helper method we have to determine what wizard step we're on, and render the appropriate class in the table cell.

Style Sheet Rules

The rules I'm using above to generate the page are as below...

/* WIZARD */
.stepNotCompleted
{
    background-color: rgb(153,153,153);
    width: 15px;
    border: 1px solid rgb(153,153,153);
    margin-right: 5px;
    color: White;
    font-family: Arial;
    font-size: 12px;
    text-align: center;
}

.stepCompleted
{
    background-color: #4d4d4d;
    width: 15px;
    border: 1px solid #4d4d4d;
    color: White;
    font-family: Arial;
    font-size: 12px;
    text-align: center;
}

.stepCurrent
{
    background-color: #e01122;
    width: 15px;
    border: 1px solid #e01122;
    color: White;
    font-family: Arial;
    font-size: 12px;
    font-weight: bold;
    text-align: center;
}

.stepBreak
{
    width: 3px;
    background-color: Transparent;
}

.wizardProgress
{
    padding-right: 10px;
    font-family: Arial;
    color: #333333;
    font-size: 12px;

}

.wizardTitle
{
    font-family: Arial;
    font-size: 120%;
    font-weight: bold;
    color: #333333;
    vertical-align: middle;

We use DotNetNuke as a base for most of our applications. We are primarily in the space of content management, mixed with custom code. DNN handles content management pretty well for all our situations. The ability for us to create modules in DNN to do whatever we want is pretty awesome.. And after you get used to some quirks (and jumping through some pretty funky hoops, its actually pretty easy to use).

One thing we came across recently was doing some zebra striping with jQuery, and using a table-less layout skin (DIV's only). When you hovered over a table row, the whole page would jump up about 6-ish pixels. I'd noticed it, and hoped no-one else would, but alas it was discovered, and left up to me to fix.

I won't go into the complete set of styles and the full skin file, but I'll post enough to give a few hints.

    <!-- B. MAIN -->
    <div class="main">
        <!-- B.1 MAIN CONTENT -->
        <div class="main-content">
            <!-- Content unit - One column -->
            <div id="topPane" runat="server" class="column1-unit" visible="false">
                <hr class="clear-contentunit" />
            </div>
            <div id="contentPane" runat="server" class="column1-unit" visible="false">
                <hr class="clear-contentunit" />
            </div>
            <!-- Content unit - Two columns -->
            <div id="leftPane" runat="server" class="column2-unit-left" visible="true" />
            <div id="rightPane" runat="server" class="column2-unit-right" visible="false" />
            <hr class="clear-contentunit" />
            <div id="bottomPane" runat="server" class="column1-unit" visible="false">
                <hr class="clear-contentunit" />
            </div>
        </div>
        <hr class="clear-contentunit" />
        <!-- C. FOOTER AREA -->
        <div class="footer">
            <span class="credits">
                <dnn:TERMS ID="TERMS" runat="server" Text="Terms & Conditions" />
                |
                <dnn:PRIVACY ID="PRIVACY" runat="server" Text="Privacy Policy" />
            </span>
&nbsp;&nbsp;&nbsp;
<span>Copyright &copy; Ellington Management &amps; Information Services, <%=DateTime.Now.ToString("yyyy")%>. All rights reserved.
</span> </div> </div>

The key here is make sure you add "visible=false" to all of your DIVs. When DotNetNuke adds a module to a pane, it also sets visible=true on the DIV. This way we make sure we don't get any empty DIV's rendered on the page. I don't 100% know why the empty div collapsed when you hover over a row with jQuery, but this solved the problem.

In the skin above, the only DIV element I have "visible=true" on, is the leftPane. I want this DIV to render, regardless of whether there is a module added to it or not. The repercussion we get if its not "visible=true" is that the DIV doesn't render, and the rightPane ends up rendering on the left hand side of the page.

Make sure you ALWAYS have a contentPane (Mental note to self)

Make sure you ALWAYS have a pane in your skin called "contentPane". I learnt this the hard way (very hard). We designed a skin for a customer and they effectively wanted 4 panels (top-left, top-right, bottom-left and bottom-right)... In all my wisdom I added panes with these names, and for the most part everything worked.... The big thing that didn't work was users logging out.

The reason is this: when you click the logout link, it redirects to a URL with ctl=logoff. When DotNetNuke sees Request.QueryString["ctl"], it loads this module and inserts it into the ContentPane... which in my case didn't exist. DNN does some error checking and if it can't find "ContentPane" it doesn't add the control. Kudos to DNN for good error checking. Bad form on my part for not realising that a "contentPane" is needed.

Users get impatient when something is taking a long time to run server-side. This usually results in having a form submitted more than once. Ok, maybe its not impatience, maybe its that they didn't think they clicked the button.... I don't know why.... I just have to fix the problem of duplicate records in the database.

We use a pretty simple method of tracking whether a user has submitted a form more than one. This is usually used in conjunction with other methods, such as BusyBoxes or javascript click prevention. Ultimately, this method is our absolute failsafe to ensure we only submit the form once.

This has been used and tested (and approved) by a number of different payment gateways and banks we use in Australia.

How do we do it

All our pages inherit from a common base page (inherited from System.Web.UI.Page). We override the OnInit method and add a hidden field which is a Guid. We only set this field when the page first loads.


protected override void
OnInit(EventArgs e) { Literal lit = new Literal(); lit.ID = "__PAGEGUID"; lit.Visible = false; this.Controls.Add(lit); if (!IsPostBack) { lit.Text = Guid.NewGuid().ToString(); } base.OnInit(e); } public Guid GetPageGuid() { Literal lit = this.FindControl("__PAGEGUID") as Literal; if (lit == null) { throw new System.Exception("Could not find __PAGEGUID control"); } else { Guid g = new Guid(lit.Text); return g; } }

This gives us a unique reference for every page we use. When its comes time to checking that a page is unique we do the following.

NOTE: In the scenario below, we're tracking that users don't click the "Order" button more than once when we're firing an order through to Microsoft Dynamics NAV.

/*
 * Ensure we only submit the order once.
 */
try
{
    OrderHelper.EnsureOrderIsUnique(this.GetPageGuid());
}
catch (DuplicateOrderException dupExc)
{
// Do something with the error. (Code omitted)
}

The method that does the "EnsureOrderIsUnique" is described below. I've used a static List to store the page Guids in this case. When we take credit card payments, we store the Guid in the database along with the payment information. Its up to you how to store the Guid... it just needs to be accessible by all processes.


private static
List<Guid> _submittedOrders = new List<Guid>(); /// <summary> /// Keeps track of all the Order Guid we've placed (similiar to Payment Gateway). /// If an order is not unique, then a DuplicateOrderException is thrown. /// </summary> /// <param name="orderGuid"></param> public static void EnsureOrderIsUnique(Guid orderGuid) { lock (((ICollection)_submittedOrders).SyncRoot) { if (_submittedOrders.Contains(orderGuid)) { throw new DuplicateOrderException("Order has already been placed"); } _submittedOrders.Add(orderGuid); } }

Thats it.... pretty simple really. And it works under a number of different scenarios:

  • people double-clicking on a button at the end of a wizard
  • people finishing a wizard, pressing back on the browser, then pressing finish again
  • people opening up new browser windows and submitting both..

 

I've mentioned in a previous post that we use Aspose.Words combined with Aspose.Pdf to create PDF documents/reports in all our applications.

To do this we use a method within the Aspose.Words.Reporting.MailMerge class called ExecuteWithRegions using the overload that passes in a DataTable. Within Aspose.Words this effectively loops through the fields in DataTable and creates what you'd normally refer to as a sub-report.

Within our applications we use classes to represent our business objects. As we produce quite a few reports that rely on a number of different objects, we've created a helper method that turns our business objects and/or a List of business objects into DataTables.

We came into a problem recently when one of our fields was defined as "int?" (same as Nullable<int>). The problem we had was trying to add a column on type "int?" to a DataTable. Make sense when you think about it... databases have had the concept of nullable fields for as long as I've been creating databases.

Anyway... rather than add a field of type "int?" to the DataTable, I needed to add a field of type "int" as a column. Sounded simple... sort of... A fair bit of Googling and pulling together ideas from a couple of different blog posts led me to the following code.

The code below takes a List of objects (simple... this doesn't handle complex types) and then returns a DataTable which is a representation of the object.

/// <summary>
 /// Converts a Generic List into a DataTable
 /// </summary>
 /// <param name="list"></param>
 /// <param name="typ"></param>
 /// <returns></returns>
 private DataTable GetDataTable(IList list, Type typ)
 {
     DataTable dt = new DataTable();

     // Get a list of all the properties on the object
     PropertyInfo[] pi = typ.GetProperties();

     // Loop through each property, and add it as a column to the datatable
     foreach (PropertyInfo p in pi)
     {
         // The the type of the property
         Type columnType = p.PropertyType;

         // We need to check whether the property is NULLABLE
         if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
         {
             // If it is NULLABLE, then get the underlying type. eg if "Nullable<int>" then this will return just "int"
             columnType = p.PropertyType.GetGenericArguments()[0];
         }

         // Add the column definition to the datatable.
         dt.Columns.Add(new DataColumn(p.Name, columnType));
     }

     // For each object in the list, loop through and add the data to the datatable.
     foreach (object obj in list)
     {
         object[] row = new object[pi.Length];
         int i = 0;

         foreach (PropertyInfo p in pi)
         {
             row[i++] = p.GetValue(obj, null);
         }

         dt.Rows.Add(row);
     }

     return dt;
 }

The key points from the code above are:

  • using PropertyType.IsGenericType to determine whether the property is a generic type
  • using ProprtyType.GetGenericTypeDefinition() == typeof(Nullable<>) to test whether its a nullable type
  • getting the underlying type using PropertyType.GetGenericArguments() to get the base type.

To use the code above, you can do the following. The example below is a fairly contrived example, but it should highlight what I'm trying to do below.

public class Person
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public DateTime? DateOfDeath { get; set; }
}

public class Example
{
    public static DataTable RunExample()
    {
        Person edward = new Person() { Name = "Edward", DateOfBirth = new DateTime(1900, 1, 1), DateOfDeath = new DateTime(1990, 10, 15) };
        Person margaret = new Person() { Name = "Margaret", DateOfBirth = new DateTime(1950, 2, 9), DateOfDeath = null };
        Person grant = new Person() { Name = "Grant", DateOfBirth = new DateTime(1975, 6, 13), DateOfDeath = null };

        List<Person> people = new List<Person>();

        people.Add(edward);
        people.Add(margaret);
        people.Add(grant);

        DataTable dt = GetDataTable(people, typeof(Person));

        return dt;
    }
}

And this will return a DataTable that looks like the following (I'm an Aussie, so the date format is dd/MM/yyyy):

Name (string) DateOfBirth (DateTime) DateOfDeath (DateTime)
Edward 1/1/1900 15/10/1990
Margaret 9/2/1950 [NULL]
Grant 13/6/1975 [NULL]

NOTE: as a general rule we try to NOT use nullable fields in the database, as nullable fields do some REALLY weird things to queries. Pretty much the only field types we use as nulls are DateTime fields. In my opinion, nullable fields get used far too often within databases and there is usually an alternative.

Whenever anyone anywhere mentions Reflection on a blog post, straight away there is a reply saying "you shouldn't use Reflection as its slow". I thought I'd take a look at how "slow" reflection really is in the real world.

We use reflection in a couple of instances in our applications. One situation where we use Reflection is in a previous post about getting a friendly name from an enumeration. Another situation is where we convert a List of business objects into a DataTable (we need to do this produce PDF documents in our application using ASPOSE.Words - I'll post about this later). Another common situation you'll see is object hydration.

Getting a friendly name from an enumeration

There are a couple of other options I've seen/used in the past to get friendly names from Enums.

These consist of:

  1. using Reflection to get the value of an attribute on the enum (code from my previous post)
  2. storing the enum in a table in the database and looking it up at runtime
  3. storing the enum in some other way (e.g. XML) and looking it up at runtime
  4. retrieving the friendly name from a resources file at runtime
  5. using a switch/case statement to get the values of the enum

I'm going to test all of the above options and see how we go for speed.

The Results

I'm sure some of you won't want to read through how I did it, and what methods I used... so for those people here are the results.

Startup Time

Method Time Taken
(ticks*)
Time Taken
(ms)
Reflection 36,639 3.66
Database Warm-up 637,757 63.78
Database (Stored Procedure) 9,672 0.97
Switch / Case Statement 2,744 0.27
Resources 932,752 93.28
Xml Warm-up 14,712 1.47
Xml 8,225 0.82

* - A tick is 100 nanoseconds.

The above data represents a average of 5 runs, only getting the value of the enum once. This represents the cold-start time for each different method (basically I'm trying to exclude any form of caching). What we can see from the above results, is that by far, a SWITCH / CASE statement is the fastest method we have available. I've split out Database warm-up and database stored proc runtime into 2 separate runs (likewise with XML). I'm a database guy, and everyone knows that establishing a connection to the database is pretty costly. What was a surprise to me, is that the longest method was getting the value from a resources file.

But looking at the numbers above....and putting it into a bit of context, the longest method above took 93ms.... In terms of speed, this is still pretty fast, and certainly within tolerable levels for a Web UI.

100 Iterations

I've also run the results for 100 iterations. Why 100? Maybe I'm rendering a list of data, and this is one of the columns I want to display. I know 100 is a fairly big list to render, but lets just pretend....

Method Time Taken
(ticks*)
Time Taken
(ms)
Switch / Case Statement 74 0.0074
Resources 37,809 3.7809
Reflection with cache 67,015 6.7015

Again, we see that using a switch/case statement outperforms everything else MASSIVELY. I'm actually pretty surprised how fast it is. For 100 iterations of resources and reflection, we get response times of 3.7ms and 6.7ms respectively. Again, putting this in context, we're not talking about a process that's going to put the brakes on any website I develop.

What is interesting, is that using Resources is initially slow to startup, but then runs pretty past afterwards.

How I got the Values of the enum

I'll post the code I used to get the values of the enumerations.

EnumHelper - Reflection

This is the same method I used in a previous blog post. Its posted below as well in the Reflection with Cache code.

Database

This is pretty simple stuff. Basically open the connection to the database and run a stored procedure.

public static string GetDescription(Enum en)
       {
           using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlCommon"].ConnectionString))
           {
               SqlCommand cmd = new SqlCommand();

               conn.Open();
               cmd.Connection = conn;

               cmd.CommandType = CommandType.StoredProcedure;
               cmd.CommandText = "Enum_GetDescription";

               cmd.Parameters.Add("enumName", SqlDbType.VarChar).Value = en.ToString();

               SqlDataReader dr = cmd.ExecuteReader();

               if (dr.Read())
               {
                   return Convert.ToString(dr["Description"]);
               }
           }

           return en.ToString();
       }

Switch / Case statement

Basically pass in the enum, and return a string. The only drawback I can think of about this one, is that you'd need to write one of these for each enumeration you use in your application.

public static string GetDescription(UserColours en)
{
    switch (en)
    {
        case UserColours.AliceBlue: return "Alice Blue";
        case UserColours.BrightPink: return "Bright Pink";
        case UserColours.BurntOrange: return "Burnt Orange";
        case UserColours.DarkGreen: return "Dark Green";
        case UserColours.SkyBlue: return "Sky Blue";
        default: return en.ToString();
    }
}

Resources

Again, just read the value from a resources file, using the enumeration ToString() as the Name 

public static string GetDescription(Enum en)
{
    string s = Resources.UserColoursResource.ResourceManager.GetString(en.ToString());

    if (!string.IsNullOrEmpty(s))
        return s;

    return en.ToString();

}

image

Xml File

Load up the Xml file, and use XPath to find the friendly name of the enum

public static string GetDescription(Enum en)
{
    XmlDocument xmlDoc = new XmlDocument();

    xmlDoc.Load(HttpContext.Current.Server.MapPath("Enums.xml"));

    XmlNode node = xmlDoc.SelectSingleNode(String.Format("enums/enum[@value = \"{0}\"]", en.ToString()));

    if (node != null)
    {
        return node.Attributes["description"].Value;
    }

    return en.ToString();
}

 

<?xml version="1.0" encoding="utf-8" ?>
<enums>
    <enum value="BurntOrange" description="Burnt Orange" ></enum>
    <enum value="BrightPink" description="Bright Pink" ></enum>
    <enum value="DarkGreen" description="Dark Green" ></enum>
    <enum value="SkyBlue" description="Sky Blue" ></enum>
    <enum value="AliceBlue" description="Alice Blue" ></enum>
</enums>

Resources with caching

This is effectively the same as my standard EnumHelper class library, except I've added a caching using the HttpContext Cache.

public static class RelfectionEnumHelper
{
    private static object padLock = new object();

    public static string GetDescription(Enum en)
    {
        Type type = en.GetType();

        MemberInfo[] memInfo = type.GetMember(en.ToString());

        if (memInfo != null && memInfo.Length > 0)
        {
            object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attrs != null && attrs.Length > 0)
            {
                return ((DescriptionAttribute)attrs[0]).Description;
            }
        }

        return en.ToString();
    }


    public static string GetDescriptionUsingCache(Enum en)
    {
        System.Web.Caching.Cache cache = System.Web.HttpContext.Current.Cache;

        if (cache[en.ToString()] == null)
        {
            lock (padLock)
            {
                if (cache[en.ToString()] == null)
                {
                    cache.Insert(en.ToString(), GetDescription(en));
                }
            }
        }

        return cache[en.ToString()].ToString();
    }
}

 

Conclusion

Personally, I'm going to stick with using my EnumHelper library with caching. I'm really not that fussed about shaving 3ms of a page hit...

The reasons I'll stick with this library are:

  • its nice and simple. The enum and its friendly name are located in the one spot. Developers are lazy.... if they have to maintain things in 2 or 3 different locations... plain and simple they won't!
  • its fast enough for me. None of my clients ever ask us to make it go faster. (There are usually other way we can make things run faster anyway)
More Posts Next page »