MakingItUpAsIGo_1

Making it up as I go

My very first action on this new post was to tweak the color scheme. Not because it provides any utilitarian purpose yet, but because I have a fondness for the dark theme and is my favorite Visual Studio theme. So I have spent fifteen minutes playing around with different color combinations as provided by MahApps.Metro.

Now that pretty colors are sufficient to continue, I’m actually going to make some functionality. Well, after I explain this post’s name. I have a bad tendency to think up an idea and just go start working on it, making it up as I go. This started out as one of those times before realizing that a couple of pieces of paper outlining the general flow is not a bad idea. So I have a lot of scrap paper scattered about my desk with scribblings so incomprehensible that future archeologists are going to frame them in a museum and claim the use of hieroglyphics didn’t end until a much later time period than previously believed.

Last post, I showed some pictures of a dialog but I didn’t actually show that code, so here

        private void DialogConnect()
        {
            using(DataConnectionDialog dcd = new DataConnectionDialog())
            {
                DataSource.AddStandardDataSources(dcd);
                if(DataConnectionDialog.Show(dcd) == DialogResult.OK)
                {
                    try
                    {
                        var connection = new SqlConnection(dcd.ConnectionString);
                        connection.Open();
                        //I'm gonna do some work
                    }
                    catch(Exception)
                    {
                        //I'm going to alert the user something went wrong.
                    }
                }
            }
        }

I don’t really care for this so I’m going to rip out the guts and throw it somewhere else. This is where Akka.NET is going to come in. I’ve created an actor which the ViewModel will be a wrapper around.

    internal class ViewActor: ReceiveActor
    {
        #region Public Constructors
 
        public ViewActor()
        {
        }
 
        #endregion Public Constructors
    }

I’ll figure out what to put in there in a bit. First of all, I’m going to create one. The AnalysisViewModel constructor now looks like this

        public AnalysisViewModel(ActorSystem actorSystem)
        {
            _actorSystem = actorSystem;
            CmdConnect = new RelayCommand(DialogConnect);
 
            //private readonly IActorRef _viewActor;
            _viewActor = _actorSystem.ActorOf(Props.Create(() => new Actors.ViewActor()), Actors.ActorPaths.ViewActor);
        }

The actor system is creating a new actor and we are keeping a reference to it.

namespace LeastCost.Actors
{
    internal class ActorPaths
    {
        #region Public Fields
        public static readonly string ViewActor = "viewing";
        #endregion Public Fields
    }
}

This class will be full of the paths to my actors. I’m not a fan of string literals scattered around.

Now for some logic. Actors communicate in messages. Messages are objects. Akka.NET seems to me to follow Alan Kay’s thoughts for object-oriented nicely, but that is a different topic in which I am not well-versed.

namespace LeastCost.Messages
{
    internal class SqlConnectionMessage
    {
        #region Public Constructors
 
        public SqlConnectionMessage(string connectionString)
        {
            ConnectionString = connectionString;
        }
 
        #endregion Public Constructors
 
        #region Public Properties
 
        public string ConnectionString
        { get; private set; }
 
        #endregion Public Properties
    }
}

A message is created in the AnalysisViewModel by

        private void ShowConnectionDialog()
        {
            using(DataConnectionDialog dcd = new DataConnectionDialog())
            {
                DataSource.AddStandardDataSources(dcd);
                if(DataConnectionDialog.Show(dcd) == DialogResult.OK)
                {
                    _viewActor.Tell(new Messages.SqlConnectionMessage(dcd.ConnectionString));
                }
            }
        }

And consumed by

        public ViewActor()
        {
            Receive<Messages.SqlConnectionMessage>(x => System.Diagnostics.Debug.WriteLine(x.ConnectionString));
        }

Let’s test it outMakingItUpAsIGo_2
By checking the debugger output I see

Data Source=localhost;Integrated Security=True

Tada! work offloaded. Now I’m going to offload even more. I think SQL connections are prone to errors so I’m going to put them in a child actor.

namespace LeastCost.Actors
{
    public class SqlConnectionActor: ReceiveActor
    {
        #region Public Constructors
 
        public SqlConnectionActor()
        {
            Receive<Messages.SqlConnectionMessage>(x => DoDBThing(x));
        }
 
        #endregion Public Constructors
 
        #region Private Methods
 
        private void DoDBThing(Messages.SqlConnectionMessage sqlConnectionString)
        {
            //Download schema and do something amazing.
        }
 
        #endregion Private Methods
    }
}

I also have this absurd notion that I’m going to have multiple simultaneous connections, probably won’t, but I want to. So this next part is definitely a “because I can” moment. I’m going to make a pool of these SqlConnectionActors to do my work.

                actorSystem.ActorOf(Props.Create(() => new Actors.SqlConnectionActor()).WithRouter(new Akka.Routing.RoundRobinPool(5)),
                                    Actors.ActorPaths.SqlActorPool);

But wait! There’s more!

I’m going to override the router with some cool options using HOCON configuration. I’ve changed App.config to look like this

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <akka>
    <hocon>
      <![CDATA[
          akka {
            actor{
              deployment{
                /sqlConnectRouter {
                  router = round-robin-pool
                  resizer {
                    enabled = on
                    lower-bound = 1
                    upper-bound = 5
                  }
                }
              }
            }
          }
      ]]>
    </hocon>
  </akka>
</configuration>

This is likely overkill, but fun overkill. The pool of routers should now resize as needed to fit the demand.

The ViewActor still handles those SqlConnectionMessages though, let’s pass that on.

    internal class ViewActor: ReceiveActor
    {
        #region Private Fields
        private readonly ActorSelection _sqlWorkers;
        #endregion Private Fields
 
        #region Public Constructors
 
        public ViewActor()
        {
            _sqlWorkers = Context.ActorSelection("/user/" + Actors.ActorPaths.SqlActorPool);
            Receive<Messages.SqlConnectionMessage>(x => _sqlWorkers.Tell(x));
        }
 
        #endregion Public Constructors
    }

Let’s update the SqlConnectionActor

    public class SqlConnectionActor: ReceiveActor
    {
        #region Public Constructors
 
        public SqlConnectionActor()
        {
            Receive<Messages.SqlConnectionMessage>(x => DownloadSchema(x));
        }
 
        #endregion Public Constructors
 
        #region Private Methods
 
        private void DownloadSchema(Messages.SqlConnectionMessage sqlConnectionMsg)
        {
            try
            {
                using(var connection = new SqlConnection(sqlConnectionMsg.ConnectionString))
                {
                    connection.Open();
                    //Pull some info and give a success message
                }
            }
            catch(System.Exception)
            {
                Sender.Tell(new Messages.SqlConnectionFailureMessage());
            }
        }
 
        #endregion Private Methods
    }

Oh yeah, I made a new message type.

namespace LeastCost.Messages
{
    internal class SqlConnectionFailureMessage
    {
        //Add some way to identify which connection failed.
    }
}

So the ViewActor needs to handle that, because the SqlConnectionActor will tell the sender that something failed by

            catch(System.Exception)
            {
                Sender.Tell(new Messages.SqlConnectionFailureMessage());
            }

Right now I’ll just fill out the generic debugger text

        public ViewActor()
        {
            _sqlWorkers = Context.ActorSelection("/user/" + Actors.ActorPaths.SqlActorPool);
            Receive<Messages.SqlConnectionMessage>(x => _sqlWorkers.Tell(x));
            Receive<Messages.SqlConnectionFailureMessage>(x => System.Diagnostics.Debug.WriteLine("nooooo"));
        }

I still haven’t done any actual work yet. That has to change next time. But a lot has been accomplished in this post.