2010-04-30

Dynamically Binding to Static (Class-Scoped) Members

.NET 4.0 was a huge release, containing a wide variety of much-anticipated features. One of these features is the C# support for dynamic languages via the new keyword dynamic. Dynamic brings some very powerful semantics into the language, and naturally also comes with a few limitations.

One limitation is dynamically accessing static (class-scoped) members. The dynamic type is intended to represent a dynamic instance, not a dynamic class. For example, if two different classes have the same static method defined, there is no way to use dynamic to invoke those static methods.

One can use the DynamicObject class to redirect instance member access to static member access. This approach was first explored in David Ebbo's blog post "Using C# dynamic to call static members". However, this approach brings with it its own limitation.

The general concept is to implement a DynamicObject type that uses reflection to access static members. This makes sense since dynamic may be seen as a more user-friendly type of reflection (of course, this simple interpretation ignores a lot of other DLR benefits). Unfortunately, DynamicObject does not support the concept of ref/out parameters, even though they are fully supported by dynamic. There is a work-around for this: wrapping ref or out parameters, adding a layer of indirection. The RefOutArg class was invented for this purpose (official source):

/// <summary>
/// A wrapper around a "ref" or "out" argument invoked dynamically.
/// </summary>
public sealed class RefOutArg
{
    /// <summary>
    /// Initializes a new instance of the <see cref="RefOutArg"/> class.
    /// </summary>
    private RefOutArg()
    {
    }

    /// <summary>
    /// Gets or sets the wrapped value as an object.
    /// </summary>
    public object ValueAsObject { get; set; }

    /// <summary>
    /// Gets or sets the wrapped value.
    /// </summary>
    public dynamic Value
    {
        get
        {
            return this.ValueAsObject;
        }

        set
        {
            this.ValueAsObject = value;
        }
    }

    /// <summary>
    /// Creates a new instance of the <see cref="RefOutArg"/> class wrapping the default value of <typeparamref name="T"/>.
    /// </summary>
    /// <typeparam name="T">The type of value to wrap.</typeparam>
    /// <returns>A new instance of the <see cref="RefOutArg"/> class wrapping the default value of <typeparamref name="T"/>.</returns>
    public static RefOutArg Create<T>()
    {
        return new RefOutArg { ValueAsObject = default(T) };
    }

    /// <summary>
    /// Creates a new instance of the <see cref="RefOutArg"/> class wrapping the specified value.
    /// </summary>
    /// <param name="value">The value to wrap.</param>
    /// <returns>A new instance of the <see cref="RefOutArg"/> class wrapping the specified value.</returns>
    public static RefOutArg Create(object value)
    {
        return new RefOutArg { ValueAsObject = value };
    }
}

RefOutArg is a very simple class that contains a single value (which can be accessed either as object or dynamic).

The DynamicStaticTypeMembers class enables dynamic access to static members. It is similar to David's StaticMembersDynamicWrapper, only this class allows setting static properties, invoking overloaded static methods, and ref/out parameters using RefOutArg (official source):

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Dynamic;
using System.Linq;
using System.Reflection;

/// <summary>
/// A dynamic object that allows access to a type's static members, resolved dynamically at runtime.
/// </summary>
public sealed class DynamicStaticTypeMembers : DynamicObject
{
    /// <summary>
    /// The underlying type.
    /// </summary>
    private readonly Type type;

    /// <summary>
    /// Initializes a new instance of the <see cref="DynamicStaticTypeMembers"/> class wrapping the specified type.
    /// </summary>
    /// <param name="type">The underlying type to wrap.</param>
    private DynamicStaticTypeMembers(Type type)
    {
        this.type = type;
    }

