Software Mechanics
Why do we even have that lever?

Do classes need to be DI friendly?

April 25, 2008 10:31 by Chris

I was working on a version of my MSDN magazine Wiki sample (updated code for the April 16 drop coming soon) that used Unity instead of the one-off custom controller factory that is currently in there. I've posted on this before, and my previous conclusions were that it was pretty easy. Of course, I ran into a snag.

The one-off controller factory had this code in it:

001ISpaceRepository GetConfiguredRepository(HttpRequestBase request)
002{
003    return new FileBasedSpaceRepository(request.MapPath("~/WikiPages"));
004}

Basically, the FileBasedSpaceRepository takes a path to the directory where the files are stored. Of course, in a web app we need to use the server to map from a virtual-directory relative path to a physical file system path. Nothing new or unusual here.

But then I got into replacing this code with Unity, and immediately ran into the question: how do I get the container to call that MapPath method? Unity doesn't know anything about the web. And how does it get the current request?

So, I figured I'd use a child container, shove the request in there, and then use the static factory extension to resolve my string. My controller factory looks like this now:

001public class UnityTypeBasedControllerFactory : DefaultControllerFactory
002{
003    IUnityContainer container;
004    public UnityTypeBasedControllerFactory(IUnityContainer container)
005    {
006        this.container = container;
007    }
008    protected override IController GetControllerInstance(Type controllerType)
009    {
010        IUnityContainer requestContainer = container.CreateChildContainer()
011            .RegisterInstance<RequestContext>(
012                this.RequestContext,
013                new ExternallyControlledLifetimeManager());
014        return (IController)(requestContainer.Resolve(controllerType));
015    }
016}

So basically, what I'm doing here is that for each request, I spin up a child container, stuff the request context into the container, and then resolve the requested controller type. Pretty straightforward.

Next up is to configure the container.

001public static IUnityContainer GetAPIConfiguredContainer()
002{
003    IUnityContainer container = new UnityContainer()
004        .RegisterType<ISpaceRepository, FileBasedSpaceRepository>()
005        .Configure<InjectedMembers>()
006            .ConfigureInjectionFor<FileBasedSpaceRepository>(
007                new InjectionConstructor(
008                    new ResolvedParameter<string>("PathToRepositoryFiles")))
009            .Container
010        .Configure<IStaticFactoryConfiguration>()
011            .RegisterFactory<string>("PathToRepositoryFiles",
012            c => c.Resolve().HttpContext.Request.MapPath("~/WikiPages"))
013        .Container;
014    return container;
015}

This is a little grotesque. Instead of just configuring the string to be injected into the constructor, I have to resolve it through the container. I registered the factory delegate (on line 13) to grab the current RequestContext, then use it to resolve the string.

Lots of things wrong here. You can't put this into the config file becuase of that factory method delegate. The actual string is buried in the delegate, so it's not obvious where you're actually getting the path from. And to top it off, due to an unfortunate design decision on my part, the static factory ends up getting the parent container passed into the delegate rather than the child. So the Resolve<RequestContext> call fails.

I found something that works better. I created a new class, MappedPathFileBasedSpaceRepository, which takes the RequestContext and the path to be mapped in the constructor. It inherits from the original FileBasedSpaceRepository, and does the MapPath call before passing the resulting file system path down to the base class. This results in a much, MUCH shorter configuration of the container:

001public static IUnityContainer GetAPIConfiguredContainer()
002{
003    IUnityContainer container = new UnityContainer()
004        .RegisterType<ISpaceRepository, MappedPathFileBasedSpaceRepository>()
005        .Configure<InjectedMembers>()
006            .ConfigureInjectionFor<MappedPathFileBasedSpaceRepository>(
007                new InjectionConstructor(typeof(RequestContext), "~/WikiPages"))
008        .Container;
009    return container;
010}

I'm pretty happy with where I am now, except for one thing: MappedPathFileBasedSpaceRepository wouldn't exist if I hadn't plugged in the container. Is this just a case of finding a new dependency that I hadn't realized before? Or is it that the presence of the DI container is intruding on my domain model?

I'd love to get some feedback from folks on what you've done to handle issues like this. What's your opinion here?

