August 2009 - Posts
Ik heb zojuist een nieuwe versie van .NET Events in Nederland beschikbaar gemaakt.
Nieuw is de mogelijkheid om de gegevens ook als iCalendar agenda binnen te halen in Microsoft Outlook of een andere agenda die met een iCalendar feed om kan gaan. Wel zo handig om te zien of er conflicten zijn met andere afspraken als je naar een bijeenkomst wil gaan.
Hoe het een en ander in 4 eenvoudige stappen in Outlook 2007 moet configureren staat hier.
En zoals altijd, weet je een bijeenkomst die voor .NET ontwikkelaars interessant is maar die nog niet op de lijst staat? Geef hem dan even door.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
In the previous two blog posts (here and here) I showed how to create and expose a Windows Workflow Foundation 4 workflow via WCF and have both a workflow and a regular C# client work with it. But the parameter and return value where real simple with just a string each. So how about passing some more complex data.
To show how to do so I will replace the singe string with a person object. Admittedly not the most complex person with only an id, first and last name and their birth date but enough to demonstrate the principal.
The main of the service, which uses a WorkflowServiceHost, stays exactly the same so see the first blog post for that part. The CreateWorkflow() function will change now reflecting the fact that the service will no longer expect a string but a person object.
private static WorkflowElement CreateWorkflow()
{
var result = new Sequence();
var input = new Variable<Person>();
result.Variables.Add(input);
XNamespace ns = "http://tempuri.org";
var handle = new Variable<CorrelationHandle>();
result.Variables.Add(handle);
var receive = new Receive()
{
OperationName = "Operation1",
ServiceContractName = ns + "MyService",
Value = new OutArgument<Person>(input),
AdditionalCorrelations = {
{"ChannelBasedCorrelation", new InArgument<CorrelationHandle>(handle)}
},
CanCreateInstance = true
};
result.Activities.Add(receive);
var write = new WriteLine()
{
Text = new InArgument<string>(env => string.Format("\tThe workflow was called with '{0}'.", input.Get(env)))
};
result.Activities.Add(write);
var reply = new SendReply()
{
Request = receive,
Value = new InArgument<string>("The result")
};
result.Activities.Add(reply);
return result;
}
Not a big change really as we only have to change the input variable from Variable<string> to Variable<Person> and do the same with the Value property of the Receive activity which goes from new OutArgument<string>(input) to new OutArgument<Person>(input).
That leaves the Person class and this is just straightforward WCF work by turning the basic class into a data contract.
[DataContract(Namespace = "urn:WF4Sample:person")]
public class Person
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public DateTime BirthDate { get; set; }
public override string ToString()
{
return string.Format("{0} {1} was born on {2} (ID: {3})", FirstName, LastName, BirthDate, Id);
}
}
Again no big deal 
So with the service done we need to make the same changes to the two client applications. First the workflow client using the Send activity.
The Person class is exactly the same as on the server so just copy the code as is. Again the main in the workflow client doesn’t change, see the first blog post for that part. The part that does change a little is the CreateWorkflow() function so it creates and sends a Person instead of a string. The code goes as follows:
private static WorkflowElement CreateWorkflow()
{
var result = new Sequence();
XNamespace ns = "http://tempuri.org";
var endpoint = new Endpoint()
{
Uri = new Uri("http://localhost:8090/Sequence1/Operation1"),
Binding = new BasicHttpBinding()
};
var response = new Variable<string>();
result.Variables.Add(response);
var handle = new Variable<CorrelationHandle>();
result.Variables.Add(handle);
var person = new Person()
{
Id = 7,
FirstName = "Maurice",
LastName = "de Beijer",
BirthDate = new DateTime(1962, 8, 24)
};
var request = new Send()
{
OperationName = "Operation1",
Endpoint = endpoint,
AdditionalCorrelations =
{
{"ChannelBasedCorrelation", new InArgument<CorrelationHandle>(handle)}
},
ServiceContractName = ns + "MyService",
Value = new InArgument<Person>(person)
};
result.Activities.Add(request);
var reply = new ReceiveReply()
{
Request = request,
Value = new OutArgument<string>(response)
};
result.Activities.Add(reply);
var write = new WriteLine()
{
Text = new InArgument<string>(response)
};
result.Activities.Add(write);
return result;
}
Again a very minor change.
So how about the C# console client from the second blog post?
The service contract changes a little and is now:
[ServiceContract]
interface MyService
{
[OperationContract]
Operation1Response Operation1(Person request);
}
The person class is very different from the service though and looks like this:
[MessageContract(WrapperNamespace = "urn:WF4Sample:person")]
internal class Person
{
[MessageBodyMember(Namespace = "urn:WF4Sample:person")]
public int Id { get; set; }
[MessageBodyMember(Namespace = "urn:WF4Sample:person")]
public string FirstName { get; set; }
[MessageBodyMember(Namespace = "urn:WF4Sample:person")]
public string LastName { get; set; }
[MessageBodyMember(Namespace = "urn:WF4Sample:person")]
public DateTime BirthDate { get; set; }
}
But besides the difference from using a message contract as opposed to a data contract this isn’t a big deal.
The main program changes a bit but not a whole lot. Again the only changes are due to the fact we are passing in a Person instead of a string.
static void Main(string[] args)
{
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://localhost:8090/Sequence1/Operation1");
var factory = new ChannelFactory<MyService>(binding, endpoint);
var proxy = factory.CreateChannel();
var request = new Person()
{
Id = 23,
FirstName = "Joe",
LastName = "Regular",
BirthDate = new DateTime(1975, 7, 1)
};
var result = proxy.Operation1(request);
Console.WriteLine(result.Value);
Console.WriteLine("Regular client is done.");
Console.ReadLine();
}
All together not bad.
But so far we have only used a very simple workflow with a single message send to it. Suppose you want to send multiple messages to the same workflow? Well in that case we need to use message correlation as we will see next time.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
In a previous blog post I described how to use the WorkflowServiceHost and host a workflow with a Receive activity that waits for WCF messages. I also added a WF4 client that called the service and received a response. However a lot of clients out there are not going to be workflows but “regular” code that calls into out workflow. So what does it take to have a simple console application talk to our WF4 service?
The first thing we need is an service contract describing the operation we can call. In our workflow the operation is named “Operation1” and our service contact name was “MyService” with the default namespace of “http://tempuri.org”. So our service contract looks like this:
[ServiceContract]
interface MyService
{
[OperationContract]
Operation1Response Operation1(Operation1Request request);
}
Next up are the request and response objects. In this case I am using just two strings so they are pretty simple as well.
[MessageContract(IsWrapped = false)]
public class Operation1Request
{
[MessageBodyMember(
Namespace = "http://schemas.microsoft.com/2003/10/Serialization/",
Name = "string")]
public string Value { get; set; }
}
[MessageContract(IsWrapped = false)]
public class Operation1Response
{
[MessageBodyMember(
Namespace = "http://schemas.microsoft.com/2003/10/Serialization/",
Name = "string")]
public string Value { get; set; }
}
The interesting to note here is that I have to use a MessageContact instead of a DataContract and I have to make sure the data isn’t wrapped in an extra element. Also interesting is the fact that the data is send across using the name “string”, not the easiest C# identifier to work with so I called them “Value” instead.
Using these WCF definitions creating a simple console app that calls the workflow is a breeze.
static void Main(string[] args)
{
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://localhost:8090/Sequence1/Operation1");
var factory = new ChannelFactory<MyService>(binding, endpoint);
var proxy = factory.CreateChannel();
var request = new Operation1Request()
{
Value = "Test from a console."
};
var result = proxy.Operation1(request);
Console.WriteLine(result.Value);
Console.WriteLine("Regular client is done.");
Console.ReadLine();
}
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Michael Kennedy, one of the co instructors from DevelopMentor, has created a combined feed from all the blogs of the various DevelopMentor. An awesome group of people with a lot of knowledge to share. Highly recommended in you RSS reader.
http://feeds.feedburner.com/DevelopmentorInstructors
If you want to check out a list of the individual blog feeds look here.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Recently I started using ASP.NET MVC for a real project. SO far I had been reluctant to use ASP.NET MVC as it meant giving up on the post back model that so many of the available ASP.NET controls depend on. Yet a lot of people I know and respect where saying good things about ASP.NET MVC so I decided to try it out on a small but real project.
Well the project isn’t finished yet but I am a convert 
Using ASP.NET MVC is much nicer that I expected it to be. Sure the post back model, and with it a lot of controls, are gone but I started doing more client side stuff using jQuery and the many plug-ins available. And even where not doing a lot of client side work ASP.NET MVC makes live quite easy.
The main difference is that ASP.NET MVC lends itself very well to test driven development. Now I not a pure TDD zealot but covering a lot of the code with unit test, regardless if you create the test first or later, is pretty much a requirement of a good software project. And ASP.NET MVC lend itself much better to unit testing than ASP.NET web forms.
ASP.NET MVC will not be the thing for everyone. If you are heavy into designers and drag-drop development web forms will be a better match for you. But if you are like me and like working with code ASP.NET MVC is a joy to work with.
The book I keep by my side is Steven Sanderson’s Pro ASP.NET MVC Framework. It has been very valuable, both on giving me a behind the scenes insight and solving some practical issues I ran into.
Recommended.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
I am working on a new ASP.NET MVC app and like so many other applications out there I need to log any errors should they occur. recently I heard about ELMAH Error Logging Modules and Handlers for ASP.NET through this blog post of Scott Hanselman. So as using en existing and proven solution is always better that reinventing the wheel I decided to try ELMAH and see how easy it is to get started.
Well I can only say I am positively amazed at how easy it is.
Starting from scratch it took me less that 2 hours to download and integrate it into my current ASP.NET MVC application and log all errors to SQL Server. That is including security so not everyone can check the error log.
There are lots of additional capabilities I haven’t looked at yet like setting up an RSS feed, emailing or even tweeting errors messages. But judging from the experience so far that should prove easy enough.
My only regret is that I didn’t check it out before.
Checkout the project run by Atif Aziz here.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
There are several ways you can go about it if you want to post a tweet when you can upload a photo to Flickr. The official Flickr way is add Twitter as a blog in your account “Extending Flickr” page and clicking “Blog this” on a new picture you want to tweet.
While this works perfectly well there is also an automatic way if using the Flickr REST API. One of the options is to generate an RSS feed. Using this and the free TwitterFeed service I can automatically tweet whenever I add a new image to Flickr.
The Flickr FSS feed looks like this: http://api.flickr.com/services/feeds/photos_public.gne?id=[[your flickr user id]]&format=rss_200.
Nice and simple. And there are additional option of the RSS feed to filter only images with a specific tag if you don’t want to auto twitter al your new images.
Enjoy!
There are several ways to use WCF in combination with Windows Workflow Foundation 4. The two can be combined inside of a XAMLX file as Ron Jacobs describes here.
Another option is using the WF4 Receive and SendReply activities and hosting the workflow yourself using a WorkflowServiceHost. This is quite a useful option but, at least at the moment, not quite straightforward. When I was trying to get things working using a declarative workflow and the designer Visual Studio 2010 would keep in locking up so all workflows in this example will be coded using C#. Not quite the way things are supposed to be done but it does give some useful insight.
Creating a workflow to handle requests
The basic activity we need on the service side is the Receive activity. This allows us to wait for incoming requests and process them, either by using a new workflow or an existing one. If we want to send a response we need to use a SendReply activity as well, if not we are creating a one way contract.
Note that there is not going to be a formal contract as we normally have in WCF. Instead we configure the Receive and SendReply and a contract is derived from that. Not quite sure if I like that as a service contract is supposed to be very much locked down.
The code for the service workflow looks like this:
private static WorkflowElement CreateWorkflow()
{
var result = new Sequence();
var input = new Variable<string>();
result.Variables.Add(input);
XNamespace ns = "http://tempuri.org";
var handle = new Variable<CorrelationHandle>();
result.Variables.Add(handle);
var receive = new Receive()
{
OperationName = "Operation1",
ServiceContractName = ns + "MyService",
Value = new OutArgument<string>(input),
AdditionalCorrelations = {
{"ChannelBasedCorrelation", new InArgument<CorrelationHandle>(handle)}
},
CanCreateInstance = true
};
result.Activities.Add(receive);
var write = new WriteLine()
{
Text = new InArgument<string>(env => string.Format("The workflow was called with '{0}'.", input.Get(env)))
};
result.Activities.Add(write);
var reply = new SendReply()
{
Request = receive,
Value = new InArgument<string>("The result")
};
result.Activities.Add(reply);
return result;
}
For the most part quite straightforward. We receive a message as defined by the Receive activity Value property, in this case just a string. The message is printed and we return another string through the Value property of the SendReply. Using C# code really shows where we need to use arguments and variables, something that is somewhat hidden when using XAML.
One thing I don’t like is having to create and add the CorrelationHandle. It might be needed internally but I don’t really want to be bothered. Setting the Request property on the SendReply to hook the two together should be enough. Lets hope this disappears before WF4 ships.
Hosting the service workflow
With the service workflow in place we need to create a WorkflowServiceHost and actually make the workflow available. The WorkflowServiceHost is configured using a Service definition which in turn contains a WorkflowServiceImplementation containing the actual workflow and a WCF endpoint. The hosting code looks like this:
XNamespace ns = "http://tempuri.org";
var service = new Service();
service.Implementation = new WorkflowServiceImplementation()
{
Name = ns + "MyService",
Body = CreateWorkflow()
};
service.Endpoints.Add(new Endpoint()
{
Uri = new Uri("Operation1", UriKind.Relative),
Binding = new BasicHttpBinding(),
ServiceContractName = ns + "MyService"
});
var host = new WorkflowServiceHost(
service,
new Uri("http://localhost:8090/Sequence1"));
host.Open();
Console.WriteLine("Press enter to stop");
Console.ReadLine();
host.Close();
The main point here is making sure the Name and ServiceContractName, both for the Endpoint and Receive, are configured correctly or the WorkflowServiceHost will not be able to start and you will get a System.InvalidOperationException with a message something like “Cannot add endpoint because ContractDescription with Name='MyService' and Namespace='http://tempuri.org' can not be found.”.
Creating a calling workflow
With the service side in place we now need to create a client workflow to call into our service. In this case the main activity to use is the Send which sends the request to the WCF service and the ReceiveReply which waits for the response to arrive. The whole is very similar to the service workflow and again we need to use the annoying CorrelationHandle. The workflow code looks like this:
private static WorkflowElement CreateWorkflow()
{
var result = new Sequence();
XNamespace ns = "http://tempuri.org";
var endpoint = new Endpoint()
{
Uri = new Uri("http://localhost:8090/Sequence1/Operation1"),
Binding = new BasicHttpBinding()
};
var response = new Variable<string>();
result.Variables.Add(response);
var handle = new Variable<CorrelationHandle>();
result.Variables.Add(handle);
var request = new Send()
{
OperationName = "Operation1",
Endpoint = endpoint,
AdditionalCorrelations =
{
{"ChannelBasedCorrelation", new InArgument<CorrelationHandle>(handle)}
},
ServiceContractName = ns + "MyService",
Value = new InArgument<string>("Test")
};
result.Activities.Add(request);
var reply = new ReceiveReply()
{
Request = request,
Value = new OutArgument<string>(response)
};
result.Activities.Add(reply);
var write = new WriteLine()
{
Text=new InArgument<string>(response)
};
result.Activities.Add(write);
return result;
}
Just like any other WCF service the main point is to make sure that the service contract names, namespaces and data types match or message will not be processed correctly (or at all). Running this workflow has no special hosting requirements so using the WorkflowInvoker will do just fine.
var workflow = CreateWorkflow();
WorkflowInvoker.Invoke(workflow);
Console.WriteLine("Client Done.");
Console.ReadLine();
Conclusion
Using WCF and WF4 together is not hard. Unfortunately the designer seems to be letting me down but fortunately everything we can do using the designer can also be done using code.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu