Building the Business Layer Using WF ASP.NET

The entire business layer is developed using WF. Each of the methods in the Dash board Facade do nothing but call individual workflows.There’s absolutely no business code that is not part of any workflow.

“This is insane!” you are thinking.I know.Please listen to why I went for this approach. Architects can “design” business layer operations in terms of activities, and developers can just fill in a small amount of unit code to implement each activity.

This is actually a really good reason because architects can save time by not having to produce Word documents on how things should work. They can directly go into Workflow designer,design the activities,connect them, design the data flow, and verify whether all input and output are properly mapped or not.This is lot better than drawing flow charts, writing pseudocode, and explaining in stylish text how an operation should work. It’s also helpful for developers because they can see the workflow and easily understand how to craft the whole operation They just open upeach activity and write a small amount of very specific reusable code inside each one.They know what the activity’s input (like function parameters) will be and the know what to produce (return value of function).This makes the activities reusable, and architects can reuse an activity in many work flows.

Workflows can be debugged right in Visual Studio Designer for WF. So, developers can easily find defects in their implementation by debugging the workflow. Architects can enforce many standards like validations,input output check, and fault handling on the workflow. Developers cannot but comply and, therefore, produce really good code.Another great benefit for both architect and developer is that there’s no need to keep a separate technical specification document up to date because the workflow is always up to date and it speaks for itself.If someone wanted to study how a particular operation works, they could just print out the workflow and read it through.

Performance Concerns with WF

But what about performance? You will read from some blog posts that WF is a pretty big library and can be a memory hog.Also, the workflow runtime is quite big and takes time to start up. So, I did some profiling on the overhead of workflow execution, and it is actually very fast for synchronous execution. Here’s proof from Visual Studio’s output window log:

334ec662-0e45-4f1c-bf2c-cd3a27014691 Activity: Get User Guid 0.078125
b030692b-5181-41f9-a0c3-69ce309d9806 Activity: Get User Pages 0.0625
b030692b-5181-41f9-a0c3-69ce309d9806 Activity: Get User Setting 0.046875
b030692b-5181-41f9-a0c3-69ce309d9806 Activity: Get Widgets in page: 189 0.0625
334ec662-0e45-4f1c-bf2c-cd3a27014691 Total: Existing user visit 0.265625

The first four entries are the time taken by individual activities during data access only.not the total time it takes to execute the whole activity. The time entries here are in seconds, and the first four entries represent the duration of database operations inside the activities. The last one is the total time for running a workflow with the four activities shown and some extra code.If you sum up all of the individual activity execution time for only database operations, it is 0.2500, which is just 0.015625 seconds less than the total execution time.This means that executing the workflow itself along with the overhead of running activities takes about 0.015 seconds,which is almost nothing (around 6 percent) compared to the total effort of doing the complete operation.

Mapping User Actions to a Workflow

Each user action can be mapped to a workflow that responds to that action.For example, when a user wants to add a new widget, a workflow can take care of creating the widget, positioning it properly on the page, and configuring the widget with the default value.The first visit of a brand new user to the site is a complex

operation, so it is a good candidate to become a workflow.This makes the architecture quite simple on the web layer—just call a workflow on various scenarios and render the UI accordingly, as illustrated in Figure

User actions are mapped to a workflow

User actions are mapped to a workflow

For example, when a user adds a new tab, therequest goes to a workflow. The workflow creates a new tab, makes it current, configures tab default settings, adds default widgets, etc.Once done, the workflow returns success and the page shows the new tab.

Instead of using complex diagrams and lines of documentation to explain how to handle a particular user or system action, you can draw a workflow and write code inside it.This serves both as a document and a functional component that does the job.The next sections show scenarios that can easily be done in a workflow.

Dealing with First Visit by a New User (New User Set up Work flow)

Handling the first visit of a brand new user is the most complex operation your web site will handle.It’s a good candidate for becoming a workflow.Figure shows a workflow that does all the business layer work for the first-time visit and returns a complete page setup.The Default. aspx just creates the widgets as it receives them from the workflow and is not required to perform any other logic.