    /// <summary>
    /// Gets a value for a static property defined by the wrapped type.
    /// </summary>
    /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
    /// <param name="result">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result"/>.</param>
    /// <returns>
    /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.)
    /// </returns>
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var prop = this.type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (prop == null)
        {
            result = null;
            return false;
        }

        result = prop.GetValue(null, null);
        return true;
    }

    /// <summary>
    /// Sets a value for a static property defined by the wrapped type.
    /// </summary>
    /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
    /// <param name="value">The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, the <paramref name="value"/> is "Test".</param>
    /// <returns>
    /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)
    /// </returns>
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        var prop = this.type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (prop == null)
        {
            return false;
        }

        prop.SetValue(null, value, null);
        return true;
    }

    /// <summary>
    /// Calls a static method defined by the wrapped type.
    /// </summary>
    /// <param name="binder">Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
    /// <param name="args">The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, <c>args[0]</c> is equal to 100.</param>
    /// <param name="result">The result of the member invocation.</param>
    /// <returns>
    /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)
    /// </returns>
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        // Convert any RefOutArg arguments into ref/out arguments
        var refArguments = new RefOutArg[args.Length];
        for (int i = 0; i != args.Length; ++i)
        {
            refArguments[i] = args[i] as RefOutArg;
            if (refArguments[i] != null)
            {
                args[i] = refArguments[i].ValueAsObject;
            }
        }

        // Resolve the method
        const BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public;
        object state;
        MethodBase method;

        var methods = this.type.GetMethods(flags).Where(x => x.Name == binder.Name);
        method = Type.DefaultBinder.BindToMethod(flags, methods.ToArray(), ref args, null, null, null, out state);

        // Ensure that all ref/out arguments were properly wrapped
        if (method.GetParameters().Count(x => x.ParameterType.IsByRef) != refArguments.Count(x => x != null))
        {
            throw new ArgumentException("ref/out parameters need a RefOutArg wrapper when invoking " + this.type.Name + "." + binder.Name + ".");
        }

        // Invoke the method, allowing exceptions to propogate
        try
        {
            result = method.Invoke(null, args);
        }
        finally
        {
            if (state != null)
            {
                Type.DefaultBinder.ReorderArgumentArray(ref args, state);
            }

            // Convert any ref/out arguments into RefOutArg results
            for (int i = 0; i != args.Length; ++i)
            {
                if (refArguments[i] != null)
                {
                    refArguments[i].ValueAsObject = args[i];
                }
            }
        }

        return true;
    }

    /// <summary>
    /// Creates a new instance of the <see cref="DynamicStaticTypeMembers"/> class wrapping the specified type.
    /// </summary>
    /// <param name="type">The underlying type to wrap. May not be <c>null</c>.</param>
    /// <returns>An instance of <see cref="DynamicStaticTypeMembers"/>, as a dynamic type.</returns>
    public static dynamic Create(Type type)
    {
        Contract.Requires<ArgumentNullException>(type != null);
        return new DynamicStaticTypeMembers(type);
    }

    /// <summary>
    /// Creates a new instance of the <see cref="DynamicStaticTypeMembers"/> class wrapping the specified type.
    /// </summary>
    /// <typeparam name="T">The underlying type to wrap.</typeparam>
    /// <returns>An instance of <see cref="DynamicStaticTypeMembers"/>, as a dynamic type.</returns>
    public static dynamic Create<T>()
    {
        return new DynamicStaticTypeMembers(typeof(T));
    }
}

An instance of DynamicStaticTypeMembers may be constructed by passing either a generic type or Type instance into the Create method:

var mathClass = DynamicStaticTypeMembers.Create(typeof(Math));
var intEqualityComparerClass = DynamicStaticTypeMembers.Create<EqualityComparer<int>>();
var threadClass = DynamicStaticTypeMembers.Create<Thread>();
var intClass = DynamicStaticTypeMembers.Create<int>();

Once created, any static property or method of that class may be invoked using instance syntax:

int result0 = mathClass.Min(13, 15); // invokes Math.Min(int, int)
var comparer = intEqualityComparerClass.Default; // gets EqualityComparer<int>.Default
threadClass.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob"), new string[] { }); // sets Thread.CurrentPrincipal

Invoking methods with ref or out parameters is more awkward, but possible:

int result1;
var result1arg = RefOutArg.Create<int>(); // or: RefOutArg.Create(0);
intClass.TryParse("13", result1arg); // invokes int.TryParse(string, out int)
result1 = result1arg.Value;

