Mohammed Atef’s Technical blog

Workflow Foundation 4.0 Collections

Introduction

In this post we will see an important built in activities comes with Workflow foundation 4.0., these built-in activities enable you to manipulate a collection in your workflow. this post guide you to do the most required actions for manipulating collections like add,remove and delete items from collection and sorting, searching and clearing the collection.

We will build a console application that demonstrates these activities using a Book Store application.

Building Book Store application
To build the Book Store application you should follow the below steps

1- Create new console application and add System.Activities reference to the new project

2- Open the program.cs file and add the following list of code for declaring BookStoreListItem this class contains a few public properties that store information about an item to be stored.

   1: public class BookStoreListItem
   2:     {
   3:         public string Description { get; set; }
   4:         public int Quantity { get; set; }
   5:         public decimal UnitPrice { get; set; }
   6:         public string Author { get; set; }
   7:         public string BookName { get; set; }
   8:         public BookStoreListItem(string description, int quantity, decimal unitPrice,string author, string bookName)
   9:         {
  10:             Description = description;
  11:             Quantity = quantity;
  12:             UnitPrice = unitPrice;
  13:             BookName = bookName;
  14:             Author = author;
  15:         }
  16:         public BookStoreListItem(string bookName)
  17:         {
  18:             BookName= bookName;
  19:         }
  20:     }

3- Initiate the Workflow by adding the following namespace to the top of program.cs class

using System.Activities.Expressions; now add the following list of code after the closed practices for the main method in the program.cs class

   1: private static Activity CollectionWF()
   2:         {
   3:             // myList is a collection of ListItem objects
   4:             Variable<ICollection<BookStoreListItem>> myList = new Variable<ICollection<BookStoreListItem>>()
   5:             {
   6:                 Name = "MyList",
   7:                 Default = new LambdaValue<ICollection<BookStoreListItem>>
   8:                     (env => new List<BookStoreListItem>())
   9:             };
  10:             return new Sequence
  11:             {
  12:                 Variables = { myList },
  13:                 Activities =
  14:                 {
  15:                     new WriteLine
  16:                     {
  17:                         Text = "Workflow starting..."
  18:                     },
  19:                     new AddToCollection<BookStoreListItem>
  20:                     {
  21:                         Collection = myList,
  22:                         Item = new LambdaValue<BookStoreListItem>
  23:                         (env => new BookStoreListItem("New WorkFlow 4.0 book", 5, 50,"Mohammed", "WorkFlow 4.0"))
  24:                     },
  25:                     new AddToCollection<BookStoreListItem>
  26:                     {
  27:                         Collection = myList,
  28:                         Item = new LambdaValue<BookStoreListItem>
  29:                         (env => new BookStoreListItem("New Linq 4.0 book", 3, 30,"Sherif", "LINQ 4.0"))
  30:                     },
  31:                     new AddToCollection<BookStoreListItem>
  32:                     {
  33:                         Collection = myList,
  34:                         Item = new LambdaValue<BookStoreListItem>
  35:                         (env => new BookStoreListItem("New Windows Communication Foundation 4.0 book", 8, 80,"Atef", "WCF 4.0"))
  36:                     },
  37:                     new AddToCollection<BookStoreListItem>
  38:                     {
  39:                         Collection = myList,
  40:                         Item = new LambdaValue<BookStoreListItem>
  41:                         (env => new BookStoreListItem("Visual studio 2010 book", 15, 40,"Khalid", "VS 2010"))
  42:                     },
  43:                     new WriteLine
  44:                     {
  45:                         Text = "Workflow ended"
  46:                     }
  47:                 }
  48:             };
  49:         }

This workflow defines a variable that is a collection of BookStoreListItem classes named myList. The variable can be any typeof collection that supports the ICollection interface.the LambdaValue Represents a lambda expression used as an r-value, which supports binding of In arguments so it is bind the default value of myList with the returned new instance of BookStoreListItem class .

After that we are going to build the sequence activity for our workflow and the sequence activity will have the following activities

a- writeline activity that printing “Workflow starting…”

b- four AddToCollection activity that used for adding new item of BookStoreListItem to myList

c- another writeline activity to print “Workflow ended…”

4- Now we need to invoke the workflow, so please add the following lines of code in the main method at program.cs class

   1: WorkflowInvoker.Invoke(CollectionWF());
   2: Console.WriteLine("Press ENTER to exit");
   3: Console.ReadLine();

These few line of code used to invoke the workflow by calling collectionWF into the Invoke method.

If you have run the application now you will find the following lines printed

Workflow starting…

Workflow ended…

Press ENTER to exit

5- Printing Collection , we will provide a way to display the contents of the books list, to do that right-click the project and choose Add new Item and select Class, For the class name, enter PrintBooksList.cs. The implementation of this class is shown in Listing below

   1: using System;
   2: using System.Activities;
   3: using System.Collections.Generic;
   4: namespace WFFBookStoreApp
   5: {
   6:     public sealed class PrintBooksList: CodeActivity
   7:     {
   8:         public InArgument<ICollection<BookStoreListItem>> Collection { get; set; }
   9:
  10:         protected override void Execute(CodeActivityContext context)
  11:         {
  12:             ICollection<BookStoreListItem> list =
  13:             this.Collection.Get<ICollection<BookStoreListItem>>(context);
  14:             if (list.Count == 0)
  15:             {
  16:                 Console.WriteLine("The Book list is empty");
  17:             }
  18:             else
  19:             {
  20:                 foreach (BookStoreListItem l in list)
  21:                 {
  22:                     Console.WriteLine("Book Named {0} has the following information :", l.BookName);
  23:                     Console.WriteLine("(Description:{0} ,Quantity: {1},Price: {2} ,Author {3})",
  24:                     l.Description,l.Quantity.ToString(), l.UnitPrice, l.Author);
  25:                 }
  26:                 Console.WriteLine();
  27:             }
  28:         }
  29:     }
  30: }

This custom activity receives the collection as an input argument. It expects a collection of BookStoreListItem classes. the overridden execute method first check if the list empty or not, if yes it is printing the book list is empty message, else it is loop throw the list and print each book item information, this code is very simple you can understand but if you do not know how to create custom activity please visit the following link WFF 4.0 custom activity.

6- To use this custom activity, Open the program.cs file and add the following activity definition to the collectionWF () method before the final writeline activity

   1: new PrintBooksList
   2:                     {
   3:                         Collection=myList
   4:                     },

If you run the application now you will find the following message printed

clip_image002

