Friday, April 22, 2011

Pitch in

Let's frustrate a bit about MS way of doing things.


Just recently I was to implement a super small system (super small is due to deadline, as always) which will eventually grow into a robust management console.
The domain turned into a small set of persistent (and not) classes, and the structure of it is a topic yet to come. Just to gain the top level idea, take a look at the schema produced by unlicensed copy of Visio.
A quick note to prevent skepticism right away:

  • Separating service factory and ASP.NET driven management console will indeed cause an intolerant amount of issues with locking, session times, memory consumption and overall performance. These all are a subject of a soon refactoring.
  • I detest personally some concepts of these guys (http://www.domaindrivendesign.org/), among which is the strange recommendation to make domain aware about the CRUD repository commands yet keep the actual implementation on a level of infrastructure. There too many things here to discuss - marker interfaces which will be required, complications when moving to service-oriented design, redundant interfaces for most domain entities and so forth.
Now note we've got those generics declared in a repository. Looks just right since we have the WCF contract talking to a repository on one side and to a number of clients on another. The parties can become aware of a different data contracts at some point due to scalability requirements and the service is the one responsible of inter contracts conversions.
Now, since we've got generics on DAL, the following are the options for ASP.NET to handle them gracefully:
  • Direct Proxy. Just put the stubs of all the operations into ASP.NET page, make programmatic binding and enjoy. It's not that bad if you think about it - you've got all the power of transformations and extending in place. There few downsides however:
    • ASP.NET way of handling lifecycles is implementation specific. Meaning that IIS6 handles it a little different than IIS7. When it comes to IIS8, one should not get surprised that they deprecate events your application heavily rely on. So if you don't want to entertain your sysadmin with a couple of sleepless nights figuring out what is the exact difference between this and this, leave it alone for now.
  • Indirect Proxy. Same as above except for a fact that we'd create another entity in App_Code folder so that ObjectDataSource can handle them. You can inherit from Repository here and create non-generic invariants for parent object.
  • Just use ObjectDataSource. 
Last is the sweetest, so you'd want certainly to start from it. MSDN specs look sufficient to attempt to gather the repository feedback directly on ASP.NET databound control. The main contributor here will be SelectMethod property. The specs clearly say that you can use any method that is returning one of the following: DataSet, DataView, DataTable, Object orIEnumerable. The last one is the thing that we need as our repository returns a list of entities. If you try it right away you gonna get this code:

and this exception:
ObjectDataSource "DALObjectsSetSourceId" could not find a non-generic method 'List' that has no parameters.

The concern is - why non-generic? Specs did not say a word about generics, the code doesn't acquire non-generics, but for whatever reason handler went to seek for this. Actually, MSDN did say that IEnumerable should be returned, not IEnumerable<T> (which is actually covariant to T, so I don't see technical difficulties mapping my custom T to Object via direct hierarchy, but whatever).
This strange gentleman explained that no worries - it is just missed in the VS designer, but if you manually declare generic method call or buy his ExtendedObjectDataSource tool, you gonna be fine.
Let's go with the first solution for now:


Result:
ObjectDataSource "DALObjectsSetSourceId" could not find a non-generic method 'List`1[[SomeNameSpace.DataAccessLayer.Domain.Entity]]' that has no parameters.

So let me make it clear:
SelectMethod property in ObjectDataSource type does not support generics. At all.
You can verify this by going to reflection of ObjectDataSourceView.cs in System.Web.UI.WebControls and enjoy seeing this:

in method resolution function GetResolvedMethodData.

[Note. This collected from .net source code, not the Reflector]


I saw quite a few examples of .net framework developers doing strange actions - they implement binary search explicitly sorting the passed array, encourage using string.Concats and Path.Combine when those are implemented in the most terrible way possible etc so don't get surprised.

Interesting that when they locate the method's best match within the type, the type itself bypasses the generic-non-generic check, so you can actually do this:

reverting the repository methods into non-generic yet marking the type itself as generic, or you always have first two proxy methods to go.

Cheers,

No comments:

Post a Comment