Saturday, September 13, 2008

C# mod operator (%) and negative numbers

The C# mod operator, %, takes the sign of the dividend as the sign of the result. Simply, this means that -1 % 3 is -1, and not 2 as I was expecting. Apparently every language I've ever programmed professionally in behaves the same as C#, so I'm surprised I never noticed it before. Of the other 2 languages I have handy, F# behaves just like C#, while Ruby gives me the result I expected.

A more comprehensive list can be found at Wikipedia.

This came up while trying to learn some WPF. I have a main window and a bunch of child windows that I want to cycle through with ctrl-tab. When I went to add cycling backwards with ctrl-shift-tab I was rewarded with a nice ArgumentOutOfRangeException.

Tuesday, July 01, 2008

NUnit within Visual Studio

My current client is not licensed for TFS, so we're going with NUnit for unit testing. Rather than pay actual money for TestDriven.net, we're using NUnitForVS, a nice free codeplex tool that integrates NUnit with all the unit testing infrastructure present in Visual Studio 2008 Professional and Team Editions.

It was a bit flaky at first, but a recent release has fixed all the non-trivial problems.

Check it out here.

Tuesday, June 10, 2008

Windsor and Linq DataContexts

For one of the systems I built I needed to use the Windsor container to resolve instances of a Linq DataContext. The DataContext was created using the standard Linq dbml designer. Using standard Windsor stuff, the configuration should look something like this:

<properties>
<connectionString>
Data Source=server;
Initial Catalog=Sample;
Integrated Security=True
</connectionString>
</properties>

...

<component
id="datacontext"
service="Sample.SampleDataContext, Sample"
type="Sample.SampleDataContext, Sample"
lifestyle="transient">
<parameters>
<connection>#{connectionString}</connection>
</parameters>
</component>

Easy, right? Unfortunately if you try to run this and do container.Resolve<SampleDataContext>(); you'll get an error like: "Key invalid for parameter connection." It turns out that what is happening is that Windsor doesn't know which Constructor to use. The generated DataContext has 2 single parameter constructors, one that takes a string named "connection", and the other that takes an IDbConnection named "connection". I think what happens is that the container tries to convert the property to an IDbConnection and it fails.

What we need to do is change the way the constructor is chosen. One simple way is just to add another constructor to your DataContext with a dummy ignored parameter. Like this:

public SampleDataContext(string connection, int ignoreThis)

If you then add <ignoreThis>5</ignoreThis> to the parameters section in the config then Windsor will find your new constructor and everything will work. This, however, is ugly.

A better way is to create a Facility. What we're going to do is assume that all our DataContexts will follow the same pattern, i.e., that we always want to use the constructor that takes a single string parameter.

First, we create a facility that inherits from Castle.MicroKernel.Facilities.AbstractFacility. We want to replace the default ComponentActivator, so we'll need to get ahold of the ComponentModel when it's created. We can override Init like this:

protected override void Init()
{
Kernel.ComponentModelCreated +=
(model) =>
{
if (typeof(System.Data.Linq.DataContext)
.IsAssignableFrom(model.Implementation))
{
model.CustomComponentActivator = typeof(CustomActivator);
}
};
}

Notice we're only setting a custom activator for classes that inherit from DataContext. Now all that's left is to implement CustomActivator. Luckily, the default activator is designed to be inherited from; everything we need to change is virtual. Create CustomActivator that inherits from Castle.MicroKernel.ComponentActivator.DefaultComponentActivator. You'll need a constructor that takes the same parameters. All we need to do is override SelectEligibleConstructor to force the container to choose the single string parameter one. We can do that just like this:

protected override
ConstructorCandidate SelectEligibleConstructor
(CreationContext context)
{
return
Model.Constructors.Cast<ConstructorCandidate>()
.First(c => c.Constructor.GetParameters().Length == 1
&& c.Constructor.GetParameters()[0]
.ParameterType == typeof(string));
}

The final step is just to add the facility to our configuration.

<facilities>
<facility id="linqFacility" type="Core.LinqFacility, Core" />
</facilities>