7- Sorting the collection, we will provide a way to sort the books list by book price, to do that right-click the project and choose Add new Item and select Class, For the class name, enter SortBooksList.cs. The implementation of this class is shown in Listing below

   1: using System;
   2: using System.Activities;
   3: using System.Collections.Generic;
   4: namespace WFFBookStoreApp
   5: {
   6:     public sealed class SortBooksList : CodeActivity
   7:     {
   8:         public InOutArgument<ICollection<BookStoreListItem>> Collection { get; set; }
   9:         protected override void Execute(CodeActivityContext context)
  10:         {
  11:             ICollection<BookStoreListItem> tempList = this.Collection.Get<ICollection<BookStoreListItem>>(context);
  12:             if (tempList.Count > 0)
  13:             {
  14:                 List<BookStoreListItem> sortedList = new List<BookStoreListItem>(tempList);
  15:                 ItemComparer c = new ItemComparer();
  16:                 sortedList.Sort(c as IComparer<BookStoreListItem>);
  17:                 Collection.Set(context, sortedList as ICollection<BookStoreListItem>);
  18:             }
  19:         }
  20:     }
  21:     public class ItemComparer : IComparer<BookStoreListItem>
  22:     {
  23:         public int Compare(BookStoreListItem x, BookStoreListItem y)
  24:         {
  25:             // Handle null arguments
  26:             if (x == null && y == null)
  27:                 return 0;
  28:             if (x == null)
  29:                 return -1;
  30:             if (y == null)
  31:                 return 1;
  32:             // Perform comparison based on the priority
  33:             if (x.UnitPrice == y.UnitPrice)
  34:                 return 0;
  35:             if (x.UnitPrice > y.UnitPrice)
  36:                 return 1;
  37:             else
  38:                 return -1;
  39:         }
  40:     }
  41: }

This custom activity receives the collection as an input argument and return the same argument after sorting it. It expects a collection of BookStoreListItem classes .the overridden Execute() method of this activity takes a collection as both an input and output argument.The Sort() method of the List class is used to perform the sort, but you must supply a class that implements the IComparer interface because the standard implementation will not know how to sort BookStoreListItem objects. The IComparer interface provides a single method called Comparer (), which receives two objects (x and y) as input parameters. It returns 0 if the two objects are equal, 1 if x is greater than y, and -1 if x is less than y.

8- To use this custom activity, Open the Program.cs file and add the following activity definition to the collectionWF () method before the final writeline activity

   1: new SortBooksList
   2: {
   3:     Collection=myList
   4: },
   5: new WriteLine
   6: {
   7:     Text = "Books List sorted by Price"
   8: },
   9: new PrintBooksList
  10: {
  11:     Collection=myList
  12: },

If you run the application now you will find the following message printed

clip_image002[7]

if you have reviewed the printed lines in console, you will find the new books listed after line “books list sorted by price are order desc by price.

9- Searching in the collection, now we are going to use built in activity in Workflow Foundation 4.0 like ExistsInCollection, so we will check if the item found in the book list or not.

As the ExistsInCollection should iterate between books list items so it is require to use Equals() methods which mean we need to implement this method to our BookStoreListItem class, For our purposes, you should consider two items equal if they have the same name,To do that add the following list of code to BookStoreListItem class in program.cs file

   1: public override bool Equals(object obj)
   2: {
   3:     BookStoreListItem i = obj as BookStoreListItem;
   4:     if (i == null)
   5:         return false;
   6:     else
   7:     {
   8:         if (i.BookName == this.BookName)
   9:             return true;
  10:         else
  11:             return false;
  12:     }
  13: }
  14: public override int GetHashCode()
  15: {
  16:     return base.GetHashCode();
  17: }

The Equals() method cast the input object to a BookStoreListItem and returns True if the BookName property matches. When overriding the Equals() method, the compiler expects you to also override the GetHashCode() method. This implementation simply calls the base method

10- Now , we can use ExistsInCollection to do that add the following lines of code before the final writeline activity

   1: public override bool Equals(object obj)
   2:        {
   3:            BookStoreListItem i = obj as BookStoreListItem;
   4:            if (i == null)
   5:                return false;
   6:            else
   7:            {
   8:                if (i.BookName == this.BookName)
   9:                    return true;
  10:                else
  11:                    return false;
  12:            }
  13:        }
  14:        public override int GetHashCode()
  15:        {
  16:            return base.GetHashCode();
  17:        }
  18:

If you have run the application now you will see this line printed before workflow ended

“LINQ 4.0 Book has been added before”

11- Remove item from Collection, Workflow Foundation 4.0 has activity named RemoveFromCollection that is responsible for removing item from collection it very easy in implementation, we will use it to remove book named “LINQ 4.0“,to do that add the following line of code before the final writeline activity

   1: new WriteLine
   2: {
   3:     Text = "Removing LINQ 4.0 book from Books Store..."
   4: },
   5: new RemoveFromCollection<BookStoreListItem>()
   6: {
   7:     Collection = myList,
   8:     Item = new LambdaValue<BookStoreListItem>
   9:         (env => new BookStoreListItem("LINQ 4.0"))
  10: },
  11: new PrintBooksList()
  12: {
  13:     Collection = myList
  14: },

if you have run the application now you will see the following lines printed before workflow ended line

clip_image002[9]

12- Clearing the collection, Workflow Foundation 4.0 has built in activity to clear collection named ClearCollection to use this activity add the following lines of code before the final writeline activity

   1: new ClearCollection<BookStoreListItem>()
   2: {
   3:     Collection = myList
   4: },
   5: new PrintBooksList()
   6: {
   7:     Collection = myList
   8: },

If you have run the application now you will find line printed before workflow ended that says

“The book list is Empty”

Conclusion:

I was trying to learn you how WFF 4.0 are manipulation with collection,you can download The complete implementation of that post from here and you can return back to workflow posts list here

Back to other Workflow Foundation 4.0  posts

I Hope that helped

Advertisements

September 26, 2010 Posted by | .Net 2010 | , , , , , , | 1 Comment

Workflow Foundation 4.0 Custom activities

WFF 4.0 helps you to implement you own custom activity. sure creating custom activity is very important part that all Workflow developers are interested in.the new Workflow Foundation 4.0 give you two ways of generating custom activities.
As we need to prove concept only, my custom activity will be simple, just I am going to build custom activity that print the message “Hello FirstName Last Name” this custom activity taking two input parameters First Name and Last Name and return the full message,let’s see how to implement this simple example by Workflow Foundation 4.0.

Using Code Activity template

Code activity template give you advantage to inherit the codeactivity class and build your custom activity from scratch but the new Workflow Foundation helps you to do that in easy way, so to implement the new custom activity follow the following steps

1- Open Visual Studio 2010 and select file->new project->workflow->workflow consol application

2- In the name textbox write CustomactivitySample as the project name

3- After the solution has opened right click in the project name and select add new item that will open the list of items as shown in the below picture

clip_image002

select code activity and enter code activity name such as “HelloMsg
4- By default you with find the below list of code has been generated in your new file that named HelloMsg.cs

   1: public sealed class HelloMsg : CodeActivity
   2:     {
   3:         // Define an activity input argument of type string
   4:         public InArgument<string> Text { get; set; }
   5:         // If your activity returns a value, derive from CodeActivity<TResult>
   6:         // and return the value from the Execute method.
   7:         protected override void Execute(CodeActivityContext context)
   8:         {
   9:             // Obtain the runtime value of the Text input argument
  10:             string text = context.GetValue(this.Text);
  11:         }
  12:     }

5- Now we are going to add our code for printing hello message

– First we will prepare the activity parameters, so replace line no 4 in the above codes list with the following list of codes

   1: public InArgument<string> FirstName { get; set; }
   2: public InArgument<string> LastName { get; set; }
   3: public OutArgument<string> HelloMessgae { get; set; }

As shown in the above codes list we have declared two input parameters first name and last name and one output parameter for returning the complete hello message.

