Sunday, January 20, 2013

Workflow Versioning - Part 2

Continue from the previous post Workflow Versioning - Part 1.

Today I want to share how to host workflow with multiple version in IIS/WAS by using Windows Service Host Factory.

First, create a workflow and name it as v1 and one more different workflow as v2. For example, in my case I name it as VersionWFv1 and VersionWFv2.


Note: this is a different way of creating multiple workflow version compare to my previous post for the part 1. In part 1, I sign the assembly WorkflowVersioning.Workflows.dll into 2 different version but same assembly name. If you had followed the part 1 and created the 2 assemblies with different version, it is difficult to host them in IIS as I read some article found from the google search that we need to do custom service routing to locate the correct version of workflow service. And I found one article in MSDN, in .net 4.5, we save all the hassle and it is now very easy to have different version of workflow running side by side.

Today, I create 2 workflow xaml (class) with different name to differentiate the version. I find that when we sign a same assembly name with different versions, it is also difficult to trace back previous implementation since we had compiled it into dll. In today part 2, I create new class base on an existing class with different name, it is easier to look back the previous implementation, and also we can rollback changes easily.

Back to the topic, how to host 2 different workflow version with Windows Service Host Factory?

We cannot use the original Windows Service Host Factory because the existing implementation does not support service versioning with config file, also the service name is set base on the class name by default. We need to extend it to support hosting same service name but is reference from different classes. For my case, I would like to host the 2 different workflow with the same service name call "VersionWF" (see below yellow highlight), but 2 different classes (blue highlight) which tell the version difference.

The following sample code is sourced from Serena. We need the following assembly reference to extend the Workflow Service Host Factory.
System.Activities
System.ServiceModel
System.ServiceModel.Activities
System.ServiceModel.Activation


public class CustomServiceHostFactory : WorkflowServiceHostFactory
{
    protected override WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)
    {
        // Current workflow service.
        WorkflowService current = new WorkflowService
        {
            Name = "VersionWF",
            Body = new VersionWFv2(),
            DefinitionIdentity = new WorkflowIdentity
            {
                Name = "VersionWF v2",
                Version = new Version(2, 0, 0, 0)
            }
        };

        // Older version.
        WorkflowService version1 = new WorkflowService
        {
            Name = "VersionWF",
            Body = new VersionWFv1()
        };

        // Create WorkflowServiceHost
        WorkflowServiceHost host =
            new WorkflowServiceHost(current, baseAddresses);
        host.SupportedVersions.Add(version1);

        return host;
    }
}


Take note that the workflow service version 1 does not have DefinitionIdentity. If you already had an existing instance in the persistence store, you cannot define the definition identity for version 1 because you never define the definition identity in the first time, if you define it now, you would get an error.

Now, we use the extended service host factory by defining it in the config file. Below is my complete configuration:


<system.serviceModel>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true">
    <serviceActivations>
      <add factory="WorkflowVersioning.Hosts.CustomServiceHostFactory"
                       relativeAddress="./VersionWF.svc" service="WorkflowVersioning.Workflows.VersionWF"/>
         </serviceActivations>
  </serviceHostingEnvironment>
  <services>
    <service name="VersionWF"
    behaviorConfiguration="WorkflowServiceBehavior">

      <endpoint name="basicHttpWorkflowService"
          address=""
          binding="basicHttpBinding"
          contract="IService" />

      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="WorkflowServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
        <serviceTimeouts transactionTimeout="00:10:00"/>
        <serviceThrottling maxConcurrentCalls="1000000"
                            maxConcurrentInstances="1000000"
                            maxConcurrentSessions="1000000" />
        <sqlWorkflowInstanceStore connectionStringName="WorkflowInstanceStore"
          hostLockRenewalPeriod="00:00:30" runnableInstancesDetectionPeriod="00:00:05"
          instanceEncodingOption="GZip" instanceCompletionAction="DeleteNothing"
          instanceLockedExceptionAction="AggressiveRetry" />
        <dataContractSerializer maxItemsInObjectGraph="2147483647" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>


That's all about it. Here are the source if you wish to read more about it: MSDN






Tuesday, January 15, 2013

C# - using

Every C# developer is familiar with the "using" syntax. But, what does "using" actually do and what are the benefits of using it?

Source from MSDN: Provides a convenient syntax that ensures the correct use of IDisposable objects.
For the object which implement IDisposable, we can use the "using" syntax on it. But, before that, the question is why and when do we need to implement IDisposable?

For the objects which use unmanaged or native resources such as file system, COM objects, network, database, any hardware related or third party component or library or etc, we need to ensure those resources to be released once we no longer need it. Otherwise, we are very likely in encountering memory leak problem.

We implement IDisposable in order to have the Dispose method for us to call to flag or indicate our object is no longer in used, so that Garbage Collector will prioritize which object to be finalized first.

Therefore, the "using" syntax is actually used to ensure the used object is dispose correctly. How to ensure that? With the following code:

using (SqlConnection sqlConn = new SqlConnection(connString))
using (SqlCommand sqlCmd = new SqlCommand(cmdText, sqlConn))
{
    sqlCmd.ExecuteNonQuery();
}

The compiler will translate it into:

{ //Create a new scope for SqlConnection
    SqlConnection sqlConn = new SqlConnection(connString);
    try
    {
        { //Create a new scope for SqlCommand
            SqlCommand sqlCmd = new SqlCommand(cmdText, sqlConn);
            try
            {
                sqlCmd.ExecuteNonQuery();
            }
            finally
            {
                if (sqlCmd != null)
                    ((IDisposable)sqlCmd).Dispose();
            }
        }
    }
    finally
    {
        if (sqlConn != null)
            ((IDisposable)sqlConn).Dispose();
    }
}


You save a lot of time in writing that long code as above by just using the "using".
There is a try... catch... implemented for you. In case anything wrong happen during the execution of the code that work with unmanaged resource, it will make sure it get disposed.

Imagine with the following code without the try... catch... and also without the using block, an error occur at the highlighted line of code sqlCmd.ExecuteNonQuery( ). The Dispose( ) method after the error will never be reached, and the instantiated unmanaged resource will get hold up.


SqlConnection sqlConn = new SqlConnection(connString);
SqlCommand sqlCmd = new SqlCommand(cmdText, sqlConn);
sqlCmd.ExecuteNonQuery();
sqlConn.Close();
sqlCmd.Dispose();
sqlConn.Dispose();


Back to the code translation of "using", you can see any codes within the "using" block are group with context or scope { }

I have one doubt yet to confirm, when the code execution exit the scope, any object which is instantiated within that scope will be collected at the same time with the object had been called for dispose by Garbage Collector or not? For example,

using (SqlConnection sqlConn = new SqlConnection(connString))
{
    SqlCommand sqlCmd = new SqlCommand(cmdText, sqlConn);
    sqlCmd.ExecuteNonQuery();
}


Will SqlCommand object get collected by the Garbage Collector after the code execution exit the using block?

I tried to use CLR profiler tool but I can't find my answer and I don't know any other memory profiler tool can help, please leave a comment if you know the answer.

However, base on the Garbage Collector behavior, what I am certain is the objects within the scope will definitely be collected by the Garbage Collector, just that the priority is not higher than the object which had been called for dispose. The reason is it is impossible for any other code which is outside from one scope to use the object in this one scope. Since the object in one scope is not possible to be used by any other scope from outside, therefore the object will not be referenced and it will be cleared after some time.

In summary, it will be the best if we can always call the Dispose method whenever we do not need the object. Relying on scope is still acceptable but not efficient enough. Recommended way is to use "using" whenever possible.


Saturday, January 12, 2013

Workflow Versioning - Part 1

Past 2 weeks ago, I fell sick and took me sometime to do research about Workflow Versioning and write up this post. I believe every workflow user would encounter such scenario whereby you have created a workflow application which were already deployed and running in production environment, and then you need to make some changes to the workflow definition in the production environment, you would want those existing instance continue to run with old workflow definition until it is complete, but the new instance will be run with the new workflow definition.

How?

You can use WorkflowIdentity class.

If you host your workflow with workflow application, it is easy to implement version control to your workflow definition by using WorkflowIdentity class.

But, before that, we need to sign the assembly first. The reason is later we will load the assembly with the same name but different version.



Then, build your workflow project, then identify the assembly public key token by opening the Visual Studio Tool command prompt, and then enter the following command:

sn -T "<assembly file path>"



Now, create a new folder in your bin folder or move your compiled dll to some where else, for example create a folder call v1.0.0.0, and then put your compiled dll into that folder. Then, we need to make sure the application know which folder to find the v1.0.0.0 assembly.

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="WorkflowVersioning.Workflows" publicKeyToken="c0f56e0617db9e22" />
      <codeBase version="1.0.0.0" href="v1.0.0.0/WorkflowVersioning.Workflows.dll"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Alright, now you can use the WorkflowIdentity to indicate the assembly version to run  in workflow application with following code:

SqlWorkflowInstanceStore instanceStore =
    new SqlWorkflowInstanceStore(@"Data Source=.\MSSQL2008;Initial Catalog=WorkflowInstanceStore;Integrated Security=True;");

WorkflowIdentity identityV1 = new WorkflowIdentity();
identityV1.Name = "VersionDemo v1";
identityV1.Version = new Version(1, 0, 0, 0);

WorkflowApplication wfApp = new WorkflowApplication(new VersionWF(), identityV1);
wfApp.InstanceStore = instanceStore;
wfApp.Run();

Do a test run and let's create an instance in persistence store. After that, make some changes to your workflow definition, then change the assembly version to 2.0.0.0, then rebuild your project. Now you have v2.0.0.0 dll in the bin folder, and v1.0.0.0 dll in the bin\v1.0.0.0 folder.

With the following code, the workflow application actually run with v2.0.0.0 assembly, while the existing instances in the persistence store will keep continue running with v1.0.0.0 assembly until the instance is completed.

Then, from now onward, you need to use new WorkflowIdentity for v2.0.0.0 assembly when you run your workflow application.

WorkflowIdentity identityV2 = new WorkflowIdentity();
identityV2.Name = "VersionDemo v2";
identityV2.Version = new Version(2, 0, 0, 0);

WorkflowApplication wfApp = new WorkflowApplication(new VersionWF(), identityV2);
wfApp.InstanceStore = instanceStore;
wfApp.Run();


Next research will be about how to make workflow versioning work with IIS/WAS. See Part 2.

Send Transactional SMS with API

This post cover how to send transactional SMS using the Alibaba Cloud Short Message Service API. Transactional SMS usually come with One Tim...