This can be a powerful tool in some cases, allowing a higher form of "duck typing." For instance, the new BigInteger numeric type defines its own DivRem method similar to the existing DivRem methods defined on the Math class for int and long. Using DynamicStaticTypeMembers, it is possible to define a generic DivRem that attempts to invoke Math.DivRem but falls back on a DivRem defined by the numeric type:

public static T DivRem<T>(T dividend, T divisor, out T remainder)
{
    var remainderArg = RefOutArg.Create<T>();
    dynamic ret;
    try
    {
        var dT = DynamicStaticTypeMembers.Create(typeof(Math));
        ret = dT.DivRem(dividend, divisor, remainderArg);
    }
    catch
    {
        var dT = DynamicStaticTypeMembers.Create<T>();
        ret = dT.DivRem(dividend, divisor, remainderArg);
    }

    remainder = remainderArg.Value;
    return ret;
}

Our generic DivRem can be invoked with T being int, long, BigInteger, or any other type as long as that type defines its own DivRem with a compatible signature.

Most programs will not require this level of type flexibility, but it's nice to know it's there for those few cases that do need it.

2010-04-26

Innovations Are Great, but Content Is Necessary

Remember when Bing came out? It was a little freaky how every single Microsoft blogger simultaneously started referencing Bing instead of Google. In fact, Google has become something of a taboo among Microsoft bloggers. Shortly after Bing's launch, I heard a couple of Microsoft presenters make light of the topic ("so if you Google this... ah, I mean... Bing this, because we don't use that other search engine, right?" as he continues to use Google); but they were careful not to get on record (their blog entries always do use Bing).

Bing has some pretty good innovations. I saw a video of Bing Maps in particular, where they showed not only the 3-D perspective with skylines and everything, but also live video if it was being shared with location data. That was pretty cool, I thought. I've also read how their street view is higher resolution than Google's (though Google has now gone near-HD as well, and are gradually redoing all their older street views).

The other day, I was looking for a good street view of an unfamiliar nearby location; Google's was too fuzzy to make out the name of the business, so I figured I'd give Bing a try. Bing didn't have any at all, which is not too surprising (since I live in Northern Michigan). I tried looking up a much larger city, with no luck. How about the state capital? No.

It turns out that all of Bing's street view coverage in the entire state is just a few streets in downtown Detroit. So all of Bing's innovation is completely worthless to me (and the more than 9 million other people in non-Detroit Michigan). Google, on the other hand, kept their innovation secret until they could provide it to the majority of people in the country. Their "street view" innovation was immediately useful when it was announced.

Because they had content.

2010-04-23

Generic Methods with Dynamic Implementations

Dynamic binding is one of the many new features included in .NET 4.0. I've been doing some testing today with mixing dynamic and generics, and came across a slightly obscure scenario that may or may not prove useful in the future.

When a dynamic object performs method resolution at runtime, the result is cached by the DLR in a "call site". The next time this code is run, the call site is only recomputed if there is a cache miss (i.e., different types of arguments are passed to the method).

We can use generics to turn one call site into many call sites, all cached independently, thereby improving performance when invoked later:

static dynamic SingleCallSite(dynamic arg1, dynamic arg2)
{
    return arg1 + arg2;
}

static T MultipleCallSites<T>(T arg1, T arg2)
{
    dynamic darg1 = arg1;
    return darg1 + arg2;
}

Even though the SingleCallSite method only has one call site (for the + operator) and the MultipleCallSites method has two call sites (one for the + operator, and one for converting the dynamic result to T), MultipleCallSites reliably runs faster, as this remarkably unscientific test code demonstrates:

static void Main(string[] args)
{
    try
    {
        int count = 1000000;
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i != count; ++i)
        {
            MultipleCallSites(13, 17);
            MultipleCallSites("test1", "merged");
            MultipleCallSites(30.5, 23.5);
        }
        sw.Stop();
        Console.WriteLine("Multiple call sites: " + sw.Elapsed);
        sw.Restart();
        for (int i = 0; i != count; ++i)
        {
            SingleCallSite(13, 17);
            SingleCallSite("test1", "merged");
            SingleCallSite(30.5, 23.5);
        }
        sw.Stop();
        Console.WriteLine("Single call site: " + sw.Elapsed);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: [" + ex.GetType().Name + "]: " + ex.Message);
    }

    Console.ReadKey();
}