– The last step for implementing this custom activity is to add code for using input parameters and concatenating it to return the complete hello message, so please replace line 10 at the codes list in step 4 with the following list of codes

   1: string fname = context.GetValue(this.FirstName);
   2: string lname = context.GetValue(this.LastName);
   3: string completeMsg = " Hello " + fname +" "+ lname;
   4: context.SetValue(this.HelloMessgae, completeMsg);

6- Build the project to refresh the toolbar, and you will notice new activity hellomsg activity has been added to the toolbar.

7- Open Workflow1.xaml in designer view and drag sequence activity then drag hellomsg and writeline activity by ordered in the new added sequence activity

8- Create variable named fullname and has data type string from the variables window at bottom of the workflow1 designer

9-Open the writeline property windows and set the text property to the new created variable name in the previous step

10- Open the hellomsg property window and set it is properties as follow:

a- FirstName: “Mohammed”

b- Last Name: “Atef”

c- HelloMessage: fullname which added in step no 8

Finally run the application you will see this message in the console window

“Hello Mohammed Atef”

Using Activity

Using the activity you can create your own activity and use it in another work flow as independent activity and you can pass parameters between your activity and the main workflow designer

This kind of activities is very simple as you are using the workflow designer with all toolbar activities available to implement you custom activity.

We are going to do the same business scenario in the previous example but we will add the following message before the hello message “Custom Activity using Designer.” this only to determine the message printed for each custom activity.

Now , to implement the new custom activity follow the following steps

1- Write click into the project name and select add new item then select activity icon from the windows as shown in picture below

clip_image002[4]

name that activity hellomsgActivity.xaml

2- Drag sequence activity to the new created activity named hellomsgActivity.xaml and then drag writeline activity into the sequence activity

3- Add two arguments from arguments window below the designer of that activity named hellomsgActivity.xaml

4- Write the following line into the text property of the writeline activity

“Custom Activity using Designer: Hello Mr. ” + FName + LName

5- Build the application

6- Open the main workflow1.xaml in design mode and drag hellomsgActivity activity from the toolbar

7- Open the hellomsgActivity property window and set it is properties as follows

a- FName:”Mohammed”

b-LName:”Atef”

Now Run the application you will find the following messages are printed

Hello Mohammed Atef”

Custom Activity using Designer: Hello Mr. Mohammed Atef”

Now we have finished this example and the main workflow1.xaml should be like the following picture below

clip_image002[6]

You can also download the complete example by source code from here.
Back to other Workflow Foundation 4.0  posts

I hope that helped.

September 26, 2010 Posted by | .Net 2010 | , , , , , | 3 Comments

Workflow Foundation 4.0 Tracking

Introduction

This post will guide you to use extensions for tracking Workflow events while it is executing the defined activities.This is useful for monitoring a workflow’s execution and for triggering external processing.

Tracking
In WF 4.0, tracking is accomplished through tracking participants, which are extensions that are derived
from the TrackingParticipant abstract class.
First of all to implement tracking extensions you need to inherit TrackingParticipant class and overrides the Track() method, which is where most of the work is done. When a trackable event occurs, the workflow instance will enumerate all the extensions and will call the Track() method in any that are derived from the TrackingParticipant base class.
A TrackingRecord is passed into the Track() method. This is an abstract class; the actual instance passed
in will be one of the following classes, which are derived from the TrackingRecord class:
WorkflowInstanceRecord contains data about the workflow instance.
You can use this class to print the Workflow instance ID and Workflow instance state as shown in the below list of codes:

   1: WorkflowInstanceRecord instance = record as WorkflowInstanceRecord;
   2: if (instance != null)
   3: {
   4: Console.WriteLine(String.Format(" InstanceID: {0} State: {1}",instance.InstanceId, instance.State));
   5: }

BookmarkResumptionRecord contains data about the bookmark being resumed.

You can use this class to print the book mark name as shown in the below list of codes:

   1: BookmarkResumptionRecord bookmark = record as BookmarkResumptionRecord;
   2: if (bookmark != null)
   3: {
   4: Console.WriteLine(String.Format(" Bookmark {0} resumed",bookmark.BookmarkName));
   5: }

ActivityStateRecord contains data about a specific activity.

You can use this class to print information about activities hosted in the Workflow instance as shown in the below list of codes:

   1: ActivityStateRecord activity = record as ActivityStateRecord;
   2: if (activity != null)
   3: {
   4: IDictionary<String, object> variables = activity.Variables;
   5: StringBuilder s = new StringBuilder();
   6: if (variables.Count > 0)
   7: {
   8: s.AppendLine(" Variables:");
   9: foreach (KeyValuePair<string, object> v in variables)
  10: {
  11: s.AppendLine(String.Format(" {0} Value: [{1}]",
  12: v.Key, v.Value));
  13: }
  14: }
  15: Console.WriteLine(String.Format(" Activity: {0} State: {1} {2}",
  16: activity.Activity.Name, activity.State, s.ToString()));
  17: }

CustomTrackingRecord contains user-defined data.

You can use this class to print about user-defined data as shown in the below list of codes

   1: CustomTrackingRecord user = record as CustomTrackingRecord;
   2: if ((user != null) && (user.Data.Count > 0))
   3: {
   4: Console.WriteLine(String.Format(" User Data: {0}", user.Name));
   5: foreach (string data in user.Data.Keys)
   6: {
   7: Console.WriteLine(String.Format(" {0} : {1}", data, user.Data[data]));
   8: }
   9: }

To use the tracking extension you should add the tracking extension to the Workflow instance as shown in the below list of codes

   1: i.Extensions.Add(_tracking);
   2: //where i is an instance of WorkflowApplication  
   3: //and _tracking is an instance of class that inherits TrackingParticipant class

Then you should set up the tracking extensions participants by using TrackingProfile collections, A TrackingProfile defines a collection of queries that specify which events are to be tracked by the associated tracking participant. These queries are used to determine if an event is trackable. The queries are stored in the Queries property, which is a collection of classes derived from the abstract TrackingQuery class. There are four derived classes that correspond to the four types of tracking records:

WorkflowInstanceQuery

A WorkflowInstanceQuery is used to define the workflow instance events that should be tracked. These