(I think I like the "child container shove the request context in" approach, but I'd love to get opinions on that too.)


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | Unity
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Unity 1.0 is released!

April 4, 2008 09:43 by Chris

I just finished uploading the release of Unity 1.0 to Codeplex. The bits have also been uploaded to MSDN, but it'll take a while to propagate.

The release includes the Unity MSI, plus two more MSIs with Visual Studio 2005 and 2008 integrated documentation. Rather than bloat the main download with three copies of the docs, we chose to make the separate installers available for those who want them.

We've also split out the source as a separate download, so for those who don't trust MSIs or something, you can still grab the source code.

Enjoy! I'm off to work on version 1.1. :-)

 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | p&p | Unity
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

Magazine article obsolete? Not if I can help it!

March 15, 2008 16:50 by Chris

My first MSDN Magazine article, ASP.NET MVC: Building Web Apps Without Web Forms, just hit the stands in the March issue. Unfortunately, due to the slow pace of the publishing business (although, to their credit MSDN magazine is actually really quick on the production side) the article had to be done in January. With the release of the ASP.NET MVC Preview 2 bits at Mix '08, the sample code in the article was up to date for all of two days.

Not that I'm complaining, that's just how it works when writing about rapidly moving prerelease software. But I have to attempt to stay relevant, and as such, I've updated the code download. Until the MSDN site updates (these things usually take a few days) you can download the updated samples here. As new releases come out I'll try to keep this code updated as long as it's till relevant.

MVCPreview2UpdatedSamples.zip (64.51 kb)


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Using Unity and the ASP.NET MVC Preview 2

March 13, 2008 07:40 by Chris

The recent release of the ASP.NET MVC Framework made a change to the IControllerFactory interface at the request of users of dependency injection containers. Instead of passing the controller factory the type of controller desired, it now gets the string from the route, and the factory can now resolve that type however it wishes.

This fits with most other DI containers, since they have to have everything pre-configured anyway. However, Unity is a little different, in that you don't have to register concrete types ahead of time. This change requires Unity users to register types ahead of time like everyone else, or do reflection to find controller types at runtime. Kind of annoying.

However, there's another answer. Recent (ahem) discussions on the net has shown an obsession with interfaces, to the point that even when there's a useful base class that will solve the problem, many will go straight to the interface and duplicate a lot of work.

In this case, there's a simple way to hook Unity up to ASP.NET MVC preview 2. Rather than implement IControllerFactory, inherit from DefaultControllerFactory instead. There's a method in there, GetControllerInstance, which is called after the name has already been resolved to a type. In other words, the DefaultControllerFactory already does the reflection for you.

Here's the code:

    public class UnityControllerFactory : DefaultControllerFactory
    {
        IUnityContainer container;

        public UnityControllerFactory(IUnityContainer container)
        {
            this.container = container;
        }

        protected override IController GetControllerInstance(Type controllerType)
        {
            if (controllerType == null)
            {
                throw new ArgumentNullException("controllerType");
            }
            if (!typeof(IController).IsAssignableFrom(controllerType))
            {
                throw new ArgumentException("Type requested is not a controller", "controllerType");
            }

            return container.Resolve(controllerType) as IController;
 }

To hook this up, in global.asax.cs, do something like this:

            IUnityContainer container = new UnityContainer();

            // Configure container here

            IControllerFactory controllerFactory = new UnityControllerFactory(container);
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);

Simple and easy! Hope this helps!

 


Currently rated 1.5 by 2 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: ,
Categories: .NET | Unity
Actions: E-mail | Permalink | Comments (5) | Comment RSSRSS comment feed

End of the Deconstruction

February 28, 2008 18:01 by Chris

I'd like to thank everyone for the great reception for my Deconstructing ObjectBuilder series. It's good to know I was filling a gap.

However, I'm currently thinking that I'm not going to post the last segment on using OB to wire up to the event broker. I was editing the text for the post last night, and I realized that it needed serious work to update to OB2. Serious enough to take at least a couple of days. And, quite honestly, I think I've got more important things to write about.

So I think I'm going to call an end to the Deconstructing ObjectBuilder series. And intead start a new one, on Unity, extensibility, and how Unity uses OB2. The EventBroker example I've been using is actually included as one of the Unity quickstarts, so I don't even need to update that code for the container. Wink

I have uploaded all the code from the DeconstructingObjectBuilder series so far. This code even works, unlike some of the blog posts with last minute typos in it. Feel free to play with it. You'll need to download and compile the OB2 sources first. But to be honest, with Unity out there (which has made some significant changes to OB2) I'm not sure how much effort that's worth right now. You can tell me.

Thanks for reading, now on to something (sorta) new!

DeconstructingObjectBuilder.zip (37.93 kb)


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

The last vsvars32.ps1 I'll ever need

January 14, 2008 15:25 by Chris

By now, I hope I don't need to sell folks on Windows Powershell. It's a fantastic command line environment once you get used to it, and I love using it.  However, for the .NET developer, there's the standard set of command line utilities (sn.exe, gacutil, ildasm, etc. ad nauseum) which only work properly once you've run the vsvars32.bat file that ships with Visual Studio.

When Powershell was first released, there was a bunch of people who scrambled to translate vsvars32.bat into vsvars32.ps1, the equivalent Powershell script. And now that VS 2008 is out, the process is repeating itself. The best current version was posted recently by Brad Wilson. While this approach worked, the duplication of effort always bothered me. The batch file just sets a bunch of environment variables, and Powershell will run .bat files, but unfortunately it runs them in a child shell. Which means they set the environment variable in the child shell, which promptly goes away, taking the variables with it. Darn.

The translation route seemed like the only option, but it just rubbed me the wrong way. What happens when a service pack updates the batch file? Then we have to re-translate. Or another release of VS? Argh, more mindless work.

The ultimate solution came to me while I was reading Bruce Payette's fantastic book, Windows Powershell in Action. Buried in there is this very nice little function:

function Get-Batchfile ($file) {
    $cmd = "`"$file`" & set"
    cmd /c $cmd | Foreach-Object {
        $p, $v = $_.split('=')
        Set-Item -path env:$p -value $v
    }
}

What does this do? Basically, it runs the .bat or .cmd file you give it in a child shell, then runs the 'set' command in that shell to dump out the environment. Then it parses the resulting output, and sticks those environment variables into the powershell environment. This way, you can run any batch file and get the environment variables set. Just what we need!

This was part of the way there. I also wanted some easy way to run vsvars32 specifically, as I end up doing that a lot. Looking around, I found that VS 2005 and VS 2008 store their install path in a very predictable spot in the registry. The only only difference is a version number: 8.0 for 2005, 9.0 for 2008. A little more hacking, and I got this function:

function VsVars32($version = "8.0")
{
    $key = "HKLM:SOFTWARE\Microsoft\VisualStudio\" + $version
    $VsKey = get-ItemProperty $key
    $VsInstallPath = [System.IO.Path]::GetDirectoryName($VsKey.InstallDir)
    $VsToolsDir = [System.IO.Path]::GetDirectoryName($VsInstallPath)
    $VsToolsDir = [System.IO.Path]::Combine($VsToolsDir, "Tools")
    $BatchFile = [System.IO.Path]::Combine($VsToolsDir, "vsvars32.bat")
    Get-Batchfile $BatchFile
    [System.Console]::Title = "Visual Studio " + $version + " Windows Powershell"
}

Having this in my profile lets me type "vsvars32" and I'll be set up with my VS 2005 environment, or "vsvars32 9.0" and I'll have a VS 2008 environment. I also had it update the window title so I can keep track of which environment I'm running in. Hopefully, if the VS team maintains their registry conventions when a patch or the next version of VS comes out, this script shouldn't need to change.

I hope these little  scripts help folks out there work better with Powershell and Visual Studio.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

About ObjectBuilder

January 5, 2008 17:29 by Chris

I'm the development lead on the next version of Enterprise Library. The big feature we're adding, as mentioned by Grigori Melnik, is the Dependency Injection Application Block. There's already been quite a bit of discussion on the blogosphere about it, and I don't want to reopen the discussion here. What I do want to ask about is about the underpinnings of many p&p assets, that will play an important role in the implementation of the block: ObjectBuilder.

 For those who don't know, ObjectBuilder (OB) is a fairly small library that is used at the heart of EntLib, CAB, and WCSF.  It's p&p's current implementation of a dependency injection system. And the overall concensus is that it sucks.

The problem with concensus is that, after a while, folks remember the conclusions, but nobody actually remembers how or why that conclusion is reached. So I ask you: why does OB suck?

For what it's worth, my personal opinions on the matter are:

  1. There are no docs other than pretty useless XML doc comments.
  2. OB is only half of the DI story. The other half, the DI container itself, doesn't exist (yet). Without the container, you've got to deal with an extremely general API which doesn't make any sense at first glance.
  3. Perf needs to be improved.

We're going to be working on all three of these for Entlib 4.

So, tell me: other than the above, why do YOU think OB sucks? 

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | Entlib | p&p
Actions: E-mail | Permalink | Comments (4) | Comment RSSRSS comment feed