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.

Monday, October 02, 2006

Enabling Sane Project and Solution Structure

One of the constant pains of Visual Studio 2005 and Visual SourceSafe is the strong tie between solution, file system, and VSS structures. If you only ever have a single large solution with all of your projects underneath it, this never becomes apparent. If, however, you have several core components that need to be shared across several distinct solutions (systems/applications/whatever), things get gross. Visual Studio likes the solution to be at a higher level in VSS and the file system than all the projects contained in it. Once you have a project that needs to be in more than one solution (i.e., have more than one parent folder), this is impossible. Ideally I'd like my file system to look something like:

c:\projects (all solution files live here)
c:\projects\sharedlib1
c:\projects\sharedlib2
...
c:\projects\websites\site1
c:\projects\websites\site2
etc.


with a similar VSS structure:
$/ (all solutions here)
$/sharedlib1
$/sharedlib2
...


Here's what I do when creating a new solution and project to make this work:

  1. Create a blank solution
    File->New Project
    Other Project Types/Visual Studio Solutions/Blank Solution

    Don't check "Add to Source Control"
    Location: c:\projects
    Name: whatever (application name)

  2. File System Surgery
    File->Save As...
    c:\projects\whatever.sln
    Delete the subdirectory under projects (should be c:\projects\whatever\)

  3. Add solution to VSS
    Right click on sln, Add to Source Control
    Leave name alone (will be whatever.root)
    Location $/

  4. VSS Surgery
    Start the VSS Client
    Drag and drop Whatever.sln and Whatever.vssscc from c:\projects into $\ in VSS
    In Visual Studio, go to File->Source Control->Change Source Control
    There should be line line listed that says "Solution: Whatever.sln"
    Click the elipsis ("...") in the Server Binding column
    Pick $/
    Hit Ok twice
    In VSS, right click on $/whatever.root and pick delete (check the box to destroy permanently)
    Close VSS



When adding new projects, always choose "C:\projects" for Location
When adding new websites, always choose "C:\projects\websites" for Location
and they will automatically be added to the right place in VSS

And that's it. Basically I change the binding root of the solution from the automatically created "whatever.root" folder to its parent, allowing multiple solutions to live in the same directory and in effect share the same binding root.

Monday, September 18, 2006

Lightweight Promotable Transactions and Connection Pooling

We're moving an existing system from a SQL 2000 backend to SQL 2005. The system uses a custom persistence framework and System.Transactions.TransactionScope for all transactions. The framework was developed with the best practices for connection pooling in mind. Basically, connections are cheap; open them when you need them and close them when you're done. This results in a connection for each type being fetched during a request. For example, a Customer with an Address would require 2 connections, one to fetch the Customer and one to fetch the dependent Address.

When SQL 2005 enters the picture, however, we have a problem. TransactionScope and SQL 2005 are smart enough to realize that not all transactions are distributed, so they start out as local ADO transactions and are supposed to be seamlessly promoted when necessary. There are 2 problems we've run into so far. The first is that it's way too easy to trigger a promotion. Although I guess it makes sense, opening a second connection to the same data source always triggers a promotion. The second problem arises if the first connection is busy (say, reading a Customer object from a DataReader) when the second connection is open. This causes an immediate failure since the first connection is blocked, preventing a promotion.

Although you can work around the blocked connection problem with a new SQL 2005 feature, Multiple Active Result Sets (MARS), it still seems a bit gross. I may end up rewriting bits of the persistence framework to properly share a single connection, queuing the objects to be loaded and then working through them rather than having multiple connections with multiple DataReaders going at once.

Monday, September 04, 2006

HttpListenerContext is not serializable

Today I started working on my own subclass of HttpWorkerRequest so that my webserver could handle POSTs and binary data like rails.png on the Welcome Aboard page. After writing all the code to handle the necessary overrides I went to actually run the thing and discovered the troubling fact in my subject line. HttpListenerContext is not serializable. Since my host runs in a separate AppDomain, this is a big problem.

