Thursday, November 28, 2013

Emulating Back and Forward On A Regular 2 Button Scroll Mouse

I have discovered just how much I depend on the back and forward buttons on my mouse. Working on a lot of different computers where I cannot control the hardware I am provided, but thankfully I can over come that by using AutoHotKey and adding the following script to the default script.

It is important to ensure the first line is in the script. If it is not there, you will not be able to use your right button for anything. Seems unintuitive, but that is how it is.
RButton::click right
RButton & WheelDown::Send {Browser_Back}  ; Left Arrow, Browser Back Button
RButton & WheelUp::Send {Browser_Forward}  ; Right Arrow, Browser Forward Button
Now I can navigate forward and backward by right clicking and scrolling.

Tuesday, November 19, 2013

Suppressing Compiler Warnings

Sometimes there are warnings that are necessary, but they can clog up your compiler output or MSBuild output. There is a simple way to turn off the ones that need to be there. Simply find the codes that should be suppressed by looking at the compiler output. For example, below is a warning from MSBuild (these can also be found in the Error List panel in Visual Studio).
c:\<path to file with the warning>\SomePage.aspx.cs(1196): warning CS0219: The variable 'SomeString' is assigned but its value is never used [C:\<path to build file>\Build.xml]
Then you surround the code that is generating the warning and surround it with #pragma warning tags like below. You can suppress multiple warnings like in the example below.
#pragma warning disable 0649
#pragma warning disable 0219

// Put your code here that will generate the warnings.  

#pragma warning restore 0219
#pragma warning restore 0649

Friday, November 8, 2013

MsBuild CodeTaskFactory Custom Task to Warming Up a Web App

I remember reading about the MSBuild CodeTaskFactory a couple years ago and hadn't run into a situation where I needed it until now. CodeTaskFactory is a great way to extend MSBuild's capabilities without having to go through the hassle of creating a custom MSBuild Task and having to make sure everyone has the dll.
<UsingTask TaskName="TestWebAppAvailable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
  <ParameterGroup>
    <hostname ParameterType="System.String" Required="true" />
    <servers ParameterType="System.String[]" Required="true" />
    <Result ParameterType="System.String" Output="true" />
    <!--<TestSuccess ParameterType="System.Boolean" Output="true" />-->
  </ParameterGroup>
  <Task>
    <!--<Reference Include="System.Xml"/>-->
    <Reference Include="System.IO"/>
    <Reference Include="System.Net"/>
    <Using Namespace="System"/>
    <Using Namespace="System.IO"/>
    <Using Namespace="System.Net"/>
    <Code Type="Fragment" Language="cs">
      <![CDATA[
string requestUrl = "http://" + hostname + "/Default.aspx";
Result = "success";
foreach (string server in servers)
{
    Log.LogMessage("Server: " + server, MessageImportance.Normal);
    if (string.IsNullOrEmpty(server))
    {
        continue;
    }
    Log.LogMessage("Warming up: " + requestUrl, MessageImportance.Normal);
    System.Net.HttpWebResponse res = null;
    try
    {
        System.Net.WebRequest wr = System.Net.WebRequest.Create(requestUrl);
        wr.Timeout = 20000;
        wr.Proxy = new System.Net.WebProxy("http://" + server, false);
        res = (HttpWebResponse)wr.GetResponse();
        Log.LogMessage(server + " - " + res.StatusCode, MessageImportance.Normal);
    }
    catch (System.Net.WebException ex)
    {
        res = (HttpWebResponse)ex.Response;
        Log.LogMessage("EXCEPTION: " + ex.ToString(), MessageImportance.High);
        Log.LogMessage("res == null: " + (res == null).ToString(), MessageImportance.High);
        Log.LogMessage("Server: " + server, MessageImportance.High);
        Log.LogMessage("res.StatusCode: " + (res != null ? res.StatusCode.ToString() : "Res was null"), MessageImportance.High);
    }
    catch (System.Exception ex) {
        throw;
    }
    Log.LogMessage("res == null: " + (res == null).ToString(), MessageImportance.High);
    if (res.StatusCode != System.Net.HttpStatusCode.OK)
    {
        string message = server + " Web request failed with code: " + res.StatusCode.ToString();
        System.Net.WebException exception = new System.Net.WebException(message);
        if (res != null)
        {
            res.Close();
        }
        Result = server;
        Log.LogMessage("EXCEPTION: " + message, MessageImportance.High);
        break;
    }
    
    if (res != null)
    {
        res.Close();
    }
}
]]>
    </Code>
  </Task>