This idea came from Luca Bolognese's blog post Simulating INumeric with dynamic in C# 4.0, where he states that with a generic signature "you get a different call site with each combination of type arguments and, since they are separate, the binding caches should stay small."

Final note: this is only an implementation detail of the DLR. These performance characteristics may change in a .NET service pack or future version.

2010-04-19

SVN Source Indexing to CodePlex

Open-source libraries naturally come with source code. However, the source is often not easy to use; compiling from source usually includes duplicating another programmer's toolset. Most programmers who use open-source libraries only use the executables, and ignore the source. They act as a "consumer programmer," a technologically-savvy end-user of the library, which was created by a "producer programmer."

When the consumer programmer is debugging, it would certainly be nice to step into the producer programmer's source code. Microsoft has enabled this for many of the .NET source files in their libraries. There is a way to enable a similar capability for open-source libraries as well.

The PDB

The symbol file (PDB) for an executable (DLL) includes information about where the original source files were (see PDB Files: What Every Developer Must Know, Source Server Helps You Kill Bugs Dead, and of course the Debugging .NET Apps book from the bugslayer man himself). Normally, this is just a simple file path, so the source file will only be found if the producer programmer is debugging his own code. The consumer programmer is out of luck.

However, there's a way for the producer programmer to add information to the PDB; specifically, he can add instructions to the PDB to check files out of version control on demand. This works great for the consumer programmer if the producer programmer uses a public source control server like CodePlex. In this case, if the consumer programmer needs to debug the library code, they can literally just step into it, and Visual Studio will automatically check out the correct source file from the matching revision and load it into its workspace!

There's a bit of setup to be done, and it's not quite automatic (there are a few prompts for security reasons). But it is still cool.

The Producer Programmer: Distribute Source-Indexed PDBs

The programmer who is developing the library must distribute "source-indexed" PDBs along with his library DLLs. A "source-indexed" PDB is a PDB that has extra information so it knows how to check out the appropriate source file. There are a few installation prerequisites for the producer programmer:

When the producer programmer is ready to create a release of his library, he follows these steps:

  1. Build the library binaries (and PDBs).
  2. Ensure all source code is checked in.
  3. Source-index the PDBs; assuming the PDBs are in the "..\Binaries" directory and DTfW was installed in "c:\Program Files\Debugging Tools for Windows (x86)":
    "c:\Program Files\Debugging Tools for Windows (x86)\srcsrv\ssindex.cmd" /SYSTEM=SVN /SYMBOLS=..\Binaries /Debug

All the PDBs in "..\Binaries" are updated in-place to point to the current source in source control. They are now ready to be released (note that the PDBs should be included in every release along with DLLs and XML documentation files).

Note that the "/Debug" switch is just an output verbosity option for SSIndex.cmd. The output from SSIndex should include a "wrote stream" message for each PDB. If there is anything in the output that looks like "[ERROR]", "zero source files found", or if no PDB files were found, then the source indexing was not successful for those PDB files.

The following command can be used to verify that the PDB was correctly source indexed:
"c:\Program Files\Debugging Tools for Windows (x86)\srcsrv\srctool.exe" MyLibrary.pdb
If the PDB is not source indexed, srctool will simply print "MyLibrary.pdb is not source indexed". If it is source indexed, then it will display all the source server commands that will retrieve the correct source files.

The Consumer Programmer: Allow Source-Indexed PDBs

The consumer programmer does have an installation prerequisite; since Visual Studio will use svn.exe to retrieve the source files, it must first be installed:

Once svn.exe is in %PATH%, the consumer programmer may enable source-indexed PDBs by checking the following option box in Visual Studio 2010: Options -> Debugging -> General -> Enable source server support.

