Posts filed under 'Microsoft and .NET'
Curious about the Correlation example in Microsoft Windows Workflow Foundation Step by Step book
I have read the Microsoft Windows Workflow Foundation Step by Step book. Overall, it is a good reference book.
However, I am not quite sure about the application example illustrated in the Microsoft Windows Workflow Foundation Step by Step book in “External Data Communication” section. The example may not illustrate the true purpose of using the correlation parameter.
The example is about a process of a truck. One workflow has only one truck. There could be many workflows in the system. Each workflow has one truck ID. A truck ID is part of the correlation parameter.
Perhaps, I am wrong. It seems to me that the application try to use the truck ID to differentiate different workflows, so the runtime could send the message to the correct workflow. I think that the runtime uses Guid which is a workflow instance ID stored in the EventArgs object. The EventArgs is created when the runtime fires an event to the workflow. This Guid is used to differentiate between different workflows, but not the correlation parameter.
Activities in the same conversation are chained together through the value of the correlation parameter. A better example of using the correlation parameter could be that there are many tasks running parallel in a workflow. Note, this example could be found in my previous blog, “Communication Between Inside And Outside Of A Workfow In Windows Workflow.” Each task sends a request and waits for response. Each task has uniquely Task ID. The response sent by task 1 would go back to task 1. The response sent by task 2 would go back to task 2. In this case, there are two values of Task ID which are 1 and 2. The example found in the book simply has only one Truck ID for the whole workflow which is not make sense.
I think that the objective of the correlation parameter is to bring back an event from outside to the correct activity in a workflow, not to bring back an event to the correct workflow.
Add comment October 20, 2008
Communication between inside and outside of a workfow in windows workflow
In this blog, I will demonstrate an example of communication between outside of a workflow and the workflow. Let’s assume that a workflow consists of tasks. We need to send task information to outside of a workflow, and outside can send a result back into a workflow.
Basically, our workflow consists of tasks. There is nothing much going on in a task except that there is communication between a workflow and outside of a workflow. A workflow needs to inform the outside what task is, and the outside has to inform the workflow result of the task. We would like to group of these logics into a composite activity.
Mike Taulty provided an easy understanding screencast called, “Windows Workflow Foundation: Two-Way Host/Workflow Communication,” ”Windows Workflow Foundation: Workflow to Host Communication,” and “Windows Workflow Foundation: Host to Workflow Communication.” Source codes presented here are adapted from Mike Taulty’s screencasts.
1) Defining an interface for a local service
A local service is needed for communication. Please refer to this MSDN page, “Using Local Services in Workflows” for a better understanding of the local service. A local service runs independently outside of a workflow. If a workflow would like to send a message to outside, it sends through a local service. If an outside wants to send a message to a workflow, it sends through a local service. We need to define the interface containing a function which a workflow will call to outside and an event which outside sends an event to a workflow. We have defined an interface called ILocalService1. A local service is a class which will implement this ILocalService1 interface.
[ExternalDataExchange]
public interface ILocalService1
{
void distributeTask(int task_id, string workDescription, Guid workflowInstanceID);
event EventHandler<TaskEventArgs> taskEventArgsEventHandler;
}
The interface defines one function, distributeTask, and one event, taskEventArgsEventHandler.
- The distributeTask function is used by a workflow to send a message to outside of a workflow which can be done using the CallExternalMethod activity. Please refer to Tiago Oliveira blog, “Using WF CallExternalMethod activity in Windows Workflow” for a better understanding of the CallExternalMethod activity.
- The taskEventArgsEventHandler event is used when the outside wants to send a message to a workflow which can be done by the HandleExternalEvent activity. The TaskEventArgs class is used to contain data sent from outside. Following is the TaskEventArgs class.
[Serializable]
public class TaskEventArgs : ExternalDataEventArgs
{
public TaskEventArgs(Guid instanceId) : base(instanceId)
{
}
private int task_id;
public int Task_id
{
get { return task_id; }
set { task_id = value; }
}
private string status;
public string Status
{
get { return status; }
set { status = value; }
}
}
A workflow instance ID, instanceId, is needed for creating a TaskEventArgs object, so that an event is sent to the correct workflow. The TaskEventArgs class contains two fields: task_id and status. These two fields are data that we send into a workflow.
2) Creating a local service class by implementing an interface
Next, we need to to create a local service class by implementing the ILocalService1. The distributeTask function is fake. It does not distribute a task to a resource. It just sleeps for a period of time to stimulate that someone has performed a task.
[Serializable]
public class LocalService1 : ILocalService1
{
private int count = 5;
void ILocalService1.distributeTask(int task_id, string description, Guid workflowInstanceID)
{
ThreadPool.QueueUserWorkItem(delegate
{
count–;
Thread.Sleep(count * 15000); //sleep for a certain period of time
//create taskEventArgs and set its field
TaskEventArgs taskEventArgs = new TaskEventArgs(workflowInstanceID);
taskEventArgs.Task_id = task_id;
taskEventArgs.Status = “finished”;
if (taskEventArgsEventHandler != null)
{
taskEventArgsEventHandler(this, taskEventArgs); //Firing the taskEventArgsEventHandler
}
}
);
}
public event EventHandler<TaskEventArgs> taskEventArgsEventHandler;
}
The distributeTask function is called by a workflow. It sleeps for a certain period of time. It creates a taskEventArgs parameter which it will sent into a workflow when it firs an taskEventArgsHandler event.
3) Custom activity for communication between a workflow and outside
Our composite activity has to call the distributeTask defined in the local service, LocalService1, to send a task data to outside. When outside finishes performing a task, it sends back a task’s result through firing the taskEventArgsEventHandler event.
3.1 Go ahead and add a new activity into a workflow project.
3.1 Add four activites sequentially : codeActivity1, callExternalActivity1, handleExternalActivity1, and codeactivity2.
We would like to define two dependency properties as metadata for this composite activity. Please refer to my previous blog for creating a metadata.
3.2 Open the code view of this composite activity and add two dependency properties : Task_idProperty and WorkDescriptionProperty. A dependency property is used here as a metadata property for our custom activity. Metadata property can be edited only in design time, not in the runtime.
- Task_idProperty represents the task ID.
- WorkDescriptionProperty represents the work description of this particular task.
//class Activity1
…
public static DependencyProperty Task_idProperty = DependencyProperty.Register(
“Task_id”, typeof(System.Int32),
typeof(callexternal.Activity1),
new PropertyMetadata(DependencyPropertyOptions.Metadata) );
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public Int32 Task_id
{
get
{
return ((int)(base.GetValue(callexternal.Activity1.Task_idProperty)));
}
set
{
base.SetValue(callexternal.Activity1.Task_idProperty, value);
}
}
public static DependencyProperty WorkDescriptionProperty = DependencyProperty.Register(
”WorkDescription”, typeof(System.String), typeof(callexternal.Activity1),
new PropertyMetadata(DependencyPropertyOptions.Metadata));
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public String WorkDescription
{
get
{
return ((string)(base.GetValue(callexternal.Activity1.WorkDescriptionProperty)));
}
set
{
base.SetValue(callexternal.Activity1.WorkDescriptionProperty, value);
}
}
…
3.3 Add two fields to our custom activity class. They are tmpWorkflowInstanceID of type Guid representing a workflow’s instance ID and tmpTaskEventArgs of type TaskEventArgs representing an input from outside. This field will store a workflow instance ID which we can retrieve in the codeActivity1. It will be passed to outside when calling the distributeTask function in the LocalService1.
…
public static Guid tmpWorkflowInstanceID ;
…
public TaskEventArgs tmpTaskEventArgs = default(callexternal.TaskEventArgs);
…
3.4 Implementing the codeActivity1
- Type the function name which is “StartActivity” in the ExecuteCode textbox in the properties window of the codeActivity1. Press enter and the StartActivity function is generated.
The StartActivity function looks like following.
private void StartActivity(object sender, EventArgs e)
{
//initialize the workflow instance ID
tmpWorkflowInstanceID = this.WorkflowInstanceId;
Console.WriteLine(“Task : “ + this.Task_id+ ” is started of workflow ” + tmpWorkflowInstanceID);
Console.WriteLine(“Description : “ + this.WorkDescription );
}
3.5 Implement the callExternalActivity1
3.5.1 Select an interface implemented by a local service.
The callExternalActivity1 activity will call distributeTask function which has three parameters: int task_id, string description and Guid workflowInstanceID. These variable appeared on the properties window. We bind these varibles into fields of the custom activity which we have declared before in the 3.2 and 3.3 section. When binding, there are two things to set: name and path. Name is the parent object containing a field. In this case, it is the custom activity, Activity1. Path is the field in the parent object. Path refers to a field of the parent object. You can bind variables easily by clicking on a small button at each variable textbox in the property window.
3.5.2 Bind task_id to Task_id field.

