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.

dotnet, 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.

General Ramblings comments edit

Jeff Atwood just posted an article about Aaron Swartz, his unfortunate story, and the notion of ragequitting.

I agree with Jeff on Swartz and the thoughts about that case. Rather than restate all that, check out the article. My thoughts go out to Swartz and his family. He’ll be missed.

What I disagree with is this:

Ragequitting is childish, a sign of immaturity.

We’ve often used “vote with your feet” as an idiom describing how people can effectively support (or show lack of support) for a thing, particularly an internet (or programming, or technology) thing. It occurs to me that ragequitting, while abrupt, is effectively foot-voting-in-action. I’ve done it myself, I admit, and I’m sure you have, too. Point is, just because it’s fast or unannounced doesn’t mean it’s any less valid, and, in my opinion, certainly doesn’t mean it’s childish. It’s within everyone’s rights to choose their situation and decide what’s best for them regardless of the emotion that may be associated with said decision.

windows comments edit

I swear every time I change the Java settings to stop auto-updating it still pops up that stupid “A Java Update is Available” toast in the corner and I want to punch it repeatedly. Killing the scheduled task from startup works until you actually do install the next update, at which point you forget it and it puts itself back.

I run as a non-admin user. The Java auto-update thing hates that. It tells me there’s an update, then I say, “OK, do it then.” It asks me for admin credentials, I enter them, and I instantly get a failure message. Again, I want to punch it repeatedly.

The only way I can get this thing to go away is to manually run the update (or download the entire package and manually install the update). For my own reference, here’s how I do it:

  1. Log in as the administrative user.
  2. Run “C:\Program Files (x86)\Common Files\Java\Java Update\jucheck.exe” with elevated privileges.
  3. Follow the prompts to get the update and make sure to uncheck all the freeware crap they want to install alongside it.

dotnet, gists, build, teamcity comments edit

We use TeamCity as our build server and one of the cool things TeamCity has built in is the ability to serve as a NuGet server. You build your product, run a nuget packtask on it, and TeamCity will automatically add it to the feed.

One of the somewhat odd things I’ve found with TeamCity’s NuGet server is that it seems to require that you let TeamCity run the actual nuget packon packages it should host. That is, even if you wanted to do that action in your build script, you can’t – simply putting the package into your set of build artifacts doesn’t get it into the feed. You actually have to use the “NuGet Pack” build step in your build. When you do that, the build step ignores any version information you put inside your .nuspec files because the “NuGet Pack” build step requires you to specify the version right there.

That’s fine as long as the build number for the build (or some similar existing variable) is also the version you want on your NuGet package. But when you want to have tighter control over it, like calculating the version as part of a build task, it becomes less clear how to get things working. This should help you.

First, you have to establish a NuGet package configuration variable. You need this so you can use it in the NuGet Pack build steps. In your TeamCity build configuration, go to the “Build Parameters” tab and define a “System Property” with your calculated NuGet package semantic version. I called mine “CalculatedSemanticVersion” so it ends up showing in the TeamCity UI as “system.CalculatedSemanticVersion” like this:

system.CalculatedSemanticVersion = 0.0.0 Set it to some simple, default value. It won’t stay that value so it doesn’t matter; it’s more for when you come back later and look at your configuration – this way it’ll make a little more sense.

Next, set up your NuGet Pack build steps. Use this new “system.CalculatedSemanticVersion” property as the NuGet package version you’re building.

On the NuGet Pack step use the new version variable.

Finally, insert a build script step before all of your NuGet Pack steps. In that build script step, calculate the version you really want for your packages and use a TeamCity message to update the variable value. You do that by using a specially formatted message written to the console, like this:

##teamcity[setParameter name='system.CalculatedSemanticVersion' value='1.0.0-beta1']

In MSBuild, you might have something that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Project
  DefaultTargets="SetVersion"
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
  ToolsVersion="4.0">
  <Target Name="SetVersion">
    <!--
      Calculate your semantic version however you like.
      This example uses a made-up build task, but you
      could do anything.
    -->
    <CalculateMySemanticVersion>
      <Output TaskParameter="Version" PropertyName="SemanticVersion" />
    </CalculateMySemanticVersion>
    <!-- The message task here is the important part. -->
    <Message Text="##teamcity[setParameter name='system.CalculatedSemanticVersion' value='$(SemanticVersion)']" />
  </Target>
</Project>

Now when your build configuration runs, the script will calculate your NuGet package version and update the value of the property before the NuGet Pack tasks run. The NuGet Pack tasks will build your packages using the correct calculated version that you controlled through script.