Understanding InvalidCastException

We can sometimes get an InvalidCastException thrown when reading a record from the database, the usual reason for this is that the database column does not match the property type on the class. For example, we have a column defined in the database as:

PhoneNumber int not null

and in the class we have

public string PhoneNumber { get; set; }

The reason this will fail is that MicroLite will read the value using the most efficient method and since the property is a string and IDataReader has a method GetString that will be called, essentially doing this:

obj.PhoneNumber = dataReader.GetString(idx);

However since the actual returned value in the IDataReader is an int which cannot be implicitly cast to a string we get an InvalidCastException. To resolve this, change the property type and database column to be compatible types (e.g. change the database column to string or change the class property to int).

MicroLite 6.0 Logging/Debugging

One of the things we focused on in MicroLite 6.0 is making the logging and debugging process even nicer for developers.

Since very early on MicroLite has had support for writing to your application log via the logging extension packages. However it has never been easy to see how a class has been mapped. To make this easier to understand, we have created an extension method for IObjectInfo which can be used to write the mapping to a TextWriter. We also write this to the log if the log is capturing Debug statements.

It’s as easy as this:

// Resolve the IObjectInfo for the mapped class.
var objectInfo = ObjectInfo.For(typeof(Customer));

// Write the mappings to the console
// or write the mappings to a string
var stringWriter = new StringWriter()

// Write mappings to a TextWriter
var mappingDetails = stringWriter.ToString();

For the following class using the default conventions:

