Coalesce operator basic example

There was some null checks for trimming that were added in our codebase like this:

if (model.SearchEmail != null)
    model.SearchEmail = model.SearchEmail.Trim();

A tiny bit “easier”* alternative would be to use the coerce operator:

model.SearchEmail = (model.SearchEmail ?? String.Empty).Trim();

It is a little less typing and a single line. I think it is still pretty obvious what you are trying to do, so if you like it, use it.

If you don’t already know about coalesce, it is basically “if the value is null, use this other value”. So in the above, if model.SearchEmail is null, then use String.Empty. Then, trimming String.Empty would return null. But, if model.SearchEmail has a value, it gets trimmed and everything works as expected.

If you are interested in more examples/info, check out this StackOverflow Q&A.

* I say “easier” because it is my preference for terse yet understandable code. It may not be your preference, and that is cool

WebAPI – Y U NO DELETE?!!

37098508

Ok, silliness aside, WTF? At first I thought I was going insane. After wasting about 20 minutes thinking it was my fault, I realized it had to be something else. Well, it turns out that, by default, IIS Express doesn’t handle PUT and DELETE. So it isn’t a WebAPI thing, it is an IIS Express thing, but it isn’t immediately obvious what the problem is.

A little googling, a little reading, and I stumbled upon this post that explains how to update IIS Express (as well as IIS proper):

  1. Open the IIS Express config file (located at C:\Users\\Documents\IISExpress\config\applicationhost.config)
  2. Find the key “ExtensionlessUrl-Integrated-4.0”
  3. Add PUT and DELETE to the “verb”
<add name="ExtensionlessUrl-Integrated-4.0" 
     path="*." 
     verb="GET,HEAD,POST,DEBUG,PUT,DELETE" 
     type="System.Web.Handlers.TransferRequestHandler" 
     preCondition="integratedMode,runtimeVersionv4.0" />

Shortcodes in widgets

I just switched to this new theme, and I wanted to transfer over the customizations I made to the last theme. I was a WordPress n00b when I started the blog, and I did not initially use widgets. To transfer all my customizations over, I knew widgets would be the way to do it.

I have the Last.fm plugin, and I made mods to my sidebar.php file to include it before. All I needed to do this time was put the shortcode in a text widget, right? WRONG! I knew there had to be a way.

A quick google revealed this post on using shortcodes in widgets. It turns out it is super-simple, but does require editing the functions.php file. You simply add the following:

add_filter('widget_text', 'do_shortcode');

MSBuild and VisualStudioVersion

Lately I have built up our deployment scripts to get them to be a bit more bullet-proof. I have also been creating some new web-based tooling to automate other tasks. I recently created a new web-tool using MVC 4, WebAPI and WCF. I needed to deploy to our test server, and I realized that I did not have MVC 4 and .NET 4.5 installed.

Then it dawned on me – this tool would probably go on our www server too, and that runs Server 2003 – so no .NET 4.5.

I changed up the projects no problem, but it wasn’t that simple. When I built, I ran into an error regarding the version of Microsoft.WebApplication.targets being used. I started digging in the csproj, and I found this bit:

<PropertyGroup>
  <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">
    10.0
  </VisualStudioVersion>
  <VSToolsPath Condition="'$(VSToolsPath)' == ''">
    $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\
      v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\
  WebApplications\Microsoft.WebApplication.targets"
  Condition="'$(VSToolsPath)' != ''" />

I banged my head a bit because, from the looks of it, the version is explicitly set to 10.0, but my error kept referencing 11.0? What gives?!? Then I found this post. The important piece for me was this:

To simplify this statement, the .sln file will build with specifying VisualStudioVersion to the value of the version of VS which created the .sln file.

I made the switch to VS 2012 a few months ago, and my co-worker and I were just talking about SLN files and some showing the “10” icon while others showed the “11”. I told him, “I am not sure why that is? But I do know that there is version-specific details in the SLN.” Isn’t it funny how the timing on some things can be so uncanny?

So, the workaround referenced within that post was the solution I needed:

msbuild.exe Web.csproj /p:VisualStudioVersion=10.0

All fixed!

Trolliminator!

I am a big soccer fan, and I love my MLS. I frequent the site and read up on all the articles. Unfortunately, there are a few faces that are always trolling in the comments. I really don’t even care to read what they have to say, as it doesn’t contribute to the discussion. I decided I’d do something about it.

Trolliminator!

Introducing the Trolliminator! bookmarklet.

javascript: (function () {
  var trolls = [
		'troll', // <-- add troll names here
	];
 
    var el = document.createElement('div'),
        b = document.getElementsByTagName('body')[0];
    otherlib = false, msg = '';
    el.style.position = 'fixed';
    el.style.height = '32px';
    el.style.width = '220px';
    el.style.marginLeft = '-110px';
    el.style.top = '0';
    el.style.left = '50%';
    el.style.padding = '5px 10px 5px 10px';
    el.style.zIndex = 1001;
    el.style.fontSize = '12px';
    el.style.color = '#222';
    el.style.backgroundColor = '#f99';
    if (typeof jQuery != 'undefined') {
        msg = 'This page already using jQuery v' + jQuery.fn.jquery;
        return showMsg();
    } else if (typeof $ == 'function') {
        otherlib = true;
    }
    function getScript(url, success) {
        var script = document.createElement('script');
        script.src = url;
        var head = document.getElementsByTagName('head')[0],
            done = false;
        script.onload = script.onreadystatechange = function () {
            if (!done && (!this.readyState || this.readyState == 'loaded' 
|| this.readyState == 'complete')) {
                done = true;
                success();
            }
        };
        head.appendChild(script);
    }
    getScript('http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js', 
function () {
        if (typeof jQuery == 'undefined') {
            msg = 'Sorry, but jQuery wasn\'t able to load';
        } else {
            msg = 'This page is now jQuerified with v' + jQuery.fn.jquery;
            if (otherlib) {
                msg += ' and noConflict(). Use $jq(), not $().';
            }
        }
        return showMsg();
    });
 
    function showMsg() {
        el.innerHTML = msg;
        b.appendChild(el);
        window.setTimeout(function () {
            if (typeof jQuery == 'undefined') {
                b.removeChild(el);
            } else {
                jQuery(el).fadeOut('slow', function () {
                    jQuery(this).remove();
                });
                if (otherlib) {
                    $jq = jQuery.noConflict();
                }
                trolliminator();
            }
        }, 2500);
    }
 
    function trolliminator() {
    	var $ = jQuery;
    	var matchCounter = 0;
    	$.each(trolls, function(index, value) {
    		$('.gig-comments-comment-username').filter(function() {
    			var match = $(this).text() == value;
    			if (match) {
    				var table = $(this).closest('table');
    				table.hide();
    				table.parent().append(
$('<div>').css({ 'color':'#666', 'font-style':'italic' })
.html('Trolliminated!'));
    				matchCounter++;
    				return match;
    			}
    		});
    	});
    	$('<div>').css({ 
'position':'fixed', 'right':'0', 'bottom':'0', 
'padding':'5px', 'font-weight':'bold', 
'color':'#090', 'z-index':'99999' })
.html(matchCounter + ' trolls eliminated').appendTo('body');
    }
})();

To use it:

  1. Edit the “trolls” using comma-separated, single-quoted names
  2. Save it as a bookmarklet
  3. Hit it up prior to reading any article

It removes posts for matching “trolls” and replaces them with a “Trolliminated!” message. It also puts a counter down in the bottom-right corner. I started to develop a Chrome extension, but I ran into a little trouble and, to be honest, I did not want to put much effort into blocking the trolls – that is just another way they are fed.
πŸ™‚

MLSSoccer.com uses Gigya, so this should technically work with any other site that uses Gigya comments.

Cool CSS gradient text effect in Webkit

