Saturday, 27 August 2011

Fixing MiniProfiler with NHibernate “Unable to cast transparent proxy to type 'System.Data.SqlClient.SqlCommand'”

I’ve been using the excellent MiniProfiler with asp.mvc and NHibernate 3.20GA, but started running into an error – “Unable to cast transparent proxy to type 'System.Data.SqlClient.SqlCommand'” when I tried to flush my session.

Thankfully some smart people had already come up with a fix (in the comments for the post above)… albeit one that requires making some changes to the source NHibernate. Rather than have to recompile NH to get the fix in, here is a version that works against a standard NHibernate build.

Friday, 15 July 2011

Portable ASP.NET code using EmbeddedResourceVirtualPathProvider now on Nuget

It's not often I see my name written alongside such illustrious names as Phil Haack, Jeremy Miller and Rick Strahl, but today in the “Recent NuGet Packages” feed there it is.

And what have I done to get it there? I’ve released the EmbeddedResourceVirtualPathProvider library. What does it do, in a nutshell?

Makes ASP.NET search referenced assemblies for resource files like .css, .js, .aspx files when it can’t find them in the current project.

And what does that let you do?

Make assemblies containing redistributable chunks of web applications

How does it do it? It registers a custom VirtualPathProvider with ASP. The VPP is fed a list of assemblies containing EmbeddedResources of .css/.js/.png/.aspx/.whatever files. When a path is requested, if it isn’t found in the host directory, these assemblies are checked and the resource is returned.

So to use it, just install the eponymous Nuget package to your ASP.NET web project and it will do the rest. Then move some content files into a referenced assembly, mark them as EmbeddedResource and start your app up. It should continue to work!

Nuget: http://nuget.org/List/Packages/EmbeddedResourceVirtualPathProvider

GitHub: https://github.com/mcintyre321/EmbeddedResourceVirtualPathProvider

Things to know before going into production

  • ASP must process the file extension in order for this to work, so handlers for static file types have to be registered in web.config. The Nuget package registers .css, .js, .png and .jpg for you using the System.Web.StaticFileHandler class. This handler doesn’t set cache headers properly, so you may want to switch the StaticFileHandler for another one that does, like the Talifun static file handler.
  • In order to give a nice out of the box experience, the default Nuget package will register and scan all assemblies in the /bin directory that don’t start  with “System”. You may want to manually configure which assemblies get registered yourself in App_Code/RegisterPathProvider.cs

Wednesday, 28 July 2010

10 print "hello"

You’ve probably seen it if you are reading this, but if you haven’t then go visit www.tenprinthello.com – links to many of the projects and sites I’ve put on the web.

Thursday, 22 July 2010

XML-free …compiled mappings WITHOUT Fluent NHibernate – sample project available

In the earlier posts in the series, we saw how to write conventions that map Id and properties on domain objects automatically. The point of the series is to show that writing your own set of conventions is actually a pretty simple if you are familiar with System.Reflection, and you can have a very fine grained level of control over your NHibernate mappings.

The project contains a simple domain model and a suite of convention that generate NHibernate mappings for identities, properties and many-to-one relationships for the domain model, and should provide a good starting point for your own convention suite. Just run the project and you can see the generated xml.

UPDATE: I've created a new version of the project at https://github.com/mcintyre321/NhCodeFirst which has some fairly cunning mapping support

Wednesday, 21 July 2010

Reading CSVs into anonymous types

Following on from my post on using anonymous types to build strongly typed sql queries, here’s one on extracting data from csv files into a data structure of your choosing.

Suppose we have a CSV file like this:

Date,Bank,Account,Description,In,Out,Category
"2010-07-21","Halifax Online (UK)","Halifax Current Account","Direct Debit - Ukonline","","£9.99","Utilities & bills"
"2010-06-21","Halifax Online (UK)","Halifax Current Account","Direct Debit - Ukonline","","£9.99","Utilities & bills"


Using my snazzy new method, we can parse it into an array of anonymous-typed objects using some code like this:

tmp2C2E

Wow. Notice that the DateColumn is an actual DateTime object, not just a string. So what just happened? Basically, the type defined in the call to FromCsv is interrogated using reflection, the name of each parameter is matched up to the correct column from the CSV file, and the value converted into the correct Type using Convert.ChangeType.

Here’s the code. Do with it what you will.

IEnumerable<T> FromCsv<T>(T template, string csv)
{
    using (var ms = new MemoryStream()){
        using (var sw = new StreamWriter(ms)){
            sw.Write(csv);
            sw.Flush();
            ms.Seek(0, SeekOrigin.Begin);
            var tfp = new Microsoft.VisualBasic.FileIO.TextFieldParser(ms){
                Delimiters = new[] {","}, HasFieldsEnclosedInQuotes = true
            };
            var headers = tfp.ReadFields();
            var @params = typeof(T).GetConstructors().Single().GetParameters().Select (p => new {Type = p.ParameterType, Index = Array.IndexOf(headers, p.Name)}).ToArray();
            while(!tfp.EndOfData){
                var data = tfp.ReadFields();
                yield return (T) Activator.CreateInstance(typeof(T), @params.Select(p => Convert.ChangeType(data[p.Index], p.Type)).ToArray());
            }
        }
    }
}

Note the use of TextFieldParser, the MS way to get at your CSVs. If you don’t like the VisualBasic namespace, feel free to do it some other way.