public class Customer
    public int Id { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public DateTime DateOfBirth { get; set; }
    public CustomerStatus Status { get; set; }

It will emit the following:

MicroLite Mapping:
Class ‘MyApplication.Customer’ mapped to Table ‘Customers’

Property ‘DateOfBirth (System.DateTime)’ mapped to Column ‘DateOfBirth (DbType.DateTime)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Forename (System.String)’ mapped to Column ‘Forename (DbType.String)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Id (System.Int32)’ mapped to Column ‘Id (DbType.Int32)’
Allow Insert: False
Allow Update: False
Is Identifier: True
Identifier Strategy: DbGenerated

Property ‘Status (ConsoleApplication5.CustomerStatus)’ mapped to Column ‘CustomerStatusId (DbType.Int32)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Surname (System.String)’ mapped to Column ‘Surname (DbType.String)’
Allow Insert: True
Allow Update: True
Is Identifier: False

MicroLite OData update

The latest release of MicroLite.Extensions.WebApi (6.1) and Net.Http.WebApi.OData (3.1) now provide support for nearly the entire OData 3 spec that can be supported by MicroLite.

It is now possible to compare 2 properties:

$filter=FirstName eq LastName

And call nested functions:

$filter=concat(concat(City, ', '), Country) eq 'Berlin, Germany'

Decimal/Double and Single values don’t require .0 for whole values:

$filter=Price eq 5M can now be used as well as $filter=Price eq 5.0M

Method parameters no longer require a space after the comma:

$filter=endswith(CompanyName,'Futterkiste’) can now be used as well as
$filter=endswith(CompanyName, 'Futterkiste')

Literal strings (text wrapped in single quotes) can now contain a single quote by escaping it with another single quote:

$filter=LastName eq ‘O’’Brien’

Grouping is now supported in queries:

$filter=LastName eq 'Smith' and (Title eq 'Mr' or Title eq 'Mrs')

Without the grouping, the query would be translated as:

LastName = Smith and Title = Mr
Title = Mrs

There is no concept of an “in list” in OData so a grouped set of “or”s is the way to achieve the same result.

endswith, startswith, and substringof now no longer require eq true at the end:

startswith(CompanyName,’Alfr’) is the same as startswith(CompanyName,’Alfr’) eq true

The not operator has also been implemented which means you can negate function calls:

not startswith(CompanyName,’Alfr’)


Since very early on MicroLite has had support for writing to your application log via the MicroLite.Logging.Log4Net or MicroLite.Logging.NLog.

With the release of MicroLite 6.1 we have added support for Serilog via the MicroLite.Logging.Serilog package.

You can see the details of how to configure it on the GitHub site.

Please note that whilst this will enable MicroLite to write to your log, it doesn’t support the usual Serilog format log messages so the statements will be formatted strings.

For example, you would see

Beginning a new Transaction with the IsolationLevel 'ReadCommitted'

In the log rather than

Beginning a new Transaction with the IsolationLevel '{isolationLevel}'

This is because MicroLite does not know which if any logging library it will be writing to at runtime so it has to use standard .NET format strings for its log messages.

Upgrading to MicroLite 6.1

There are a couple of changes in MicroLite 6.1 which you need to be aware of when updating from a previous version.


In MicroLite 6.1, we have split the IListener interface into 3:

IDeleteListener containing the following methods:

void AfterDelete(object instance, int rowsAffected);
void BeforeDelete(object instance);

IInsertListener containing the following methods:

void AfterInsert(object instance, object executeScalarResult);
void BeforeInsert(object instance);

IUpdateListener containing the following methods:

void AfterUpdate(object instance, int rowsAffected);
void BeforeUpdate(object instance);

You can create as many listeners as you like implementing all or some of the above interfaces and register them in the appropriate collections.

Example – Create a listener which only cares about insert operations:

public class InsertOnlyListener : IInsertListener
   public void AfterInsert(object instance, int rowsAffected) { ... }
   public void BeforeInsert(object instance) { ... }

Listener.InsertListeners.Add(new MyInsertListener());

Example – Create a listener which cares about insert and update operations:

public class AuditListener : IInsertListener, IUpdateListener
   public void AfterInsert(object instance, int rowsAffected) { ... }
   public void AfterUpdate(object instance, int rowsAffected) { ... }
   public void BeforeInsert(object instance) { ... }
   public void BeforeUpdate(object instance) { ... }

var auditListener = new AuditListener();

SQL Builder

The “write” builders (SqlBuilder.Delete and SqlBuilder.Update) now offer the same functionality for single columns as the read builder (SqlBuilder.Select):

  • Between(object lower, object upper);
  • In(params object[] args);
  • In(params SqlQuery[] subQueries);
  • In(SqlQuery subQuery);
  • IsEqualTo(object comparisonValue);
  • IsGreaterThan(object comparisonValue);
  • IsGreaterThanOrEqualTo(object comparisonValue);
  • IsLessThan(object comparisonValue);
  • IsLessThanOrEqualTo(object comparisonValue);
  • IsLike(object comparisonValue);
  • IsNotEqualTo(object comparisonValue);
  • IsNotLike(object comparisonValue);
  • IsNotNull();
  • IsNull();
  • NotBetween(object lower, object upper);
  • NotIn(params object[] args);
  • NotIn(params SqlQuery[] subQueries);
  • NotIn(SqlQuery subQuery);

MicroLite 6.0 – Specifying the DbType

In MicroLite 6.0, we have exposed the ability to control the mapping between a .NET Type and the Database Type (DbType).

If not explicitly configured, the types will be mapped using the default mappings – you can see the default mappings here

If you use the Attribute based mapping and want to specify the DbType for a specific property, you can set it in the ColumnAttribute applied to that property:

[Column("DoB", DbType.DateTime2)]
public DateTime DateOfBirth { get; set; }

If you use convention based mapping and want to specify the DbType for a specific property, you can define that in your own convention:

        new ConventionMappingSettings
            ResolveDbType = (PropertyInfo propertyInfo) =>
                if (propertyInfo.PropertyType == typeof(DateTime) && propertyInfo.ReflectedType == typeof(Customer))
                     return DbType.DateTime2;

                // Use the default
                return TypeConverter.ResolveDbType(propertyInfo.PropertyType);

If you always want to use a specific DbType for a .NET Type, you can set it via the TypeConverter class:

// Always use DbType.DateTime2 instead of DbType.DateTime for System.DateTime
TypeConverter.RegisterTypeMapping(typeof(DateTime), DbType.DateTime2);

MicroLite 6.0 – Dynamic Connection Strings

Prior to MicroLite 6.0, in order to create a session factory you had to specify the connection name as defined in the connection strings section of your application configuration. This is generally a good idea as the connection string is a configuration value which should not be baked into the code as you would need a different value if you have separate Dev/Test/Production environments.

We did have a request from a MicroLite user to be able to specify the connection string at runtime as there is a requirement for that in his application so we have added functionality for doing just that.

The ForConnection methods now have an additional overload:

ForMsSql2005Connection(string connectionName, string connectionString, string providerName)

The reason that the new overload needs a connection name is to still allow support for the MVC and WebApi extensions which are dependent on a named connection to resolve the correct session factory.

The provider name needs to be the same as you would set in the connection string in the application config, this is used by MicroLite to resolve the correct DbProviderFactory.

This gives you two ways to configure a connection in MicroLite 6.0:

Option 1 (the recommended approach for most use cases)

Define the connection string in the application configuration

    <add name="NorthwindDB"
         connectionString="Data Source=localhost;Initial Catalog=Northwind;Persist Security Info=False;Integrated Security=SSPI;"
         providerName="System.Data.SqlClient" />
// Create the session factory for the named connection
var sessionFactory = Configure

Option 2 (if you really really need to)

// Create the session factory with the specified name, connection string and provider name
var sessionFactory = Configure
               "Data Source=localhost;Initial Catalog=Northwind;Persist Security Info=False;Integrated Security=SSPI;",