Saturday, April 16, 2016

C# Mapping Properties; FastMapper , Automapper performance Comparision

Nowadays, almost in all n-tier  projects you need property  mapping. In an MVC project,  mapping might be needed from view model to domain model  or vice versa, or  you might need property mapping from entity class to a DTO class.

You can achieve mapping by  manual mapping ( mapping each property by writing code ) or you can use a third party  library.   Actually ,  manual mapping ( mapping each property by writing code ) is the safest way.  As in performance terms, it is the fastest way to achieve mapping   moreover  code  is easy to understand and easy to maintain.  As disadvantage your code gets bloated as following;



customerDto.Balance = customer.Balance;
customerDto.BirthDate = customer.BirthDate;
customerDto.City = customer.Address.City;
customerDto.District = customer.Address.District;
customerDto.DoorNo = customer.Address.DoorNo;
...
...


If your project requires massive property mapping  ,  a third party might ease up your development stage and you can do mapping by writing  a few lines of code.  This is basically the advantage you get.  You achieve mapping by writing a few lines of code ( suppose both destination and source class has same properties).

There are  a few disadvantages such as performance and maintenance. First of all, adding a third party library makes maintenance more difficult since you will probably add some custom mapping rules and the library you use might have bugs that are hard to maintain. Secondly, as expected,  it will work slower than manual mapping.

So far in my projects  I've used  Automapper  I can tell, I am not really pleased with it.  Firstly, its usage has changed a lot as they published new versions. Secondly , its performance is really poor.

Recently , I've seen another mapping library Fastmapper.  Which is quite easy to use with its fluent api design  and its performance is very close to manual mapping. In terms of feature , it is not as rich as Automapper , but it works fine for simple property mapping. And in most of the applications, that is all you need.

 I've created a performance benchmark project to  see the result myself;

Here is the result ;



Actually,  you will probably never  map 100.000 objects from one  to another in an enterprise application. It is a very rare case.  Yet still, you should be aware of performance  of the tool/API/framework/library you are using.

Here's  the  source code of  the performance test project ;



//Customer Class
public class Customer
{
   public int Id { get; set; }
   public decimal Balance { get; set; }
   public string Name { get; set; }
   public string Surname { get; set; }
   public DateTime BirthDate { get; set; }
   public AddressInfo Address { get; set; }
   public List Accounts { get; set; }

   public Customer()
   {
      this.Address = new AddressInfo();
   }
}
public struct Account
{
   public int BankCode { get; set; }
   public int BranchCode { get; set; }
   public int Number { get; set; }
   public int AccountPostFix { get; set; }

   public override string ToString()
   {
      return string.Format("{0}-{1}-{2}-{3}", BankCode, BranchCode,
      Number, AccountPostFix);
   }
}
public class AddressInfo
{
   public string City { get; set; }
   public string District { get; set; }
   public string Street { get; set; }
   public int DoorNo { get; set; }
   public int ZipCode { get; set; }
}
//CustomerDTO Class
public class CustomerDto
{
   public int Id { get; set; }
   public decimal Balance { get; set; }
   public string Name { get; set; }
   public string Surname { get; set; }
   public DateTime BirthDate { get; set; }
   public string City { get; set; }
   public string District { get; set; }
   public string Street { get; set; }
   public int DoorNo { get; set; }
   public int ZipCode { get; set; }

   public List Accounts { get; set; }

   public static implicit operator CustomerDto(Customer customer)
   {
      CustomerDto customerDto = new CustomerDto();
      customerDto.Accounts = new List();

      foreach (Account account in customer.Accounts)
      customerDto.Accounts.Add(account.ToString());
      customerDto.Balance = customer.Balance;
      customerDto.BirthDate = customer.BirthDate;
      customerDto.City = customer.Address.City;
      customerDto.District = customer.Address.District;
      customerDto.DoorNo = customer.Address.DoorNo;
      customerDto.Id = customer.Id;
      customerDto.Name = customer.Name;
      customerDto.Street = customer.Address.Street;
      customerDto.Surname = customer.Surname;
      customerDto.ZipCode = customer.Address.ZipCode;

      return customerDto;
   }
}
...
...
//Manual Mapping
CustomerDto customerDto = new CustomerDto();
customerDto.Accounts = new List();

foreach (Account account in customer.Accounts)
customerDto.Accounts.Add(account.ToString());
customerDto.Balance = customer.Balance;
customerDto.BirthDate = customer.BirthDate;
customerDto.City = customer.Address.City;
customerDto.District = customer.Address.District;
customerDto.DoorNo = customer.Address.DoorNo;
customerDto.Id = customer.Id;
customerDto.Name = customer.Name;
customerDto.Street = customer.Address.Street;
customerDto.Surname = customer.Surname;
customerDto.ZipCode = customer.Address.ZipCode;

