Silverlight 4 Runs Natively in .NET

by justin 1. March 2010 04:04

This is a big deal.

I just learned this the other day and found surprisingly little information about it online. It was announced at PDC so it’s not a secret but it seems like a big deal to me. The feature is otherwise known as “assembly portability”.

When doing Silverlight one of the most frustrating things currently is the inability to run unit tests out of browser. This results in a break in continuous integration and a frustrating manual step in your testing process. Well no more!

This is only the beginning of the implications however. If you’re writing any application with a business logical layer, you should probably be writing it in Silverlight exclusively now. No more duplicating projects and creating linked file references. You can literally just create one project, compile it, and run it in both runtimes. Incredible.

Of course there are some limitations. But in this case I almost feel like the limitations are actually benefits. The thing is, you are likely to have features in one environment that are different or inaccessible in another. For example, file system access. In .net if you’re easily accessing the file system, but you might not be able to access it directly in Silverlight in the same way.

Enter System.ComponentModel.Composition. Otherwise known as MEF. By making your application logic composable you can solve all of the problems of framework differences and make your project imminently unit test friendly and better in general (if you buy into the principals of IoC at least).

For example, in Silverlight you cannot get a FileStream directly, you must make a call to OpenFileDialog which will give you the FileStream, if a user allows it. This is all well and good but when running in .net or unit tests you may want to allow it to access the file system directly or give it a mock stream instead. The solution is to make your calls to retrieve streams composable (otherwise known as dependency injection). Create a service interface, and create service instances for different environments.

For example, suppose you have the following (contrived) method in a Silverlight class:

public void DoWork()
{
    var dto = new SimpleDTO { Id = 100, Foo = "Hello World!" };

    Stream stream = Open();
    Save(stream, dto);

    stream = Open();
    dto = Load<SimpleDTO>(stream);

    Console.WriteLine("{0} : {1}", dto.Id, dto.Foo);
}

The process of opening a stream in Silverlight is different from the way it must be done when running in .net. So we make it composable.

public Stream Open()
{
    var stateService = container.GetExport<IStateService>().Value;
    stateService.State.Seek(0, SeekOrigin.Begin);
    return stateService.State;
}

Instead of opening the stream ourselves we import an exported service via MEF, that does know how to do it. To do this we simply need to have access to a container.

private CompositionContainer container;

public ComposableObject(CompositionContainer container)
{
    this.container = container;
}

Our constructor accepts a CompositionContainer as a parameter, which gives us access to all of the composable parts configured for our runtime. Keep in mind this is all Silverlight code at this point. And here is the IStateService.

public interface IStateService : IDisposable
{
    Stream State { get; }
}

The following code snippets are plain-old-dot-net-console-application snippets. First off, here is a snapshot of my solution explorer so you can see how things are structured.

image

You can see that I have created a reference from a Console Application project directly to a Silverlight 4 Class Library project. Visual Studio gives me a yellow banger, presumably because of the framework differences but it builds just fine. My program loads and calls my Silverlight library just this easily:

using SilverlightClassLibrary1;
class Program
{
    static void Main(string[] args)
    {
        var assembly = new AssemblyCatalog(typeof(Program).Assembly);
        using (var container = new CompositionContainer(assembly))
        {
            var co = new ComposableObject(container);
            co.DoWork();
        }

        Console.ReadKey(true);
    }
}

The bits at the beginning are creating a CompositionContainer using the current assembly. MEF allows you to load containers from all sorts of sources however, including entire directores full of Assemblies so you can have an easy add-in system. The ComposableObject is the one defined in my Silverlight Assembly! No interop nastiness, no AppDomain hassles, it just loads the dll as if it were true .NET code!

Next all I have to do is create an instance of the IStateService and export it.

[Export(typeof(IStateService))]
public class ParallelProcessingService : IStateService
{
    private Stream state;

    public Stream State
    {
        get
        {
            if (state == null)
                state = File.Create("state.dat");
            return state;
        }
    }

    public void Dispose()
    {
        if (state != null)
            state.Dispose();
    }
}

Now when I run this application, my Silverlight code will use MEF to load an Exported IStateService instance for me. Running this code will the access the FileSystem directly even though I’m running a Silverlight class library.

So what you should do is to create a Class Library with all of your logic, composed in a similar fashion as the above. Then in your Silverlight Application you simply implement and Export all of the Silverlight specific code as services. You do the same for your unit testing in .net projects and you’ll be able to run the exact same assembly in both locations.

The bonus to this, of course, is that you’ll also be able to swap out logic that you want to actually be different in different locations as well. For example, if you’re creating a business application you could put all of your business logic into a single assembly that could be run on both the client and the server. However, what that logic does and how it does it might be different in both locations. You may need to do a server call to a database to determine if a particular value of your business object is unique. On the client you want to make an asynchronous web request back to the server but on the server you want to make a call directly to the Database. It’s the same object and assembly in both locations so in order to achieve this you need to make the ValidateUnique rule itself composable, then this is possible even though the object is simply applying the rule in the same way.

In fact this technique can be very pervasive and powerful in general. Running on multiple frameworks requires you to be composable, which may also inadvertently force you into some good practices in general.

One other thing to note. I had to set CopyLocal=True for some of my references in the Silverlight Class Library to get it to run correctly in .NET. Since those assemblies aren’t in the GAC by default, it won’t load them unless they tag along with your assembly.