Now everything works as expected for all DataContexts in our config.

Wednesday, May 14, 2008

Anonymous Interface Implementation

With the introduction of lambdas, it's now incredibly easy to pass tiny bits of functionality around. Unfortunately, some existing methods in the Framework take parameters of an interface type, instead of a delegate. Contains, for example, takes an IEqualityComparer instead of a Predicate. This makes using these methods in an ad-hoc manner difficult. What we need is the ability to quickly throw together a temporary class that implements the interface, basically an anonymous type only with method implementation.

I submitted a Connect item about this (here), but as you can see it won't be making it into this release.

To tide myself over I wrote a version that is built on anonymous types, Reflection.Emit, and Funcs. You can download it here. This is a proof of concept...no warranties...don't use in production...blah blah blah.

As a sample, here's how to create an instance of IEqualityComparer that thinks strings are equal if they are the same length:

Make.Instance<IEqualityComparer<string>>(
new {
Equals = Make.Func(
(string x, string y) => x.Length == y.Length)
})


I had to use Eric Lippert's trick to get lambdas and inferencing working in anonymous types.

Friday, April 04, 2008

DataContractSerializer and 0 length array

In short, I don't think the DataContractSerializer for WCF likes 0 length arrays at all. I was getting mysterious exceptions and random crashing of my WCF service. I was using wsHttpBinding and getting some WS-Trust invalid or expired security token message so I switched to basicHttpBinding. When debugging that, after the return of my method on the server side, cassini would crash and I'd get Fatal Execution Engine Error messages in my event log.

I cut my service method down to nearly as simple as it could go:

return new MyClass { Name = "BLARG", Children = new MyClass[0] }

and that was still dying. But when I changed it to
Children = null
everything magically started working.

This really merits more investigation but it's after 5 on a Friday and I'm going home.

Tuesday, March 25, 2008

New stuff

New job means new laptop. New laptop means new laptop bag.

The new laptop is a Lenovo T61p with the 15" screen. I'm running Vista x64 on it and that part has gone smoothly so far. Design-wise, I think I liked my Dell D820 better. The T61p feels much heavier than the Dell (though I do have a 9 cell battery in this one), the screen is slightly off center, and I don't like the keyboard layout at all. I'm perhaps overly concerned about keyboard layouts and this one just doesn't do it for me. The biggest issues for me are that the arrow keys aren't normal sized keys, the escape key sits above F1, and the lower left corner is a special Fn key, rather than Ctrl. By default, Fn-Space triggers the built in Lenovo Zoom utility, which is really jarring when you just intended to pop up intellisense. I'm sure I'll get used to all that though.

The new laptop bag is an Ogio Metroid and it's nothing but fantastic. I was originally worried that the T61p wouldn't fit, but it easily does. The Metroid is a backpack with a laptop pocket, but it also has a file section in the front that keeps my papers from sliding down and getting crumpled in the main pocket. There's plenty of room for all my junk and the mp3 player pocket fits my external hard drive just fine. Plus, I got it from amazon for $60 (of which work reimbursed me $40).

Wednesday, February 27, 2008

Derived Properties in LINQ to SQL

When using a rich domain model, you often end up with properties that are dervied from other persisted values. To take a trivial example:

public bool HasMiddleName
{
get { return MiddleName != ""; }
}

where MiddleName is a persisted property (column in the database, mapped by LINQ, etc.).

This works fine in object land, but breaks down when you need to query the database based on this property. LINQ to SQL can't read into the definition of the property itself and figure out what to do. If you try to run something that looks like:

setOfObjects.Where(o => o.HasMiddleName)

you'll get an exception saying that LINQ to SQL doesn't know how to translate HasMiddleName.

Now you're left with a choice: either duplicate the implementation of your property in the query, or come up with something clever. Starting with the assumption that duplicating domain knowledge is bad, let's explore the clever path.