Binding the task_id parameter of the function that the workflow calls to the Task_id field of the custom activity, Activity1
3.5.3 Bind workDescription to WorkDescription field.

Binding the workDescription parameter to the WorkDescription field of the custom activity, Activity1.
3.5.4 Bind workflowInstanceID to tmpWorkflowInstanceID.

Binding the workflowInstanceID parameter to the tmpWorkflowInstanceID field of the custom activity, Activity1.
3.6 Implement the handleExternalEventActivity1
When the local service fires an event, it passes TaskEventArgs object into a workflow, so we store it into a variable of the custom activity, Activity1, called tmpTaskEventArgs.

Binding an event argument passed from outside into a workflow to tmpTaskEventArgs of the custom activity, Activity1
3.7 Implement the codeActivity2
Finally, we just print out the values of fields here. Type “finishActivity” in the executeCode textbox in the property window of the codeActivity2 activity.
private void finishActivity(object sender, EventArgs e)
{
Console.WriteLine(“Task “ + this.Task_id + ” receives taskEventArgs “ + tmpTaskEventArgs.Task_id + ” : “ + tmpTaskEventArgs.Status );
}
4) Create a workflow
You need to build first. If the build is successful, the activity1 will be added into the toolbox of the workflow designer.
4.1 Open up the workflow in the workflow designer and drop the custom activity, Activity1. Add five of the activity1. A ParallelActivity is needed at the top. Then add SequenceActivity up to 5. Then add the custom activity, Activity1, into each SequenceActivity.
4.2 Remember that we have declared two metadata properties in the section 3.2 (Task_id and WorkDescription). Let’s initialize it by selecting a custom activity and typing a value in the property window as shown below.

