Software Mechanics
Why do we even have that lever?

Announcing: The IServiceLocator interface

October 1, 2008 16:41 by chris

Back in August, Jeremy Miller posted It's time for IoC Container Detente. In this post, he argued that the embarrassment of riches we currently have around .NET IoC/DI containers are actually hindering the adoption of the Inversion of Control. Anyone who wants to write a library that uses a DI container has to choose one and force that decision on the library's users. Either that or hide the container under the hood and suddenly one application can end up with two or three different, incompatible, containers, each of which needs to be configured. What was really needed was a simple, small, standard adapter interface that library authors could build against.

Oren Eini sent out an email to a bunch of DI container authors (yours truly included) suggesting that we just build it. After batting ideas around for a while we ended up with this:

namespace Microsoft.Practices.ServiceLocation
{
    public interface IServiceLocator : IServiceProvider
    {
        object GetInstance(Type serviceType);
        object GetInstance(Type serviceType, string key);
        IEnumerable<object> GetAllInstances(Type serviceType);

        TService GetInstance<TService>();
        TService GetInstance<TService>(string key);
        IEnumerable<TService> GetAllInstances<TService>();
    }
}

This interface includes sufficient overloads to be convenient for users while mapping well to most DI containers currently out there.

We specifically chose not to include container configuration or type registration in the interface. The general conclusion is that this is the area where containers differ the most, and offer the most unique values. Forcing a common registration semantic would just emasculate them. And, looking at how containers are best used, in most cases the containers are set up in a bootstrap phase at the start of the application and then you just resolve stuff, so it seems to work out pretty well.

I just pushed the button to publish our binaries containing this interface (and a few other useful bits) on Codeplex. We're starting out with Castle Windsor, Spring.NET, and Unity adapters, with more to come soon.

If you're writing a library or framework and want to use a DI container, but don't have a need for specific features of one container or the other, please consider using this small isolation layer. This way your users get to pick the container they want. For example, right now Enterprise Library is pretty well wedded to Unity and ObjectBuilder2. For the next version, I'm planning to use this interface instead and break that tight coupling, so Entlib can play nicer with other frameworks and libraries.

I'm pretty happy with the way this came out, particularly with the way the project ran. Lots of great collaboration both inside and outside of Microsoft. Hopefully a sign of things to come.


Currently rated 1.5 by 79 people

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

HP - Printer great, software is epic fail

September 16, 2008 16:56 by chris

My old HP Deskjet 970cse gave up the ghost about six months ago in a very annoying way. The print head worked fine, but the roller lost its grip on the paper, so every printed page skewed sideways as it printed.

I don't need color printing that much, but the Deskjet printed great photos and the occasional color PDF, albeit very slowly. I'd been researching a replacement for quite a while, asked around ... and then impulse bought an HP Color Laserjet CP1515n at Costco. ;-)

For less than $300, I'm thrilled with the print quality, and it eats toner a lot slower than the deskjet ate ink. Network interface included as well, so it just plugged in and worked. Loving the hardware.

The software, on the other hand...

I installed the print driver. At least, I thought it was a print driver. But oh, no - apparently I was to be treated to the HP experience. I now have not one, but TWO HP crapplets in my notification tray. One, the HPToolboxFX, is semi-useful, as it lets me look at all the printer settings, toner levels in the various cartridges and how many more pages I'll get out of them, that sort of thing. But does it really have to be in the system tray?

The other one, the "HP Digital Imaging Monitor", is apparently useless. If you double click on it, it brings up the "HP Solution Center", yet another crapplet whose primary function is to - open the HPToolboxFX! ARGH!

And, to top it off, for the last week every time I log in there's a background HP Updater process that demands admin privileges. If I give it, it tells me there's "two high priority updates". Try to download, it downloads two files and then - promptly fails to install them. And there's not even a configuration button to tell it just go the heck away!

I'm about to go looking for the business drivers, which HP usually has, which is the stripped down driver only install for companies that don't put up with this crap. But why would they go out of their way to force their crap into my face at every opportunity? This is not selling me on future HP products, people!


Currently rated 3.8 by 9 people

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

Hosting BZR Repositories on IIS

September 16, 2008 16:42 by chris

I posted quite a while ago about using the Bazaar distributed version control system to provide offline capabilities for TFS. I've still been using it that way, but I've found that Bazaar is working quite well for me as a personal, low overhead source control system.

One of the nicer things about Bazaar is the easy hosting and sharing of repositories. All you need for a read-only repository is to put it up on web server. No special configuration required. And yet, every time I tried putting a branch up on this server, it failed.

Turned out that the problem comes down to the bazaar repository format. More specifically, there are filenames in there without file extensions, and IIS just doesn't like that (unless you put in a wildcard mapping which has tons of other issues). I was at a loss, when I remembered that I can just fake it with ASP.NET.

The trick was to give the request an extension. And there's an extension already configured that's perfect here - .ashx, or the ASP.NET HTTP Handler. So what I did was build a hander that takes an url like this:

http://www.tavaresstudios.com/branches.ashx/[Repository Name]/... bzr paths here ...

and feed the resulting files back to the bazaar client. The actual path gets munged a little. I don't need to worry about encoding or anything else, just stream the bytes straight back out to the client.

Here's the code:

using System;
using System.Web;
using System.IO;
using System.Configuration;

/// <summary>
/// A small <see cref="IHttpHandler"/> that returns the contents of the file
/// under given pathdata. Used to serve up files that don't have an extension.
/// </summary>
public class BranchesHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string requestedPath = context.Request.PathInfo;
        string root = GetBranchRoot();

        string resultPath = context.Request.MapPath(root + requestedPath, root, false);
        string rootPath = context.Request.MapPath(".", root, false);

        if (!resultPath.StartsWith(rootPath))
        {
            throw new HttpException(404, "File not found");
        }


        context.Response.ContentType = "application/octet-stream";
        CopyFileToResponse(resultPath, context.Response);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    private string GetBranchRoot()
    {
        return ConfigurationManager.AppSettings["BranchRoot"];
    }

    private void CopyFileToResponse(string filePath, HttpResponse response)
    {
        if (!File.Exists(filePath))
        {
            throw new HttpException(404, "File not found");
        }

        response.TransmitFile(filePath);
    }
}

As I build future samples, I'll still make them available as .zip files, but I'm also planning to put the bazaar repository up as well for folks who want to track them.


Currently rated 1.6 by 44 people

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

Just 'cause it's a business DSL doesn't mean it's not Computer Science

September 6, 2008 16:11 by chris

Ayende posted an interesting question recently about writing a DSL for business rules. His position that the context in which a rule runs should be a first-class construct in the DSL is a very important one and I think would help make the development of rules almost doable by non-programmers. Maybe. ;-)

In reading the comments, there were requests for tooling and visualization, and concerns that just running the rules in order wouldn't do the trick. While reading, I kept getting this nagging feeling I'd seen this before. Then I realized - he's building a production system.