I thought about trying to make some serializable dummy class to shuttle data back and forth, but then I came across Aaron Skonnard's Service Station article in MSDN Magazine here where he hit the same thing. His solution was just to move the HttpListener into the host's AppDomain, which is exactly the right thing to do. After doing that, everything works great. I successfully served the whole Rails Welcome Aboard page including the png (and the AJAX link for environment info), as well as a few test aspx pages with postbacks. There are still some rough edges (no default page handling, untested auth, etc.), but I think this is good enough to move on to working with a pool of Ruby processes for handling Rails.

Sunday, September 03, 2006

More Http.sys and Rails

Magically I found some time to work on my web server for Rails based on Http.sys. In the interest of having something definitely working, I went down the path of creating a basic CGI server. Given a virtual directory and a physical path to a Rails public folder, I can now successfully serve pages, with a few caveats.

One minor thing is that I've only tested a few pages in my first ever Rails app, so I'm sure there are things I've missed. I haven't attempted to support things like auth or https yet, but those should definitely be possible.

More importantly, I'm using HttpRuntime.ProcessRequest for serving static content, but I'm only using SimpleWorkerRequest at the moment. This means binary files as well as POSTs and things don't work. It looks like I'm going to have to subclass HttpWorkerRequest myself to make things work. I've looked at the Cassini source for how they do it (and to see if I could just use that), so this shouldn't be too bad. Not exactly fun though.

Once I get those things handled I'll move onto a pooled interpreter approach and leave the horrible performance of CGI behind. Seeing the Rails 'Welcome aboard' page served from my code was nice, even if the images didn't work yet. Soon.

Saturday, August 19, 2006

FP on the brain

I did a presentation for our internal user group about languages other than C# including SML, Scheme, and Ruby. I was attemping to illustrate functional programming, code as data, lazy evaluation, and dynamic typing to a group who had mostly only dealt with C#, partly to talk about elements from those sources that LINQ will incorporate and partly just to share my enthusiasm.

I hadn't touched SML in quite awhile, but it was really easy to pick back up and still was just as much fun to write. It's powerful, expressive, and has a nice, clean syntax. It might fit really well in a middle-tier type setting, since that would side step the need for strongly typed database access or a web service toolkit. I need to investigate SML.NET and F# some more as potential avenues to make this happen. The OCAML syntax of F# bugs me, but I read a cool paper linked off of LtU about its template/meta-programming capabilities which seemed really promising.

The more I learn about Ruby, the more I like it as a language, too. The dynamic typing bit still scares me some (especially after SML), but metaprogramming as a means to eliminate boilerplate junk and also to build internal DSLs is just cool. The interop with .net story isn't quite there yet, but I bet it will be soon. For the time being, I'm going to play around with using Ruby to generate C#/XML/WSDL/etc.

Tuesday, August 08, 2006

WF, ASP.NET, and transactions

My current project has some pretty simple business logic that seemed like it would be a good fit for WF. I was looking for a good excuse to try it out for real so I started investigating using it and immediately ran into several key problems.

The first is that there aren't many samples available relating to using WF with an ASP.NET host. Some of this is because it's still beta, but the only ASP.NET stuff available is either hopelessly trivial (start a workflow on a button click and then wait for it to finish before returning) or just not analogous to a real situation (no error handling, transactions, etc.). Additionally, you have to use a manual scheduler as opposed to the default one. I'm trying to get WF to replace business logic, so it would live in the service layer. I'd need extra code there to check whether we were running with the manual scheduler or not (in order to call RunWorkflow if necessary), which seems gross.

The other big issue is that it doesn't seem possible to have workflows participate in a transaction that is initiated by the host. My scenario involves keeping track of many running instances that all need to be finished and exported at once. This would involve iterating over each instance, sending it a specific event, and then, once all instances have been notified, running a stored proc (or something) once to do the export. All of that needs to be in one transaction, but it appears this isn't possible.

I might have to not use WF for this scenario if I can't find answers to those questions. I'm also concerned that if there aren't good answers, it may severely limit the applicability of WF.