Our particular architecture builds up queries using IQueryable, to make sure that as much of our logic as possible is executed by the database, rather than in memory. IQueryable<T>.Where takes an Expression<Func<T, bool>>, basically an expression that represents a function taking your object and returning a boolean. In the normal case, you just pass a lambda to Where and the compiler builds the expression for you. In our case, we have to build the expression ourselves. Back in the domain object we do:

public static readonly Expression<Func<MyObject,bool>>
HasMiddleNameExpr = o => o.MiddleName != "";

Now we can write queries that look like:

var result = setOfObjects.Where(MyObject.HasMiddleNameExpr)

and things will run just fine. Great! Except we still have duplication: our object has a property with logic in it, and the definition of the expression with the logic in it. Let's remove that.

First, since Expressions can't be invoked directly, save a compiled version of the expression (i.e., a Func<MyObject,bool>).

public static readonly Func<MyObject,bool> HasMiddleNameFunc =
HasMiddleNameExpr.Compile();

Now, define the property in terms of the Func.

public bool HasMiddleName
{
get { return HasMiddleNameFunc(this); }
}

Now all the duplication is removed. Unfortunately this seems like quite a few hoops to have to jump through. Instead of just a property we now have a property, a static function, and a static expression representing the function.

Unfortunately, it gets worse. The particular query we were writing depended on two derived properties and not just one. That meant that we couldn't just call Where with our expression. We wanted all objects where either one or the other property was true. That meant we had to build the or expression ourselves. It looks something like this in the query:

ParameterExpression p =
Expression.Parameter(typeof(MyObject), "p");

var result = setOfObjects.Where(
Expression.Lambda<Func<MyObject,bool>>(
Expression.OrElse(
Expression.Invoke(MyObject.HasMiddleName,p),
Expression.Invoke(MyObject.HasLastName,p)),
p));

What this does is build an expression that represents something like:

p => MyObject.HasMiddleNameFunc(p) ||
MyObject.HasLastNameFunc(p)

The combining of two Func<T,bool> expressions via a logical operator could probably be hidden by an extension method to clean things up a bit.

Ultimately, though, we ended up deciding that there was no way a junior developer reading this code in the future would be able to maintain this, much less understand it. After all this exploration we opted just to duplicate the domain logic in the query.

Friday, January 25, 2008

Also

Why does SqlMethods.Like throw NotImplementedException when you try to use it against in memory objects?

It seems like it would be pretty easy to actually implement it with RegEx or something. It's really inconvenient that you can't mock your database to test tricky queries with in memory objects because of this.

Edit: Vote for my feedback!

Misc. Project Notes

First, a minor annoyance: If you happen to have join tables without primary keys defined, the LINQ designer won't generate the properties corresponding to the association. Either go have a talk with your DBA or update the Primary Key property for your Properties in the designer and you'll be fine.

Second, TFS is proving more of a hindrance than a help sometimes. So much of the build setup requires duplicated settings on all clients, rather than being centrally managed. Policies must be installed on all machines, code analysis configurations have to be imported into the solution, etc. It seems like the right way for this to work would be for the TFS server to transparently distribute and install any artifacts required by the project.

Additionally, code analysis is nice, but there's no way to have a check in policy that uses it that only applies to some of the projects in the solution. We'd like to exclude our unit test projects (since [ExpectedException] tests in particular result in unreferenced variable warnings), but it's all or nothing.

The source control piece is definitely nicer than VSS, but really, what isn't? There are a few recurring issues, though. Sometimes opening a solution causes lots of the project files to get checked out, even though there are no changes locally (doing a Compare confirms that all files are identical). The other issue revolves around the vsmdi file used with the testing bits. For some reason this file is included in the solution and checked into source control, even though it contains user-specific information. If you bring up the test list window and pick 3 tests to run, the vsmdi is updated to show this. VS tries to check out the file (which someone invariably already has out), which results in VS checking out the solution and adding a new vsmdi file named solutionname1.vsmdi (followed by solutionname2.vsmdi, etc.). Excluding vsdmi from source control entirely as part of TFS settings gets ignored, excluding the file manually from the solution gets ignored, etc. I'd love a workaround for this problem.

