-
Notifications
You must be signed in to change notification settings - Fork 24
Type Converters
Type Converters are one of the ways you can inject custom code into the MicroLite pipeline.
They are commonly used to allow non primitive types to be converted to and from database types (e.g. enums).
There are 4 methods defined by the ITypeConverter
interface which are called during read or write operations:
bool CanConvert(Type type);
object ConvertFromDbValue(object value, Type type);
object ConvertFromDbValue(IDataReader reader, int index, Type type);
object ConvertToDbValue(object value, Type type);
The type is passed to all methods to cater for a type converter which can deal with more than 1 type.
The CanConvert
method is called by MicroLite to determine whether the type converter can convert the given type. The first type converter whose CanConvert
method returns true
is used to convert the type.
There are 2 implementations of this method and you will need to implement both.
ConvertFromDbValue(object value, Type type)
ConvertFromDbValue(IDataReader reader, int index, Type type)
The overload which accepts an object
is only called when the type in question has been returned by a call to ExecuteScalar
as there is no IDataReader
used. All other read operations will use the overload which accepts an IDataReader
. The advantage to this method is that it allows the type converter to read the record based upon the specified index using the most appropriate reader method which may avoid boxing if the actual database value is stored as a value type (as int
-> enum
would be).
The ConvertToDbValue
is called when inserting or updating a mapped object to convert the property values into database values. The value
is the property value (which may be a boxed value type) and the type
is the property type.
In our application, we have the need to store IP addresses in a database as a string but in our application we have a custom struct which we want to use.
The IP Address struct looks like this:
public struct IPv4Address
{
private readonly byte octet1;
private readonly byte octet2;
private readonly byte octet3;
private readonly byte octet4;
public IPv4Address(byte octet1, byte octet2, byte octet3, byte octet4)
{
this.octet1 = octet1;
this.octet2 = octet2;
this.octet3 = octet3;
this.octet4 = octet4;
}
public byte Octet1 { get { return octet1; } }
public byte Octet2 { get { return octet2; } }
public byte Octet3 { get { return octet3; } }
public byte Octet4 { get { return octet4; } }
public override string ToString()
{
return string.Format("{0}.{1}.{2}.{3}", this.octet1, this.octet2, this.octet3, this.octet4);
}
}
We could build a type converter as follows:
using MicroLite.TypeConverters;
public class IPv4AddressTypeConverter : ITypeConverter
{
public bool CanConvert(Type type)
{
return type == typeof(IPv4Address);
}
public object ConvertFromDbValue(IDataReader reader, int index, Type type)
{
// Value is stored in the database as a string.
var readerValue = reader.GetString(index);
var ipAddress = FromString(readerValue);
return ipAddress;
}
public object ConvertFromDbValue(object value, Type type)
{
// Value is stored in the database as a string.
var stringValue = value.ToString();
var ipAddress = FromString(stringValue);
return ipAddress;
}
public object ConvertToDbValue(object value, Type type)
{
// Value is stored in the database as a string.
return value.ToString();
}
private IPv4Address FromString(string value)
{
// If you do this for real, be more defensive - verify the length of parts is 4
var parts = value.Split('.');
// If you do this for real, be more defensive - use TryParse instead
var octet1 = byte.Parse(parts[0]);
var octet2 = byte.Parse(parts[1]);
var octet3 = byte.Parse(parts[2]);
var octet4 = byte.Parse(parts[3]);
return new IPv4Address(octet1, octet2, octet3, octet4);
}
}
Lastly, in your application startup:
using MicroLite.Configuration;
using MicroLite.TypeConverters;
// Register the custom IPv4AddressTypeConverter.
TypeConverter.Converters.Add(new IPv4AddressTypeConverter());
...
Configure
.Fluently()
...