August 2008 - Posts
As far as I am concerned Silverlight 2 is pretty cool and should have been developed years ago
. Well guess that isn't the case but it is here now.
One thing I like about Silverlight is how easy it is to call a web service. I guess that is a must be because when developing a LOB application in Silverlight you are going to be calling your server to get and store data. So calling the back end is as easy as adding a new Silverlight-enabled WCF Service, implementing the ServiceContract and setting a service reference from your Silverlight project. Things will work immediately and you are all good to go.
Or maybe not 
Well your service will work just fine in your development machine, no problems there. But when you move your project to another machine thing might just stop working and you will see a ProtocolException with message "The remote server returned an unexpected response: (404) Not Found.".
So what gives?
Well the problem is that the WCF stores the absolute Uri for the WCF service in its configuration file, the ServiceReferences.ClientConfig. In this case the configuration looks like this:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_Service" maxBufferSize="65536"
maxReceivedMessageSize="65536">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:4370/SilverlightApplication3Web/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_Service"
contract="SilverlightApplication3.ServiceReference1.Service"
name="BasicHttpBinding_Service." />
</client>
</system.serviceModel>
</configuration>
The problem here is the endpoint address that points to localhost port 4370. So as this service is part of the same website using a relative Uri sounds like the reasonable thing to do. Unfortunately this doesn't work and results in an UriFormatException with message: "Invalid URI: The format of the URI could not be determined.". Not good. So this means we have to change the address for every local endpoint when we move the Silverlight application, and its WCF services, to a different location. Not good, specially when we could have a long list of services used
.
A partial solution
So fortunately there is a way around this as we can specify the service address when creating the WCF service proxy, all we need to do is insert the correct Uri based upon the location of the Silverlight application.
Normally the code I write looks something like this:
ServiceClient proxy = new ServiceClient();
proxy.DoWorkCompleted += proxy_DoWorkCompleted;
proxy.DoWorkAsync();
What I need to do is change this somewhat so that the ServiceClient is created through a factory method like this:
ServiceClient proxy = GetServiceClient();
proxy.DoWorkCompleted += proxy_DoWorkCompleted;
proxy.DoWorkAsync();
The interesting work occurs in the GetServiceClient() function:
private ServiceClient GetServiceClient()
{
Uri uri = new Uri(HtmlPage.Document.DocumentUri, "Service.svc");
EndpointAddress address = new EndpointAddress(uri);
return new ServiceClient("*", address);
}
First I determine where the Silverlight application was loaded from in the first place through the HtmlPage.Document.DocumentUri. Next I create a new Uri with the relative address where the service should be located. And finally I create and return the WCF proxy object. The first parameter, the "*" indicated that the WCF runtime should use a wildcard match and the first endpoint found with the same contract, which is the same as when no parameters are passed in.
A better solution
Of course the solution above works but requires extra coding and care with every service we create. And being easy to forget, specially when you just get started with Silverlight, is not exactly an ideal solution. So the proper solution is that the WCF stack inside of Silverlight should accept relative Uri and understand that this Uri is relative to the current page. Now this is not exactly rocket science and exactly what browsers have been doing for years. So lets hope the Silverlight team adds this feature before the RTM (which I hope is real soon).
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
In this post I demonstrated how to create IronPython objects and call them from strongly typed .NET code. So suppose we want to do so with Windows Workflow Foundation where could we use this?
Well the most obvious place would be a runtime service. The example below uses a very simple message that needs to be displayed but it is easy to see how to same concept could be applied in other places.
But first the basics. I have created a very simple custom DisplayMessageActivity like this:
public partial class DisplayMessageActivity : System.Workflow.ComponentModel.Activity
{
public DisplayMessageActivity()
{
}
public string Message { get; set; }
protected override ActivityExecutionStatus Execute(
ActivityExecutionContext executionContext)
{
IDisplayMessageService service = executionContext.GetService<IDisplayMessageService>();
service.Display(Message);
return base.Execute(executionContext);
}
}
Next I have created a very simple workflow with only the DisplayMessageActivity and set the Message property to: "This is the message to show.".
You might have noticed in the code above that I am looking for a service of type IDisplayMessageService. This is pretty simple as well and looks like this:
public interface IDisplayMessageService
{
void Display(string message);
}
In this case I am using an interface but you could just as well use a concrete baseclass with virtual methods.
For the actual implementation I created two classes in IronPython, the first displays the message on the console while the second uses a MessageBox to display the same message. The IronPython source looks like this:
import clr
clr.AddReference('PythonWorkflowConsoleApplication1')
from PythonWorkflowConsoleApplication1 import IDisplayMessageService
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import MessageBox
# Display all messages in the console window
class ConsoleDisplayMessageService(IDisplayMessageService):
def Display(self, message):
print message
# Display all messages using a Windows.Forms.MessageBox
class MessageBoxDisplayMessageService(IDisplayMessageService):
def Display(self, message):
MessageBox.Show(message, 'IronPython')
Like in the previous example I first import the clr so I can set references to additional assemblies. Next add a reference to the PythonWorkflowConsoleApplication1 assembly. This is my sample application that contains the runtime service interface definition. With this reference set I can import the IDisplayMessageService interface so I can derive from it.
I included two implementations, lets first look at the ConsoleDisplayMessageService as this is the simpler of the two. All this does is use the Python print function to display the message on the console. The first parameter, self, is the current object, so this in C# or me in VB. We make sure this class derives from IDisplayMessageService by specifying this after the class name. BTW the lines starting with # are comments in Python.
The second class is MessageBoxDisplayMessageService and this actually uses a MessageBox to display the message from the workflow. First we need to add a reference to the System.Windows.Forms assembly and once that is done we need to import the MessageBox type. Once this is done we can use it like this:
MessageBox.Show(message, 'IronPython')
Simple enough right.
So now for the trick part, adding the IronPython runtime service to the workflow runtime.
The console main function is as follows:
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AddMessageService(workflowRuntime, DisplayMode.Windows);
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
typeof(PythonWorkflowConsoleApplication1.Workflow1));
instance.Start();
Console.ReadLine();
}
}
With the AddMessageService() doing the actual work. Note the second parameter specifies which IronPython class to load.
So the AddMessageService looks like this:
static void AddMessageService(WorkflowRuntime workflowRuntime, DisplayMode mode)
{
string className;
if (mode == DisplayMode.Console)
className = "ConsoleDisplayMessageService";
else
className = "MessageBoxDisplayMessageService";
ScriptRuntime runtime = PythonEngine.CurrentEngine.Runtime;
ScriptScope scope = runtime.ExecuteFile("DisplayMessageService.py");
PythonType pythonType = scope.GetVariable<PythonType>(className);
object service = runtime.Operations.Call(pythonType);
workflowRuntime.AddService(service);
}
The basics are the same as in my previous IronPython post. Depending on the display mode I make a choice of class to load and I use the same code as previous time to create the object. Finally I add it to the WorkflowRuntime as a runtime service. This last bit is easy as this accepts every object type as a valid service and only when we call the GetService do we check the actual type.
I used IronPython 2.0 Beta 4 for this example. More info about IronPython can be found here, the download of version 2 here.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
.NET Reflector, by Lutz Roeder, must be one of the most useful tools I have when developing .NET code. Usually it is the first thing I install right after Visual Studio not even waiting until I need it because I know I will.
So the big news is that Red Gate, makers of the Ants profiler and lots of other tools, are taking over from Lutz Roeder and will continue developing .NET Reflector. Interesting move and I hope this means a bright future for the .NET Reflector.
Read more about this here.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
The following are two batch files I use a lot when working with WF persistence and or tracking as I find it desirable to clear the out often. Just drop them in the "C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN" directory with the four SQL scripts and recreating the required databases is just a few clicks away.
CreatePersistence.bat
osql -E -S .\sqlexpress -Q "Drop Database WorkflowPersistence"
osql -E -S .\sqlexpress -Q "Create Database WorkflowPersistence"
osql -E -S .\sqlexpress -d WorkflowPersistence -i SqlPersistenceService_Schema.sql
osql -E -S .\sqlexpress -d WorkflowPersistence -i SqlPersistenceService_Logic.sql
CreateTracking.bat
osql -E -S .\sqlexpress -Q "Drop Database WorkflowTracking"
osql -E -S .\sqlexpress -Q "Create Database WorkflowTracking"
osql -E -S .\sqlexpress -d WorkflowTracking -i Tracking_Schema.sql
osql -E -S .\sqlexpress -d WorkflowTracking -i Tracking_Logic.sql
Of course you could also use my SqlCeWFPersistence as the persistence service, download it from here. I never did create a TrackingService based upon SQL Compact but if enough people are interested I might just do so
Enjoy!
www.TheProblemSolver.nl
Wiki.windowsworkflowfoundation.eu
Want to know what is new in the .NET 3.5 SP1 framework or Visual Studio 2008 SP1? Then check out the presentations and labs here: http://www.microsoft.com/downloads/details.aspx?FamilyID=355C80E9-FDE0-4812-98B5-8A03F5874E96&displaylang=en
Overview
The .NET Framework 3.5 Enhancements Training Kit includes presentations, hands-on labs, demos, and event materials. This content is designed to help you learn how to utilize the .NET 3.5 Enhancement features including: ASP.NET MVC, ASP.NET Dynamic Data, ASP.NET AJAX History, ASP.NET Routing, ADO.NET Data Services, ADO.NET Entity Framework, WCF 3.5 SP1, and the .NET Framework Client Profile.
Now this is nowhere near complete but a good place to start.
Enjoy!
Having worked with Python in the past I find IronPython an interesting language to work with. However the story becomes really interesting if you can combine IronPython with regular strong typed code into one.
So I decided to take a look at what it would take to do so with the current IronPython version. I used IronPython 2 Beta 3, based upon the current version of the Dynamic Language Runtime, which is still evolving so the classes might have changed, take care! You can download the latest IronPython release here.
Lets take a look at what it takes to use an IronPython class from a Visual Basic Project.
The first thing we need is a base class we are actually going to derive from. This is because IronPython doesn't compile its code into a static type but VB requires its variables to be typed. This is the base class I am using:
Public Class HelloWorldVB
Public Overridable Function HelloWorld(ByVal name As String) As String
Return String.Format("Hello '{0}' from Visual Basic", name)
End Function
End Class
And a main module to start thing off:
Sub Main()
Dim helloWorld As New HelloWorldVB()
Console.WriteLine(helloWorld.HelloWorld("Maurice"))
Console.ReadLine()
End Sub
No big surprise here
.
So how do we derive an IronPython class from our VB type?
The following code is the IronPython code I added to the file HelloWorld.py.
import clr
clr.AddReference('IronPythonTest2')
from IronPythonTest2 import HelloWorldVB
class HelloWorldIronPython(HelloWorldVB):
def HelloWorld(self, name):
return "Hello '" + name + "' from IronPython"
Basically this code adds a reference to the IronPythonTest2 assembly, this is my console application containing the previous VB code. Next it imports the HelloWorldVB type from the assembly. Now it know about the type we can go ahead and derive from that type and create a new one. This exactly what the line class HelloWorldIronPython(HelloWorldVB) does, it creates a new type called HelloWorldIronPython. Next we override the HelloWorld function and return a different welcome string. A few things to note here: Python uses indentation to specify blocks, so the function being indented from the class is a part of that and the line of code with the return is indented from the def that defines the function so it is part of the function body. Another interesting thing is the self parameter. Every function in Python is passed a reference to itself as the first parameter. Sort of like the implicit Me in VB except a bit more obvious.
If you want to know more about IronPython I suggest you get the book IronPython in Action from Michael Foord.
To make sure the HelloWorld.py file is available to the console application I have set the Copy to Output Directory to Copy always.
OK so far so good. We have an IronPython class with the code we need. Now we still need to create an object from it. This isn't hard it just takes a bit more doing than just using the New operator.
Instantiating the IronPython object
The first step is adding the required references. We need to add the following assemblies:
- IronPython.dll
- IronPython.Modules.dll
- Microsoft.Scripting.dll
- Microsoft.Scripting.Core.dll
We will only be using the 1st and 3rd ourselves but the others are needed as well.
Once we have the references set we can add the required Imports:
Imports Microsoft.Scripting.Hosting
Imports IronPython.Hosting
Imports IronPython.Runtime.Types
And now we can get really going with the code 
We need to load the file with the Python source code using an IronPython ScriptRuntime. Once done we can get a reference to the IronPython type object using the GetVariable() function by passing in the class name. Once we have that we call the ScriptRuntime again to actually create the object. See the code below:
Dim runtime As ScriptRuntime = PythonEngine.CurrentEngine.Runtime
Dim scope As ScriptScope = runtime.ExecuteFile("HelloWorld.py")
Dim pythonType As PythonType = scope.GetVariable(Of PythonType)("HelloWorldIronPython")
helloWorld = CType(runtime.Operations.Call(pythonType), HelloWorldVB)
Console.WriteLine(helloWorld.HelloWorld("Maurice"))
And with this code we are good to go. Running the complete code will show the output below:
The complete code in the main module:
Option Explicit On
Option Strict On
Imports Microsoft.Scripting.Hosting
Imports IronPython.Hosting
Imports IronPython.Runtime.Types
Module Module1
Sub Main()
Dim helloWorld As New HelloWorldVB()
Console.WriteLine(helloWorld.HelloWorld("Maurice"))
Dim runtime As ScriptRuntime = PythonEngine.CurrentEngine.Runtime
Dim scope As ScriptScope = runtime.ExecuteFile("HelloWorld.py")
Dim pythonType As PythonType = scope.GetVariable(Of PythonType)("HelloWorldIronPython")
helloWorld = CType(runtime.Operations.Call(pythonType), HelloWorldVB)
Console.WriteLine(helloWorld.HelloWorld("Maurice"))
Console.ReadLine()
End Sub
End Module
Enjoy!
Windows Workflow Foundation, WF for short, is one of the technologies I work a lot with and as a consequence I own several books about WF. Comparing this book with the others I can only say it is one of the best books you can get on the subject. It has a good coverage of almost all the subject you are going to need to know. Not only is there a good coverage but the explanation and examples are very clear. Now there are a few thing missing from the book. As it was written with the .NET framework 3.0 there is no coverage of the WCF integration that comes in the form of the SendActivity and the ReceiveActivity. While this is unfortunate it is also understandable and I can only hope that the author has the time to update the book with one more chapter.
For a book this size, about 700 pages, I was amazed at how little I could find that I didn't like. In fact one of few errors I could find is the statement that only a single instance of the WorkflowRuntime can be created per AppDomain. This is a myth that stems back to the first beta's where it was briefly the case but the restriction has been lifted long ago and has never been part of the released product. But given the size of the book and how few people ever need to create multiple WorkflowRuntime objects it is hardly a big objection.
So my advise: If you are getting into Windows Workflow Foundation make sure you buy this book!
Enjoy.
Part 1part 2Part 3Part 4 In two previous blog posts, part one and part two, I covered the fact that the ReceiveActivity and the TransactionScopeActivity don't work together very well. I demonstrated this using a sequential workflow and did show a, clumsy and hacky, workaround to get at least the initial request working. So while the request that starts the sequential workflow could work the same is not true for any subsequent calls.
But what about a state workflow?
State workflow's are very different then sequential workflow's because they are completely event driven. With every state you need to add an EventDrivenActivity and the first child should implement the IEventActivity interface. Well the ReceiveActivity does just that so we can use it to initiate a state machine workflow and triggers its events. However as you might expect a TransactionScopeActivity is not an IEventActivity so it cannot be the first child of the EventDrivenActivity. And that means you cannot wrap the ReceiveActivity inside of an TransactionScopeActivity, something that sort of solved the problem with a sequential workflow. Of course nesting the TransactionScopeActivity inside of the ReceiveActivity won't work either for the reasons described in the first two post. So far so bad 
So we need another workaround
Again there is no real good workaround
. In fact the only one I can come up with is stop using the TransactionScopeActivity all together. So how to do transactions without using the TransactionScopeActivity?
Well the solution, ahem workaround, is to use the WorkflowEnvironment.WorkBatch object and add all pending work to it. The first parameter is an object of type IPendingWork and this is the one that is actually going to be called to do the work. The second parameter, the workItem, contains the data. Now when a workflow per persistence point is reached the IPendingWork object is called to do its work.
[Serializable()]
class Workflow1PendingWork : IPendingWork
{
#region IPendingWork Members
public void Commit(Transaction transaction, ICollection items)
{
foreach (var Workflow1PendingWork in items)
{
using (TransactionScope tx = new TransactionScope(transaction))
{
// Do my own transaction work
tx.Complete();
}
}
}
public void Complete(bool succeeded, ICollection items)
{
}
public bool MustCommit(ICollection items)
{
/// We want to commit!
return true;
}
#endregion
}
The MustCommit function is called to check if the Commit needs to be called. The Commit itself is called as part of the workflow persistence point. Now you can use something like a CodeActivity and add your workItem to the batch like this:
WorkflowEnvironment.WorkBatch.Add(_pendingWork, myTransactionData);
When do we reach a persistence point?
This leaves us with the question of when these persistence point occur. The best way to think if these is when a workflow reaches a state that is final, no matter what happens. This includes the point where a workflow is done and when it is persisted to the persistence store. Using the SqlWorkflowPersistenceService with the PersistOnIdle option set to true will mean this will happen as soon as the event handler is done executing and the workflow is idle. However sometimes that just isn't good enough and you need to do so sooner. Well the easiest way is to create a custom activity, I call it the PersistStateActivity, and decorate it with the PersistOnClose attribute. No need to add any code, all we are interested in is the attribute.
[PersistOnClose()]
public partial class PersistStateActivity : Activity
{
public PersistStateActivity()
{
}
}
Now drop the activity at any point where you want your transactional data to be committed and the workflow runtime will take care of things for you 
Conclusion
Although these workarounds are possible they are all but intuitive and it took quite a bit of digging around and brainstorming with some people to get this to work. So be very careful when using the TransactionScopeActivity, or any form of transactions for that matter, and the WCF ReceiveActivity!
Enjoy!
It is available from the subscriptions download at http://msdn.microsoft.com/en-us/subscriptions/default.aspx
Get it while it is hot 
Enjoy!
Part 1part 2Part 3Part 4 In a previous blog post I write about what happens when you place a TransactionScopeActivity within a ReceiveActivity and an exception occurs that is supposed to roll back the transaction. In short the story was very bad and we could come up with only a partial workaround, not a pretty sight.
But there is more to it than just that little horror story. Suppose you do the obvious and place the a TransactionScopeActivity within a ReceiveActivity and no exception occurs. Say like the workflow below, please note that the codeActivity1 only sets the return value and causes no error.
Now the transaction is committed and the WCF call returns perfectly normally so everything is good right. Well not quite
The obvious first point is that the TransactionScopeActivity serves no real purpose. After all if it isn't allowed to fail under any circumstances why bother with it in the first place. Well ok there is the point of doing several updates as a single transaction so other users cannot see a partially committed order but that is about it.
But that is actually the least of my worries as there is a far bigger issue to worry about and that is called workflow persistence.
Yes that is right. After all when we are using a TransactionScopeActivity workflow persistence is mandatory. The TransactionScopeActivity is decorated with the PersistOnClose attribute so the state of the workflow will be persisted as soon as the transaction is complete. And normally that is a good thing but in this case it is the cause of the second problem because this is still inside the ReceiveActivity. So basically we are storing the workflow state as it is just before returning an answer to the client. Now if everything is running fine that won't matter because the workflow will continue until it is finished and everyone is happy. But suppose the workflow host terminates before the workflow is finished? In this test I added the DelayActivity, and set UnloadOnIdle to false so it doesn't persist the state, giving me the opportunity to kill the workflow runtime. Now if I restart the runtime It is going to reload the last state of the workflow and continue from there. And guess what it's going to do first? You guessed it: it is going to send the response to the client for a second time. Of course the client is no longer around and that action fails with an InvalidOperationException with message "Workflow unloaded between request & response."
I guess the message is not entirely correct as it should say "Workflow reloaded between request & response." but it's close enough.
The bottom line is the workflow terminates unless you specifically allow for this to happen and catch the error.
So basically we have a choice between putting the TransactionScopeActivity inside a ReceiveActivity, not being able to throw an error and having a restore problem, or putting the TransactionScopeActivity around the ReceiveActivity, something that only works with a sequential workflow and an initiating ReceiveActivity as I described in the previous post.
I guess these options make me pretty unhappy
.
Enjoy your workflow transactions!
Steve Lasker just announced that SQL Server Compact 3.5 service pack 1 is released, read his announcement here.
They added support for the entity framework, great stuff. And another neat feature is native 64 bits support. No longer do you need to target X86 and use WoW [:0]. Great if you are using my SQL Server Compact Workflow Persistence Service.
Enjoy!
Part 1
part 2
Part 3
Part 4
I got an email from a friend last week asking about using a ReceiveActivity and, while receiving, using a TransactionScopeActivity to transitionally save some data in a database. Seems like a common enough scenario right? Well he was having some problems. If everything worked and the transaction succeeded everything was fine and the answer came back. But if an exception occurred and the transaction was aborted be was receiving a real weird error:
System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: Workflow service unexpectedly unloaded from memory while executing a ReceiveActivity. Make sure that the the workflow does not contain any blocking activities within a ReceiveActivity. (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
System.InvalidOperationException: Workflow service unexpectedly unloaded from memory while executing a ReceiveActivity. Make sure that the the workflow does not contain any blocking activities within a ReceiveActivity.).
If we where to believe the message there was a blocking call, something there most certainly was not!
And to make things more confusing, if we removed the TransactionScopeActivity and just let the exception occur it would bubble back to the client just as it was supposed to. So what gives?
Well a lot of people looked at this and in the end we declared this a pretty bad bug. Mind you our words not those from Microsoft. But we did find a workaround. So lets take a look at a repro and how to fix this. My original test workflow looked like this:
I receive a WCF request, start a transaction, determine the return value in a code activity, throw an exception and return. Seems reasonable right? Well I thought so but it produces the error claiming there is a blocking statement. While tracking this Marvin actually noticed that the workflow idle event was raised! Excuse me, a workflow is becoming idle to undo a transaction sounds kind of wrong. And of course when a TransactionScopeActivity is used in a regular workflow, ie non WCF call, there is no Idle event.
A partial solution
So the way to get this to work is create the following workflow:
So instead of creating a TransactionScopeActivity inside of my ReceiveActivity I am doing it the other way round. Sounds kind of weird right? Well I think so but it does do the right thing as it returns the correct fault information to the client and then undoes any transactional work done.
So why does this workaround work in this case?
The ReceiveActivity has its CanCreateInstance property set to true so this is the request that actually creates and starts the workflow. This means that the workflow is created and starts executing from the top. Yes that is right, it starts from the top, not from the ReceiveActivity so any activities before that are also executed. I suppose that potentially opens a can of worms but we will leave that be for the moment. In this case the WCF request is received, this starts the workflow, this in turn starts the transaction, the message is received and processed and the transaction either commits or, like in this case, rolls back.
How about a non creating ReceiveActivity?
Well I am afraid no luck there as this workaround isn't going to work then. The problem is that we start a transaction before we start waiting for the additional WCF calls and the TransactionScopeActivity has a a TimoutDuration. So in all likelihood the transaction timeout will occur before the message is received and this effectively cancels the ReceiveActivity meaning it cannot receive the message.
I think this is a pretty major problem with the way WF and WCF work together. After all transactions a an essential piece of business applications and not being able to use them inside of a WCF request is a deadly sin.
Enjoy with care 
Afgelopen jaar hebben we het eerste CodeCamp in Nederland georganiseerd en dat was een groot succes. De meeste deelnemers vroegen om meer, sommige zelfs om een CodeCamp per kwartaal of een heel weekend lang. Nou hebben we dat laatste nog niet gedaan maar we zijn wel aan de slag gegaan om een nieuw CodeCamp te organiseren. Als datum hebben we zaterdag 6 september gekozen. Gelukkig waren Microsoft en Class-a behulpzaam en kunnen we, net als vorig jaar, weer in het Microsoft Innovation Center in Barneveld terecht. Een mooie datum en locatie om uitgerust van de vakantie een hoop kennis uit te wisselen.
Het programma staat nog niet helemaal vast, hou daar de website voor in de gaten, maar je kan er ondermeer de bekende Nederlandse sprekers verwachten. Uiteraard kan je zelf ook nog een sessie voorstellen dus als je een idee hebt voor een leuke sessie laat het dan zo snel mogelijk weten.
Dus zet de datum vast in je agenda en meld je zo snel mogelijk aan op de website www.code-camp.nl.
Het CodeCamp is een gezamenlijk initiatief van de SDN, de stichting DotNed en VB Central.