Contents tagged with ASP.NET

  • Log4net: Log to a JavaScript Console

    While lurking and skulking in the shadows of various technical .Net sites, I've noticed many developers discussing log4net in their blogs and posts; log4net is an extremely popular tool for logging .Net Applications. So, I decided to try it out. After the initial complexities of getting it up and running, I was suitably impressed. Could it be…logging is fun? Well, I don't know if I'd go that far…at least I'd never admit it.

  • HTML 5 and jQuery – A Match Made in Heaven

    I recently attended an ASP.NET MVC seminar hosted by the Twin Cities .Net User Group. The speaker was K. Scott Allen. Scott is a charismatic, gifted speaker and did a great job. You can always pick up useful items when watching an expert write a program from scratch.

  • jQuery Selector Tester and Cheat Sheet

    I've always appreciated these tools: Expresso and XPath Builder. They make designing regular expressions and XPath selectors almost fun! Did I say fun? I meant less painful. Being able to paste/load text and then interactively play with the search criteria is infinitely better than the code/compile/run/test cycle. It's faster and you get a much better feel for how the expressions work.

  • Create Image Maps with GIMP

    Having a clickable image in a web page is not a big deal. Having an image in a web page with clickable hotspots is a big deal. The powerful GIMP editor has a tool to make creating clickable hotspots much easier.

    GIMP stands for GNU Image Manipulation Program. Its home page and download links are here: http://www.gimp.org/ (it is completely free).

    Beware: GIMP is an extraordinarily advanced and powerful image editor. If you wish to use it for general image editing tasks, you have a steep learning curve to climb. FYI: I used it to create the shadows you see on the images below. Fortunately, the tool to make Image Maps is separate from the main program.

    To start, open an image with GIMP or, drag and drop an image onto the GIMP main window. I'm using the image of a bar graph.

    Next, we have to find the Image Map tool and launch it (Filters->Web->Image Map…):

    Why is the Image Map tool under Filters and not Tools? I don't know. It's mystery—much like the Loch Ness Monster, the Bermuda Triangle, or why my socks keep disappearing when I do laundry. I swear I've got twenty single unmatched socks. But I digress…

    Here is what the Image Map tool looks like:

    If we click the blue 'I' button, we can add information to the Image Map:

    Now we'll use the rectangle tool to create some clickable hotspots. Select the Blue Rectangle tool, drag a rectangle, click when done and you'll get something like this:

    You can also make circle/oval and polygon areas. You can edit all the parameters of an image map area after drawing it.

    Rectangle settings (for fine tweaking):

    JavaScript functions (it's up to you to write them):

    Here is a setup with two rectangles and one polygon area:

    When you hit save a map file is generated that looks something like this:

    <img src="BarGraphImage.png" width="326" height="306" border="0" usemap="#BarGraphImageMap">
    
    <map name="BarGraphImageMap">
      <!-- #$-:Image map file created by GIMP Image Map plug-in -->
      <!-- #$-:GIMP Image Map plug-in by Maurits Rijk -->
      <!-- #$-:Please do not edit lines starting with "#$" -->
      <!-- #$VERSION:2.3 -->
      <!-- #$AUTHOR:Steve Wellens -->
      <!-- #$DESCRIPTION:A bar graph with  no instrinsic value -->
      <area shape="rect" coords="213,62,253,269" onmouseover="ImageMapMouseHover(&apos;Biggest Bar&apos;)" onmouseout="ImageMapMouseHover(&apos;&apos;)"  nohref="nohref"></area>
      <area shape="rect" coords="114,131,158,267" href="~/Details2.aspx"></area>
      <area shape="poly" coords="57,44,76,100,181,102,183,62,142,34" href="http://www.microsoft.com"></area>
    </map>
    

    Paste the contents into a web page and you are almost there. I made some tweaks before it became usable:

    • Replaced &apos; with apostrophes in the javascript functions.
    • Changed the image path so it would find the image in my images directory
    • Tweaked the href urls.
    • Added Title="Some Text" to get tool tips.
    • Cleaned out the comments.

    Result:

    The final markup (with JavaScript function):

    <script type="text/javascript" language="javascript">
    
        function ImageMapMouseHover(Msg)
        {
             $("#Label1").html(Msg);
        }
    
    <img src="Images\BarGraphImage.png" width="326" height="306" border="0" usemap="#BarGraphImageMap">
    
    <map name="BarGraphImageMap">
      <area shape="rect" coords="213,62,253,269" onmouseover="ImageMapMouseHover('Biggest Bar')" onmouseout="ImageMapMouseHover('')"  nohref="nohref"></area>
      <area shape="rect" coords="114,131,158,267" href="Details2.aspx" title="Details 2"></area>
      <area shape="poly" coords="57,44,76,100,181,102,183,62,142,34" href="http://www.microsoft.com"></area>
    </map>
    
    

    It may seem like a lot of bother but, the tool does the heavy lifting: i.e. the coordinates. Getting the regions positioned and sized is easy using a visual tool…much better than doing it by hand.

    This, of course, isn't a full treatise on the tool but it should give you enough information to decide if it's helpful.

    I hope someone finds this useful.

    Steve Wellens

  • Web.Config is Cached

    There was a question from a student over on the Asp.Net forums about improving site performance. The concern was that every time an app setting was read from the Web.Config file, the disk would be accessed. With many app settings and many users, it was believed performance would suffer.

    Their intent was to create a class to hold all the settings, instantiate it and fill it from the Web.Config file on startup. Then, all the settings would be in RAM. I knew this was not correct and didn't want to just say so without any corroboration, so I did some searching.

    Surprisingly, this is a common misconception. I found other code postings that cached the app settings from Web.Config. Many people even thanked the posters for the code.

    In a later post, the student said their text book recommended caching the Web.Config file.

    OK, here's the deal. The Web.Config file is already cached. You do not need to re-cache it.

    From this article http://msdn.microsoft.com/en-us/library/aa478432.aspx

    It is important to realize that the entire <appSettings> section is read, parsed, and cached the first time we retrieve a setting value. From that point forward, all requests for setting values come from an in-memory cache, so access is quite fast and doesn't incur any subsequent overhead for accessing the file or parsing the XML.

    The reason the misconception is prevalent may be because it's hard to search for Web.Config and cache without getting a lot of hits on how to setup caching in the Web.Config file.

    So here's a string for search engines to index on: "Is the Web.Config file Cached?"

    A follow up question was, are the connection strings cached?

    Yes. http://msdn.microsoft.com/en-us/library/ms178683.aspx

    At run time, ASP.NET uses the Web.Config files to hierarchically compute a unique collection of configuration settings for each incoming URL request. These settings are calculated only once and then cached on the server.

    And, as everyone should know, if you modify the Web.Config file, the web application will restart.

    I hope this helps people to NOT write code!  

    Steve Wellens

  • Finding Controls in a Master Page with jQuery

    This question popped up on the Asp.Net forums where I moderate:

    "How do I find an HTML element on a Master Page, from a child page, using jQuery?"

    I licked my chops. I like questions like this because when I don't know the answer, it gives me an excuse to explore and learn.

    The problem is that element ids on Master Pages get mangled, or decorated, to prevent duplicate ids on the final rendered HTML.

    For instance a textbox with an id like this: MasterPageTextBox

    Ends up with an id like this: ctl00$MasterPageTextBox

    Solution 1:

    We could hard code the mangled id into the jQuery search criteria and it would work. But what a maintenance nightmare, in the future, the mangled id might change: Not acceptable. When people pay you money to write code, you should write good code.

    Solution 2:

    If you are using Asp.Net 4, you have control over the generated ids and can make them predictable. Then you can hard code the generated id into the CSS selector. However, that isn't the case for most sites at this time.

    Solution 3:

    After Googling and Binging around a bit, I came up with this approach to use in the Master Page:

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.ClientScript.RegisterHiddenField("HiddenFieldClientID", this.MasterPageTextBox.ClientID); 
        }

    The code above takes the generated ClientID and puts it in a HiddenField that gets sent to the browser. The jQuery code in the child page can then get the value in the HiddenField and use it to search for the element. I thought this was pretty cool but…the jQuery code wouldn't compile because the HiddenField wasn't on its page. So an empty HiddenField control has to be placed on the page. It's messy but it works! Here is how the jQuery on the child page accesses the hidden field and then accesses the textbox on the Master Page:   

        // ---- SetMasterPageTextBox ---------------------------
        // write hello in a textbox field on the master page
     
        function SetMasterPageTextBox()
        {
            // Get the hidden field         
            var HidField = $("#HiddenFieldClientID");
            if (HidField.length == 1)
            {
                // get the contents of the hidden field
                var ClientID = HidField[0].value;
                // use it as the ID of the TextBox control
                $("#" + ClientID).val("Hello");
            }
        }

    I went to post my 'brilliant' answer, but in the meantime another forum member posted an answer which was far superior to mine.

    Frank Hong suggested wrapping the element with a span tag.

    Solution 4:

    Two things make this next solution work.

    1. Span tag ID's are NOT mangled or decorated.
    2. CSS selectors are cool, really cool…quick review:

    div, p

    The comma (,) operator means AND. All divs and paragraphs on the page will be selected.

    div > p

    The greater than (>) operator means direct parent of. Any paragraphs directly inside of any divs are selected

    div p

    The space ( ) operator means ancestor of. Any paragraphs inside a div are selected, even if they are inside of other elements within the div.

    In the Master Page wrap the textbox with a span element:

         <%-- Span is to allow child page to jQuery select textbox--%>
         <span id="SpanMyTextBox">
             <asp:TextBox ID="MyTextBox" runat="server"></asp:TextBox>
         </span>

    Here's what it looks like rendered, note the TextBox id got mangled but the span id remains unscathed: 

        <span id="SpanMyTextBox">
            <input name="ctl00$MyTextBox" type="text" id="ctl00_MyTextBox" />
        </span>      	

    In the Child Page we can use the greater than or the space operator. The greater than operator is more explicit as to our intent. We use 'input' because textboxes render as HTML input elements.

    So the CSS selector is:   #SpanMyTextBox > input 

        // ---- SetMasterPageTextBox ---------------------------
        // write hello in a textbox field on the master page        
     
        function SetMasterPageTextBox()
        {
            //Textbox is wrapped in span element
            $("#SpanMyTextBox > input").val("Hello");
        }
     

    Now, isn't that better? Of course, it's up to the developer to ensure duplicate span ids are not used.

    [Update:]

    Solution 5: (from the comments)

    You can also use a wild card CSS selector.

       input[id$=MyTextBox]

    The above line matches all HTML input elements with an id attribute that ends with "MyTextBox".  

    It will match:

       <asp:TextBox ID="ctl00$MyTextBox" runat="server"...
       <asp:TextBox ID="LaLaLaMyTextBox" runat="server"...
       <asp:TextBox ID="abc123MyTextBox" runat="server"...

    I hope someone finds this useful.

    Steve Wellens

  • Goodbye Ajax Toolkit, Hello jQuery UI

    Like most developers, I love finding tools that do my work for me and make me look good. And, like most developers, I am extremely wary of adding too much outside crap to a project which can make maintaining it a nightmare. You may end up not only maintaining your own code but someone else's code, or worse, not being able to update the project because a third-party control won't let you.

    The Ajax Toolkit has some great stuff that is very easy to use. It's from Microsoft so you can be pretty comfortable adding it to a project. Drag and Drop and off you go. But often things don't work out exactly as you would like. Deploying and debugging are not always easy.

    A viable alternative to the Ajax Toolkit is the jQuery UI.

    I was happy to see on the jQuery web site they have their own UI controls…very happy. If you are already using jQuery, you don't feel as if you are adding a third party component. And, it seems, Microsoft has 'adopted' jQuery.

    Here's their website: http://jqueryui.com/. It's also reachable from http://jquery.com/

    I decided to try out the DatePicker control, since picking a date is one of the most useful and common tasks a control can do.

    Downloading and installing the jQuery UI was no more difficult than downloading and installing jQuery itself. The download is customizable; you pick which components you want and which visual theme you want.

    In the download you get:

    • A CSS file and images
    • Minimized versions of the jQuery UI and jQuery code
    • "Development bundle"
      • Documentation
      • Demos
      • Separate code files
      • Misc.

    I added the CSS file, image directory and jQuery code file to my project. I already had the jQuery library. When you drag and drop the files onto the page, you get entries like these:

        <script src="Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
        <script src="Scripts/jquery-ui-1.8.4.custom.min.js" type="text/javascript"></script>
        <link type="text/css" href="css/smoothness/jquery-ui-1.8.4.custom.css" rel="stylesheet" />

    Note: Other versions of the source code are available: non-minimized and documented versions.

    Now, let's create a TextBox and hookup the DatePicker control to it:

       <script type="text/javascript" language="javascript">
     
            $(document).ready(DocReady);
     
            function DocReady()
            {
                $('#DatePicker_TextBox').datepicker();
            }
       
        <asp:TextBox ID="DatePicker_TextBox" runat="server" ></asp:TextBox>

    Note: jQuery code is usually so ugly its own mother would slap it. I strive for legibility and maintainability by NOT nesting and chaining functions and using a more 'traditional' C# style of coding.

    Here's what happens when you click on, or tab into, the text box:

    Dang, that wasn't hard, it works well and looks pretty. When you select a date, it fills in the textbox:

    You can edit the text in the box by hand and the DatePicker control reads it. If the text isn't a valid date, the DatePicker control ignores it. Nice. It has a good solid feel. I know engineers shouldn't talk like that but…it has a good solid feel.

    Let's change the date format. Sadly, the date formatting codes are different than the .Net DateTime formatting codes (more on this later). I added a few more options just for fun. For numberOfMonths, you supply a two dimensional array: 3 by 4 would show an entire year.

            $(document).ready(DocReady);
     
            function DocReady()
            {
                var DatePicker = $('#DatePicker_TextBox').datepicker();
     
                DatePicker.datepicker('option',
                        {
                            dateFormat: 'DD, d MM, yy',
                            numberOfMonths: [1, 2],
                            showWeek: 'true' 
                        }); 
            }

    Why didn't I just chain the formatting code to the creation code? Why did I create a separate variable?

    Debugging: If something goes wrong, I can tell if the problem is in the creation of the DatePicker or in the formatting of the DatePicker. Until you have to debug code, you don't know how valuable and useful this is. The local variable avoids a duplicate search operation.

    Why the weird code formatting when setting the options?

    I tried to make it as readable as possible. When there is more than one option, it is easier to read if each option is on a separate line. It's also easier to tell when the braces and parenthesis match up.

    Here's what it looks like with the options set:

    Note: In the above image you can see a bug: The fifth day of both months is selected. I checked the website and it was already reported here: http://dev.jqueryui.com/ticket/5984. The posted workaround corrected the problem.

    It's pretty cool. But, the textbox is going to be sent back to the server and will need to be converted to a DateTime object. As mentioned earlier: .NET and jQuery use different formatting codes.

    So the code to convert the string to a DateTime is:

            String DateText = DatePicker_TextBox.Text;
     
            DateTime TheDate;
     
            // jquery format: DD, d MM, yy
            // .Net format:   dddd, d MMMM, yyyy
            // Sample:        Friday, 3 September, 2010
            if (DateTime.TryParseExact(DateText, 
                                      "dddd, d MMMM, yyyy", 
                                      null, 
                                      DateTimeStyles.None, 
                                      out TheDate) == false)
            {
                TheDate = DateTime.Now.Date;  // default value on error
            }

    In a real application, you'd want to centralize the format strings in one place so they are easy to maintain (by using constants or utility functions).    

    Once you start playing with and using the jQuery UI components, you'll be hooked.

    By the way, I still use and appreciate the Ajax UpdatePanel in the Ajax Extensions toolbox. Although some treat it disdainfully, what you get, for what you pay, is a great bargain.

    I hope someone finds this useful.

    Steve Wellens.

     

  • Unwanted Page Breaks in ReportViewer

    I needed to create a dynamic PDF document based on user selections for a system I created this summer. Rather than use a 3rd party tool and learn a new API, I decided to try the ReportViewer control since it had the capability of exporting to PDF (and Excel).