.textfade {
  background: 
    -webkit-gradient(linear,left top,right top,from(#0060F3),to(#00339A));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

“Borrowed” from Polygon

This makes some pretty cool gradient-filled text!

* If you aren’t using a Webkit browser, then the above is an image to show you what you are missing

Here Be Dragons

Probably just as interesting was the hoops I had to jump through to get something to show up to illustrate how it looks in Webkit browsers for non-Webkit browsers. Only an image would do, so I needed to do some CSS trickery. First, the Firefox-only CSS:

@-moz-document url-prefix() {
  .textfade {
    background: url(/wp-content/uploads/2013/03/gradient-text.png) 
      left top no-repeat;
    width: 590px;
    height: 27px;
    text-indent: -99999em;
  }
  q { display: none; }
}

The Firefox-only CSS was made easy by the Firefox-specific plugin syntax.

Now, for the IE-specific stuff:

<!--[if IE]>
<script>document.documentElement.className='ie10';</script>
<![endif]-->
<script>
if(Function('/*@cc_on return 10===document.documentMode@*/')()){
  document.documentElement.className='ie10';
}
</script>
.ie10 .textfade {
  background: url(/wp-content/uploads/2013/03/gradient-text.png) 
    left top no-repeat;
  width: 590px;
  height: 27px;
  text-indent: -99999em;
}
.ie10 q { display: none; }

The IE stuff was (as expected) much more difficult. Conditional comments make most of it easy, but with IE 10 not supporting them, that made it tricky. So, you need to perform a little js check and attach a classname tot he document as a nice work-around. I decided to use this same thing in the conditional comments too, that way I only needed to make 1 CSS change for all IE browsers.

Since IE forced me into using js to do the conditional comments checking, I really could have just went full-js and it probably would have been easier. I thought this was interesting, however, and I was striving for a strictly CSS solution. Alas, IE comes along to screw things up (as usual) and I was unable to create the solution I was looking for. The tricks are still cool.
πŸ™‚

Telerik MVC sorcery!

Ok, maybe that is totally link-bait, but I did do some semi-cool stuff with Terlerik MVC in the NopCommerce admin.

I reworked the entire order edit page, including adding knockout.js to wire up all the total and tax calculations – something I think should have been automatic within the admin, but I digress…

I setup an event consumer to tap in to add/edit/deletes or OrderProductVariant entities. I did not want the extra traffic of updating the OrderNote grid every time something happened with an order item, so I decided that I’d refresh the grid whenever the user selected the order notes tab. But how to do this? I found these two helpful links in the Telerik forums:

With these two posts I was given all the info I needed. I could tap into the tab select client event, then perform an ajax request for the order note grid.

Massive

I finally had a good situation to use Massive, so I took it.

I was working on some functionality of a web service, and I needed to refactor some data access code. We were using SubSonic, and that is great and simple (typically), but this data access code is in a library, so changing meant opening up the project, making changes, building, pulling the new DLL over, etc. Not a huge amount of work, but too much work for a web service that is basically working with a single table.

There was minor learning curve, but Massive is pretty darned simple. It was mostly my mistakes in not paying attention, or old ASP classic-style blunders like using the wrong name for the column. Overall, it was a lot of fun.

My favorite bit was when I needed to get a SUM and a GROUP BY. If I were using EF or SubSonic, I may have struggled a bit with the proper LINQ syntax to do this (I need to increase my LINQ-FU skills, they are not strong), but with Massive I simply… wrote SQL… GASP!

I made a custom object with the 2 properties I needed, and then I looped over the returned values, pushed ’em into a list and returned it as an array. Here is the code:

[WebMethod, SoapHeader("Authorization")]
public DownloadDetail[] GetOrderDownloadCounts(object orderId, 
                                               object profileId) {
    var list = new List<DownloadDetail>();

    dynamic table = new DownloadAuthorization();
    object[] queryargs = { orderId, profileId };
    var auths = table.Query(@"SELECT Id, SUM(DownloadCount) AS Total
FROM Downloads
WHERE TagString=@0 AND ProfileID=@1
GROUP BY Id", queryargs);
    foreach (dynamic auth in auths) {
        list.Add(new DownloadDetail { Id= auth.Id, 
                                      DownloadCount = auth.Total });
    }

    return list.ToArray();
}

I am thinking I could have done some sort of LINQ-y extension to eliminate the foreach loop, but maybe not? I don’t really know much (read: anything) about dynamic, so maybe it would not work? Not really sure. I guess I am showing my Intellisense crutch dependency here.
πŸ™

Restrict form access and set a hidden input

There was a question I just ran across on Stack Overflow asking how to set a hidden input with js, and also to restrict access to one form from another. Setting the hidden input value is pretty simple, and I figured this would be a breeze. Overall it was, but I scrapped the guys code and rewrote it from scratch. It was easier for me to do that than to figure out his code. I wanted to share what I did here:

It isn’t the most robust thing, but it works. Once you select one answer on form A or B, you have to select only from that form. Annoying alerts are used, but it is just a prototype – the real deal would need to be much slicker.

I added simple validation; if there aren’t 3 checked radio buttons the form is not complete. Also, the validation triggers the submit button enable, so it’s a two-fer
πŸ™‚

Here is the code (in case jsFiddle ever blows up):

<h2>Table A</h2>
<table id="tableA" border="1">
    <tr>
        <td>
            A1
        </td>
        <td>
            <input type="radio" name="a1" value="1" /> Yes
            <input type="radio" name="a1" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            A2
        </td>
        <td>
            <input type="radio" name="a2" value="1" /> Yes
            <input type="radio" name="a2" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            A3
        </td>
        <td>
            <input type="radio" name="a3" value="1" /> Yes
            <input type="radio" name="a3" value="0" /> No
        </td>
    </tr>
</table>

<h2>Table B</h2>
<table id="tableB" border="1">
    <tr>
        <td>
            B1
        </td>
        <td>
            <input type="radio" name="b1" value="1" /> Yes
            <input type="radio" name="b1" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            B2
        </td>
        <td>
            <input type="radio" name="b2" value="1" /> Yes
            <input type="radio" name="b2" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            B3
        </td>
        <td>
            <input type="radio" name="b3" value="1" /> Yes
            <input type="radio" name="b3" value="0" /> No
        </td>
    </tr>
</table>

<p>
    <button id="submit">Submit</button>
    <button id="reset">Reset</button>
</p>

<input type="hidden" id="activeTable" />
​
window.ns = {};
ns.activeTable = null;
ns.validate = function() {
    // Simple validation
    // If we don't have 3 checked radio buttons, it is invalid
    var checked = $("#" + ns.activeTable).find("input[type=radio]:checked");
    var valid = (checked || []).length === 3;
    $("#submit").prop("disabled", !valid);
    return valid;
};

ns.validate();

$("#submit").click(function() {
    var valid = ns.validate;
    if (valid == false) {
        alert("You must complete the form!");
        return;
    }
    
    var results = $("#" + ns.activeTable).find("input[type=radio]:checked");
    var output = ns.activeTable + " Results\n";
    $.each(results, function(idx, data) {
        output += "\t" + $(this).prop("name") + 
            " - " + $(this).val() + "\n";
    });
    alert(output);
    $("#activeTable").val(ns.activeTable);
});

$("#reset").click(function() {
    $("input[type=radio]").prop("checked", false);
    ns.activeTable = null;
    ns.validate();
});

$("input[type=radio]").click(function() {
    var selectedTable = $(this).closest("table");
    if (ns.activeTable != null && 
        selectedTable.prop("id") != ns.activeTable) {
        alert("Invalid form selection. Onlye selections from " + 
              ns.activeTable + " are allowed");
        $(this).prop("checked", false);
    } else {
        ns.activeTable = selectedTable.prop("id");
    }
    ns.validate();
});​
html { margin: 10px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
table td { border: 3px solid #CCC; padding: 5px; }
table td:nth-child(1) { width: 75%; }
table td:nth-child(2) { text-align: center; }
h2 { font-size: 1.8em; font-weight; bold }
button { padding: 5px; border-radius: 15px; background-color: #CCC; 
         width: 100px; }​