</UsingTask>
Basically this takes in a host header for the hostname and a list of servers. It then iterates over the servers and requests the Default.aspx page. A successful request returns "success". A request that returns a status code that is not 200 returns the server name that failed.

Then using the new custom task is as easy as the following:
<ItemGroup>
  <Servers Include="$(DeploymentWebServer1)"></Servers>
  <Servers Include="$(DeploymentWebServer2)"></Servers>
</ItemGroup>
<TestWebAppAvailable hostname="$(DeploymentHostname)" servers="@(Servers)" ContinueOnError="True">
  <Output TaskParameter="Result" PropertyName="TestResult" />
</TestWebAppAvailable>
<Error Text="Server $(TestResult) returned a bad response.  Recopy web application files." Condition="'$(TestResult)' != 'success'" />

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.

Tuesday, September 10, 2013

Branching Current Changes Into New TFS Branch

Every once in a while I find myself in the middle of a change and think that the changes I am making need to be pushed into a new branch. Being in an evironment using TFS as the source control system, that kind of flexibility is not something I generally think of in the scope of TFS.

From a Stack Overflow question, I was able to get a start. The most important line was the TFPT line. It appeared the task at hand was achievable.

1. You need to include the new branch in your workspace in order to see any changes (otherwise you'll only see the checked-in versions). From Source Control Explorer, select Workspace->Workspaces... from the toolbar.
2. Select Edit for your workspace and add a mapping to your new branch, e.g. Active|$/Root/MyProject-Branch|<my Local TFS Storage>\MyProject-Branch
3 .Run the command tfpt unshelve <shelveset> /migrate /source:$/Root/MyProject /target:$/Root/MyProject-Branch. It should create a new shelveset with mappings changed to your new branch.
4 .Try unshelving the new, migrated shelveset onto your new branch.

This wasn't very clear, so I continued my search. I found Brian Franklin's post was far more detailed and gave a better picture of what needed to happen.

1. Shelve the pending changes.
2. Create a new Dev branch with the latest changes and perform a Get on the branch.
3. Start Visual Studio Command Prompt.
4. Set the path to the folder the new branch is mapped to.
5. Execute tfpt unshelve command supplying the following arguments:
1. Shelveset name
2. Source server path
3. Target server path
4. Migrate
5. No Backup

In the process of going through his steps, which was easy enough, I ran into a peculiar error.

TFPT.EXE unshelve bundles /migrate /source:"$/<TFS project path>/branches/Feature1Rewrite" /target:"$/<TFS project path>/branches/Feature1RewriteExploritory"
An item with the same key has already been added.

Googling yielded no fruitful paths forward. And after some thought, it occurred to me that I might need to check in my branch before migrating my shelf to the new target. After checking in my branch and retrying, the did not occur.

It may be pertinent to note that when I create branches in this environment, I receive an error saying that I don't have permission to create a branch. However, the branch is created and everything seems to work.

TL;DR:

Make sure you check in your branch before running the command.

Wednesday, September 4, 2013

Handling Twitter Bootstrap Modals and UpdatePanels with PostBacks

In the process of updating a web application from an extremely rigid design to a responsive design using the Twitter Bootstrap framework. The goal is to keep the changes to the application to the HTML layout as possible. There are some situations where server side code can be removed or updated for display purposes.

This works great until you have situations which are more complicated like Bootstrap modal dialogs which need to display after a UpdatePanels and UpdatePanels which need to update in modal dialogs.

Searching the internet did not provide very fruitful results. Some involved registering script blocks, but I was not able to get them to work. This was not my preferred implementation because it deviated from my initial goal, but I was looking for solutions.

I remembered that I could execute code on an UpdatePanel PostBack and that led me to the following solution. I think there should be a better way to handle it, but it will do for a first pass. In my situation, I had a master page with a script tag using the PageRequestManager like the example below. I added the highlighted lines to call a function (RequestCallback) if it had been declared.

var prm = Sys.WebForms.PageRequestManager.getInstance();

prm.add_initializeRequest(initializeRequest);
prm.add_endRequest(endRequest);

function initializeRequest(sender, args) {
    if (prm.get_isInAsyncPostBack()) {
        args.set_cancel(true);
    }
}

function endRequest(sender, args) {
    ToggleProgressMsg('Please Wait While Your Content Loads...');
    if (RequestCallback) {
        RequestCallback(sender, args);
    }
}

Now we can declare the RequestCallback function on any page to execute when a call back occurs. This leaves us in an situation where we need to know what panel was updating or what control initiated the request. I found the following variable referenced in several places on the web.

sender._postBackSettings.panelID

I found that in several situations, this variable is not reliable. I found that the following variable was always what I expected.

sender._postBackSettings.asyncTarget

In a situation where a grid needs to populate fields on a modal dialog and display the dialog. The grid and modal dialogs were already wrapped in an UpdatePanel so I can leverage the RequestCallback function to clean up the backdrop (the modal closes, but leaves the backdrop) and then open or reopen the dialog based on the control that executed the request.

function RequestCallback(sender, args) {
    var editLink = "lnkEditCar",
        altAddr = "lnkbtnAlternativeAddress",
        trigger = sender ? sender._postBackSettings.asyncTarget : "";

    console.log("RequestCallback", sender, args, trigger, "END");
    
    // Clean up the backdrop
    $('body').removeClass('modal-open');
    $('.modal-backdrop').remove();
    
    // Handle Alternate Address request callback
    if (trigger.indexOf(altAddr, trigger.length - altAddr.length) !== -1) {
        console.log('Reopening Dialog', altAddr);
        $('#pManageCar').modal();
    }
    // Handle Edit Card request callback
    if ($('span[id$="tabpCars_tab"]').hasClass("ajax__tab_active") && trigger.indexOf(editLink , trigger.length - editLink .length) !== -1) {
        console.log("tabpCars_tab");
        $('#pManageCars').modal('show');
    } else if ($('span[id$="tabpTrucks_tab"]').hasClass("ajax__tab_active") && trigger.indexOf(up, trigger.length - up.length) !== -1) {
        console.log("tabpTrucks_tab");
        $('#pManageTrucks').modal('show');
    }
}

The result is that the modal behaves pretty much as expected. I am sure I will revisit this code, but that is how refactoring works.

Wednesday, August 28, 2013

Strip Time From Date and Last Moment in SQL

Pretty simple SQL statement that strips the time off of a date and gets the last moment of today.

SELECT 
    DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
  , DATEADD(ms, -100, DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()) + 1))

