Sunday, September 30, 2012

Windows Workflow Foundation

What is a workflow?

It is a framework that enables user to create system and process flow easily. Users can see controls that look like blocks and connectors in the UI design page, and you can simply drag and drop these blocks and connectors together to construct a flowchart, then a system will be created and functioning without the need to write lots of code. Finally, you can understand how the system work base on the flowchart.

Here is one sample that I had done while I was learning it.
I created a very simple workflow for leave application with the scenario of when I submit my leave application, it should automatically check for leave cannot be taken for more than 10 days, the application start date must be a future date, and the end date must be greater than start date.


Sample workflow


Things that we must know when we create workflow.

1. Variable - you can declare variables and use it in the workflow or inside a scope (block). It is useful for flagging purpose.

 
2. Arguments - you can determine the input or output parameters of a workflow


3. Imports - you can find the imported assembly namespaces here.



How to pass entity / object into workflow?

After you have created your own entity class, just simply add it as project reference to your workflow project. You actually pass and use your own object in workflow by setting the argument. But, there is another way to pass object into workflow, which is going through WCF via messaging way, but I have yet to discover how to do it. I will update and cover it in my next blog post.

So, go to the arguments of your workflow (as above screenshot), declare a name, set the direction, then set the argument type. While setting argument type, you are suppose to choose your entity object, but it will not be listed there. You just need to import it manually by selecting "Browse for Types...". Then select your entity project under <Referenced Assemblies>.



I have contructed my workflow, so how to test or debug?

Create a new unit test project. Then, add the workflow and entity project reference to your unit test project. Refer to following sample code to create an unit test.

        [TestMethod]
        public void ApplyLeave()
        {
            IDictionary input = new Dictionary();
            IDictionary output;

            Leave leave = new Leave();
            leave.Duration = 3;
            leave.StartDate = DateTime.Now.AddDays(1);
            leave.EndDate = DateTime.Now.AddDays(4);

            input.Add("LeaveApplication", leave);

            output = WorkflowInvoker.Invoke(new ApplyLeave(), input);

            Assert.AreEqual(((Leave)output["LeaveApplication"]).IsApproved, true);
        }

WorkflowInvoker is the class that you use to invoke your workflow. You can execute your workflow at any place such as ASP.net, WCF, windows form, console application, even unit test, and etc. The WorkflowInvoker accept and return Dictionary<string, object> type only. The dictionary key is the argument name, while the value is the argument value.

In my workflow design, I set my input argument type as my entity object type. Therefore, base on my above sample code, I actually construct my entity object, then keep it in my Dictionary<string, object> object instance, then pass it to the WorkflowInvoker. The passed in object will go through the workflow process and then return the final result back to WorkflowInvoker.

Summary

You should be able to notice that the idea of workflow actually is to make an object properties value change after one process end by another process. And, the value actually represent a status of a "thing".

By the way, you can create breakpoint in your workflow by right clicking at the block, then select Insert Breakpoint. So, you are able to identify the problem easily when you encounter any error or workflow does not work correctly while running the unit test.

You can find my sample code here: Download Here

 

Saturday, September 22, 2012

Layered Architecture Solution Guidance (LASG)

Ever think of how nice if there is a tool that able to generate code for you and shorten the application development time? Have you ever notice that when you create an application, there are a lot of code are repetitive in term of pattern (not design pattern) and the way it execute? For example pulling data and manipulating data from DB with ADO.net. Normally you would write the same style or pattern of code but what it actually does is getting the data from DB then store in different variables.

Here is the tool to generate the code for you: Layered Architecture Solution Guidance (LASG).
It is created by my mentor, Serena Yeoh (firedancer).
Download for Visual Studio 2010
Download for Visual Studio 2012

Note:
Some prerequisite components are needed to be installed first in order to install LASG.
1. Enterprise Library 5
2. Open GAX (for Visual Studio 2012)
3. GAX 2010 (for Visual Studio 2010)

Actually, the tool itself is not only meant for code automation, its main purpose is to guide developer to create application with proper and correct layering design. When you start using the tool and then create a new project with LASG template, you will see multiple projects will be created automatically and they are nicely structured into different folders which follow the layering design.
Logical Component Architecture
Physical Deployment Architecture


After installing the tool, how to use the tool?

Create a new project, then look for Guidance Packages installed template.

 

Then, enter your project namespace, then select the project type that you wish to create from the preset templates. Each template have different sets of projects to be created. The checkboxes indicate the projects that will be automatically created after you hit the OK button. Unfortunately, there has no icon or detail show in the UI saying what kind of project type is that. So, here are the details:
- When you see "Web" keyword mean ASP.net Web Forms
- "WinForm" of course is Windows Forms
- "Workflow" of course is Workflow
- "Database" of course is Database
- "Services" and "Contracts" mean WCF
- "Entities", "Process", "Data", "Framework" are Class Library
- "Test" is a Unit Test




After the projects are created, Follow the steps below:

I am not going to share the details on how to do it here. Instead, I will provide you the available link.

Step 1: Generate Business Entities
Step 2: Generate Data Access Components
Step 3: Generate Business Components
Step 4: Generate Services
Step 5: Generate Workflow Activities (optional if you do not have a workflow project)
Step 6: Generate UI Controllers

The steps without documentation require you to explore by yourself. It is not hard to use anyway.

The most interesting part to me is the auto generated code. You can do the code preview first before generate it into code file. And also, the tool automatically keep track which code had been generated before. If you go back to the tool and do some adding or removing, then regenerate the code, it actually give you an option to append or rewrite the code file.