//Using Automapper
var config = new MapperConfiguration(cfg => cfg.CreateMap()
          .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.Address.City))
          .ForMember(dest => dest.District, opt => opt.MapFrom(src => src.Address.District))
          .ForMember(dest => dest.DoorNo, opt => opt.MapFrom(src => src.Address.DoorNo))
          .ForMember(dest => dest.ZipCode, opt => opt.MapFrom(src => src.Address.ZipCode))
          .ForMember(dest => dest.Street, opt => opt.MapFrom(src => src.Address.Street)));

var mapper = config.CreateMapper();
...
...
CustomerDto customerDto = mapper.Map(customer);
...
//Using FastMapper
TypeAdapterConfig
   .NewConfig()
   .MapFrom(dest => dest.City, src => src.Address.City)
   .MapFrom(dest => dest.District, src => src.Address.District)
   .MapFrom(dest => dest.DoorNo, src => src.Address.DoorNo)
   .MapFrom(dest => dest.ZipCode, src => src.Address.ZipCode)
   .MapFrom(dest => dest.Street, src => src.Address.Street);
...
...
CustomerDto customerDto = TypeAdapter.Adapt(customer);
...
..



Regards,

Monday, April 4, 2016

Executing MySql stored procedure by using Enterprise Library

Once I needed a simple data access layer class to execute simple db commands. And I've come up with a class that wraps  Enterprise Library  Data Application classes and makes it even easier to call for me. This is my implementation ;



/// 
/// Facade interface to data access class 
/// 
public interface IDatabaseFacade
{
   int ExecuteNonQuery(string spName, List<object> parameters);
}
...
...

public class DatabaseFacade : IDatabaseFacade
{
   private Database database;

   public DatabaseFacade()
   {
      DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory(),false);
      this.database = DatabaseFactory.CreateDatabase();
   }

   public int ExecuteNonQuery(string spName, List<object>parameters)
   {
      using (DbCommand command = this.database.GetStoredProcCommand(spName, parameters.ToArray()))
      {
         return this.database.ExecuteNonQuery(command);
      }
   }
}

It is pretty straightforward. Sure it may have some design issues, i just implemented in hurry and used it right away and once it worked fine i didn't return back to it and checked my design. I've added this implementation to my tiny toolkit  to use it further.

This is just a simple class to execute a non-query store procedure.  Simple use is ;



DatabaseFacade dbFacade = new DatabaseFacade();
List<object> parameters = new List<object>()
{
   "Test",
   123,
   null,
   DateTime.Now,
   "Tester"
};
int result = dbFacade.ExecuteNonQuery("DbCommand_INS", parameters);


No need parameter name definition. You can just pass  stored procedure name with  parameters as a list of object. It worked fine. However, it turns out , this only works on Sql Server.  When i tried to execute mysql  stored procedure it produced following exception ;



System.NotSupportedException : Parameter discovery is not supported for connections using GenericDatabase. You must specify the parameters explicitly, or configure the connection to use a type deriving from Database that supports parameter discovery.

It seems that we cannot call MySql stored procedure without parameters.We have to pass them with names. So I had to pass parameters with their names. However, I didn't want to change my interface because the purpose of this implementation was to make data access as  simple as possible. So  I have changed the implementation of concrete class as following ;



public class DatabaseFacade : IDatabaseFacade
{
   private Database database;

   public DatabaseFacade()
   {
      DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory(), false);
      this.database = DatabaseFactory.CreateDatabase();
   }

   public int ExecuteNonQuery(string spName, List<object> parameters)
   {         
     if (database.DbProviderFactory is MySqlClientFactory)
     {
        string spStr = this.BuildMysqlSpString(spName, parameters);

        using (DbCommand command = this.database.GetSqlStringCommand(spStr))
        {
            DbCommand commandWithParameters = this.AddParameters(command, parameters);

            return this.database.ExecuteNonQuery(commandWithParameters);
        }
    }
    else {
       using (DbCommand command = this.database.GetStoredProcCommand(spName, parameters.ToArray()))
       {
          return this.database.ExecuteNonQuery(command);
       }
    }
   }
   #region MySql Functions
   private DbCommand AddParameters(DbCommand dbCommand, List<object> parameters)
   {
      for (int i = 0; i < parameters.Count; i++)
      {
         DbParameter parameter = dbCommand.CreateParameter();
         parameter.ParameterName = string.Format("@parameter{0}", i + 1);
         parameter.Value = parameters[i];

         dbCommand.Parameters.Add(parameter);
      }
      return dbCommand;
   }
   private string BuildMysqlSpString(string spName, List<object> parameters)
   {
      StringBuilder spBuilder = new StringBuilder();
      spBuilder.AppendFormat("call {0}(", spName);
      List dbParameters = new List();

      for (int i = 0; i < parameters.Count; i++)
      {
         spBuilder.AppendFormat("@parameter{0},", i + 1);
      }

      if (parameters.Count != 0)
         spBuilder.Length--;
      spBuilder.Append(")");

      return spBuilder.ToString();
   }
   #endregion
}


