Monday, October 28, 2013

500.22 HTTP Error After Implementing Bundles in Web Forms Application and Publishing to IIS

So that was a very long title, but this really threw me for a loop. I implemented bundling via the Microsoft ASP.NET Web Optimization Framework NuGet package and it worked great in my ASP.NET development web server. The issue came when I deployed the site to the (previously working) development environment running IIS 7.5. All of the CSS and JS files referencing the bundles returned 404 errors. I looked through the Web.config and verified that everything was correct. I put Event Log entries into the Global.asax and found that they were all adding as expected.

I did some digging through Google but the number of people adding Bundles to their Web Forms application is smaller than I had expected and didn't find to much (nothing useful). Not having setup the environments, I thought that would be a great place to investigate further.

Investigating the web site in inetmgr, yielded nothing out of place. I am not sure why I looked at the application pool, but I did, and noticed that the pipeline was set to Classic, so I tried changing it to Integrated (just trying something). When I refreshed the page, I received a 500 HTTP internal server error and no other information. There was no information in the Event Log and the debugger never caught any breakpoints.

I went back to inetmgr and I turned on logging, recreated the error, and looked at the log. I found that the status code was 500 and the sub-status was 22 (500.22). This was a key bit of information. Googling this code yielded gold. I found this site, ASP.NET 2.0 Breaking Changes on IIS 7.0, which contained the status code I was looking for. Below is the important section:
1. ASP.NET applications require migration when specifying configuration in <httpModules> or <httpHandlers>

You will receive a 500 - Internal Server Error. This can include HTTP Error 500.22, and HTTP Error 500.23: An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode. This occurs because ASP.NET modules and handlers should be specified in the IIS <handlers> and <modules> configuration sections in Integrated mode.

Workaround

A. You must migrate the application configuration to work properly in Integrated mode. You can migrate the application configuration with AppCmd:

> %windir%\system32\inetsrv\Appcmd migrate config "<ApplicationPath>"

B. You can migrate manually by moving the custom entries in in the <system.web>/<httpModules> and <system.web>/<httpHandlers> configuration manually to the <system.webServer>/<handlers> and <system.webServer>/<modules> configuration sections, and either removing the <httpHandlers> and <httpModules> configuration OR adding the following to your application’s web.config:

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>

I opted for the first part of B. The latter part may have been a little easier, but the first part seemed cleaner.

Refreshing the page allowed the bundles to be served up without issue. Apparently the Microsoft ASP.NET Web Optimization Framework requires the application pool to be in Integrated mode. That was a very weird error and obscure solution.

Tuesday, October 15, 2013

Reflections: Table Based Layout To Responsive Design Layout Conversion

I recently had the pleasure of converting a web application to a responsive design layout. The goal was to only change the structure of the HTML. I was able to stick to this with the exception of the Modal Popup Extender, but the changes were very minimal.

Considerations

  • Used the Modal Popup Extender
  • XHTML
  • CSS files, inline CSS styling, HTML style tags
  • Ridged table layout
  • All buttons are images

Expected Outcome

  • Use Bootstrap 2.3.x
  • HTML5
  • Responsive design layout
  • Must maintain support for IE8+ (potentially IE7)
  • Layout organization and text should be as close as possible to the original. Styles and structure implementation will be completely different.
  • Limit the code changes as much as possible.

The update process

The update process had a logical progression. Below I detail the highlights.


Update master page

I thought it was important to start with the master page; seemed logical. Below is the highlights on the things that I updated.

  1. Update the DocType
  2. Add meta tags
  3. Add new style tags to Bootstrap styles and place a ContentPlaceholder for styles after it
  4. Remove any tags which don't have 'runat="server"' or isn't a control. Leave the content.
  5. Put the content in the following div tag: <div class="container">
  6. Structure the header area
  7. Convert the menu bar/navigation section to the Bootstrap navbar
  8. Implement the design with Bootstrap design patterns/style
  9. Add Bootstrap scripts to the bottom of the page and place a ContentPlaceholder for scripts after it

The beginning of the page is the pretty boilerplate. I do as much as possible to promote other developers putting style code at the top of the page and the scripts at the bottom of the page. With Web Forms, this isn't always possible, but I try to stick to it when possible.

<!DOCTYPE  html>
<html lang="eng">
<head id="header" runat="server">
    <meta charset="utf-8" />
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
 <meta content="on" http-equiv="cleartype" />
 <meta content="True" name="HandheldFriendly" />
 <meta content="320" name="MobileOptimized" />
 <meta content="width=device-width, initial-scale=1" name="viewport" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <link rel="apple-touch-icon" href="iphon_tetris_icon.png"/>
    <link rel="apple-touch-startup-image" href="startup.png" />
 <title />
    <link rel="stylesheet" href="/Content/style.css" type="text/css" />
    <asp:ContentPlaceHolder ID="StylesPlaceHolder" runat="server" />

I put the following .snippet as close to the bottom of the page as possible.

<script src="/bundles/bootstrap.js"></script>
<asp:ContentPlaceHolder ID="ScriptPlaceHolder" runat="server" />

Update ASPX pages and User Controls

The process for updating the rest of the pages and user controls were pretty consistent.

  1. Remove any tags which don't have 'runat="server"' or isn't a control. Leave the content.
  2. Reimplement the design with Bootstrap design patterns/style
  3. Move any needed scripts specific for that page to the scripts placeholder

Updating Modals

These are in the ASPX pages and User controls, but I thought it deserved a separate section because the process is a bit more involved. It assumes that the above points have been completed on the modal sections.

There were 2 different processes for this.

  1. Modal which can be populated at page load
  2. Modal which must be populated with information from an item select from a grid view

Below is the general process for converting the modals.

  1. Remove the Modal Popup Extender tags and any dummy links tied to it.
  2. Implement the design with Bootstrap design patterns/style. Below is a template.
    <div class="modal fade" style="display: none" id="pDemo" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
     <div class="modal-dialog">
     <div class="modal-content">
      <div class="modal-header" style="vertical-align: middle">
       <asp:Button ID="Button3" class="close" data-dismiss="modal" aria-hidden="true" Text="×" runat="server" />
       <h4 class="modal-title">Header Text</h4>
      </div>
      <div class="modal-body form-horizontal">
       <!-- Modal Content -->
      </div>
      <div class="modal-footer">
       <div class="control-group">
       <div class="controls">
        <asp:Button ID="btnSave" CssClass="btn btn-success" Text="Save" OnClick="btnSave_Click" runat="server" />
        <asp:Button ID="btnClose" CssClass="btn" data-dismiss="modal" Text="Close" runat="server" />
       </div>
       </div>
      </div>
     </div>
     </div>
    </div>
    
  3. IF the data was already loaded at the page load, update the link like the following:
    <a data-toggle="modal" href="#pDemo">
    
    There can be other attributes in the link, but the "data-toggle" and the "href" are the important points.
  4. IF the data needs to be loaded, wrap the modal in an UpdatePanel and follow the pattern in my previous blog post Handling Twitter Bootstrap Modals and UpdatePanels with PostBacks. If you can get into the code more than I could, you could omit a bunch of JavaScript using the following link in your code behind:
    AjaxControlToolkit.ToolkitScriptManager.RegisterStartupScript(this, typeof(System.Web.UI.Page), "pDemo", "$('#pDemo').modal('show');", true);

There are other little things, but these were the most important parts.

All in all, I found the conversion to be very easy to implement and it gave the old page layout a new breath of life.

Thursday, October 3, 2013

XCode development with Team Foundation Server

Occasionally, I do work on multiple platforms and historically mixed development has been an issue when your environment requires TFS. However, with TFS supporting Git, it should make that development much easier. I just ran across a couple posts that with instructions on how to use TFS w/ XCode and thought I would share.

Microsoft has a page dedicated to making this happen: (UPDATE: 2016-05-05, Microsoft moved the page) https://www.visualstudio.com/get-started/code/share-your-code-in-tfvc-xcode http://tfs.visualstudio.com/en-us/learn/use-git-and-xcode-with-tfs.aspx . I don't have a Team Foundation Server at my disposal, but it looks like you should be able to do this with onsite Team Foundation servers.

In projects with .Net code and iOS (and/or potentially Android), it might be a good idea to keep the code in separate repositories. It appears that Team Foundation Server 2012 supports multiple Git repositories with a single TFS team project.

http://stackoverflow.com/questions/17591461/can-you-add-multiple-git-repositories-to-a-team-project-in-tfs-tfs-service
You can create multiple git repositories under a single Team Project. Navigate to the Code Explorer, and locate the repository chooser in the web interface and select Manage Repositories...

<repository chooser image>

From the repository manager, you can add a new repository:

<team Project Version Control tab image>

This, of course, is provided that the Team Project uses Git as the version control provider - you can't mix and match Git repositories and Team Foundation Version Control in a single Team Project.

If you have an existing project w/ TF source control, you are out of luck. You can't do multiple TF SC repositories or have a TF and Git repository, so the only option is Git for this.

It is nice to see Microsoft embracing an incredibly powerful tool like Git. Just need to be weary about them reverting back to the days of the 3 E's.

Tuesday, September 24, 2013

Trello Board Bing Wallpaper GreaseMonkey UserScript

I occasionally use Trello for maintaining tasks for projects. It helps me stay on task and estimate completion times better. The interface makes managing/creating/completing tasks very easy. It is a breath of fresh air for task management.

I thought it would be cool to see a different background everyday. So decided to use the Bing wallpaper rss feed to get me an amazing image every day.

The GreaseMonkey script below works in Firefox. I have tested it in Chrome (via TamperMonkey) and there are a couple issues. I will try to resolve them and update it here.

// ==UserScript==
// @name        Trello Board Canvas Bing Image
// @namespace   net.intellectualponderings.TrelloBoardCanvas
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_log
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @include     https://trello.com/b/*
// @version     1
// ==/UserScript==

GM_xmlhttpRequest({
    url: "http://feeds.feedburner.com/bingimages",
    dataType: "xml",
    //data: "",
    //type: "GET",
    method: "GET",
    //success: function (data){
    onload: function (responseObject){
        var data = responseObject.responseText;
        GM_log(data);
        var enclosures = $(data).find("enclosure"), // /rss/channel/item/enclosure[url]
            imgurl = $(enclosures[0]).attr('url'); //alert(imgurl);
        $(".board-canvas").css({ 
            'background': 'url(' + imgurl.replace("http://", 'https://') + ') no-repeat center center', 
            'background-size': '100%;'});
    },
    //Error: function (XMLHttpRequest, textStatus, errorThrown) {
    onerror: function () {
      // Same code as in my question...
    }
});

Thursday, September 19, 2013

Image Information For Filtered Files in Directory

Just a quick script that lists information about the PNG and JPG images in a directory. I wrapped the important parts in a Start/Stop Transcript so that all output is logged to a file. I needed to get a feel for the image sizes and resolutions uploaded by users in our production environment in order to make recommendations for updates to the system.

add-type -AssemblyName System.Drawing;
try { Start-Transcript ".\Get-ImageInformation-log.txt" -ErrorAction SilentlyContinue; } catch {}
gci "C:\Demo\Images\*" -Include @("*.png","*.jpg") | % {
    $img = New-Object System.Drawing.Bitmap $_.FullName;
    $obj = New-Object PSObject;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name Name -Value $_.Name;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name Length -Value $_.Length;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name Height -Value $img.Height;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name Width -Value $img.Width;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name HRes -Value $img.HorizontalResolution;
        Add-Member -InputObject $obj -MemberType NoteProperty -Name VRes -Value $img.VerticalResolution;
    [Void]$img.Dispose();
    $obj;
} | ft -AutoSize Name, @{n='Length';e={"{0:N2} KB" -f ($_.Length / 1Kb)};align='right'}, Height, Width, HRes, VRes;
try { Stop-Transcript -ErrorAction SilentlyContinue; } catch {}

Monday, September 16, 2013

Adding Bundles to ASP.NET 4.0 Web Applications

I recently encountered an opportunity while updating (rewriting the HTML) the UI on an existing application. Having worked on a a couple .Net 4.5/MVC 4 applications previously and learning the awesomeness of the .NET bundling functionality, I wanted to see if I could bring that functionality back into a .Net 4.0 Web Forms application. I hadn't heard of anyone doing it, but doesn't mean it can't happen.

I ran across a couple sites which lead me in the correct direction. They both target .Net 4.5. The Bundles and Minify CSS and Javascript in your ASP.Net Web Form Web Site post pointed me to the Microsoft ASP.NET Web Optimization Framework NuGet package. It didn't say that it required the .Net 4.5 framework so I added it to my project and it worked without issue.

using System.Web.Optimization;
public namespace SomeNS {
public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new StyleBundle("~/bundles/style.css").Include(
            "~/Content/bootstrap-cust.min.css",
            "~/Content/styles.css"));

        bundles.Add(new StyleBundle("~/bundles/kui.css").Include(
            "~/Content/styles/kendo.common.css",
            "~/Content/styles/kendo.default.css"));

        bundles.Add(new ScriptBundle("~/bundles/kui.js").Include(
                "~/Scripts/kendo.core.js",
                "~/Scripts/kendo.calendar.js",
                "~/Scripts/kendo.popup.js",
                "~/Scripts/kendo.datepicker.js",
                "~/Scripts/kendo.validator.js"));

        bundles.Add(new ScriptBundle("~/bundles/Common.js").Include(
            "~/Scripts/jquery-1.9.1.js",
            "~/Scripts/Common.js"));

        bundles.Add(new ScriptBundle("~/bundles/UserCommon.js").Include(
            "~/Secure/User/Scripts/Script.js",
            "~/Secure/User/Scripts/CustomValidation.js"));

        bundles.Add(new ScriptBundle("~/bundles/SysAdminCommon.js").Include(
            "~/Scripts/jquery-ui-1.8.17.custom.min.js"));

        bundles.Add(new ScriptBundle("~/bundles/bootstrap.js").Include(
            "~/Scripts/bootstrap-cust.js"));

        BundleTable.EnableOptimizations = true;
    }
}
}

With the NuGet package added to the project all of the functionality surrounding the CDN functionality is available.

Next add the following line to the Application_Start function in the Global.asax.

BundleConfig.RegisterBundles(BundleTable.Bundles);

The post says to use the following block to get the scripts to render. This doesn't work because Scripts/Styles do are not available.

<asp:PlaceHolder runat="server">
        <%: Scripts.Render("~/Scripts/jquery") %>
        <%: Styles.Render("~/Styles/css") %>
</asp:PlaceHolder>

This is not a show stopper; the functions merely generate standard HTML elements. The style bundles can be added to the application pages like the example below.

<link rel="stylesheet" href="/bundles/style.css" type="text/css" />

Similarly, the script bundles can be added to the application pages like the example below.

<script src="/bundles/bootstrap.js"></script>

Using Firebug/developer tools/fiddler, it is easy to see that the files are bundled and minified.