At this point, a consumer programmer may step into the library code, and (after prompting for permission) Visual Studio will download the correct source file and allow stepping through the source.

2010-04-15

Declarative Programming Languages

There's a lot of excitement about declarative languages, as opposed to imperative languages.

Any programmer who has been around for a while knows that there's always been a lot of excitement about declarative languages. There's a tendency to overinflate their importance. Why, by using declarative constructs, we can program more efficiently (developer time gains)! Why, by using declarative constructs, we can have more intelligent interpreters (run-time gains)! Why, by using declarative constructs, we can have threadsafe programs (safety gains)!

And all of this is true, but only to a point. That point is at a very specific location: where the designers of the declarative language stopped adding features. So, declarative languages work great when the programmers stay within the box. However, no declarative language can do everything, and one of two things happens:

  1. The declarative language eventually ceases to evolve; e.g., a standards body decides that it is complete.
  2. The declarative language includes extension points (which are not written in the declarative language itself), so that others may add to the language; this results in a handful of experts feeding libraries to the masses.

Neither solution is maintainable in the long term.

Note that I'm only addressing declarative programming here; declarative languages are perfectly well-suited for declaring things, such as file structure or GUI layouts. But why do we take a perfectly good declarative language and try to shove programs into it?

Blast from the Past

I'm a relatively new programmer, entering the workforce in 1995. There was a big, new thing that came out around that time. It was called XML. XML was a declarative language, and if you believed all the hype about it, it could cure cancer.

XML was perfectly fine for what it was used for: structuring text data. Binary data was a bit more complex, but there were ways to make it work. Relational databases didn't fit perfectly into the XML world, but there were mappings that worked sufficiently. XML was even used to represent function calls (as data).

So, XML worked for data, and worked well. But then some genius decided to write an XML programming language. There was lot of talk about how XML declarative languages would be the future of all programming - seriously!

A lot of work went into designing various XML languages, only one of which has survived. It is called XSLT, and pretty much everyone hates it. Is it possible to program in XML? Yes. It is fun? No.

A Word about Functional Languages

Functional languages are sometimes called declarative languages, but I disagree with this classification. Imperative languages and functional languages are both concerned with how a program is supposed to run. Declarative languages attempt to make the semantic leap to only being concerned with what a program is supposed to do.

When looked at from this perspective, functional languages are really the same as imperative languages; they are just inside-out from each other. Declarative languages are completely different.

Partially-Declarative Languages