Tuesday, August 20, 2013

SQL Server Table Space Used

I recently found a bit of SQL that I haven't run across in a while and thought I would share. From time to time I need to know the space used by large tables. In tables that require millions of records, it can be useful. Below is the SQL script that I use to get the space used by each table and the total number of rows in the database.

DECLARE @t TABLE
(
    [name] NVARCHAR(128),
    [rows] int,
    reserved VARCHAR(18),
    data VARCHAR(18),
    index_size VARCHAR(18),
    unused VARCHAR(18)
)

INSERT @t EXEC sp_msForEachTable 'EXEC sp_spaceused ''?'''

SELECT *
FROM   @t

-- # of rows.
SELECT SUM([rows]) AS [rows]
FROM   @t

Thursday, August 8, 2013

Chocolatey Goodness and Environment Setup

I have been using Chocolatey (apt-get for Windows) - get it, use it, love it - for many months now and absolutely love the project. I think there are things that could be improved, but from a just do it approach, it works perfectly. I recently acquired a new laptop and what better way to get it setup than to create a reusable script.

First install Chocolatey from the Command Prompt. You can copy the script block below and paste it into the prompt and let it install.

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin

Now I have Chocolatey installed, I need to get a list of the applications that need to be installed. My list is pretty short compared to other bloggers on the net, but my list grows over time.

cinst git
#cinst ruby  # I uncomment this if I want ruby installed
#cinst ruby.devkit  # I uncomment this if I want ruby installed
cinst nodejs.install
cinst notepad2
cinst sublimetext2
cinst SublimeText2.PackageControl
cinst EthanBrown.SublimeText2.GitPackages
cinst PowerGUI
cinst FoxitReader
cinst ilspy
cinst linqpad4
cinst sysinternals
cinst SkyDrive
cinst paint.net
cinst 7zip
cinst virtualbox
cinst Firefox
cinst GoogleChrome
cinst fiddler4
#cinst fiddler
cinst lastpass
cinst Devbox-Clink

I also have some general setup that I like to automate which I run after the applications are installed. Eg. Mounting network drives, make the window border width smaller (it is incredibly thick, by default), and fixing an issue that prevents Netflix from playing videos.

Below is the full script

# @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin
cinst git
#cinst ruby  # I uncomment this if I want ruby installed
#cinst ruby.devkit  # I uncomment this if I want ruby installed
cinst nodejs.install
cinst notepad2
cinst sublimetext2
cinst SublimeText2.PackageControl
cinst EthanBrown.SublimeText2.GitPackages
cinst PowerGUI
cinst FoxitReader
cinst ilspy
cinst linqpad4
cinst sysinternals
cinst SkyDrive
cinst paint.net
cinst 7zip
cinst virtualbox
cinst Firefox
cinst GoogleChrome
cinst fiddler4
#cinst fiddler
cinst lastpass
cinst Devbox-Clink