Design may look a bit ugly, yet it works for both MySql and Sql Server database ( haven't tested for others) , and you got the idea. To make it work for mysql , you have to build stored procedure call string and pass parameters with names.



Happy Coding!

Saturday, April 2, 2016

NLog Custom Target With Constructor Dependency Injection by using Autofac

Recently, I have decided to switch to NLog from log4net. Personally, I do prefer to implement my own  class(  appender/target  or whatever you call it) to  do the actual logging  and  i prefer to log to database with some session variables. After switching to NLog  I've implemented my own custom target as below;



[Target("AS.Custom.NLogTarget")]
public class NLogCustomTarget : Target
{
   private readonly ISessionContext _sessionContext;
   private readonly IDbContext _dbContext;

   public NLogCustomTarget(ISessionContext sessionContext, IDbContext dbContext)
   {
      this._sessionContext = sessionContext;
      this._dbContext = dbContext;
   }
   protected override void Write(LogEventInfo logEvent)
   {
      AppLog log = new AppLog();
      log.AppDomain = AppDomain.CurrentDomain.FriendlyName;
      log.ClientIP = this._sessionContext.ClientIP;
      log.Level = logEvent.Level.Name;
      log.LoggerName = logEvent.LoggerName;
      log.MachineName = Environment.MachineName;
      log.Message = logEvent.FormattedMessage;
      log.Username = this._sessionContext.UserName;

      this._dbContext.Set().Add(log);
      this._dbContext.SaveChanges();
   }
}

Here the registration ;


IContainer _container;
ContainerBuilder builder = new ContainerBuilder();
_container = builder.Build();
builder = new ContainerBuilder();
builder.RegisterType()
       .As()
       .InstancePerRequest();
builder.RegisterType()
       .As()
       .InstancePerRequest();
builder.RegisterType()
       .AsSelf()
       .InstancePerLifetimeScope();
builder.Update(_container);
....
As you can guess ISessionContext    is an interface to current HttpContext wrapper and IDbContext is interface to my current EntityFramework DbContext class. I will not get in detail to those since it is not the subject of this post.


Unfortunately , this configuration is not enough to get constructor injection working on  custom NLog target. The reason is , target class is created by NLog factory which has no information about the type registrations you have done or any information about your container. Luckily , NLog provides a delegate to setup your own instance creating method.

With  a simple dependency resolver interface and implementation over the great Autofac   IOC, i got it working.
Here is  my implementation ;


IDependencyResolver :



/// 
/// Simple interface to create a dependency resolver
/// 
public interface IDependencyResolver
{
    object GetService(Type serviceType);
}

My Custom Dependency Resolver Class:



public class ASAutofacDependencyResolver : IDependencyResolver
{
   private readonly IContainer _container;

   public ASAutofacDependencyResolver(IContainer container)
   {
      this._container = container;
   }

   public object GetService(Type serviceType)
   {
      return this.Scope().Resolve(serviceType);
   }
   private ILifetimeScope Scope()
   {
      try
      {
         if (HttpContext.Current != null)
            return AutofacDependencyResolver.Current.RequestLifetimeScope;
         return _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
      }
      catch (Exception)
      {
         return _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
      }
   }
}

Configuration of logger:



public static class LoggingConfigurator
{
   private static readonly string NLogDefaultFileName = "NLog.config";
   private static IDependencyResolver _resolver;

   public static void SetResolver(IDependencyResolver resolver)
   {
      _resolver = resolver;
   }
   public static void ConfigureNLog()
   {
       ConfigurationItemFactory.Default.CreateInstance = (Type type) => _resolver.GetService(type);
       string path = AppDomain.CurrentDomain.BaseDirectory + NLogDefaultFileName;
       LogManager.Configuration = new XmlLoggingConfiguration(path, false);
   }
}
And we setup up the dependency resolver as below;


LoggingConfigurator.SetResolver(new ASAutofacDependencyResolver(_container));


That is it!