Production systems have been around for decades in the AI community, and are also very useful in language parsing theory. I most recently saw them back during grad school as part of building UI widgets of all things. It turns out that version of a production system (from this very good, readable book) looks like it maps quite well to the business rule processing too. (although when did the price go to $90? That's insane!)

Anyway, the idea of a production system includes fields, conditions, and productions.

The system has a state. This state is a combination of fields, where each field is an independent state variable. The conditions are the possible variables that a field can have. Looking at Ayende's example, there's not a whole lot of direct state, but fields aren't just state variables. There's also input events, actions, and queries. The input event field looks like this:

Inputs { *OrderShipped, *NewOrder, *BouncedCheck, *RefusedCredit }

(The leading * is a convention saying this is an event).

Next up, queries - this lets you express boolean true/false tests. There's two queries here:

CustomerQueries { ?CanSendSpam, ?IsPreferred }

(Queries have leading ? by convention)

And finally, actions, which are simply methods that are executed:

OrderActions { !SendMarketingStuff, !CallTheCops, !ApplyDiscount, !AuthorizeMoreCredit }

Finally, we have productions. A production is simply a pair of tuples of conditions. If the one on the left matches current conditions, the ones on the right are applied. The example in question comes down to:

*OrderShipped, ?CanSendSpam -> !SendMarketingStuff
*BouncedCheck, ?IsPreferred -> !AuthorizeMoreCredit
*RefusedCredit, ?IsPreferred -> !AuthorizeMoreCredit
*NewOrder, ?IsPreferred -> !ApplyDiscount(5.percent)
*BouncedCheck -> !CallTheCops
*RefusedCredit -> !CallTheCops

This looks a little more technical than the original DSL, so I wouldn't recommend you make your business analysts write this. But it buys quite a bit. You can simply scan down the list and see how the system runs. You can build a GUI tool that displays a simple grid - inputs on the left, actions on the right. You can sort by the inputs and queries and quickly find out everything the system could do in response to a particular input. And it's trivial to see if you have contradictory rules - you'll know because you'll have two productions with the same tuple on the left.

Anyway, I just wanted to drag out some stuff from my rusty education. I think a little rigor sometime can actually make things easier to use.


Be the first to rate this post

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

Podcast ho!

August 29, 2008 16:24 by chris

Arr, mateys! We be on a podcast!

Ok, that's enough of the pseudo-pirate thing.

The folks over at the Herding Code podcast were kind enough to let me blather on at them for about an hour. We talked about ancient history, what p&p's doing, Unity, Entlib and a few other miscellaneous things.

I wanted to thank the guys for having me on; it was a lot of fun and a very interesting conversation.

My episode is apparently not now on the main page yet, you can get to it here.


Be the first to rate this post

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

Writing Custom Lifetime Managers

July 15, 2008 11:00 by Chris

 

Note: I'm going to be doing a webcast on extending the Unity container on July 24th. I'm going to be doing the preparation here since I also need to work on the general extension docs anyway. Let's hear it for killing three birds with one stone! In any event, I'd love to get feedback on this doc before I do the webcast. Does it flow well? Make sense? Are you able to write custom lifetime managers after reading this? Thanks!

The Unity Dependency Injection Container has many extension points. One of the easiest to take advantage of is creating custom lifetime managers. A lifetime manager controls how instances are reused within the container. By default, the Unity container creates a new instance every time the Resolve method is called. This can be changed by registering a lifetime manager, like so:

container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());

With this registration any time an instance of Foo is requested, you'll get back the same one as long as the container is alive.

Since you can pass in any instance of a lifetime manager, it's pretty easy to write your own to customize how object instances get reused. Let's take a look at the LifetimeManager class and how it works within Unity.

The LifetimeManager class

To implement a custom lifetime manager, you need to create a class that derives from Microsoft.Practices.Unity.LifetimeManager. The important methods are:

public abstract class LifetimeManager : ILifetimePolicy
{
    public abstract object GetValue();
    public abstract void SetValue(object newValue);
    public abstract void RemoveValue();
}

It's also important to preserve the semantics of the LifetimeManager. In particular:

  • There is one instance of a LifetimeManager per object that is resolved from the container. Don't try to write a lifetime manager that handles multiple objects at once. The base class and the container enforce this requirement at runtime.
  • Thread safety around your GetValue and SetValue call are your job. We'll see an example of this later.

The container uses the lifetime manager in a fairly straightforward way. If the object in question hasn't been created yet, the sequence looks like this:

Sequence diagram - No object exists 

(Why yes, my handwriting does stink, thanks for noticing :-))

Basically, when a resolve call happens, type mapping happens first (not in the diagram), and then the current lifetime manager is looked up (based on the type and name being resolved). The GetValue method is called, and it returns null. At that point the construction of the object happens, and at the end the SetValue method is called to store the created object for next time.

That next time looks like this:

Sequence - object exists

If GetValue returns something other than null, that becomes the return value of the Resolve call and the rest of the build up process is short-circuited.

Example: Implementing a PerThreadLifetimeManager