cmd /C net use N: \\srv1\Common /Persistent:Yes
cmd /C net use G: \\srv1\GIT /Persistent:Yes

# Windows 8 Smaller Chrome Border
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop\WindowMetrics" BorderWidth "-4"

# Fix for Netflix audio issue
Remove-Item -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Audio -Name DisableProtectedAudioDG
net stop audiosrv;
net start audiosrv;

write-host @"
Sublime Text 2 User Preferences file

{
    "color_scheme": "Packages/Theme - Flatland/Flatland Monokai.tmTheme",
    "draw_white_space": "all",
    "ensure_newline_at_eof_on_save": true,
    "flatland_square_tabs": true,
    "ignored_packages":
    [
        "Vintage"
    ],
    "rulers":
    [
        50,
        72,
        80,
        120
    ],
    "theme": "Flatland Dark.sublime-theme",
    "translate_tabs_to_spaces": true,
    "trim_trailing_white_space_on_save": true
}
"@

Thursday, July 25, 2013

Powershell Script to Periodically Monitor a Web Page, Parse, and Notify

Since Apple's developer portals have been down for a while, I got tired of checking the website. I created a script that I will hourly check Apple's System Status page, parse and see if the iOS Developer Center is back online. If it is online, it will send an email to me letting me know and remove the scheduled task. The code could be repurposed to look for the other things in the html if needed.

First the scheduled task needs to be created, it requires a PowerShell console in Administrator mode.