Friday, 16 July 2010

XML-free convention based compiled mappings WITHOUT Fluent NHibernate – Part 3 –

So in part 2, we came up with code to find and sort our conventions. Now we need some conventions! In my model , I use hilo int Id {get; private set;} properties on my entity classes, mapped to a column called {EntityName} + Id. If you do something different, write your own convention!

First up, the IClassConvention interface:

public interface IClassConvention
{
    void Apply(Type entityType, @class classElement, IEnumerable<Type> entityTypes, hibernatemapping mapping);
}

As you can see, the current entityType and its class mapping are passed in, along with references to the other entity types and the whole mapping document. This lets you do things like check to see if a particular property is an Entity or a component.

public class CreateHiloIdIfTypeHasIntIdProperty : IClassConvention
{
    public void Apply(Type entityType, @class classElement, IEnumerable<Type> entityTypes, hibernatemapping mapping)
    {
        //use reflection to get the Id property from the current class
        var idProperty = entityType.GetProperty("Id", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        if (idProperty != null)
        {  
            //if the id property exists, add a new id element to the @class element
            classElement.id = new id() 
            {
                name = "Id",
                generator = new generator() {@class = "hilo"},
                column = {new column() {name = entityType.Name + "Id"}}
            };
        }
    }
}

Remember, you can write your own convention for this. You could get really clever with this: imagine you use Identity generated columns, but the names are inconsistent in the db – why not look up the table schema and find the identity column and use the name from that?

Here is a convention for turning properties on a type into properties on the @class.

public class CreateBasicProperty : IClassConvention, IRunAfter<CreateHiloIdIfTypeHasIntIdField>, IRunAfter<CreateHiloIdIfTypeHasIntIdProperty>
{
    //list of types. If you need longs, just add them!
    private readonly IList<Type> basicTypes = new[] { typeof(Guid), typeof(Guid?), typeof(int), typeof(int?), typeof(string), typeof(bool), typeof(bool?), typeof(DateTime), typeof(DateTime?) }.ToList().AsReadOnly();
 
    public void Apply(Type type, @class @class, IEnumerable<Type> entityTypes, hibernatemapping mapping)
    {
        var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
            .Where(p => p.Name != @class.id.name) //check its not the Id property!
            .Where(p => basicTypes.Contains(p.PropertyType));
        foreach (var propertyInfo in properties)
        {
            @class.property.Add(new property()
            {
                name = propertyInfo.Name,
            });
        }
    }
}

That’s all for this post! Next time we’ll see a convention for doing many-to-one mappings.

UPDATE: A sample project is available for download on google code. It contains the convention for many-to-one mapping.

Thursday, 15 July 2010

XML-free convention based compiled mappings WITHOUT Fluent NHibernate – Part 2 – calling the conventions

In part 1 we found out how to generate a mapping file using c# and Linq To XSD. In this post we will extend that to show the use of conventions.

The first thing we need an automapping framework to do is to create a class element in our xml mapping file for each of the entity types in our project. We will need a list of the entities in our project:

var types = typeof(User).Assembly.GetTypesSafe().Where(t.Namespace.StartsWith("Servit.Domain.Entities")).ToList();
var mappingXDoc = new hibernatemapping();
foreach (var type in types)
{
    var @class = new @class()
    {
        name = type.AssemblyQualifiedName,
        table = type.Name + "s", //feel free to use a more advanced pluralization method (http://bit.ly/b98JK6) – adding an s works for me! 
    };
    mappingXDoc.@class.Add(@class); //LINQ to XSD didn't pluralize the @class collection, 
    //it might have been better if it generated mappingXDoc.classes instead of mappingXDoc.@class...
}

A pretty simple convention, but it will do for now. So far we have a mapping document with all our classes, but they are all empty – no properties! We need some conventions. The idea is that these conventions should be easy peasy to write so that you don’t need a big framework like FNH to get your mapping written.

Imagine we want to add conventions to do the following:

  1. add an Id element for each class with an Id property, mapped to a entity.Name + "Id" column in the db
  2. add property elements for each int, string, bool etc. etc. except the id property
  3. Add many-to-one properties automatically

Lets suppose we have an interface IClassConvention. We’re going to get hold of the conventions and apply them to the mappingXDoc variable we defined in the bootstrap code from part 1. Note the use of the TopologicalSort method from my last post, called via an extension method, because we want the conventions to execute in a certain order.

//get all the convention types in our assembly
var conventions = typeof(IClassConvention).Assembly.GetTypesSafe()
    .Where(t => typeof (IClassConvention).IsAssignableFrom(t))
    .Where(t => t.CanBeInstantiated()) //check they aren't abstract or have open generic types
    .TopoSort((t, potentialTypes) => potentialTypes.Where(pt => typeof (IRunAfter<>).MakeGenericType(t).IsAssignableFrom(pt)))
    .Select(t => (IClassConvention)Activator.CreateInstance(t)).ToList(); //and instantiate them
 
foreach (var convention in conventions)
{
    foreach (var type in types)
    {
        var @class = mappingXDoc.@class.Single(c => c.name == type.AssemblyQualifiedName);
        convention.Apply(type, @class, types, mappingXDoc);
    }
}

OK, so we haven’t got any conventions yet, but you can see how we call them and apply them. This is pretty much the whole “framework” right there. As you can see, there isn’t much to it.

In the next post, we’ll implement a convention or two.