The operations involved in creating the first-visit experience for a new user are as follows:

  1. Create a new anonymous user
  2. Create two default pages
  3. Put some default widgets on the first page
  4. Construct a object model that contains user data, the user’s page collection, and the widgets for the first page

If you put these operations in a workflow, you get the workflow shown in Figure

New user visit workflow creates a new user account and configures the account with the default setup

New user visit workflow creates a new user account and configures the account with the default setupNew user visit workflow creates a new user account and configures the account with the default setup

The workflow takes the ASP.NET anonymous identification provider generated by UserName as an input to the workflow from the Default.aspx page.

The first step in passing this input parameter to the workflow while running the workflow is to call the Get User Guid Activity to get the UserId from the aspnet_users table for that user (see Example).

GetUserGuidActivity Execute function

This activity is used in many places because it is a common requirement to get the UserId from the username found from the ASP.NET Context object.All the tables have a foreign key in the UserId column but ASP.NET gives only the UserName.So,in almost all the operations,UserName is passed from the web layer and the business layer converts it to UserId and does its work.

The next step is to create the first page for the user using Create New Page Activity shown in Example.

Create New Page Activity Execute function

This activity takes the UserID as input and produces the NewPageId property as output.It creates a new page,and default widgets are added on that page.Create Default Widget Activity creates the default widgets on this page as shown in example.

Create Default Widge tActivity Execute function

This is what needs to happen next:
  1. Decide how many widgets to add per column.
  2. Compute the number of widgets to put in each column so they have an even distribution of widgets based on the number of default widgets in the database.
  3. Run the foreach loop through each default widget and created widget instances.
  4. Create the second empty page.
  5. Call another workflow named UserVisitWorkflow to load the page setup for the user.This workflow was used on both the first visit and subsequent visits because loading a user’s page setup is same for both cases.

The Invoke Work flow activity that comes with WF executes a work flow asynchronously.So, if you are calling a work flow from ASP .NET that in turn calls another work flow,the second work flow is going to be terminated prematurely instead of executing completely.This is because the workflow runtime will execute the first workflow synchronously and then finish the workflow execution and return.If you use Invoke Work flow activity to run another workflow from the first workflow,it will start on another thread, and it will not get enough time to execute completely before the parent workflow ends,as shown in Figure

Invoke Work flow executes a workflow asynchronously,so if the calling workflow completes before the called workflow, it will terminate prematurely

Invoke Work flow executes a workflow asynchronously,so if the calling workflow completes before the called workflow, it will terminate prematurely

So,Invoke Work flow could not be used to execute the User Visit Work flow from New User Set up Wor flow.Instead it is executed using the CallWorkflow activity, which takes a workflow and executes it synchronously.It’s a handy activity I found on Jon Flanders’

The beauty of this activity is that it properly maps both inbound and outbound properties of the workflow that it calls,as shown in Figure

The User Name property is passed from the New User Visit Workf low, and it is returning the User Page Set up,which contains everything needed to render the page for the user.

Dealing with the Return Visit of an Existing User(User Visit Work flow)

User Visit Work flow creates a composite object named User Page Set up that holds the user’s settings, pages, and widgets on the current page .The Default. aspx gets everything it needs to render the whole page from Use rPage Set up,as shown in Figure

You can map CallWorkflow to a workflow and it will call that work flow synchronously.

You can map CallWorkflow to a workflow and it will call that work flow synchronously.

UserVisitWorkflow design view

UserVisitWorkflow design view

Just like the previous workflow, UserVisitWorkflow takes UserName and converts it to User Guid.It then calls the GetUserPagesActivity,which loads the pages of the user (see Example).

GetUserPagesActivity’s Execute function

After that, it calls the Get User Setting Activity, which gets or creates the user’s setting.The User Setting object contains the user’s current page, which is used by Get User Setting Activity to load the wid gets of the current page.

The code in Get User Setting Activity is not straight forward(see Example). It first checks if User Setting has been created for the user and, if not, Get User Setting Activity creates it.

GetUserSettingActivity Execute function