$dailyTrigger = New-JobTrigger -RepetitionInterval (New-TimeSpan -Hours 1) -RepetitionDuration (New-TimeSpan -Days 7) -At "11:00 AM" -Once # -At 
$option = New-ScheduledJobOption -StartIfOnBattery –StartIfIdle
Register-ScheduledJob -Name PingAppleSystemStatus -ScriptBlock `
{ powershell -command C:\\PingAppleSystemStatus.ps1 } -Trigger $dailyTrigger -ScheduledJobOption $option
The code below requires a little setup.
  • Set the SMTP Server
  • Change the 2 instances of someone@mail.com
function Send-Email([string] $From, $To, [string] $Subject, [string] $Body, $AttachmentPaths = $null, [bool] $IsImportant = $FALSE) {
 $msg = new-object Net.Mail.MailMessage;
 $smtp = new-object Net.Mail.SmtpClient("yoursmtpserver.com");
 $atts = @();
 $msg.From = $From;
 $To | % { $msg.To.Add($_); }
 $msg.Subject = $Subject;
 $msg.Body = $Body;
 if ($AttachmentPaths -ne $null) {
  $AttachmentPaths | % {
   $att = new-object Net.Mail.Attachment($_);
   $msg.Attachments.Add($att);
   $atts += $att;
  }
 }
 if ($IsImportant) {
  $msg.Priority = [System.Net.Mail.MailPriority] "High";
 }
 $smtp.Send($msg);

 $atts | % { $_.Dispose(); }
 $msg.Dispose();
}

$url = 'https://developer.apple.com/support/system-status/';
$result = Invoke-WebRequest $url;
$foundElement = $result.AllElements | 
    Where Class -eq "online" | 
    Where innerText -eq "iOS Dev Center" | 
    Select -ExpandProperty innerText;

if ($foundElement) {
 Write-Host "$([DateTime]::Now) - iOS Dev Center LIVE";
 Send-Email "Me <someone@mail.com>" @("<someone@mail.com>") "$([DateTime]::Now) - iOS Dev Center LIVE" "$([DateTime]::Now) - iOS Dev Center LIVE" $null $TRUE;
 Unregister-ScheduledJob  -Name PingAppleSystemStatus
} else {
 Write-Host "$([DateTime]::Now) - iOS Dev Center Offline";
}

Saturday, July 13, 2013

NodeJS Sublime Text Auto Start Debugger On Build

A quick awesome note. When developing in NodeJs, it is rather nice to have the nodejs automatically start again. This simple little change to helped with debugging in Sublime Text.

Edit the following file:
C:\Users\Brock\AppData\Roaming\Sublime Text 2\Packages\Nodejs\Nodejs.sublime-build
I'll leave it to the read to find it on linux.

Merge the following code into the file:
{
"cmd": ["node --debug", "$file"],
"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
"selector": "source.js",
"shell":true,
"encoding": "cp1252",
"windows":
{
"cmd": ["taskkill /F /IM node.exe & node --debug", "$file"]
},
"linux":
{
"cmd": ["killall node; node", "$file"]
}
}
Now every time you build, it will restart the node process with debugging enabled.

Tuesday, May 14, 2013

MVC4 NULL Action Form Binding Parameter

Suppose that you are creating a new POST action like the following:
[Authorize(Roles="Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(DailyTotal total)
It would be reasonable to expect that a form posting all the correct values to create a new fully hydrated DailyTotal object, but that would be incorrect; you get a total parameter set to "null". The fix is mind numbingly simple, the variable must be the entity name in all lowercase characters.

The below example given the same POSTed data will produce a fully hydrated object.
[Authorize(Roles="Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(DailyTotal dailytotal)

Thursday, April 25, 2013

Accessing a Network Share in OSX

It is not obvious how to access network drives in OSX. Thankfully knowing a little Linux goes a long way. My main need for this was to create a way to access a shared Git repository on a network share.
cd /Volumes
mkdir netshare
mount -t smbfs //username@server/netshare netshare
This can be condensed to just one line.
mkdir /Volumes/netshare && mount -t smbfs //username@server/netshare /Volumes/netshare
If the network share requires authentication, a password prompt will appear.

In good fashion it is good to know how to undo what you did; here is the unmout command.
umount netshare
rm -r /Volumes/netshare

Tuesday, March 26, 2013

Create Remote Git Repository From Existing Local Repository

I ran across a situation where I needed source control in the absence of a TFS. So off to my favorite DVCS, Git. It worked great except I want to have a backup off of my computer. I know that Git can have remote repositories and I know how to pull from them, however I had never had to create a new remote repository on a network share from the a local repository. Below how I did it...

First, create the directory where the new repositorty will be created, then create a bare Git repository.
$ cd /n/Home
$ mkdir Demo.git
$ cd Demo.git/
$ git init --bare
Initialized empty Git repository in n:/Home/Demo.git/
Then change back to the local repository location and add a remote repository to your local repository. I'll name mine backup, you might want to name it origin if you don't have any remote repositories yet or potentially something more descriptive if you already have an origin remote repository.
$ cd /c/TFS/Demo/
$ git remote add backup /n/Home/Demo.git/
Lets check to see that the backup remote was added to the local repository.
$ git remote
backup
Now, push your branch to the backup remote repository.
$ git push backup master
Counting objects: 390, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (378/378), done.
Writing objects: 100% (390/390), 4.56 MiB | 4.87 MiB/s, done.
Total 390 (delta 255), reused 0 (delta 0)
To n:/Home/Demo.git
 * [new branch]      master -> master
The output will be a bit different every time, but the end result is the same... the files have been pushed to the remote repository.

Thursday, March 21, 2013

Lock Your OSX Computer

Fun tip. It is not obvious how to lock an OSX computer without logging off. After some searching a ran across a Gist which suspends the current session. This is equivalent to locking (Win+L) a Windows computer.
    #!/bin/bash
    /System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend
If you save that into a file, you can make it executable by running:
    $ chmod 755 lock
This works great since I always have a terminal window open. Presuming the file is accessible via the path. I can just run the following and it locks the Mac.
    $ lock

Wednesday, March 13, 2013

Fixing ActiveAdmin Exception "undefined method `humanize' for nil:NilClass"

I am working on a Ruby on Rails project at the moment and ran across an interesting issue in ActiveAdmin. When I attempt to show an entity by id in a ActiveAdmin.register file, I would receive an error:

NoMethodError in MyEntity#show

undefined method `humanize' for nil:NilClass

I was lucky enough to get an Application Trace telling me the line to look at:

row(_nil) { "#{MyEntity.education_from_date} - #{MyEntity.education_thru_date}"}

Note: The formatting javascript removes the parameter "nil". Assume "_nil" is "nil".

Digging into to the database I discovered that the properties in the database were null, so I figured perhaps that was the issue (shouldn't be, but verifying this would be easy). I populated the fields, but the exception remained.

After some additional pondering, I looked at the nil parameter. There were other occurrences of this following that line, so I didn't think this would be fruitful. With a lack of other possible solutions, I pursued this farther. The row was supposed to not display a label, but just display the value. My first attempt was to change nil to "", but the exception remained. Not to be deterred, I attempted " " and that fixed my issue.

row(" ") { "#{MyEntity.education_from_date} - #{MyEntity.education_thru_date}"}