The only other thing that would make things easier is an update for BizTalk 2006 R2 so we can use VS2008 to develop against it and not have to run 2 IDEs (and have custom build steps using the 2005 devenv in our team build).

Despite all that complaining, we still have a pretty clever solution going that uses a ton of cool technologies like LINQ, CI, MSTEST, Rhino Mocks, Watin, Windsor, ASP.NET MVC, WCF, and BizTalk 2006 R2.

Thursday, December 20, 2007

Whining

WatiN is a reasonably nice tool for automating UI tests. It even has a recorder that we could probably get our BAs to understand. It seems like a great fit for having the BAs (basically 'the customer') create our acceptance tests. They click around for a bit, save the recorded test as an MSTest cs file, and send it to a developer who adds this file to our Test Project. Now, through the magic of Team Builds, we have automated acceptance tests that are owned by the business and not developers.

Except:
- WatiN basically scripts IE so it needs to open an IE window.
- VS Team Build runs as a service.
- The client's policy forces that service to run as a specific service account, not LocalSystem.
- Only a service running as LocalSystem can be allowed to interact with the desktop.

End result:
There's no way to have automated acceptance tests with WatiN as part of our CI Team Build.

Great.

There are arguments to be made about not needing acceptance tests to run at every build and maybe they could be scheduled to run nightly or something. The downside is that all the test results are now outside of all the TFS reporting. We're talking ourselves into this being ok.

What's not ok is that we were also planning to use WatiN for developers to create UI-related integration tests. Those definitely need to run as part of our CI build. Given the above restrictions, we decided to investigate the Web Test feature of MSTest. Feature-wise they seemed to be a good fit.

Except:
Web Tests are only available in the Tester edition of VSTS and all the developers have Developer edition.

How frustrating.

Friday, November 16, 2007

More functional Ruby

I just stumbled across Reg's blog today after a link from Jeff Atwood's. Almost immediately I found this post about turning strings into procs in Ruby. Wow.