Let's look at a sample implementation. One thing that can be useful is a per-thread lifetime: each thread that requests a particular type gets its own instance, but multiple requests from the same thread get the same instance.

The first thing you need to do is decide how you're going to save the instance. In this case, we need some kind of thread local storage (TLS). Luckily, the .NET framework has support for TLS built in. All we need to do is create a static field in our class, and add the [ThreadStatic] attribute. Since this is a static, we'll need to store multiple objects in it (one per PerThreadLifetimeManager). A Dictionary will do the trick. I'm using a Guid as a key because they're an easy way to generate a key. Our class starts off like this:

public class PerThreadLifetimeManager : LifetimeManager
{
    [ThreadStatic]
    private static Dictionary<Guid, object> values;
    private Guid key;

    public PerThreadLifetimeManager()
    {
        key = Guid.NewGuid();
    }

...
}

Now we just need to implement the GetValue and SetValue methods. They're very straightfoward:

public override object GetValue()
{
    InitializeValues();
    if (values.ContainsKey(key))
    {
        return values[key];
    }
    return null;
}

public override void SetValue(object newValue)
{
    InitializeValues();
    values[key] = newValue;
}

private void InitializeValues()
{
    if (values == null)
    {
        values = new Dictionary<Guid, object>();
    }
}

(The InitializeValues method is used to guarantee that each thread gets it's copy of the dictionary properly initialized, see MSDN for more details).

What About RemoveValue?

There's one more method that we have to implement: RemoveValue. This is a little embarrassing, but there's no reason to implement this method. Nothing in the Unity pipeline ever calls RemoveValue. It's there for those doing more advanced extensions, but out of the box it does nothing. The sample code with this article implements it as an empty function that does nothing.

Example: CachedLifetimeManager and Multithreading

Ironically, the PerThreadLifetimeManager class doesn't actually deal with multithreading. The use of TLS meant that we could pretty much ignore concurrency issues. However, as I'm sure you can imagine, proper threading is a major concern in most other lifetime managers. As an example, we'll build one that provides access to a value stored in a cache. This could be the ASP.NET cache, the Enterprise Library caching block, or anything else.

(Sidebar: The ASP.NET cache works just fine in non-ASP.NET applications. Don't let the System.Web namespace prevent you from using this great piece of technology!)

To insulate our code from the details of caching, I've defined a simple interface that does the bare minimum we need - get and retrieve items:

public interface IStorage
{
    object GetObject(string key);
    void StoreObject(string key, object value);
}

It's named IStorage rather than ICache because this is useful for more than just caching. I'm sure you can easily imagine an implementation that maps to the ASP.NET cache; see the code sample for this article for a working one.

When dealing with multithreaded access, the initial approach is usually to do something like this:

public override object GetValue()
{
    lock (lockObj)
    {
        return storage.GetObject(key);
    }
}

Unfortunately, this doesn't work. Look again at the sequence diagram above. If the object isn't in storage, we want to return null. But the lock is released as soon as GetValue returns, and now we're still open to race conditions. What we need to do is take a lock, and if the value is not in storage, hold the lock until SetValue completes. This serializes the object creation process so that we're guaranteed not to new up more objects than we need.

So, we need to hold onto the lock after GetValue returns. This will, I admit, feel a little weird at first. The basic idea is that if there's no object in storage, return without releasing the lock, and then release the lock in the corresponding call to SetValue. Of course, you can't use the lock() statement anymore to do this, so we need to drop down to the lower-level Monitor.Enter and Exit calls. The resulting methods look like this:

public override object GetValue()
{
    Monitor.Enter(lockObj);
    object result = storage.GetObject(key);
    if (result != null)
    {
        Monitor.Exit(lockObj);
    }
    return result;
}

public override void SetValue(object newValue)
{
    storage.StoreObject(key, newValue);
    TryExit();
}

private void TryExit()
{
    try
    {
        Monitor.Exit(lockObj);
    }
    catch (SynchronizationLockException)
    {
        // This is ok, just means we don't hold the lock
    }
}

The TryExit helper method is there because there are circumstances (particularly when you're calling container.RegisterInstance) where you'll call SetValue directly without having gone through GetValue first. The TryExit method avoids throwing an exception if we're not actually holding the lock.

Experienced multithreaded programmers reading this are probably a little worried right now. We exit GetValue holding a lock. What happens if an exception happens and SetValue never gets called? Isn't the lock abandoned at this point? The answer is yes, but there's a safety net.

There's a new interface defined in ObjectBuilder2 called IRequiresRecovery:

public interface IRequiresRecovery
{
    void Recover();
}

The Recover method will be called by ObjectBuilder if an exception happens during the build up process. So, to make sure the lock gets released, we just implement IRequiresRecovery on our lifetime manager:

public class CachedLifetimeManager : LifetimeManager, IRequiresRecovery
{
    ...

    #region IRequiresRecovery Members

    public void Recover()
    {
        TryExit();
    }

    #endregion
}

... and we're all set.

Odds and Ends

We've spent a lot of time talking about how lifetime managers handle creation and retrieval of instances. What about the end of an instance's lifetime? There's a pretty simple hook here: implement IDisposable on your lifetime manager class, and when the container is Disposed, the lifetime manager will be too. This is your opportunity to do whatever cleanup you need. Take a look at the code for the ContainerControlledLifetimeManager for an example.

Our final detail has to do with the container's open generic support. As I said above, there should be one lifetime manager instance per instance being managed. What happens when you do:

container.RegisterType<IRepository<>, CustomRepository<>>(new ContainerControlledLifetimeManager());

You've actually got many different instances at this point, one for each generic type argument: CustomRepository<User>, CustomRepository<Account>, CustomRepository<Flamethrower>, etc. This causes havoc with the semantics of the lifetime manager, and will result in all sorts of weird exceptions down the line.

The solution to this is generally transparent, but is useful to know about. When you register a lifetime manager for an open generic type, the lifetime manager instance to pass in isn't actually used. Instead, the container holds on to the type of the lifetime manager. When creating a closed generic type, it uses the container itself to resolve a new instance of that lifetime manager type.

Normally, you don't care. However, if for some reason you need a lifetime manager that takes constructor parameters, be aware that for open generics the container will be used to create the lifetime manager, and will need to be configured accordingly.

Wrap-up

That's it for lifetime managers. A complete copy of the sample code is available for download below. The unit tests make use of the Moq mock object framework; you'll need to download that separately to compile and run the tests.

TavaresStudios.Unity.zip (11.52 kb)


Be the first to rate this post

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

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:

[code=C#;ln=on;Original Code]ISpaceRepository GetConfiguredRepository(HttpRequestBase request)
{
    return new FileBasedSpaceRepository(request.MapPath("~/WikiPages"));
}[/code]

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:

[code=C#;ln=on;UnityTypeBasedControllerFactory.cs]public class UnityTypeBasedControllerFactory : DefaultControllerFactory
{
    IUnityContainer container;
    public UnityTypeBasedControllerFactory(IUnityContainer container)
    {
        this.container = container;
    }
    protected override IController GetControllerInstance(Type controllerType)
    {
        IUnityContainer requestContainer = container.CreateChildContainer()
            .RegisterInstance<RequestContext>(
                this.RequestContext,
                new ExternallyControlledLifetimeManager());
        return (IController)(requestContainer.Resolve(controllerType));
    }
}[/code]

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.

[code=C#;ln=on;GetAPIConfiguredContainer method - first attempt]public static IUnityContainer GetAPIConfiguredContainer()
{
    IUnityContainer container = new UnityContainer()
        .RegisterType<ISpaceRepository, FileBasedSpaceRepository>()
        .Configure<InjectedMembers>()
            .ConfigureInjectionFor<FileBasedSpaceRepository>(
                new InjectionConstructor(
                    new ResolvedParameter<string>("PathToRepositoryFiles")))
            .Container
        .Configure<IStaticFactoryConfiguration>()
            .RegisterFactory<string>("PathToRepositoryFiles",
            c => c.Resolve().HttpContext.Request.MapPath("~/WikiPages"))
        .Container;
    return container;
}[/code]

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:

[code=C#;ln=on;GetAPIConfiguredContainer method - better]public static IUnityContainer GetAPIConfiguredContainer()
{
    IUnityContainer container = new UnityContainer()
        .RegisterType<ISpaceRepository, MappedPathFileBasedSpaceRepository>()
        .Configure<InjectedMembers>()
            .ConfigureInjectionFor<MappedPathFileBasedSpaceRepository>(
                new InjectionConstructor(typeof(RequestContext), "~/WikiPages"))
        .Container;
    return container;
}[/code]

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 (4) | Comment RSSRSS comment feed

Unity and Silverlight: It can be done!

April 9, 2008 10:33 by Chris

Today was our weekly "slack time" day, where I get to go sit in a conference room and experiment with new technology. Today I did this:



Yep, got Unity running under Silverlight 2.0 beta 1. In the end it took me less than four hours (at least 30 minutes of which was waiting for the SDK to install and the obligatory xaml designer crashes). I made a couple boneheaded mistakes  in the project files, so I'm not going to post sources just yet.

Here's an overview of the porting process:

  • Install 2.0 Beta 1 plugin, SDK, Unit test tools and project templates.
  • Create a new Silverlight project.
  • Create Silverlight libraries for ObjectBuilder and Unity.
  • Copy the source for full OB, Unity, into the new projects. Add the files to the project.
  • Compile, fix errors, compile, fix errors, ... etc. ;-)

 Here's the issues I ran into.

Standard binary serialization is gone. As a result, the SerializationInfo and StreamingContext classes are not available. This is an issue because FxCop insists on the four standard constructors on every custom exception class. In Silverlight, there are now THREE standard constructors, not four. So remove them from all the custom exception classes.

The existing code uses methods like Array.Find and List<T>.RemoveAll. Many of these methods were removed from the Silverlight version. So I replaced them with the equivalent Linq expressions. This actually made some code a lot easier to read, which is nice.

System.Configuration and everything associated with it doesn't exist, which involved removing a bunch of stuff from the unit tests. My fault really, they should have been in a separate fixture to begin with.

The IL generation stuff is actually supported on Silverlight, which pleasantly surpised me. I did have to make one change though. When generating the build plan, we have some code that checks to see if you're in full trust, and chooses where to host the dynamic method based on the trust level. This way, in full trust we can do injection on internal or private classes. In Silverlight, you can't do this, and you can't choose where to host your dynamic methods anyway. The net result is that set of code goes away, and we just accept that you can't inject non-public stuff in Silverlight. Unfortunately, that meant changing a bunch of stuff in the test code, as lots of the tests have private nested classes as test subjects. Had to go through and change them all to public, and it worked.

One really weird thing I ran into is in the StagedStrategyChain class. This class takes an Enum, and uses it to determine how many stages the chain has. To figure out how many stages are present, we called Enum.GetValues(), which returns all the enum constant names. Guess what? This method is gone in Silverlight. I cheated by just looping up from zero to find the highest value defined by the enum; it's grotesque, but it worked.

One thing I'd like to throw in: I really, really appreciate the creation of the Silverlight unit test fixture. It would have taken a LOT longer to figure out if this thing was working without it. And since the SL runner is source compatible with the MSTest stuff, I just copied my existing tests in and they just ran. Very, very cool! 

I'm not going to be posting this code just yet, for a couple of reasons. The first is that the project isn't good enough yet; I really need to reorganize the solution I have right now, for example. The second reason is that this is NOT a supported scenario, and I don't want to give the impression it is. So you'll never see this on the Unity codeplex site, for example. Maybe it could be put on UnityContrib eventually?

Anyway, just wanted to let folks know it's not only possible, it was actually pretty easy!


Currently rated 1.6 by 34 people

  • Currently 1.558824/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: p&p | Silverlight | Unity
Actions: E-mail | Permalink | Comments (17) | 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. :-)

 


Currently rated 1.4 by 29 people

  • Currently 1.448275/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