LINQ is an example of a declarative sub-language within an imperative language (C# or VB). LINQ, when used with the Queryable system, will actually build a complete expression tree. The LINQ provider can then use that higher-level view of the code to generate the most efficient implementation.

Since anyone is free to implement a LINQ provider, LINQ is an example of a declarative language with an extension point (the Queryable system). People have written providers for an amazing array of data sources.

The problem: implementing a LINQ provider is hard! Getting one working is hard enough; making it general-purpose (i.e., intelligently handling all LINQ operations) is a nightmare; and creating one that is efficient is next to impossible. So, this leads us to the predictable conclusion: a handful of provider authors attempting to satisfy the demands of the masses. Furthermore, the vast majority of LINQ providers only do the minimum necessary to get it working; they are neither general-purpose nor efficient.

Declarative Languages Aren't All Bad

If a programmer can stay within the existing boundaries of a declarative language, then they are very useful! I love LINQ and I love XAML data binding, both of which are declarative. I'm just trying to point out that "declarative languages" are not general-purpose solutions for all problems.

Microsoft made a genius decision with regards to LINQ in particular: they allow a programmer to "step out" of the declarative language when the language falls short. They did this by including LINQ to Objects, which is functional and not declarative, technically speaking. Every LINQ provider has its own limitations (that "point" where the implementors stopped adding features), and at that point one can use "AsEnumerable" to transfer from the declarative system to a functional one.

Example: LINQ to Entities cannot select new object instances like this: "db.ServiceSet.Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString(), Selected = x.Id == serviceId });"
However, one can use LINQ to Entities to retrieve the entity set and then switch to LINQ to Objects to complete the transformation: "db.ServiceSet.AsEnumerable().Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString(), Selected = x.Id == serviceId });"

Final Rant: Declarative Code Is Still Code

Remember a few years ago when XAML came out? I had a hard time keeping from laughing out loud at some of those demos.

First off, the central breakthrough is that we're now using declarations to declare the UI (instead of doing it with code, a la WinForms)... But it's kind of funny that before WinForms, the way to declare the UI was using an old thing called a dialog resource... and this dialog resource was declared within an RC file, which was written in a declarative language. Going in circles is always amusing.

The really funny part of a lot of these demos, though, is when they would try to code in XAML. After showing how amazing it was to declare a UI in XML, they showed us how it could even support (limited) programming! Without fail, after cutting and pasting tons of XAML, they would show some fancy UI animation and proudly proclaim: "with zero lines of code!"

So... um... you just took a dozen lines of C# and replaced it with a couple hundred lines of XAML? And that's an improvement? I'm sorry to break it to you, fella, but XAML is still code!

Of course, XAML is good for declaring things like UIs or even animation sequences. But programmers trying to do real programming in XAML quickly run into its limitations. Ever try to chain a converter? Or apply a filter on a collection? Just like LINQ, XAML can be extended, but it is surprisingly difficult.

MVVM advocates originally attempted to achieve the "no code-behind nirvana," but quickly ran into the limitations of the declarative language (XAML). A handful of brave souls attempted to fill the gaps - at least for their specific needs - but the general advice from the MVVM community has shifted to the more practical "minimal code-behind."

Conclusion

The fundamental problem with every declarative language is that the programmer has to place themselves at the complete mercy of the language designer(s). It's simply unmaintainable as a permanent solution. I believe that every sane programmer will continue programming in imperative languages and continue declaring in declarative languages.

And there's nothing wrong with that, in spite of the declarative programming hype.

2010-04-13

VS2010 WebDeploy and VS2010 Web Deployment Projects Beta 1

Edit 2010-04-15

VS2010 will overwrite SourceWebPhysicalPath when re-loading a solution containing a WDP, so the fix below will not work. It is kept on this site for historical purposes only.

VS2010 includes a number of enhancements to web deployment, as Scott points out. One of the coolest is the web.config transformations. They also included all kinds of functionality for automatically setting up IIS as part of a "deployment package" (getting pretty close to re-writing Windows Installer, actually).

The end result is a really powerful solution that a mom-and-pop web guy like me doesn't really need. I would like the ability to precompile a web application, and this is one of the "blind spots" of VS2010.

Web Deployment Projects (WDP) does have a (beta) release for VS2010, though it starts to show its age when lined up next to VS2010's web deployment. It does, however, have the capability to precompile web apps.

It's possible to have the best of both worlds: web.config transformations from VS2010 and precompiling from WDP. All you have to do is:

  1. Create a VS2010 deployment to the local file system, in a "staging" directory. Set up the web.config transformations and make any other necessary changes.
  2. Create a WDP for the web application. By default, it will copy the web application project itself rather than the deployment output.
  3. Change the WDP project file to set the SourceWebPhysicalPath property to your staging directory.

Example:

<SourceWebPhysicalPath>c:\staging\mywebsite</SourceWebPhysicalPath>

This will work as long as you don't need the advanced IIS application setup options available through VS2010 deployment. If you do, then you're probably better off incorporating ASP.NET compilation and merging as a post-build event or within the MSBuild file.

VS2010 Without Web Deployment Projects

Visual Studio 2010 was released yesterday, as just about everyone knows. I didn't find out until tonight that the Beta 1 of WDP for VS2010 is also available.

I've been working on getting the church website moved to the new platform. It has gone fairly smoothly, aside from a compilation error which forced me to move the EF model into a separate assembly (but since that's best practice anyway, I didn't mind).

Excluding Files

We have limited bandwidth at home (Northern Michigan, remember...), so I've used WDP in the past to exclude many of the files during deployment (pdbs and xmldoc in particular). VS2010 has greatly enhanced deployment support, but it doesn't quite cover WDP's feature set.

VS2010 will ignore pdb files if you check the "Exclude generated debug symbols" under the "Package/Publish Web" tab. Other files are still thrown in the mix, though, unless you add this to your project file:

  <PropertyGroup>
    <ExcludeFilesFromPackage>true</ExcludeFilesFromPackage>
  </PropertyGroup>
  <ItemGroup>
    <ExcludeFromPackageFiles Include="$(ProjectDir)bin\*.xml">
      <FromTarget>Project</FromTarget>
    </ExcludeFromPackageFiles>
  </ItemGroup>

This is very similar to WDP's ExcludeFromBuild item group that uses the SourceWebPhysicalPath property. There are two major differences: the ExcludeFilesFromPackage property needs to be set (otherwise, the ExcludeFromPackageFiles item group would be ignored), and the ProjectDir property ends in a backslash (whereas the SourceWebPhysicalPath property did not).

Precompiling (sort of)

VS2010 does not have the option of precompiling ASP.NET web applications (it will, however, precompile ASP.NET web sites). This is sad, but there is sort-of a workaround.

It's possible to force MVC views to be precompiled by placing this in a PropertyGroup in the project file (I prefer placing it in the PropertyGroup with the condition "Release|AnyCPU", so that it only takes effect on release builds):

<MvcBuildViews>true</MvcBuildViews>

This will cause the MVC views to be compiled, catching all compile-time errors at build time. Unfortunately, the compiled views are then thrown away instead of being merged into the web application assembly.

Full precompiling (and merging with the web application) is available in WDP Beta 1. Or, if you enjoy painful programming, you can do it yourself in MSBuild. ;)