Initialize the metadata properties (Task_id and WorkDescription) that we have declared as dependency properties of the custom activity, Activity1, before.
5) Add the ExternalDataExchangeService and the local service to the workflow runtime
In the main function, declare a new ExternalDataExchangeService object called dataService. Add dataService into the workflow runtime. Finally, add the local service class, LocalService1, into the dataService.
class Program
{
static void Main(string[] args)
{
ExternalDataExchangeService dataService = new ExternalDataExchangeService();
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
workflowRuntime.AddService(dataService);
dataService.AddService(new LocalService1());//add local service
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) {waitHandle.Set();};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(callexternal.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
Console.ReadLine();
}
}
6) Run the workflow
You would see that the workflow works incorrectly. A TaskEventArgs for task 1 should go back to task 1. If you noticed, I have changed reverse the order that the local service will send an event back to the workflow.
Therefore, we need to use the correlation parameter.
7) Adding correlation parameter
The purpose of the correlation parameter is to identify an activity which outside sends a message to.
You can also read about the correlation parameter from the Programming Windows Workflow Foundation book (chapter eight). Please refer to ”Mike Taulty’s screencast on Correlation” for a quick tutorial on the correlation parameter.
7.1) Add Correlation Attributes to the Local Service Interface
The task_id parameter is chosen as the correlate parameter. Please remember that each custom activity, Activity1, has a unique Task_id field. The value in the Task_id field will be passed through the distributeTask function. Please refer to the MSDN page, “Using Correlation in Workflows,” for further information on correlation attributes: CorrelationParameter, CorrelationInitializer and CorrelationAlias.
[CorrelationParameter("task_id")]
[ExternalDataExchange]
public interface ILocalService1
{
[CorrelationInitializer]
void distributeTask(int task_id, string workDescription, Guid workflowInstanceID);
[CorrelationAlias("task_id", "e.Task_id")]
event EventHandler<TaskEventArgs> taskEventArgsEventHandler;
}
7.2) Set correlation token name
7.2.1 A Correlation Token is a string indicating a conversation between activities. A correlation token on both handleExternalEventActivity1 and callExternalMethodActivity1 activities are needed to be set to the same value, so both activities binded into the same conversation, and when a call is made from the callExternalMethodActivity1, the workflow runtime can return it to this handleExternalActivity1 in this custom Activity1, not other handleExternalActivity1 of other activities. In this case, we set the correlation token to be “tc1″ on both activities.
7.2.2 Run the application
Finally, the result is correct.
Project file : without correlation and with correlation.
1 comment October 18, 2008
Obtaining connection string from visual studio
I believe that some of you probably forget the syntax of the connection string used for connecting to a database from an application.
I had the following error message “A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 – Could not open a connection to SQL Server).” There are a lot of problems which could generate this error message. I tried enabling TCP/IP connection/ configuring firewall, etc. It was working. Finally, I tried changing the connection strings. It is still does not work, because the connection string was not correct.
Then I found out that I can obtain a connection string from the visual stdio. First, you need add a data connection to your database in visual studio first.
Then you select the server and the database.
Following figure is the result. A new dabase connection is added, and you can view its connection string from within visual studio. This technique really helps developers to quickly get a connection string which can be used in the application code.
1 comment September 1, 2008
Multithreading in C# Windows Form
What I write here was part of the application that we illustrated in this blog during our User Oriented Design lab course in summer semester 07.
Having only one thread doing both UI and processing would make the UI becoming unresponsiveness when there is a lot to process. We implemented a C# Windows Form application. There are 2 threads: UI thread and processing thread.
In the beginning of the development, we did not expect the complexity of writing a multithread application would be very high.
1. Starting a thread
Following is an example of the function for a new thread to start.
…
public static void startClusterImages(object o)
{ mainForm = (MainForm) o;
….
Before I am going to start a thread, I check whether the processing thread has started or not.
if (!clusterThread.IsAlive)
{
clusterThread = new Thread(threadFunction);
clusterThread.Start(this);
}
The parameter for the ParameterizedThreadStart is the function that we want the processing thread to start. I think that you can only pass one parameter. If there are multiple parameters, I suggest that you group all of paramaters into a single object.
static ParameterizedThreadStart threadFunction = new ParameterizedThreadStart(ImageProcessingControl.startClusterImages);
static Thread clusterThread = new Thread(threadFunction);
2. Control accessing shared variables
When accessing a shared variable, the lock mechanism is needed. However, I am not quite trusting the lock mechanism. It is better to design in a way which avoids using a shared variable.
Anyway, the “lock” keyword can be used to lock an object. The SyncRoot property of the object is used for locking.
lock (uodImageArrayList.SyncRoot)
{
…
}
3. Invoke a function in UI thread from another thread.
The processing thread can not directly invoke a function in a MainForm class which is in the UI thread. Following code is the way to access a function in the UI thread from the processing thread.
First, Check whether the call is from the UI thread or not. If this.InvokeRequired returns false, that means the call is from the UI thread. In this case, there is no problem.
However, if the call is not from the UI thread, this.InvokeRequired returns true. It will go to “else” statement and call BeginInvoke which it will call this setSelected_UODImageGroupUserControl function again eventually. Somehow, the call thread will be switched to the UI thread, so when this setSelected_UODImageGroupUserControl function is called again from beginInvoke, it is called from the UI thread.
public delegate void setSelected_UODImageGroupUserControl_delegate(UserControl userControl);
public void setSelected_UODImageGroupUserControl(UserControl userControl)
{
if (this.InvokeRequired == false)
{
//If this function is called from the same thread (UI Thread).
//then proceed
this.currentlySelectedUserControl = userControl;
this.copyToolStripMenuItem.Enabled = true;
this.cutToolStripMenuItem.Enabled = true;
this.deleteToolStripMenuItem.Enabled = true;
this.toolStripStatusLabel1.Text = ” “;
}
else
{
//If this function is called from different thread
//Then call the delegate first
//The delegate will somehow route this request to be in the UI thread
this.BeginInvoke(new setSelected_UODImageGroupUserControl_delegate(
setSelected_UODImageGroupUserControl), new object[] { userControl });
}
}
Add comment August 23, 2008
Usability Design Lab
I took a User Oriented Design lab course in summer semester 07. Students were seperated into groups. There are three students including me in our group. I and two friends decided to do an image groupping application. Basically, students develop a usability product. I would like to summarize our result here, so I won’t forget what we did and how much usability which we have approved on our image groupping application.
Basically, the application would group similar images into a group. The groupping algorithm is based on time and visual similarity. We are not really good at groupping algorithm, so I won’t talk much on this aspect. On the usability aspect, we have made two prototypes. The first prototype is shown below.
At first, we just think that there should be a panel that we put images in. Then, there is a button which starts groupping images into groups and displaying groupping images on the new panel. The first prototype also has the problem of unresponsiveness, because there is one thread for both UI and images groupping processing. The figure below shows when we loaded a lot of images which took some processing time, and the interface is kind of not responding. When groupping images, if there are a lot of images, the user interface is kind of not responsive. One way that we can improve usability is to seperate another thread for processing images such as loading or groupping. That’s all we can think.
We discussed the first prototype with the lab assistant. She made a good suggestion on which other way we can improve usability. She suggested that there is two steps when using the first prototype which were loading and groupping. There is no need to display images on the right panel. The ultimate goal of user is to group images. It is better that when images are load, the application automatically groups them instead of waiting for a user to click on the “classify” (groupping images) button.
Second of all, it should display the result immediately without waiting for the groupping of all images. The images which have been grouped should be displayed immediately on the application. Therefore, a user does not have to wait until all images groupping is finished which could take quite a great deal of time if there is a lot of images.
The first prototype displays in a group on a same row. Vertical scrollbar is often required to see other image groups. Horizon scrollbar is required to see other images in a group. The third suggestion was to display only thumbnails of images. The first picture on the thumbnail represents its image group. Perhaps, there is a stack of images displaying behind the thumbnail, so a user can have a sense of how many images in that group. The figure belown shows the second prototype. Thumbnails of group of images are displayed. When a user clicks on a thumbnail, images in that group are displayed in the second panel.
It is really interesting that usability can be significantly improved.
Note: the application was implemented with C#.
1 comment August 23, 2008
Some Error messages when trying out WCF
Some error messages (e.g. InvalidOperationException, configuration binding extension not found, etc.) that I found when I was trying WCF. I listed in here in hope that it would be useful later if entercountered.
Continue Reading 3 comments August 19, 2008
WCF And MSMQ Part 1
Messaging technology allows a client and a server to send a message to each other, and they do not have to run at the same time. One party can send a message to another party at anytime. A crash on one side does not effect the another side.
In this tutorial, I am going to implement a simple WCF client-server application without any consideration on security. We are going to use MSMQ as a transport mechanism. I use Microsoft Visual Studio 2008. Please read Queuing in WCF msdn page for further information. Note: you have to install MSMQ on your computer.
Please refer to this msn page for what is WCF (Windows Communication Foundation) and what does it solves.
Please refer to this msdn page for various WCF technical term.
Each WCF service has an endpoint. An endpoint consists fo address, binding and contract.
- An address is usually a URI which specifies where the endpoint of the service is.
- A binding defines the transport mechanism between a client and a server. There are some predefined bindings avaiable. In this tutorial, we are going to use MSMQ as a transport mechanism, so we are interested in NetMSMQBinding.
- A contract is your service, and it is implemented in C# in this tutorial.
Steps:
1. Create a server project
Create a server project by simply select a C# console application from “New Project” dialog. Let’s name the solution name as “wcf_tutorial” and the server project name as “WCFServer1.”
Please refer to “How to Add or Remove References in Visual Studio” msdn page for how to add a reference.
You need to add two references which are System.messaging (found in .NET tab when opening up the “Add Reference” dialog) and System.ServiceModel.dll (found in “C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Communication Foundation” in Windows folder, click on “Browse” tab in the “Add Reference” dialog).
2. Create server source files
IWork is an interface which will be configure as a contract in a binding configuration. WorkService is the implementation of this contract. The server does nothing. It just receives a string from a client.
Please refer to How to: Define a Windows Communication Foundation Service Contract msdn page for how define a contract. Please remember than a MSMQ is a messaging technology which is anynchronous communication. There is no respond back from a server like web service. Thus, the function has no return type which is “void.”
- Please refer to Build a Queued WCF Response Service for more information on WCF and MSMQ.
- Please refer to How to: Implement a Windows Communication Foundation Service Contract msdn page for how to implement a contract.
//////Program.cs//////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Messaging;
using System.Configuration;
namespace WCFServer1
{
[ServiceContract(Namespace = "http://sukasom.wordpress.com")]
interface IWork
{
[OperationContract(IsOneWay = true)]
void submitWork(String str1);
}
public class WorkService : IWork
{
public void submitWork(String str1)
{
Console.WriteLine(“Server has received a work : “ + str1);
}
}
class Program
{
static void Main(string[] args)
{
string queueName = ConfigurationSettings.AppSettings["queueName"];
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
using (ServiceHost serviceHost = new ServiceHost(typeof(WorkService)))
{
serviceHost.Open();
Console.WriteLine(“The service is ready.”);
Console.WriteLine(“Press <ENTER> to terminate service.”);
Console.ReadLine();
}
}
}
}
Put the above code in the Program.cs. The server part is modified from How to: Host a WCF Service in a Managed Application msdn page.
3. Configure server configuration file
You need to configure the configuration file. Add an App.config file into your project. Please refer to Specifying an Endpoint Address msdn page for more information on address configuration. My configuration file is modified from NetMSMQBinding msdn page.
///////////////App.config /////////////////////////
<?xml version=”1.0” encoding=”utf-8” ?>
<configuration>
<appSettings>
<add key=”queueName” value=”.\private$\ServiceModelSamples” />
</appSettings>
<system.serviceModel>
<services>
<service name=”WCFServer1.WorkService” behaviorConfiguration=”Behavior1“>
<endpoint address=”net.msmq://localhost/private/ServiceModelSamples“
binding=”netMsmqBinding” bindingConfiguration=”test“
contract=”WCFServer1.IWork” />
</service>
</services>
<!– Following is necessary for getting information about the service through http with the svcutil.exe tool. –>
<behaviors>
<serviceBehaviors>
<behavior name=”Behavior1“>
<serviceMetadata httpGetEnabled=”true” httpGetUrl=”http://localhost:8000/Hello/” />
</behavior>
</serviceBehaviors>
</behaviors>
<!– For first example, the security is just disabled. –>
<bindings>
<netMsmqBinding>
<binding name=”test“>
<security mode=”None“>
</security>
</binding>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
In the “service” element, an endpoint is defined with an address, a binding and a contract. This WCF sample application uses MSMQ as a transport mechanism, so the binding is the NetMsmqBinding.
The contract specifies the interface which is WCFServer1.IWork. The security is turned off in this tutorial through the bindingConfiguration named “test.”
A client needs to be able to access the metadata of the service, so it is defined through the behaviorConfiguration named “Behavior1″ where the httpGetEnabled attribute is set to true. It means that the metadata can be retrieved through the http through the URL set in the httpGetUrl attribute which is “http://localhost:8000/Hello/” in this tutorial. This URL allows the client to get a metadata about the service from the correct location. You can open up the “http://localhost:8000/Hello/“ on the browser as shown below.
More info on address and httpGetEnabled can be found in WCF Part 6 : Address blog.
4. Implement the client project.
Start a visual studio 2008 and add a new C# console project as shown in the figure below. The name of the project is “WCFClient1.” Just like the server part, add the reference to System.ServiceModel.dll. More info on accessing service through a client at Accessing Services Using a WCF Client msdn page.
5. Generate a client proxy.
The ServiceModel Metadata Utility Tool (Svcutil.exe) is needed to generate the proxy file for a client. The proxy file allows you to treat a remote service as a local service. You simply instantiate a remote object and call a function on it. This is much simple compared with some old distributed technologies.
Please refer to ServiceModel Metadata Utility Tool (Svcutil.exe) msdn page for the manaul of Svcutil.exe.
Please start the server first then type the following command in the command prompt.
“C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcUtil.exe” http://localhost:8000/Hello/
The URI is the URI that is defined in the App.config in the server part. After running the above command, you will get two files which are WorkService.cs and output.config.
Please rename the output.config to App.config. Copy those two files into your project directory, and add those files into your project.
Following is the code for the client:
////////////Program.cs in the client part/////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WCFClient1
{
class Program
{
static void Main(string[] args)
{
WorkClient wc = new WorkClient();
wc.submitWork(“hello work 1″);
}
}
}
Calling a server is very simple, instantiating the proxy object and calling a function on it. You can see that there is a class called WorkClient defined in the WorkService.cs. Please run the server first. If the queue has not been created, it will be created. When the queue is created, you don’t have to run the server before running the client. You can run the client first, and the message from the client will be stored in the queue. The message will be sent to the server when the server is started again.
You can take a look Tom Hollander’s blog for another good tutorial on this topic.
Here is the complete source code.
The book from [Lowy] is also good.
1 comment August 18, 2008
Article on WCF performance
Interesting article from Microsoft about comparing performances between WCF (Windows Communication Foundation) and existing .NET distributed technology.
Add comment August 15, 2008
Trying Adobe Express
It’s quite interesting that Adobe has created a web application for image editing called Adobe Express using Flash and Flex.
Microsoft has launched Silverlight.
I am wondering who will win between Flash/Flex and Silverlight.
Add comment March 29, 2008






















