javascript comments edit

I’m trying to write an HtmlHelper extension that lets you dump out options that build a jQuery UI datepicker on the client. (I know there are some of these out there, but for various reasons I won’t get into… I get to make one, too.)

Something that will let me do this:

@Html.DatePickerFor(m => m.SomeDate);

In doing that, I’ve uncovered a lot of frustration around getting the options specified on the server over to the client and working in a consistent format.

  • JSON date serialization continues to be a joke. I know there’s no date support, but it means you get to roll your own, even if several folks say they’re “standardizing” on something. jQuery.parseJSON doesn’t seem to support any sort of date from what I can tell, which means you get into custom serialization/deserialization or using some third party utility. I ended up using the Microsoft Sys.Serialization.JavaScriptSerializer because I’m using a compatible mechanism on the server and perf isn’t really a necessity given you’ve only got a couple of date pickers on a page generally, each of which only have a couple of date-oriented options.
  • jQuery UI datepicker has its own date formatting mechanism. It doesn’t use the same format strings as .NET, sprintf, strftime, or anything else I can figure. Same goes for parsing. That means integration with validation (or other stuff that needs to get the date on the client) is kind of painful. It also means you either end up writing crazy date format converters or you replace the date parsing/formatting wholesale. I ended up writing tiny proxy methods that make use of the Microsoft parsing/formatting extensions because then I can also let the default MVC model binder do whatever it needs to do in a locale-aware manner without having to special-case stuff.
  • jQuery UI datepicker localization is lacking. In .NET resources, you have this sort of fallback mechanism where “en-US” falls back to “en” which falls back to invariant culture. You provide the most specific culture, fallback handles the rest. Not so with the jQuery UI datepicker. You have to sort of “know” whether the specific culture is supported and/or the general culture and set it directly yourself. This, of course, means dates from the server (String.Format style) will potentially be inconsistent with dates formatted on the client side. I ended up generating all of the localized options on the server and piping them to the client rather than using the script-based localization.
  • jQuery.data() hates camelCase attributes. Yeah, I know HTML attributes are all supposed to be lowercase. But try this with jQuery 1.9.0: Set up an HTML element like this: <div id=”test” data-someDataHere=”1”>Content</div> now try and get that using jQuery.data(): var data = $(“#test”).data().someDataHere; It won’t work. You’ll get some sort of exception down in the bowels of things because it’s looking for an attribute that’s all lower-case-dashes like data-some-data-here rather than the actual attribute name.

Anyway, I got to find these through experience so hopefully it’ll help others save some time.

General Ramblings comments edit

We had a safari in our living room last night.

Jenn and I are coming to find that Phoenix (now two) has a pretty great imagination. I think she fuels it with some of the stories we read and shows she watches, but the combination of all of that in her little brain is pretty crazy.

She really likes flashlights. Doesn’t really matter if it’s a head lamp, a small flashlight, or a lantern, if it’s a hand-held light source, she’s all over it. We got her a pack of flashlights for Christmas and my parents picked her up a little pink head lamp. She runs around the house looking for dark rooms to inspect, then turns the flashlight(s) on and starts looking. “Daddy, it’s dark in here,” she says. In her little kid not-quite-English it sounds more like, “Daddy, a dock a here.” But we know what she’s saying. “Spooooooky,” she says, as she walks around with the light.

Last night after dinner we were trying to figure out a game to play with her. She wasn’t really interested in the usual tea party or Brio train thing, but she was carrying around her light. At one point she told us to turn the lights off in the room, so we did. Then she handed out lights to the rest of us. Jenn got the head lamp, I got a small lantern. She continued running around to each room telling us to turn off all the lights, and we did until the whole house was dark, just us with our flashlights. I’m sure from the outside it looked like a major burglary.

Once the house was dark, I figured I’d kick things up a notch. “Hey, Phoenix, are we going to the jungle?” She totally went with it. “Jungle, Daddy! Sshhhhhhh! Tigers sleeping!” We walked around the house, inspecting all the corners of every room.

“Phoe, do you see the birds in the trees?”

“Oh, birds, Daddy! Pretty!”

Jenn decided to take it a little further. “Look out, Phoe, there’s a tiger! He’s going to get you!”

“Nooooo! No tiger eat meeeee! Ruuuuuuuuun!” She took off running, trying to escape one of our very confused house cats, who then got spooked because… well, who wouldn’t be spooked when a toddler four times your size is running rampant and screaming.

“Phoe, look, snakes on the ground,” Jenn said, getting her going even more.

“Snakes icky,” said Phoenix, shining her light on the ground. “No get me.”

I took some throw pillows and put them around on the floor. “Quick, Phoe, step on the pillows! If you stay on the path, the snakes can’t get you!” She hopped up on one of the pillows and started jumping from pillow to pillow. It occurred to me that this is her first official step on the road to the “hot lava” game we all played as kids, where you have to step on certain spots to “stay out of the hot lava.” Chalk one up for my mad parenting skillz.

We played like that for 45 minutes or so, until it was time to get her ready for bed. She was pretty sad to have to stop playing since we were having quite a bit of fun, but I’m sure that’s not our last safari.

In fact, this morning after we got her up she went straight for the flashlights. “Jungle, Daddy.” I had to laugh. “Did you have a good time playing last night? Did the tigers get you?” She nodded her head, her wild curls shaking. “Tigers no get me. Fun!”

net, autofac comments edit

The final version of Autofac 3.0.0 is released and you can get it on NuGet or download directly from Google Code.

If you’re upgrading from 2.6, the big changes are:

  • NuGet packages for everything - you can get core Autofac, the integrations, and the extras, all on NuGet.
  • Symbol/source packages are deployed to SymbolSource so you can debug into the source.
  • New integration with MVC4, WebAPI, and SignalR.
  • Autofac core is now a Portable Class Library that can work on the full .NET stack, Windows Store apps, Silverlight 5, and Windows Phone 8 apps.
  • AutofacContrib projects are now Autofac.Extras (namespace and assembly name change).

There are also a ton of issues resolved and we’re working on enhancing the wiki docs. The Release Notes page on the Autofac wiki has the detailed list of changes.

Huge thanks to Alex Meyer-Gleaves for all the work he does (and managing the release process!) and to Nicholas Blumhardt for getting Autofac going.

net comments edit

We switched Autofac 3.0 to be a Portable Class Library so we can target multiple platforms. In consuming the updated Autofac, I’ve noticed some folks receive errors like this at runtime:

Test 'MyNamespace.MyFixture.MyTest' failed: System.IO.FileLoadException : Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
    at Autofac.Builder.RegistrationData..ctor(Service defaultService)
    at Autofac.Builder.RegistrationBuilder`3..ctor(Service defaultService, TActivatorData activatorData, TRegistrationStyle style)
    at Autofac.RegistrationExtensions.RegisterInstance[T](ContainerBuilder builder, T instance)
    MyProject\MyFixture.cs(49,0): at MyNamespace.MyFixture.MyTest()

You can solve this by getting the latest .NET framework patches from Windows Update. Article KB2468871 and the associated patch specifically address this, however in practice I’ve noticed that specific patch doesn’t always fix it for everyone. I actually don’t know if it’s a different patch that fixes the 100% case or if it’s different patches for different people. What I do know is that once the machine is patched up with the latest, the problem goes away.

If you’re on a domain where there’s an internal Windows Server Update Services instance running, you may think you have the latest but you might not. If it looks like you’re all patched up but still seeing the error, make sure you’ve checked online for updates.

See here, it looks like I’ve got the latest…

Check online for updates from Microsoft
Update

…but really, I’m missing several updates.

After checking online, several updates were
missing

A note on the version 2.0.5.0 you see in the error message: That’s the version of the framework Autofac references as an artifact of being a Portable Class Library. 2.0.5.0 is Silverlight, which is one of the platforms we target. You won’t see it installed on your machine, don’t go trying to manually hack around and install it. But don’t freak out, that version is expected and it’s OK. The .NET framework patches should allow you to dynamically redirect that reference at runtime to the appropriate version (e.g., 4.0.0.0) and the error will go away.

net, gists, aspnet, csharp comments edit

With Autofac (particularly the multitenant extensions) I see a lot of questions come through that boil down to this:

I have an ASP.NET MVC project. I have some controllers in a plugin assembly that isn’t referenced by the main project. At application startup, I do some scanning and use Autofac to dynamically register the controllers. For some reason I get an error when I try to visit one of these controllers. How can I have a controller in a plugin assembly?

Shannon Deminick has a nice blog article that explains this in a different context - similar question, but the same answer.

The problem is that the default controller factory in ASP.NET MVC 3 and 4 (the latest version as of this writing) is really tied to the BuildManager. The BuildManager is the class that maintains the internal list of all the referenced application assemblies and handles ASP.NET compilation.

The DefaultControllerFactory in ASP.NET MVC, in the CreateController method, uses a ControllerTypeCache internal type to locate the controller type being instantiated. The ControllerTypeCache uses another internal, TypeCacheUtil, to load the set of controllers from the list of referenced assemblies. TypeCacheUtil uses the BuildManager.GetReferencedAssemblies() method to initialize that list. BuildManager.GetReferencedAssemblies() includes:

  • Assemblies that are referenced by the main web application.
  • Assemblies you list in the <assemblies> part of web.config.
  • Assemblies built from App_Code.

Note that none of those automatically include non-referenced, already-built plugin assemblies.

You need to add your plugin assembly to the list of referenced assemblies in the BuildManager.

You can do that in one of three ways.

First, you can register the assembly in web.config. This makes for a less “drop-in-an-assembly” plugin model, but it also means no code getting executed. If you put your plugins in a folder other than bin, you will also have to register that path. Here’s a snippet showing a web.config with this sort of registration.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <!--
          IF you put your plugin in a folder that isn't bin, add it to the probing path
      -->
      <probing privatePath="bin;bin\plugins" />
    </assemblyBinding>
  </runtime>
  <system.web>
    <compilation>
      <assemblies>
        <add assembly="The.Name.Of.Your.Plugin.Assembly.Here" />
      </assemblies>
    </compilation>
  </system.web>
</configuration>

Another alternative is to register your assemblies in code at PreApplicationStart. This is the method outlined in Deminick’s article in more detail. The idea is that you use the PreApplicationStartMethodAttribute to bootstrap some assembly scanning and registration with the BuildManager (since that all has to happen before app startup).

Basically, you mark your main project assembly with the attribute and point to a class that has a static method that will do the auto-registration, like this:

[assembly: PreApplicationStartMethod(typeof(Initializer), "Initialize")]

Then you write your initializer class to do the assembly loading and registration with the BuildManager. Something like this:

using System.IO;
using System.Reflection;
using System.Web.Compilation;

namespace MyNamespace
{
  public static class Initializer
  {
    public static void Initialize()
    {
      var pluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins"));
      var pluginAssemblies = pluginFolder.GetFiles("*.dll", SearchOption.AllDirectories);
      foreach (var pluginAssemblyFile in pluginAssemblyFiles)
      {
        var asm = Assembly.LoadFrom(pluginAssemblyFile.FullName);
        BuildManager.AddReferencedAssembly(asm);
      }
    }
  }
}

A third way would be to create your own ControllerFactory implementation. In your custom controller factory you could search your plugin assemblies for the controller types or use some other convention to determine which controller type to resolve. I don’t have any sample code for that and there is a lot of work to accomplish that and get it right - supporting areas, properly handling the type resolution… If you go that route, and some people have, you’ll have to go out searching for samples. I don’t have any here to readily provide.

I’d recommend one of the first two options. They’re the easiest and require the least “messing around with the framework” to get things working for you.