There is one more new feature with this tool is if you happen to have your project namespace is similar to what LASG created, for example project name end with suffix "Data", "Business", "Entities", etc. You actually can enable the tool attach to your project without the need to recreate a new project with LASG template.

What you need to do is just go to the top menu, click at Tools then select Guidance Package Manager. Then, you will see the window as follow:



Then, click at the Enable / Disable Packages... button at the bottom left of the window.


Check the Layered Architecture Solution Guidance 2012 checkbox, then hit the OK button.

You will see the LASG tool menu appear after you right click at your project in the Solution Explorer.

For some reasons, you do not want LASG to attach to your project, you can do the same way, but uncheck the Layered Architecture Solution Guidance 2012 checkbox.


If you like this tool, feel free to like this facebook fan page, so if there is any new update about the tool, it will be shown in your facebook news feed.


Source and credits:
http://serena-yeoh.blogspot.com/
http://layersample.codeplex.com/
http://cloudsample.codeplex.com/
http://visualstudiogallery.msdn.microsoft.com/2dc87fb2-d6f2-4151-9dab-faad717eea41
http://visualstudiogallery.msdn.microsoft.com/c8c473b5-21a1-447a-8b24-33b43411ee7f
https://www.facebook.com/layersample#!/layersample

 

Saturday, September 15, 2012

Data Driven Unit Testing with XML

I had been stopped writing blog for the past 3 months, it is really tough for me to keep up the momentum in writing blog in a timely manner. Well, until recently I join a new company and I suppose I will encounter some unfamiliar issue and new experience to share here more oftenly.

Back to the topic, I would like to share how to write data driven unit test with XML.

Do you ever encounter a scenario that you wish to test one test case with multiple different set of test data?

I used to experience in writing data driven unit test with MbUnit. But, today I want to share about doing the same thing with Visual Studio unit test.
Here is one of the solution with XML.

        [DeploymentItem("\\TestData\\TimeOffTestData.xml"), TestMethod()]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
            "|DataDirectory|\\TestData\\TimeOffTestData.xml", 
            "TimeOffTest_ApplyTimeOffTest", DataAccessMethod.Sequential)]
        public void ApplyTimeOffTest()
        {
            TimeOff timeOff = new TimeOff();
            timeOff.UserId = int.Parse(TestContext.DataRow["UserID"].ToString());
            timeOff.StartDate = DateTime.Parse(TestContext.DataRow["StartDate"].ToString());
            timeOff.EndDate = DateTime.Parse(TestContext.DataRow["EndDate"].ToString());

            TimeOffComponent component = new TimeOffComponent();

            try
            {
                component.Apply(timeOff);
            }
            catch (Exception ex)
            {
                if (!Convert.ToBoolean(TestContext.DataRow["ExpectException"]))
                {
                    throw ex;
                }
                else
                {
                    Assert.AreEqual(typeof(InvalidTimeOffException), ex.GetType(), 
                        "This exception type was unexpected.");
                }
            }
        }
Here is the content of my test data XML:
  
<?xml version="1.0" encoding="utf-8" ?>
<TestData>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-09-10</StartDate>
    <EndDate>2012-09-13</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-13</StartDate>
    <EndDate>2012-11-10</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-12</StartDate>
    <EndDate>2012-11-13</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-15</StartDate>
    <EndDate>2012-11-20</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
</TestData>

What's does Microsoft.VisualStudio.TestTools.DataSource.XML do at the background is above XML will be parsed into a table, hence <TimeOffTest_ApplyTimeOffTest> is a table name then its child elements are columns name then the element content are the row data. Therefore above XML describe 4 set of test data and the differences of the test data.

When you perform test run, it will perform 4 runs with different set of test data accordingly to the defined XML above.

Here is how the test result look like:



Common Problem

After you have finished coding, and you could not get the same result like above screenshot. Following are the common issues that you may encounter and here is the solution:

Known Issue: The unit test adapter failed to connect to the data source or read the data.


Resolution:

Go to your Solution Explorer, add new item to your solution, then select "Test Settings" from the left menu, then add a new test setting.


In the "Test Settings" window, select "Deployment" from the left menu, then check the "Enable Deployment" checkbox.



If problem still persist, go to Solution Explorer, locate your test data XML file and then open the file properties. Make sure the "Copy to Output Directory" property is NOT set to "Do not copy", make it either "Copy always" or "Copy if newer".



If problem still persist and you are using Visual Studio 2012, move your XML file to your project root directory. The problem is the |Data Directory| is not returning correct path. I notice some odd behavior between Visual Studio 2010 and 2012.

I have a folder call "TestData" that keep all my XML files in my test project well organized.

With Visual Studio 2010, no issue in detecting my XML file in the folder.
With Visual Studio 2012, I will get the error. However, there is a workaround for it, which is not to use |Data Directory| when specifying your test data file location. Instead, use real physical path. For example:

        [DeploymentItem("\\TestData\\TimeOffTestData.xml"), TestMethod()]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
            "D:\\Projects\\DataDrivenUnitTest\\DataDrivenUnitTest.Test\\TestData\\TimeOffTestData.xml", 
            "TimeOffTest_ApplyTimeOffTest", DataAccessMethod.Sequential)]
        public void ApplyTimeOffTest()


There is one more workaround for solving the problem with |DataDirectory| in Visual Studio 2012. You can set Copy to Output Directory value to "Do not copy" for the XML file. Then, open the unit test project properties, then set the post-build event command line: copy "$(ProjectDir)TestData" "$(ProjectDir)$(OutDir)"



So that, every time you build your unit test project, the command line above copy all the files in the TestData folder to your output directory without the TestData folder automatically.



You may download my unit test project to play around: Download Here


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...