image

I didn’t test this out myself but you wouldn’t want those files appearing in your .xap file for your Silverlight application. I’m pretty sure that it would be smart enough to exclude them but double check.

Tags: , , , , , ,

Silverlight | Software Development | WPF | Visual Studio | .NET | C# | MSBuild

Finally!! MetaTask builds Pipelines in a single solution!

by justin 24. July 2009 08:59

I’ve been struggling for the last couple of weeks to try to get the MetaSharp build environment to a state where it’s not painful to debug. Since the primary system for building DSLs right now is through an MSBuild Task I have been having one heck of a time. When my Task would get loaded it would then load a supplied assembly and run the pipeline defined in it. This would cause it to get loaded into Visual Studios AppDomain and not release the assemblies, which meant you’d have to open and close Visual Studio after every build… very painful.

The obvious solution was to create an AppDomain and try to load the Pipeline assembly in that domain and do the work there. But of course, AppDomains are evil. Seriously, I’ve been chipping away at this issue for weeks to no avail… until today. I found something magical that probably everyone else in the world knew about except for me.

I found the AppDomainIsolatedTask.

Instead of having to create your own AppDomain and messing around with all that you can simply inherit from AppDomainIsolatedTask and Visual Studio will do the magic for you. Whatever assemblies you load for your Task will be definitely released. Awesome! This means you can have a task in one project, and consume it in another, both in the same solution, and build over and over. Wonderful!

To top it all off I changed my assembly loading system to use the new .NET 4.0 MEF framework (System.ComponentModel.Composition). Everything is all very elegant now.

So all you have to do is create a class that implements IPipeline, add an Export attribute and create a simple .targets file to call the MetaTask. Here is a little example of how to consume MEF in code for those who are curious:

string location = Path.GetDirectoryName(typeof(MetaTask).Assembly.Location);
using (DirectoryCatalog catalog = new DirectoryCatalog(location))
{
    using (CompositionContainer container = new CompositionContainer(catalog))
    {
        Export<IPipeline> export = container.GetExport<IPipeline>(pipelineTypeName);
        using (IPipeline pipeline = export.GetExportedObject())
        {
            // ...
            pipeline.Process();
        }
    }
}

This code will load all assemblies at the given location then find the Exported type with the provided string ‘pipelineTypeName’. This value is passed into the MetaTask based on the desired DSL. Here is a sample of how to Export a pipeline.

[Export("MetaSharp.Transformation.Lang.Builder.NodeBuilderPipeline", typeof(IPipeline))]
public class NodeBuilderPipeline : CodeDomCodeGenerationPipeline
{
    //...
}

The string is the ‘pipelineTypeName’ passed into the MetaTask. Incredibly simple. To round out the example here is the MSBuild .targets file to bring it all together.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <!--Reference the assembly where our tasks are defined-->
    <PropertyGroup>
        <MetaSharpBinPath Condition="'$(MetaSharpBinPath)' == ''">.</MetaSharpBinPath>
        
        <!-- Pipelines -->
        <NodeBuilderPipeline Condition="'$(NodeBuilderPipeline)'==''">
            MetaSharp.Transformation.Lang.Builder.NodeBuilderPipeline
        </NodeBuilderPipeline>
        
    </PropertyGroup>
    
    <UsingTask TaskName="MetaSharp.Transformation.Builder.MetaTask" 
               AssemblyFile="MetaSharp.Transformation.Builder.dll" />

    <!--Compile target (this is the target that calls the compiler task)-->
    <Target Name="BeforeBuild">

        <MetaTask
            Templates="@(Node)"
            Configuration="$(Configuration)"
            Language="$(Language)"
            DefaultNamespace="$(RootNamespace)"
            Pipeline="$(NodeBuilderPipeline)">
            <Output TaskParameter="Generated" ItemName="Generated" />
        </MetaTask>

        <ItemGroup>
            <Compile Include="@(Generated)" />
        </ItemGroup>

    </Target>
</Project>

So now I’m happy, I think I can finally get past this build environment minutiae and onto the fun stuff!

Tags: , , ,

MetaSharp | MSBuild | .NET | C#

Turn on Code Analysis Early

by justin 24. March 2009 10:24

Both at work and my most recent project MetaSharp, I have been working on retroactively hooking up StyleCop to an existing code base. Let me just say that from now on this will be one of the first things I do when I start a new project! It’s sooo much easier to simply fix up new code as you write it than it is to go back over many files and fix literally hundreds of errors all at once.

It’s also important to hook up StyleCop and FxCop or whatever code analysis tool you are using to your build process. Don’t let it be an optional manual step, get it integrated right in with your build project files so you can get those error messages right away.

I’m happy to say that MetaSharp is now fully compliant with FxCop and StyleCop with almost all of the rules turned on. I had to turn down the documentation rules a little bit and the File Header rules. Anything that goes in a file header that is unique to that file defeats the purpose in my opinion.

The moral of the story is that if you don’t turn it on right away its likely to be too much of a pain to turn it on ever! And it really does add a lot of value to the code, I believe.

Tags: , ,

MSBuild | .NET | C#

About Me

sweetest hat ever

I'm a software developer from Minnesota and this blog largely focuses on various technical concepts I am thinking about at the moment. I currently work for Microsoft in the St. Paul office of the Expression product group.

RecentPosts