Skip to content
This repository has been archived by the owner on Dec 29, 2020. It is now read-only.

Listeners

TrevorPilley edited this page Jan 1, 2015 · 5 revisions

Listeners are one of the ways you can inject custom code into the MicroLite pipeline.

Some common uses for Listeners are:

  • Auditing records (created by/updated by)
  • Assigning user generated identifier values (e.g. Guids)

There are 3 interfaces provided by MicroLite, each with 2 methods which are called during write operations:

public interface IDeleteListener
{
    void AfterDelete(object instance, int rowsAffected);
    void BeforeDelete(object instance);
}
public interface IInsertListener
{
    void AfterInsert(object instance, object executeScalarResult);
    void BeforeInsert(object instance);
}
public interface IUpdateListener
{
    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.

Invocation

The Listener collections act in the same way as a stack with each item added at the top, keep this in mind if you need your listeners invoked in a specific order.

Listener.InsertListeners.Add(new Listener1());
Listener.InsertListeners.Add(new Listener2()); // Listener2 will be added above Listener1 at the top of the collection

For example, when an object is inserted they will be invoked in the following order:

// Listener2 will be called first as it was the last item added to the collection
Listener2.BeforeInsert(object instance)
Listener1.BeforeInsert(object instance)
// The listeners are then called in reverse order for the AfterX methods.
Listener1.AfterInsert(object instance, object executeScalarResult)
Listener2.AfterInsert(object instance, object executeScalarResult)

This allows any custom listeners to be invoked prior to any shipped by MicroLite.

Example 1 - Auditing

Firstly, define an interface which exposes the audit properties which can be implemented by any of your classes:

public interface IAuditable
{
	public DateTime Created { get; set; }
	public string CreatedBy { get; set; }
	public DateTime? LastModified { get; set; }
	public string LastModifiedBy { get; set; }
}

Secondly, define a listener which acts upon the required interface:

using MicroLite.Listeners;

public class AuditListener : IInsertListener, IUpdateListener
{
    public void AfterInsert(object instance, object executeScalarResult)
    {
        return; // nothing to do
    }

    public void AfterUpdate(object instance, int rowsAffected)
    {
        return; // nothing to do
    }

    public void BeforeInsert(object instance)
    {
        // cast the instance safely in case not all entities implement IAuditable.
        var auditable = instance as IAuditable;
 
        if (auditable != null)
        {
            auditable.Created = DateTime.Now;
            auditable.CreatedBy = Environment.UserName;
        }
    }

    public void BeforeUpdate(object instance)
    {
        // cast the instance safely in case not all entities implement IAuditable.
        var auditable = instance as IAuditable;
 
        if (auditable != null)
        {
            auditable.LastModified = DateTime.Now;
            auditable.LastModifiedBy = Environment.UserName;
        }    
    }
}

Lastly, in your application startup:

using MicroLite.Configuration;
using MicroLite.Listeners;

var auditListener = new AuditListener();

// Register the listener in all relevant collections.
Listener.InsertListeners.Add(auditListener);
Listener.UpdateListeners.Add(auditListener);

...

Configure
    .Fluently()
    ...

Example 2 - Assigning User Generated Identifier Values

If you don't use database generated (identity/auto increment) keys for some classes you use with MicroLite but instead rely on Guids generated in code, you can still move this concern into the infrastructure by creating a listener which is responsible for populating the ID with a new Guid:

using System;
using MicroLite.Listeners;
using MicroLite.Mapping;
 
public class GuidListener : IInsertListener
{
    public void AfterInsert(object instance, object executeScalarResult)
    {
        return; // nothing to do
    }

    public void BeforeInsert(object instance)
    {
        var objectInfo = ObjectInfo.For(instance.GetType());
 
        if (objectInfo.TableInfo.IdentifierStrategy == IdentifierStrategy.Assigned
            && objectInfo.TableInfo.IdentifierColumn.PropertyInfo.PropertyType == typeof(Guid))
        {
            var identifier = Guid.NewGuid();
 
            objectInfo.SetIdentifierValue(instance, identifier);
        }
    }
}

Then register it in the application startup:

using MicroLite.Configuration;
using MicroLite.Listeners;

// Register the custom GuidListener.
Listener.InsertListeners.Add(new GuidListener());

...

Configure
    .Fluently()
    ...
Clone this wiki locally