T4: Almost Complete

Visual Studio 2010 was released today, and one of the (many) improvements is that T4 gets better support. T4 is a promising addition to the VS family of languages.

Currently, .NET languages do not have built-in metaprogramming support (which C++ has had for years). They do have generics and dynamic dispatch, which do handle some of the metaprogramming use cases, but they also have their own limitations. Both of these solutions generate code at runtime.

There are two other metaprogramming solutions currently available. T4 is a solution that generates code before compiling. The other solution exists at the other end of the spectrum: IL rewriters such as CciSharp can be used to modify (and generate) code after compiling.

T4 is a good step in the metaprogramming evolution. It allows generating one (or more) classes from a given template. T4 templates allow you to use an ASP-like syntax to create C# code using C# code. [Side note: T4 can generate a lot more than C# code; it can generate any kind of text files].

This is excellent, but there is one little part left out: the T4 template must be executed for it to generate its classes. It would be really great if there was a way for a T4 template to declare it can create class names matching a certain pattern (and receive a "requested class name" as a parameter). Then the compiler (or a compiler wrapper such as an MSBuild task) could execute the template "on demand," as those classes are used by other code.

Of course, this is a non-trivial change to make to the build system. But if we ever get there, then C# will become a language with complete metaprogramming support. As it currently stands, there's a small hole remaining.

Example: I recently wrote CRC16 and CRC32 classes, but they're based off a generic CRC algorithm that is valid for any bit length. They are currently independent classes, but they can be fairly easily changed to a single T4 template that can generate CRC classes for different bit lengths.
The problem: any code that needed a different bit length would have to modify the template parameters in order to generate another CRC class, instead of letting the class name itself act as an implicit template usage.

2010-04-06

Sharp Corners: IList<T>.IsReadOnly != IList.IsReadOnly

Here's a "sharp corner" of sorts, though it's with the BCL rather than the C# language. It turns out that the property IsReadOnly changed meanings from IList to IList<T>. As of this writing, it's unclear whether this change in meaning was intentional; the MSDN documentation for both properties is identical (and ambiguous).

[TestMethod]
public void IListOfT_IsReadOnly_IsDifferentThan_IList_IsReadOnly()
{
    int[] array = new[] { 13 };
    IList<int> generic = array;
    System.Collections.IList nongeneric = array;

    Assert.AreNotEqual(generic.IsReadOnly, nongeneric.IsReadOnly);
}