are the process states that occur at the instance level such as Started, Completed, Unloaded, and so on, To do that you can write the below list of codes:

   1: TrackingProfile = new TrackingProfile()
   2: {
   3:     Name = "TrackingProfileName",
   4:     Queries =
   5:     {
   6:         // For instance data, only track the started and completed events
   7:         new WorkflowInstanceQuery()
   8:         {
   9:             States = { WorkflowInstanceStates.Started,WorkflowInstanceStates.Completed },
  10:         }
  11: }

BookmarkResumptionQuery

In a BookmarkResumptionQuery, you specify the name of the bookmark that you want to track whenever it is resumed. You can specify only a single bookmark in a query. If you want to track multiple bookmarks,

you should create multiple queries—one for each bookmark, To do that you can write the below list of codes:

   1: TrackingProfile = new TrackingProfile()
   2: {
   3:     Name = "TrackingProfileName",
   4:     Queries =
   5:     {
   6:         new BookmarkResumptionQuery()
   7:                       {
   8:                           Name = "GetAssignment"
   9:                       }
  10: }

ActivityStateQuery

An ActivityStateQuery class specifies both the Name of the activity and the State collection (events) that

should be tracked. You can specify an asterisk (*) for either, which indicates that all activities and/or

states should be tracked, To do that you can write the below list of codes:

   1: TrackingProfile = new TrackingProfile()
   2:                 {
   3:                     Name = "ListBoxTrackingProfile",
   4:                     Queries =
   5:                     {
   6:                         // For activity data, track all states of the InvokeMethod
   7:                        new ActivityStateQuery()
   8:                        {
   9:                            ActivityName = "InvokeMethod",
  10:                            States = { "*" },
  11:                        }
  12:                     }
  13: }

CustomTrackingQuery

The CustomTrackingQuery specifies the ActivityName, which indicates the activity that generated the

CustomTrackingRecord and the Name property, which indicates the name given to the CustomTrackingRecord,You can specify an asterisk for either (or both) as the example, above does. When

both are set to *, it indicates that all user events should be tracked, you can do that by typing the below of codes:

   1: TrackingProfile = new TrackingProfile()
   2:                 {
   3:                     Name = "ListBoxTrackingProfile",
   4:                     Queries =
   5:                     {
   6:                         new CustomTrackingQuery()
   7:                         {
   8:                             Name = "*",
   9:                             ActivityName = "*"
  10:                         }
  11:                     }
  12: }

In this post we have understood the Tracking extension and we have learned how to use it also.now you can visit the orher posts about Workflow Foundation for here

I hope that helped.

September 26, 2010 Posted by | .Net 2010 | , , , , , , | 2 Comments

Workflow Foundation 4.0 Extensions

Introduction

Workflow foundation Extensions allow you to add configurable behavior to a workflow solution. The activities that you include in your workflow define the steps that are performed, while the extensions provide the operating environment that these activities are executed in, the persistence extension is not aware of what activities are executed; the extension however, provides the ability to persist those activities (whatever they might be) to a durable store.

SQL Persistence Extension

There are two key aspects of extensions that make then extremely useful. First, as was inferred
earlier, they are configurable. For example, the persistence provider that was used SqlWorkflowInstanceStore was designed to use a SQL Server database. Without changing the
application or the workflow definition.
The second aspect of extensions is that they can be accessed both from the application as well as the
workflow activities. This provides a convenient tool for sharing information between the application and
the workflow.

To use SQL Persistence you need to declare a reference to the InstanceStore class that will be used to persist and load the workflow instances :

   1: private InstanceStore _instanceStore;

Then add you need to Loaded event handler and configures the store to do that you need to write the following code

   1: _instanceStore = new SqlWorkflowInstanceStore(_connectionString);
   2: InstanceView view = _instanceStore.Execute(_instanceStore.CreateInstanceHandle(),
   3: new CreateWorkflowOwnerCommand(),TimeSpan.FromSeconds(30));
   4: _instanceStore.DefaultInstanceOwner = view.InstanceOwner;

where the _connectionstring is the DB sql connection string used for your SQL Persistence.above code has an InstanceStore that is an abstract class from which all persistence providers are derived. An instance of the concrete class SqlWorkflowInstanceStore is created, passing the connection string in the constructor.

The parameters to the Execute() method are a handle (provided by InstanceStore ), a command, and a

timeout value. It returns an InstanceView class, which is roughly analogous to a connection handle.

Now you need to setup The Workflow persistence, to do that add the following codes listed below

   1: i.InstanceStore = _instanceStore;//where i is and instance of WorkflowApplication
   2: i.PersistableIdle = (waiea) => PersistableIdleAction.Unload;
   3: i.Run();

The above code configures the workflow instance to be persisted. First, it sets the InstanceStore

property using the reference created as described early. It then provides an event handler for

the PersistableIdle event, which tells the instance to unload itself from memory. It is persisted to the

database prior to being unloaded.

Custom Extensions

here we will learn how to build a custom extension and how to use it in you Workflow. we are going to build simple custom extension that used to store the connection string, Instead of passing the connection string as an input argument, any activity that needs the connection string can access it from this extension.

Assume that we will create class called  that hold the custom extension and implemented as shown in list below

   1: using System;
   2: public class ConStringExtension
   3:     {
   4:         private string _connectionString = "";
   5:
   6:         public DBExtension(string connectionString)
   7:         {
   8:             _connectionString = connectionString;
   9:         }
  10:
  11:         public string ConnectionString { get { return _connectionString; } }
  12:     }

The above code simply defines a private member that holds the connection string. The value of this string

is passed in the class constructor. A public property is provided for accessing this string.To add the new Custom extension to you Workflow instance add the following code

   1: ConStringExtension _dbExtension = new ConStringExtension(_connectionString);
   2: i.Extensions.Add(_dbExtension);

Finally to use this custom extension into code activity add the following line

   1: ConStringExtension ext = context.GetExtension<ConStringExtension>();

I hope you have understand Workflow extensions well ,now you can check other posts about work flow here

I hope that helped.

September 26, 2010 Posted by | .Net 2010 | , , , , , | 1 Comment

Workflow Foundation 4.0

The new Workflow foundation comes with .Net Framework 4.0 that supports building and running the next generation of applications and services. The key components of the .NET Framework are the common language runtime (CLR) and the .NET Framework class library, which includes ADO.NET, ASP.NET, Windows Forms, and Windows Presentation Foundation (WPF), by the way all Visual Studio 2010 IDE are build in XAML language that provides a managed execution environment, simplified development and deployment, and integration with a wide variety of programming languages.

In version 4 of the Microsoft® .NET Framework, Windows Workflow Foundation introduces a significant amount of change from the previous versions of the technology that shipped as part of .NET 3.0 and 3.5.

The significant changes made were necessary to provide the best experience for developers adopting WF and to enable WF to continue to be a strong foundational component that you can build on in your applications.

I have wrote this article to give you a start point to understand and study Workflow Foundation 4.0, so I am going to write series of posts about WFF 4.0 as found in the below below List

I hope that helped

September 20, 2010 Posted by | .Net 2010 | , , , , , | 6 Comments

What’s new in Workflow Foundation 4.0

The New Workflow Foundation 4.0 introduces a significant amount of change from the previous versions of the technology that shipped as part of .NET 3.0 and 3.5. so let’s go quickly to see these new features

  • Designers are built in XAML The designer is based on Windows Presentation Foundation (WPF),so it is taking full advantage of the rich user experience one can build with the declarative UI framework.  Activity developers will use XAML to define the way their activities look and interact with users in a visual design environment.  In addition, it enables non-developers to view and interact with your workflows is now much easier as XAML language is written in XML language that give any non-developers ability to read and understand it.

    For example if you have created new project of Console Workflow and dragged a WriteLine activity in the designer and select the code view you will find the following list of XAML codes

       1: <Activity mc:Ignorable="sap" x:Class="WorkflowConsoleApplication1.Workflow1" sap:VirtualizedContainerService.HintSize="251,240" mva:VisualBasic.Settings="Assembly references and imported namespaces for internal implementation" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
       2: <WriteLine
       3: sad:XamlDebuggerXmlReader.FileName="C:\Temp\DotNet4\WorkflowConsoleApplication1\Workflow1.xaml"
       4: sap:VirtualizedContainerService.HintSize="211,200" />
       5: </Activity>

    I think any non-developer can understand the above list of XAML code

  • Different project templates The new Workflow Foundation 4.0 comes with new project templates as shown in below pictureclip_image002

    The above picture shows only four project templates of Workflow Foundation 4.0 that leads you to simplify project templates for developer. The first project template Activity Designer Library let you create you custom Workflow Foundation Activity with designer, while the second project template leads you to create your custom activity by inheriting the CodeActivity class and the third project template leads you to build new WCF Workflow Service and we are going to explain this project template deeply in another post later finally the last project type help you for creating Console application that contain Workflow Activities.

    If you reviews the below pictures that has list of project template found for Workflow Foundation 3.5 you will understand that new Workflow Foundation 4.0 has summarized and compressed the project templates in better way.

    clip_image002[7]

  • Variable and parameters new windows in the WFF IDE Workflow Foundation 4.0 introduces a helpful window for creating variables and parameters to your Workflow in easy way, the below two pictures show you the new windows generated for defining variables and parameters

    clip_image002[9]

    clip_image002[11]

    First Picture show you how to declare variable to you workflow, as shown there you can define the DataType of you variable, default value and the scope of a variable either the entire workflow or just a specific activity or its children.

    Second picture show you how to define arguments by specifying its name, direction(In,Out,In/Out), argument type and default value.

    If you have used Workflow Foundation 3.5 before you should understand what Workflow Foundation 4.0 has introduced to you for declaring variables and arguments as in WFF 3.5 you should write the following list of codes to define variable

   1: public static DependencyProperty MessageProperty =
   2:     DependencyProperty.Register("Message", typeof(string), typeof(CustomActivity));
   3:
   4:         [DescriptionAttribute("Message")]
   5:         [BrowsableAttribute(true)]
   6:         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
   7:         public string Message
   8:         {
   9:             get
  10:             {
  11:                 return ((string)(base.GetValue(MessageProperty)));
  12:             }
  13:             set
  14:             {
  15:                 base.SetValue(MessageProperty, value);
  16:             }
  17:         }
  18:

The above bulk of code writes only for defining variable Named message of type string

  • Windows Communication Foundation (WCF) Integration

    Workflow Foundation 4.0 introduce creating services and consuming or coordinating service interactions.  A great deal of effort went into enhancing the integration between WCF and WF.  New messaging activities, message correlation, and improved hosting support, along with fully declarative service definition are the major areas of improvement, We will go deeply throw WCF integration with the new WF in another post later.

  • New built in Activity The new Workflow Foundation 4.0 has a lot of built in activities as follows- New activities for manipulating data such as Assign and collection activities such as AddToCollection.

    – New flow control activities, such as DoWhile, TryCatch, ForEach, Switch, and ParallelForEach.

    – Activities for controlling transactions, such as TransactionScope and Compensate.

    – New messaging activities such as SendContent and ReceiveReply.

    Most of these Activities will be explained in the next post for WFF 4.0 toolbar.

    Back to other Workflow Foundation 4.0  posts

I Hope that Helped

September 20, 2010 Posted by | .Net 2010 | , , , , , | 1 Comment

Create new FileNet document instance using image content of exist document instance Using FileNet Web Service

Introduction

I have wrote this post to tell you how to Create new FileNet document instance using image content of exist document instance Using FileNet Web Service. Really I have spent some hours to implement this solution and I want to share it with you to save your time.

Assumption

I will assume the following points so please, do not forget to follow these points for future use:

1- The Web Service proxy named FNWSP8351.

2- The main namespace named FileNetWS

3- I will download the image from source document at the following path c:\Temp\Images\

4- I have built new class to contain all FileNet configuration that named FNWSConfiguration and the below list of codes contain implementation of that class .

   1: Public Class FNWSConfiguration
   2:         Private Shared mWSUrl As String = CSCSettingReader.FNWSURL
   3:         Private Shared mUserName As String = CSCSettingReader.FNWSUserName
   4:         Private Shared mPassword As String = CSCSettingReader.FNWSPassword
   5:         Private Shared mObjectStore As String = CSCSettingReader.FNWSObjectStoreName
   6:         Public Shared ReadOnly Property WSUrl() As String
   7:             Get
   8:                 Return mWSUrl
   9:             End Get
  10:         End Property
  11:         Public Shared ReadOnly Property UserName() As String
  12:             Get
  13:                 Return mUserName
  14:             End Get
  15:         End Property
  16:         Public Shared ReadOnly Property Password() As String
  17:             Get
  18:                 Return mPassword
  19:             End Get
  20:         End Property
  21:         Public Shared ReadOnly Property ObjectStore() As String
  22:             Get
  23:                 Return mObjectStore
  24:             End Get
  25:         End Property
  26:     End Class

Implementation

The below list of code has complete implementation for Create new FileNet document instance using image content of exist document instance, I will explain the code after this code snippet.

   1: Imports System.Configuration.ConfigurationManager
   2: Imports System.IO
   3:     Public Class FNWSHelper
   4:         Public Property WSobjBinding() As FNWSP8351.FNCEWS35ServiceWse
   5:             Get
   6:                 Return mWSobjBinding
   7:             End Get
   8:             Set(ByVal value As FNWSP8351.FNCEWS35ServiceWse)
   9:                 mWSobjBinding = value
  10:             End Set
  11:         End Property
  12:         Sub New()
  13:             mWSobjBinding = LoginFNWS()
  14:         End Sub
  15:
  16:         Private Function LoginFNWS() As FNWSP8351.FNCEWS35ServiceWse
  17:             Try
  18:                 ' Get the WS binding object and extract the WSE SoapContext for it
  19:                 '    (this will be used to add an attachment, and to set WS-Security parameters)
  20:                 Dim objBinding As FNWSP8351.FNCEWS35ServiceWse = New FNWSP8351.FNCEWS35ServiceWse
  21:                 Dim objCtx As Microsoft.Web.Services2.SoapContext
  22:                 objCtx = objBinding.RequestSoapContext ' Create a ChangeRequest and populate it
  23:
  24:
  25:                 ' Fill in the security headers...
  26:                 Dim strUser As String = FNWSConfiguration.UserName
  27:                 Dim tok As Microsoft.Web.Services2.Security.Tokens.UsernameToken
  28:
  29:                 tok = New Microsoft.Web.Services2.Security.Tokens.UsernameToken(strUser, FNWSConfiguration.Password, _
  30:                                 Microsoft.Web.Services2.Security.Tokens.PasswordOption.SendPlainText)
  31:                 objCtx.Security.Tokens.Add(tok)
  32:                 objBinding.Url = FNWSConfiguration.WSUrl
  33:                 Return objBinding
  34:             Catch ex As Exception
  35:             End Try
  36:
  37:         End Function
  38:         Public Function AddDocument(ByVal ID As String) As Boolean
  39:             Try
  40:                 Dim docpropcount As Integer = 2
  41:                 ' Create a ChangeRequest and populate it
  42:                 Dim objChangeRequest As FNWSP8351.ChangeRequestType = New FNWSP8351.ChangeRequestType
  43:                 objChangeRequest.Action = New FNWSP8351.ActionType(2) {}
  44:
  45:                 PrepareDocumentObj(objChangeRequest, dr("DocClassName"))
  46:
  47:                 ' Build a list of properties to set in the new document 
  48:                 objChangeRequest.ActionProperties = PrepareDocumentProperties(docpropcount, dr)
  49:                 'attach doc
  50:                 If Not IsImageExist(ID + ".tif") Then
  51:                     GetDocumentContentByID(ID)
  52:                 End If
  53:                 AttachDocumentContent(objChangeRequest.ActionProperties, objChangeRequest, ID + ".tif")
  54:
  55:                 PrepareExcludedProperties(objChangeRequest)
  56:
  57:
  58:                 Dim objResponseArray() As FNWSP8351.ChangeResponseType
  59:                 objResponseArray = New FNWSP8351.ChangeResponseType() {}
  60:
  61:                 objResponseArray = WSobjBinding.ExecuteChanges(FinalizeRequest(objChangeRequest))
  62:                 Return True
  63:             Catch ex As Exception
  64:
  65:                 Return False
  66:             End Try
  67:
  68:         End Function
  69:
  70:         Private Sub PrepareDocumentObj(ByVal objChangeRequest As FNWSP8351.ChangeRequestType, ByVal docclassname As String)
  71:             Try
  72:                 Dim CreateVerb As FNWSP8351.CreateAction = New FNWSP8351.CreateAction
  73:                 CreateVerb.classId = docclassname
  74:
  75:                 Dim chkin As New FNWSP8351.CheckinAction
  76:                 chkin.checkinMinorVersion = False
  77:                 chkin.checkinMinorVersionSpecified = False
  78:                 objChangeRequest.Action(0) = CreateVerb
  79:                 objChangeRequest.Action(1) = CType(chkin, FNWSP8351.ActionType)
  80:                 CType(chkin, FNWSP8351.CheckinAction).checkinMinorVersion = False
  81:                 CType(chkin, FNWSP8351.CheckinAction).checkinMinorVersionSpecified = False
  82:                 objChangeRequest.TargetSpecification = New FNWSP8351.ObjectReference
  83:                 objChangeRequest.TargetSpecification.classId = "ObjectStore"
  84:                 objChangeRequest.TargetSpecification.objectId = FNWSConfiguration.ObjectStore
  85:                 objChangeRequest.id = "1"
  86:             Catch ex As Exception
  87:
  88:             End Try
  89:
  90:         End Sub
  91:
  92:         Private Function PrepareDocumentProperties(ByVal docpropcount As Integer, ByVal dr As DataRow) As FNWSP8351.ModifiablePropertyType()
  93:             Try
  94:                 Dim objInputProps As FNWSP8351.ModifiablePropertyType()
  95:                 objInputProps = New FNWSP8351.ModifiablePropertyType(docpropcount) {}
  96:
  97:                 objInputProps(0) = GetDocPropertyObject(subjectcodesymbolicname, "Subject")
  98:                 Return objInputProps
  99:             Catch ex As Exception
 100:
 101:             End Try
 102:
 103:         End Function
 104:
 105:
 106:         Private Function GetDocPropertyObject(ByVal symbolicname As String, ByVal propval As Object)
 107:             Dim Propobj
 108:             Select Case symbolicname
 109:                 Case "Subject"
 110:                     Propobj = New FNWSP8351.SingletonString
 111:             End Select
 112:             Propobj.Value = propval
 113:             Propobj.propertyId = symbolicname
 114:             Return Propobj
 115:         End Function
 116:
 117:         Private Function GetDocumentContentByID(ByVal docid As String)
 118:             'prepare document object
 119:             Dim objSpec As FNWSP8351.ObjectSpecification = New FNWSP8351.ObjectSpecification
 120:             objSpec.objectId = docid
 121:             Dim objRequest As FNWSP8351.ObjectRequestType = New FNWSP8351.ObjectRequestType
 122:             objSpec.classId = "Document"
 123:             objSpec.objectStore = FNWSConfiguration.ObjectStore
 124:             objRequest.SourceSpecification = objSpec
 125:             objRequest.id = "1"
 126:
 127:             'prepare request properties
 128:             Dim incProps() As FNWSP8351.FilterElementType
 129:             objRequest.PropertyFilter = New FNWSP8351.PropertyFilterType
 130:
 131:
 132:             ' Ask for the content properties...
 133:             Dim maxSize As UInt64 = Convert.ToUInt64(1000000)
 134:
 135:             incProps = New FNWSP8351.FilterElementType(4) {}
 136:             incProps(0) = New FNWSP8351.FilterElementType
 137:             incProps(0).Value = "ContentElements"
 138:             incProps(1) = New FNWSP8351.FilterElementType
 139:             incProps(1).Value = "ContentData"
 140:             incProps(1).maxSize = maxSize
 141:             incProps(1).maxSizeSpecified = True
 142:             incProps(2) = New FNWSP8351.FilterElementType
 143:             incProps(2).Value = "Content"
 144:             incProps(3) = New FNWSP8351.FilterElementType
 145:             incProps(3).Value = "DocumentTitle"
 146:             incProps(4) = New FNWSP8351.FilterElementType
 147:             incProps(4).Value = "ContentType"
 148:
 149:             objRequest.PropertyFilter.IncludeProperties = incProps
 150:             objRequest.PropertyFilter.maxRecursion = 1
 151:             objRequest.PropertyFilter.maxRecursionSpecified = True
 152:
 153:             ' Create the request array
 154:             Dim objRequestArray() As FNWSP8351.ObjectRequestType = New FNWSP8351.ObjectRequestType(1) {}
 155:             objRequestArray(0) = objRequest
 156:
 157:             ' Fill in the security headers...
 158:             Dim objDimeBinding As FNWSP8351.FNCEWS35ServiceWse = New FNWSP8351.FNCEWS35ServiceWse
 159:             Dim objCtx As Microsoft.Web.Services2.SoapContext = objDimeBinding.RequestSoapContext
 160:             Dim strUser As String = FNWSConfiguration.UserName
 161:             Dim tok As Microsoft.Web.Services2.Security.Tokens.UsernameToken
 162:             tok = New Microsoft.Web.Services2.Security.Tokens.UsernameToken(strUser, _
 163:                         FNWSConfiguration.Password, _
 164:                         Microsoft.Web.Services2.Security.Tokens.PasswordOption.SendPlainText)
 165:             objCtx.Security.Tokens.Add(tok)
 166:             objDimeBinding.Url = FNWSConfiguration.WSUrl
 167:
 168:             ' Send off the request
 169:             Dim objResponseArray() As FNWSP8351.ObjectResponseType
 170:             objResponseArray = New FNWSP8351.ObjectResponseType() {}
 171:             Try
 172:                 objResponseArray = objDimeBinding.GetObjects(objRequestArray)
 173:             Catch Ex As Exception
 174:                 Exit Function
 175:             End Try
 176:
 177:
 178:             If objResponseArray(0).GetType().FullName.Contains("ErrorStackResponse") Then
 179:                 Dim objErrResp As FNWSP8351.ErrorStackResponse = objResponseArray(0)
 180:                 Dim objStack As FNWSP8351.ErrorStackType = objErrResp.ErrorStack
 181:                 Dim objErr As FNWSP8351.ErrorRecordType = objStack.ErrorRecord(0)
 182:
 183:                 Exit Function
 184:             End If
 185:
 186:             ' Extract the document object from the response
 187:             Dim objDoc As FNWSP8351.ObjectValue
 188:             If objResponseArray(0).GetType().FullName.Contains("SingleObjectResponse") Then
 189:                 Dim objSingleObjResponse As FNWSP8351.SingleObjectResponse = objResponseArray(0)
 190:                 objDoc = objSingleObjResponse.Object
 191:             ElseIf objResponseArray(0).GetType().FullName.Contains("ObjectSetResponse") Then
 192:                 Dim objSetResponse As FNWSP8351.ObjectSetResponse = objResponseArray(0)
 193:                 Dim objSet As FNWSP8351.ObjectSetType = objSetResponse.ObjectSet
 194:                 objDoc = objSet.Object(0)
 195:             Else
 196:                 Exit Function
 197:             End If
 198:
 199:             Dim objResponseContext As Microsoft.Web.Services2.SoapContext = objDimeBinding.ResponseSoapContext
 200:             If (Not (objResponseContext Is Nothing)) And (Not (objResponseContext.Attachments Is Nothing)) Then
 201:                 Dim att As Microsoft.Web.Services2.Attachments.Attachment
 202:                 Dim len As Integer
 203:                 Dim nItem As Integer = 0
 204:                 Dim byteContent() As Byte
 205:                 For Each att In objResponseContext.Attachments
 206:                     Dim objStream As System.IO.Stream = att.Stream
 207:                     byteContent = New Byte(objStream.Length) {}
 208:                     len = objStream.Read(byteContent, 0, objStream.Length)
 209:
 210:                     ' Write it out to a file
 211:                     Dim now As System.DateTime = System.DateTime.Now
 212:                     Dim strFileName As String = "C:\Temp\Images\" + docid + ".tif"
 213:                     saveContentToFile(strFileName, byteContent)
 214:                     nItem = nItem + 1
 215:                 Next
 216:             End If
 217:
 218:         End Function
 219:
 220:         Private Sub saveContentToFile(ByVal strFileName As String, ByVal binaryData() As Byte)
 221:             Try
 222:                 Dim outFile As System.IO.FileStream = New System.IO.FileStream(strFileName, _
 223:                         System.IO.FileMode.CreateNew, _
 224:                         System.IO.FileAccess.Write)
 225:                 outFile.Write(binaryData, 0, binaryData.Length)
 226:                 outFile.Close()
 227:             Catch Exp As Exception
 228:                 MessageBox.Show("Saving content failed: [" + Exp.Message + "]")
 229:             End Try
 230:         End Sub
 231:
 232:
 233:         Private Function GetFileName(ByVal filepath As String)
 234:             Dim indx As Integer = filepath.LastIndexOf("\")
 235:             Return filepath.Substring(indx + 1)
 236:         End Function
 237:         Private Sub AttachDocumentContent(ByVal objInputProps As FNWSP8351.ModifiablePropertyType(), ByRef objChangeRequest As FNWSP8351.ChangeRequestType, ByVal imgpath As String)
 238:             Try
 239:                 Dim ulContentSize As Integer
 240:                 Dim inFile As System.IO.FileStream
 241:                 Dim strContentLocation As String = "c:\Temp\Images\" + imgpath
 242:                 ' Create the content element list and set it into the document's properties
 243:                 Dim contentObjects() As FNWSP8351.DependentObjectType
 244:                 contentObjects = New FNWSP8351.DependentObjectType(1) {}
 245:                 Dim objContentList As FNWSP8351.ListOfObject = New FNWSP8351.ListOfObject
 246:                 objContentList.propertyId = "ContentElements"
 247:                 objContentList.Value = contentObjects
 248:                 objInputProps(5) = objContentList
 249:
 250:                 Dim ctProps() As FNWSP8351.PropertyType
 251:                 ctProps = New FNWSP8351.PropertyType(3) {}
 252:
 253:                 ' Set the ContentType property
 254:                 Dim typeProp As FNWSP8351.SingletonString = New FNWSP8351.SingletonString
 255:                 typeProp.propertyId = "ContentType"
 256:                 typeProp.Value = GetAttachmentFileType(strContentLocation)
 257:                 ctProps(0) = typeProp
 258:
 259:                 ' Create the dependent object type object
 260:                 Dim ct As FNWSP8351.DependentObjectType = New FNWSP8351.DependentObjectType
 261:                 ct.dependentAction = FNWSP8351.DependentObjectTypeDependentAction.Insert
 262:                 ct.dependentActionSpecified = True
 263:
 264:
 265:                 Dim nameProp As FNWSP8351.SingletonString = New FNWSP8351.SingletonString
 266:                 nameProp.propertyId = "RetrievalName"
 267:                 nameProp.Value = imgpath
 268:                 ctProps(1) = nameProp
 269:                 ' create content type object
 270:                 Dim contType As FNWSP8351.DIMEContent = New FNWSP8351.DIMEContent
 271:                 contType.size.Parse(ulContentSize.ToString())
 272:
 273:                 ' Add an attachment (uses the DIME binding)
 274:                 Try
 275:                     Dim att As Microsoft.Web.Services2.Dime.DimeAttachment
 276:                     inFile = New System.IO.FileStream(strContentLocation, _
 277:                         System.IO.FileMode.Open, _
 278:                         System.IO.FileAccess.Read)
 279:
 280:                     att = New Microsoft.Web.Services2.Dime.DimeAttachment(GetAttachmentFileType(strContentLocation), _
 281:                                     Microsoft.Web.Services2.Dime.TypeFormat.MediaType, _
 282:                                     inFile)
 283:                     att.Id = "attachment1"
 284:                     contType.Attachment = New FNWSP8351.DIMEAttachmentReference
 285:                     contType.Attachment.location = "attachment1"
 286:                     Dim objCtx As Microsoft.Web.Services2.SoapContext
 287:                     objCtx = WSobjBinding.RequestSoapContext
 288:                     objCtx.Attachments.Add(att)
 289:                 Catch Ex As Exception
 290:                     Throw New System.Exception(Ex.Message, Ex)
 291:                 End Try
 292:
 293:
 294:                 ' create content data object
 295:                 Dim contData As FNWSP8351.ContentData = New FNWSP8351.ContentData
 296:                 contData.propertyId = "Content"
 297:                 contData.Value = contType
 298:                 ctProps(2) = contData
 299:
 300:                 ' Dependent object is of type ContentTransfer
 301:                 ct.classId = "ContentTransfer"
 302:                 ct.Property = ctProps
 303:                 contentObjects(0) = ct
 304:
 305:                 objChangeRequest.ActionProperties = objInputProps
 306:
 307:             Catch ex As Exception
 308:
 309:             End Try
 310:
 311:
 312:         End Sub
 313:
 314:         Private Function GetAttachmentFileType(ByVal filepath As String)
 315:             If filepath.ToLower.Contains(".jpeg") Or filepath.ToLower.Contains(".jpeg") Then
 316:                 Return "image/jpeg"
 317:             ElseIf filepath.ToLower.Contains(".tif") Or filepath.ToLower.Contains(".tiff") Then
 318:                 Return "image/tiff"
 319:             ElseIf filepath.ToLower.Contains(".txt") Then
 320:                 Return "text/txt"
 321:             End If
 322:             Return "image/jpeg"
 323:         End Function
 324:
 325:
 326:         Private Sub PrepareExcludedProperties(ByRef objChangeRequest As FNWSP8351.ChangeRequestType)
 327:             ' Build a list of properties to exclude on the refreshed doc object that is returned
 328:             Dim strExclude() As String = New String(2) {}
 329:             strExclude(0) = "DateCreated"
 330:             strExclude(1) = "DateLastModified"
 331:             objChangeRequest.RefreshFilter = New FNWSP8351.PropertyFilterType
 332:             objChangeRequest.RefreshFilter.ExcludeProperties = strExclude
 333:         End Sub
 334:         Private Function IsImageExist(ByVal docimage As String) As Boolean
 335:             Dim dir As New DirectoryInfo("C:\Temp\Images")
 336:             If dir.GetFiles.Length > 0 Then
 337:                 For Each mfile As FileInfo In dir.GetFiles
 338:                     If mfile.Name = docimage Then
 339:                         Return True
 340:                     End If
 341:                 Next
 342:             End If
 343:             Return False
 344:
 345:         End Function
 346:         Private Function FinalizeRequest(ByVal objChangeRequest As FNWSP8351.ChangeRequestType) As FNWSP8351.ExecuteChangesRequest
 347:             Dim objRequest As FNWSP8351.ExecuteChangesRequest = New FNWSP8351.ExecuteChangesRequest
 348:             objRequest.ChangeRequest = New FNWSP8351.ChangeRequestType(1) {}
 349:             objRequest.ChangeRequest(0) = objChangeRequest
 350:             objRequest.refresh = True
 351:             objRequest.refreshSpecified = True
 352:             Return objRequest
 353:
 354:         End Function
 355:     End Class

Now let’s go deeply in the FNWShelper class, note I will give you high level of understanding and I am not going to explain this class line by line.

  • Lines 4 to 11 we create property of the web service extension for reusing it in other places.
  • Lines 12 to 14 we create the class constructor and calling the LoginFNWS function .
  • Lines 16 to 37 we create the web service extension UserNameToken for preparing login to the FileNet web service.
  • Lines 38 to 68 we commit the new document to filenet with image found in the document that has ID passed to that method, now let’s see this AddDocument function in more details.
  • Lines 40 to 43 is used for creating a ChangeRequest instance and set the Action Property with new list of two ActionType items.
  • Line 45 is calling preparedocumentobj which implemented between lines  70 an 90 at this method we create two ActionType instance one of CreateAction and another one of CheckInAction for check in the committed document at FileNet, while lines 78 to 85 are preparing the ChangeRequestType instance.
  • Go back to the adddocument method and see line 48 that used for building the list of properties to be saved in the new document, this line of code calls method named preparedocumentpreopties that implemented between lines 92 and 103 and it just creates instance of ModifiablePreopertyType list of specific length and assign only one property called subject.
  • Again back to adddocument method and see line 50,51 and 52 that check if the images folder has image named “dociid.tif” where document ID is the value of document ID passed to this method, If the image found the If statement will be escaped else it will call getdocumentcontentbyid method that will be explained in more details now.
  • Lines 117 to 218 we implement method getdocumentbyid that used for saving document image content that has ID passed throw this method to images folder that defined in assumption section.
  • Again back to adddocument method and see line no 53 that used to call method named AttachDocumentContent that take the ChangeRequestType instance and the new image path as parameter to attach the passed image to the new document this method is implemented at lines 273 to 312.
  • After calling the attachdocumentcontent method in the adddocument method build the excluded list properties for the new document with the same way we define the ModifiablePropertyType list.
  • Finally  adddocument method submit the request to FileNet at lines 58 to 61 by using filenet web service method called ExecuteChanges.

I understand that implementation is very big and all lines of code note explained in details but I was trying to save your time for searching and implementing this solution and also I was trying to give you quick help and summary about this implementation.

For testing and using this code write the following two line of code

   1: dim mFNWSHelper as new FNWSHelper
   2: mFNWSHelper.AddDocument("docid")'where docid is the id of the document that you want to copy it image content to the new created document

I hope that was helpful………………….

September 18, 2010 Posted by | FileNet | , , | 2 Comments

Software Design Architecture ebooks list

Software Design Architecture
  • (BOOK) John Wiley & Sons – Pattern-Oriented Software Architecture – A System of Patterns, Volume
  • Addison Wesley – Beyond Software Architecture. Creating And Sustaining Winning Solutions (2003)
  • Addison Wesley – Software Architecture in Practice, Second Edition
  • Addison-Wesley Professional – 2003 – Software Architecture in Practice – Second Edition – ISBN 03
  • Design.Pattern-Oriented Software Architecture, Patterns For Concurrent And Networked Objects, Vol
  • eBook.Addison_Wesley-Beyond_Software_Architecture.ShareReactor
  • Intel architecture software developer’s manual vol3
  • Internet – Seamless Object-Oriented Software Architecture – Analysis and Design of Reliable Syste
  • Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects,V2
  • Pattern-Oriented Software Architecture.Volume 3.Patterns for Resource Management
  • Recommended Best Industrial Practice For Software Architecture Evaluation
  • Wiley – Pattern-Oriented Software Architecture – A System Of Patterns
  • WILEY -the_Art_Of_Software_Architecture_Design_Methods_And_Techniques
  • Design Patterns, GOF
  • Wiley Pattern-Oriented Software Architecture (Vol 3)
  • Just Enough Software Architecture
    Microsoft patterns
  • Addison.Wesley.Effective.Use.of.Microsoft.Enterprise.Library.Jun.2006
  • Application Architecture for .NET-Designing Applications and Services
  • C# – Wrox – Professional C# Design Patterns Applied
  • DALG
  • DAMAZ
  • Data Patterns
  • Designing Data Tier Components and Passing Data Through Tiers
  • DIGWC
  • EAIArch
  • EMAG
  • EntArch
  • ESP
  • Microsoft.Press.Enterprise.Solution.Patterns.Using.Microsoft.Dot.NET.Version.2.0.eBook-iB

Data Designing and Tiers

  • Beginning C# Objects – From Concepts to Code (Apress, 2004).CHM
  • APress Developing Application Frameworks in .NET
  • Beginning C# Objects – From Concepts to Code (Apress, 2004).CHM
  • Designing Data Tier Components and Passing Data Through Tiers

DataMining new

  • Datamining-Concepts And Techniques
  • An Introduction to Data Mining
  • Building Business Intelligence and Data Mining Applications with Microsoft SQL Server 2005
  • Computer Science – Introduction To Data Mining And Knowledge Discovery
  • Elsevier, Data Mining Practical Machine Learning Tools (2005), 2Ed DDU_ OCR 7.0-2.6 LotB
  • Introduction to Data Mining and Statistical Learning
  • Morgan Kaufmann – 0120884070 – Data Mining Practical Machine Learning Tools and Techniques,Second
  • Morgan.Kaufmann,.Data.Mining.Practical.Machine.Learning.Tools.(2005),.2Ed.DDU.LotB
  • Morgan.Kaufmann][Data.Mining.-.Concepts.And.Techniques]
  • Wiley, Discovering Knowledge in Data an Introduction to Data Mining (2005) DDU BM OCR 7.0-2.6 Lot
  • Wiley,.Discovering.Knowledge.in.Data.An.Introduction.to.Data.Mining.(2005).DDU

September 6, 2010 Posted by | Architucture, Design Patterns | Leave a comment