GetUserSettingActivity Execute function (continued) Loading the existing user’s settings is optimized by getting only the Current Page Id instead of the whole UserSetting object.This results in a very small query that does a scalar selection, which is a bit faster than a row selection because it doesn’t involve constructing a row object or sending unnecessary fields to a row.The final activity loads the widgets on the current page (see Example).It takes the Page Id and loads wid get instances on the page, including the widget definition for each instance.

GetWidgetsInPageActivity Execute function

The LINQ query that loads the widget instances has two important actions:

• Loads wid get instances on the page and orders them by column, and then row.As a result, you get widget instances from left to right and in proper order within each column.

• Fetches the widget object by producing an INNER JOIN between Widget and the Wid get Instance table.

The collection of the wid get instance is mapped to the Wid get Instance property of the activity.The final code block—Return User Page Set up —populates the User Page Set up property of the workflow with loaded data (see Example).

Populate User Page Set up property with widgets, pages, and user settings needed to render the page

The workflow takes an empty UserPageSetup object; when it completes, it populates the empty object with the loaded data. So, from ASP.NET, the UserPageSetup object is passed and emptied. Once the workflow completes,the instance is fully populated.

Adding a New Tab (AddNewTabWorkflow)

Adding a new tab is quite simple, requiring only two steps, after the GUID is assigned (see Figure):

  1. Create a new blank page.
  2. Update the user settings and set the new page as the current page.

Moving Widgets (MoveWidgetInstanceWorkflow)

To move a widget, you must do the following:

  1. Ensure the current user who is calling the workflow owns the widget instance.
  2. Fetch the widget instance and put in workflow context so that other activities can use it.
  3. Pull the widget up from its previous position, which means all the widgets below are shifted up.
  4. Push the widget onto its new position so that all widgets on the new column move down.
  5. Update the widget’s position.

AddNewTabWorkflow design view

AddNewTabWorkflow design view

MoveWidgetInstanceWorkflow design view

MoveWidgetInstanceWorkflow design view

Move Wid get InstanceWorkflow verifies whether the widget being moved is really the current user’s widget.This is necessary to prevent malicious web service hacking (see the “Implementing Authentication and Authorization”section in Chapter).The Ensure Owner Activity can check both the page and the widget’s ownership(see Example ).

EnsureOwnerActivity Execute function

Ensure Owner Activity takes UserName and either Wid get InstanceId or PageId and verifies the user’s ownership.It should climb through the hierarchy from WidgetInstance to the Page and then to Asp net User to check whether the user name matches or not.If the user name is different than the one specified, then the owner is different and it’s a malicious attempt.

Checking Page owner ship requires just going one level up to Aspnet User. But checking Wid get Instance ownership requires going up to the container page and then checking ownership of the page.This needs to happen very fast because it is called on almost every operation performed on Page or Wid get Instance.This is why you want to make sure it does a scalar select only,which is faster than selecting a full row.

Once the owner has been verified, the wid get can be placed on the right column.The next activity,Put Wid get Instance InWork flow, does nothing but put the Wid get Instance object into a public property according to its ID so the object can be manipulated directly.The other activities in the workflow work with the object’s ColumnNo and Order No properties.The next step, Push Wid gets Down In New Column, calls the Push Down Wid gets On Column Activity, which pushes widgets down one row so there’s a room for a new widget to be dropped (see Example).

PushDownWidgetsOnColumnActivity Execute function

The idea is to move all the wid gets right below the position of the wid get being dropped and push them down one position. Now we have to up date the position of the dropped wid get using the activity Change Wid get Instance Position Activity (see Example).

ChangeWidgetInstancePositionActivity Execute function

The widget is placed on a new column, and the old column has a vacant place.But now we need to pull the wid gets one row upward on the old column.Reorder Wid get Instance On Column Activity fixes row orders on a column, eliminating the gaps between them(see Example).The gap in the column will be fixed by recalculating the row number for each widget on that column, starting from zero.

ReorderWidgetInstanceOnColumnActivity Execute function

That’s all that is required for a simple drag-and-drop operation.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

ASP.NET Topics