Search code examples
c#dapperservice-fabric-actor

static class configuration for service fabric actors


Service fabric actors are used to access database and all the methods suppose to use Dapper as ORM tool.

One thing I found out as the best way to solve current problem is using something called SqlMapper in Dapper. With that, you can define general behavior in handling certain data types, for example:

SqlMapper.AddTypeHandler(new DateTimeHandler());

public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
{
    public override void SetValue(IDbDataParameter parameter, DateTime dateTime)
    {
        parameter.Value = dateTime.ValidateDateTime();
    }

    public override DateTime Parse(object value)
    {
        return ((DateTime)value).ValidateDateTime();
    }
}

As you declare static method above (AddTypeHandler) with custom handler such as DateTimeHandler, the mapping done using Dapper framework will make sure any dateTime type goes through above handler correctly.

I would like to see this happening as each Actor communicates to database via Dapper. I haven't seen it happening yet declaring above static method in attempts with several different places such as Actor constructor() or the main method such as below:

private static void Main()
{
        try
        {
            // This line registers an Actor Service to host your actor class with the Service Fabric runtime.
            // The contents of your ServiceManifest.xml and ApplicationManifest.xml files
            // are automatically populated when you build this project.
            // For more information, see https://aka.ms/servicefabricactorsplatform

            ActorRuntime.RegisterActorAsync<SqlRepositoryActor>(
               (context, actorType) => new ActorService(context, actorType)).GetAwaiter().GetResult();

            // This doesn't seem like a right place as I don't see the handler being called when Actor uses dapper mapping methods.
            SqlMapper.AddTypeHandler(new DateTimeHandler());

            Thread.Sleep(Timeout.Infinite);
        }
        catch (Exception e)
        {
            ActorEventSource.Current.ActorHostInitializationFailed(e.ToString());
            throw;
        }
} 

Solution

  • I usually don't want to answer my own question, but here is what I found out so far.

    First of all, maybe I need to change the title of this question if I want the actual solution solving the issue to be more relevant to the title itself. However since the titled question is answered with this post, I will keep it as is.

    To give the short answer, static class configuration can be done with all the places I mentioned above such as Actor constructor, OnActivateAsync(), etc, as static class is still shared across different threads (Actors are all single independent threads) within the AppDomain (And actors are running within the AppDomain. Please correct me if I am wrong.)

    What actually caused the above issue was because the mapping definition using Dapper was declared as dynamic; shown below:

    return sqlConnection.Query<dynamic>(some_sql_script, new { objInstance }).FirstOrDefault();
    

    Once you change the expected return type T to strong type which contains the typeHandler type, then Dapper invoked the typeHandler correctly:

    return sqlConnection.Query<StrongType>(some_sql_script, new { objInstance }).FirstOrDefault();