One of the only things about Ruby that consistently bugged me was the difficulty of passing existing functions into methods expecting blocks without having to wrap them in boilerplate junk. This (and Symbol#to_proc) basically cleans all that up.

He also has a nice implementation of unfold posted.

IronRuby can't get here fast enough.

Monday, October 22, 2007

A quick note about Extension Methods

If you're ever adding extension methods to a generic type (like say, IEnumerable<T>), nothing says you have to keep the same constraints on T for your method. For example, maybe your method is only relevant for reference types.

Assume you have a simple class called Box<T> with a single property Contents of type T. Box is just a box (a wrapper) around an instance of some unconstrained type T. You could define something like:

public static bool IsNull<T>(this Box<T> box) where T : class //note the new constraint

Now our extension method will only apply to Boxes whose T is a reference type.
Box<string> sbox = new Box<string>("abc");
bool isNull = sbox.IsNull(); //this works

Box<int> ibox = new Box<int>(5);
isNull = ibox.IsNull(); //does not compile

For some reason I expected the extra constraints not to work and I was surprised when they did. Of course you can only make your extension method type parameter more constrained than the existing type.

Sunday, September 30, 2007

Build your own whiteboard

Everyone knows that a developer's productivity is directly proportional to the total surface area of whiteboard he has access to, but places like Office Depot want $150 or more for a whiteboard of any appreciable size. Luckily, building your own is incredibly easy. Here's all you have to do:

  1. Head to your local hardware store to acquire materials. You'll need:

    • A 4'x8' sheet of melamine coated board. I found this in the Building Materials section. This is the key piece of the whole thing. Obviously 4'x8' is a lot of whiteboard. I had the helpful hardware store employee cut mine into 2 pieces, a 3'x4' and a 5'x4'. The whole thing is about $11.

    • Since the board is thin and wobbly, you'll need something to stabilize it. I opted to build a simple wood frame to mount the board to. You could glue it to a big sheet of plywood, but that will make the whole thing pretty heavy and difficult to move. Alternatively you could just mount the board directly to one of your walls with glue or cleverly placed trim or something.

      The hardware store sold nice 1.5" wide pieces of pine that came in 8' lengths. I bought 4 and had them custom cut to the size I needed. 2 were cut into a 3' length and a 5' length (for the top and bottom of the frames), and the other 2 were cut into 2x 3'-9" pieces each (4 total) to form the sides of each board (4' tall - 1.5" for the width of the top frame piece - 1.5" for the width of the bottom frame piece). Each one of these was about $2.

    • To assemble the frame I bought some flat L-shaped brackets. The packages I found came with 4 brackets and all the screws. I bought two of these for about $3 each.

    • Finally, to glue the board to the frame I bought some construction adhesive. It comes in a tube that fits in a caulk gun which you may have to buy if you don't have one. It was about $4.

    • If don't have some already, get some sandpaper to smooth out the frame edges.


    Total material cost is just under $30. For the record, $30 < $150.

  2. Now to build the thing. First sand the frame pieces nice and smooth.

  3. The brackets I bought said to drill 5/64" pilot holes before running the screws, so I dutifully complied.

  4. Then I screwed in all the brackets. I did the first 2 one at a time, but for the final 2 I put them in loosely and then tightened gradually going from one side to the other to make sure everything lined up fine.

  5. Now, place the melamine white side down on the floor (maybe on a towel so as not to scratch anything). Run a nice solid line of construction adhesive along the frame you just built on the side you didn't mount the brackets on.

  6. Place the frame onto the melamine, line things up, and press down firmly all along the edges. This step is much easier if you can procure the aid of a Lovely Assistant.

  7. Put some bricks or something heavy along the edges of the frame to hold things together while the adhesive sets up.


I let mine set up for a day and by then it was rock solid. I now have 2 giant whiteboards that cost about $30 and less than an hour of labor total. Not bad at all.

Tuesday, June 12, 2007

Extending the CalendarExtender

The Ajax Control Toolkit comes with an extender that automatically adds a javascript-based calendar popup to any TextBox. While the calendar is certainly nicer than the ASP.NET control that requires a postback for every action, the customization options are severely limited. In particular, the CalendarExtender always allows selection of every single date. For one of our apps we needed to limit the selection to certain days. This is how we did it.

The implementation of the CalendarExtender (mostly) lives in CalendarExtender.cs and the client-side javascript file, CalendarBehavior.js. Nearly everything we need is in the javascript. For our limited scenario, we decided to simply add a property to the control that lets you specify a javascript function to call that returns a bool, indicating whether or not the date is selectable. First, add the new property to the cs file:

[ExtenderControlProperty]
[ClientPropertyName("isDateSelectableFunction")]
public string IsDateSelectableFunction
{
get { return GetPropertyValue("IsDateSelectableFunction", ""); }
set { SetPropertyValue("IsDateSelectableFunction", value); }
}


The ExtenderControlProperty attribute tells the toolkit to magically make your property available on the client side, while the ClientPropertyName attribute tells the toolkit what name to give the client property. GetPropertyValue and SetPropertyValue just move things back and forth from ViewState.

The real work is done in the behavior file. First we have to initialize our new property. This happens right at the top of the file.

this._yearsBody = null;
this._button = null;
//new
this._isDateSelectableFunction = null;


Now we have a private field that will automatically get populated with the value set on the server control. Since javascript doesn't support Properties like C#, we need to add getter and setter methods. Above the definition for "get_animated" add the following

get_isDateSelectableFunction : function() {
return this._isDateSelectableFunction;
},
set_isDateSelectableFunction : function(value) {
this._isDateSelectableFunction = value;
},


Next, we have to use it. There's a lot of javascript to wade through, but the important bits are all in one place. The CalendarExtender has several views, allowing you to select days, zoom out to months, or zoom out to years. Since date selection only happens on the days view, that's the only thing to be modified. The extender builds a single grid to represent the month and then renumbers each cell whenever you switch months. All we're going to do is insert a bit of code when the numbering is happening. This numbering happens in the _performLayout function. Find this function in the js file. There's a big switch statement on this._mode to handle which view is currently active. We're interested in the "days" case.

There are 2 main for loops here. The first (from i = 0, i < 7) renders the headers, while the next one is nested and walks over both weeks and days. Right after

$common.removeCssClasses(dayCell.parentNode,
[ "ajax__calendar_other", "ajax__calendar_active" ]);
Sys.UI.DomElement.addCssClass(dayCell.parentNode,
this._getCssClass(dayCell.date, 'd'));


but before

currentDate = new Date(currentDate.getFullYear(),
currentDate.getMonth(), currentDate.getDate() + 1);


we're going to add our code. At this point, the cell (dayCell) has been populated with the right number and currentDate is set to the date in the cell. All we do is pass this date into our function and take action based on the result. Here's the code:

$common.removeHandlers(dayCell, this._cell$delegates);
if(eval(this.get_isDateSelectableFunction() + "(currentDate);"))
{
$addHandlers(dayCell, this._cell$delegates);
}


What we've done is really simple. First, we unhook the event handlers for the cell. This makes them not clickable (and removes the mouseover highlighting). Next, if the result of our function is true, we add the handlers back. It's important to remove and re-add instead of just doing an "if(!eval) remove" type of thing because the grid is reused for every month, so we must handle both cases every time.

That's all there is to it. An easy additional feature would be to have a separate CSS class for selectable dates. To do that, first add the name of your CSS class to the call to $common.removeCssClasses (e.g [ "ajax__calendar_other", "ajax__calendar_active", "my_new_class ]). Then, put Sys.UI.DomElement.addCssClass(dayCell.parentNode, "my_new_class"); inside the "if(eval)" block.

For completeness you should probably handle disabling the "Today" link at the bottom of the calendar when today isn't a valid date, but given the above information you can handle that the same way.

Here's a snippet of the control used in a page that limits the selectable dates to Mondays only.


<script language="javascript" type="text/javascript">
function isSelectable(x)
{
return x.getDay() == 1; //Mondays
}
</script>

...
<asp:TextBox ID="txtDate" runat="server"></asp:TextBox>

<ajax:CalendarExtender ID="calExtDate" runat="server"
TargetControlID="txtDate" PopupButtonID="imgCal"
IsDateSelectableFunction="isSelectable"></ajax:CalendarExtender>

Thursday, May 31, 2007

Quick Note

If you use regular expressions to validate email addresses, make sure you allow '+' before the '@' character. This is perfectly valid according to the RFC and some email servers let you do fun things with it. Gmail, for example, delivers anything addressed to 'youremail+anythingyouwanthere at gmail' to 'youremail at gmail'. Combined with filters that automatically label and file items, you can get email delivered directly to a specific folder. I know some unix mail systems support this stuff, too.

Don't be lazy with your regular expressions.

Tuesday, May 08, 2007

Dynamic Cast in C#

C# allows you to overload the implicit and explicit cast operators to permit your class to be converted to another, either automatically (implicit) or declaratively (explicit). All the necessary conversions are determined and applied by the compiler, at compile time. For example, if you have the following (assume A and B aren't in the same hierarchy):

A a = new B();

The compiler will look to see if B has an implicit cast operator (defined as a static method) and insert it for you if it exists, or fail with a type checking error if it doesn't. Likewise

A a = (A)(new B());

will cause the compiler to insert a call to the explicit cast operator defined in B that casts to A, or fail if it doesn't exist.

This is fine when you only need to handle conversions based on the compile-time type of your objects. If, however, you had written this extremely contrived example:

B b = new B();
object o = b;
A a = b;

This would fail to compile because the compiler is now checking the type "object" for an implicit cast to A, even though the underlying type of o is "B". If you put an explicit cast in "A a = (A)b;" it would then fail at run time, like any other invalid cast. What is really needed is a way to apply cast operators based on the run-time type of the object. This ends up being a pretty simple exercise in reflection.

public static MethodInfo GetMethod(Type toSearch, string methodName,
Type returnType, BindingFlags bindingFlags)
{
return Array.Find(
toSearch.GetMethods(bindingFlags),
delegate(Refl.MethodInfo inf)
{
return ((inf.Name == methodName) && (inf.ReturnType == returnType));
});
}

public static T DynamicCast<T>(object o)
{
Type ot = o.GetType();
MethodInfo meth = GetMethod(ot, "op_Implicit", typeof(T),
BindingFlags.Static | BindingFlags.Public);
if(meth == null)
{
meth = GetMethod(ot, "op_Explicit", typeof(T),
BindingFlags.Static | BindingFlags.Public);
}

if(meth == null) throw new InvalidCastException("Invalid Cast.");

return (T)meth.Invoke(null, new object[] { o });
}

Now we can just do

B b = new B();
object o = b;
A a = DynamicCast<A>(o);

and everything works.

Thursday, March 08, 2007

Anonymous Method Subtleties

As explained quite clearly by Raymond Chen here, the compiler generates a few different things when confronted with an anonymous method, based on what the method does. If the method doesn't refer to anything other than its parameters, it generates a static method on the containing class. If it refers to class instance members, you get an instance method. When the method refers to other variables in the lexically-enclosing method (basically when you need a closure), the compiler generates a sealed nested class to track those variables and puts the method there.

We have an interesting framework scenario where controls register event handlers with a custom base page. In the "add" section of the event in the page, we need to get a reference to the control that is adding the handler. Generally this is available by reading "value.Target" (value is a Delegate since we're inside the "add" of an event). However, if you happen to be using an anonymous method as your handler and you happen to change it to require a closure, "value.Target" will instead point at the compiler-generated nested class. This nested class inherits from nothing, implements no interfaces, and has a field for each captured variable as well as a reference to the instance the anonymous method is defined in.

As far as I can tell, there isn't a general way to get from the instance of the nested class back to the instance of the surrounding class. Furthermore, there isn't a general, easy way to detect that "value.Target" is giving you a generated class rather than the one you were expecting. Since anonymous methods are a compiler trick, there's no run time information available via reflection to tell you whether a method came from an anonymous method or not.

We still needed to get at the control, so we had to guess. We guess (with very high probability) that if "value.Target" doesn't inherit from Control, it must be an anonymous method. We then do a few sanity checks to make sure (including checking that the class is sealed, private, nested, and has a [CompilerGenerated] attribute on it). Then, to get at the original instance, we find the field of "value.Target" whose type matches the outer type of our class, and then read its value. It looks a little something like this:

if (d.Target is Control)
{
return d.Target;
}

Type targetType = d.Target.GetType();
if (!(targetType.IsNestedPrivate && targetType.IsSealed
&& (targetType.GetCustomAttributes(
typeof(CompilerGeneratedAttribute), false).Length == 1)))

{
//you've hit the Anonymous Method case with something
//that doesn't appear to be an anonymous method
throw new InvalidOperationException("Error.");
}

Type outerClassType = targetType.DeclaringType;
FieldInfo outerField = Array.Find(targetType.GetFields(),
delegate(FieldInfo field)
{
return field.FieldType.Equals(outerClassType);
});

if (outerField == null)
{
//see note on the throw exception above
throw new InvalidOperationException("Error.");
}

return outerField.GetValue(d.Target);


This would be a lot easier if the compiler-generated class implemented an interface or something with a single method returning object that pointed back to the enclosing instance. Then I could just say:

return (d.Target is IAnonymousMethodState ?
((IAnonymousMethodState)d.Target).EnclosingInstance :
d.Target);

I'm going to suggest this at the Connect site and see what happens.
Edit: Suggested here

Monday, January 22, 2007

Referencing a Master Page from a User Control

UPDATE: It turns out this works fine for debugging, but once you go to publish it doesn't work at all (if you check the Allow Updateable box). It looks like the Reference Directive is being ignored when compiling the code behind file so it can't find the class "ASP.nameofmymasterpage_master". I'll update again if I find a solution. Very discouraging.

UPDATE 2: see workarounds below

I ran into a situation where I needed to access a custom property of a master page from within a user control. Were I dealing with a regular page, the MasterType directive would have worked fine, but this doesn't work for user controls.

I started by figuring out the name of the type of my custom master page by mousing over a line like "Page.Master" in one of my aspxs that contained a MasterType directive. This told me that the type of the master page is something like "ASP.nameofmymasterpage_master". The parent class for this is the class in the master page cs file, usually something like "nameofmymasterpage".

I then tried casting "Page.Master" to "ASP.nameofmymasterpage_master" in the cs file for my user control, but the compiler complained that it didn't know about this type. To make it aware, you have add the seldom used Reference directive to the ascx file. Something like "<%@ Reference VirtualPath="~/nameofmymasterpage.master" %>". Then the type "ASP.nameofmymasterpage_master" is available so the line with the cast can compile and everything works.

In summary, put this in the ascx:
<%@ Reference VirtualPath="~/nameofmymasterpage.master" %>

So that you can do this in the ascx.cs:
string thingIwant = (Page.Master as ASP.nameofmymasterpage_master).CustomProperty;

WORKAROUNDS:
1. Just use Web Application Projects which I should be doing anyway, but I haven't yet gotten the time to update all the sites we currently have
2. Define an interface in your App_Code folder with all the operations you need exposed from your master page. In your master page cs file, mark the class as implementing your interface. Then in your ascx, just cast Page.Master to your interface type and go to town. You don't need the Reference directive at all. Not as simple as it should be, but it works.

Tuesday, January 16, 2007

Type Theory

For fun I just finished reading Pierce's Types and Programming Languages. I missed some of the formal background for PL while in school since I skipped a pre-req or two to get into a compiler class that my favorite professor was teaching. It was nice to go back and fill in the gaps. TAPL came highly recommended from LtU and it didn't disappoint. Now, of course, I'm seeing new programming languages as the answer to everything.

More specifically I'm interested in the practical difference between a statically structurally typed language with type inference and a dynamically typed language. It seems that structural typing gets pretty close (depending on the implementation) to the duck typing promised by languages like Ruby while still being checked at compile time. Obviously there are some compromises like meta-programming, but there are even some statically typed languages that offer this as well.

Unfortunately there isn't a good candidate .net language to play with. Although OCaml is structurally typed, F# remains nominally typed, probably for .net interop reasons. Because of the nature of the CLR, any structurally typed language would have to in effect fake it, via reflection or something. I'm thinking of writing a toy language just to play with this, exposing parameters as "object", invoking methods via reflection, and maybe indicating type constraints via an attribute or something. Hopefully I'll find some time for this.

Also, this is quite good (and released under a Creative Commons license), despite the Boring Manager's name.

Thursday, November 09, 2006

ObjectDataSource doesn't respect culture on update

I've recently run into an issue with ObjectDataSource, GridView, and alternate cultures. My present client has a Candian office and the project requires selection of a date from a dropdown. When the data binding to the list of possible dates occurs, the data source uses the current culture to format the dates, so I end up with a dropdown whose ListItems have values like "29/10/2006" and "30/10/2006" since they do their dates backwards up there. This is completely expected and is definitely how things should work.

The problem arises when the user clicks the update button and we have to turn that string (dropdown.SelectedValue) back into a DateTime. Here the ObjectDataSource messes up and converts the string back using the InvariantCulture, which throws an exception since "30/10/2006" isn't a valid date.

This Microsoft Connect link summarizes the issue a bit more.

I was unhappy with the workaround posted there so I figured out a better one. Basically we just do the DateTime conversion ourselves, instead of letting the ObjectDataSource handle it.

1. Handle the ObjectDataSource Updating event.
2. In the handler, replace the string input parameter with its culturally aware DateTime equivalent, using something like:

TypeConverter converter =
    TypeDescriptor.GetConverter(typeof(DateTime));
e.InputParameters["DateField"] =
    converter.ConvertFromString(
        e.InputParameters["DateField"] as string);


And that's it.