The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

January 2007 - Posts

Marcel de Vries is doing some interesting work creating WF input and output activities using WCF instead of plain web services. If you want to take a look a the code you can find it at CodePlex, to be exact at http://www.codeplex.com/WCFWorkflow.
 
See his blog here and here for more details about the project.
 
Enjoy!
 
Posted by Maurice | 1 comment(s)
Filed under: , ,
If you typing is anything like mine (that means terrible) that IntelliSense is a true blessing. And if you want IntelliSense when typing SQL code you really should check out Red-Gate SQL Prompt.
 
SQL Prompt
 
 
Enjoy!
 
Posted by Maurice | with no comments
Filed under: ,

Well it has had a lot of coverage already but now the final release has just been posted up on the web Smile

Read the latest news at Scotts blog at  http://weblogs.asp.net/scottgu/archive/2007/01/23/asp-net-ajax-1-0-released.aspx

Enjoy!

 

Posted by Maurice | 1 comment(s)
Filed under: ,
The Patterns and Practices group have just finished and shipped the Web Client Software Factory. If you haven't looked into software factories before this is a great place to get started, and even if you don't use it in your daily work just studying it will be a great experience.
 
This software factory make good use of several design pattern. Among the more interesting to be aware of are the View-Presenter and the Service Locator. If nothing else learning these will improve your software design skills Smile
 
And they have incorporated Windows Workflow Foundation as a possible engine for page navigation. Just take a  look at the PageFlow or the PageFlowWithShoppingCart samples to see how it is done.
 
One negative note though, this Software Factory only generates C# Sad
 
 
Enjoy!
 
Posted by Maurice | with no comments
Filed under: , , ,
If you are using a WCF client make sure you either Close() or Dispose() the client when you are done. I failed to do so and got bitten by a big memory leak Sad I was using a NetMsmqBinding and forgot to close the client when done. By itself the code worked just fine, no leaks or nothing. But then the same piece of code got called from inside another NetMsmqBinding server during the reception of a message and it generated a memory leak big time. Of course I should have Disposed() the client but the IDispose implementation is private so without casting it doesn't show up making it easy to forget, the Close() was public so no excuses there Smile. The best solution is to use the Using keyword (using in C#) and it will make sure Dispose() is called if it exists.
 
Another thing that would have saved the day was if the ClientBase(Of TChannel As Class) implemented the IDisposable design pattern instead of just implementing the IDisposable interface. Using the design pattern ensures that the resources are disposed regardless of Dispose() being called. See http://msdn2.microsoft.com/en-us/library/fs2xkftw.aspx for more information about the IDisposable design pattern.
 
Enjoy!
 
Posted by Maurice | 1 comment(s)
Filed under: , , ,
Is your solution plagued by a large number of assemblies that need to be loaded? Well ILMerge will merge them together into one single assembly. A single assembly is so much easier to distribute after all Smile
 
Download it here. Or read more about it over here.
 
One interesting thing is that the readme says "It does not yet support Rotor or Mono". Now how often does Microsoft use the not yet in combination with Mono? Interesting thought!
 
Enjoy!
 
Posted by Maurice | 5 comment(s)
I am probably the last person to discover this but only today I discovered the Stopwatch type in the System.Diagnostics namespace. Real nice when you want to determine how long a certain action took Smile
 
Stopwatch timer = Stopwatch.StartNew();
timer.Start();
// Do some stuff you want to time.
timer.Stop();
Console.WriteLine(timer.Elapsed.ToString());
 
Use the Stopwatch.IsHighResolution to check if the timer is using high resolution of not.
 
Enjoy!
 
Posted by Maurice | 2 comment(s)
Filed under:
It has taken a while but it's finally there. And that would be SQL Server Compact Edition, the great little in process database. Great is you need a small database in lots of applications, not just offline smart client/ Admittedly that is one of the places where it shines Smile
 
Download it form here.
 
Enjoy!
Posted by Maurice | 2 comment(s)
Filed under: ,
If you want Google to index your web site properly having a sitemap is a big bonus. Unfortunately a Google Sitemap is not the same thing as a ASP.NET sitemap. And that is a bit of a shame because you are quite likely to have the latter around. Well both are XML based files so converting from one to the other can’t be all that hard right? Right! and best of all you don’t even need to do it yourself because Bertrand Le Roy has already done it for us. See http://weblogs.asp.net/bleroy/archive/2005/12/02/432188.aspx for his blog post about it or download it from GotDotNet at http://www.gotdotnet.com/codegallery/codegallery.aspx?id=237330e0-65c5-4ebb-b62b-e486dd598604.
 
Note, all you need to do is upload the GSitemap.ashx file to your website and it will read the existing Web.sitemap just fine. All you need to do next is submit it to Google Webmaster Central at http://www.google.com/webmasters/
 
Enjoy!
 
 
Posted by Maurice | with no comments
Filed under:
Turns out I forgot to include one of the utility functions use in my previous two blog posts at and at. The code is the GetAllActivities() function in the WorkflowUtils class.
 
This is the missing method:
 
PublicSharedFunction GetAllActivities(ByVal root As Activity) As List(Of Activity)
    Dim result AsNew List(Of Activity)
    Dim i AsInteger = 0
    Dim current As Activity
    result.Add(root)
 
    While i < result.Count
        current = result(i)
        Dim ca As CompositeActivity = TryCast(current, CompositeActivity)
 
        If ca IsNotNothingThen
            result.AddRange(ca.Activities)
        EndIf
        i += 1
    EndWhile
 
    Return result
EndFunction
 
Another thing I failed to mention and got a few questions about is how the code finds the workflow type. The serialized type is contained in the SqlTrackingWorkflowInstance, or to be more specific in the WorkflowDefinition property. This is deserialized and during the process the related assemblies will be loaded. This means these assemblies, and the correct version if they are signed, must reachable by the process. Basically this means either deploying them to the GAC or copying them to the same directory or one of the directories mentioned in the private probing path. For my example I just copied the workflow assembly to the same directory as the assembly generating the image. Nice and quick for a demo but in a real live environment not quite good enough as, in all likelihood, you will contend with multiple versions of a workflow.
 
Enjoy!
 
 
Posted by Maurice | 1 comment(s)
Filed under: , , ,
Yesterday I showed in my previous blog post the minimal code required to create an image from a workflow definition. As I mentioned the most interesting reason for doing so is showing the status of an executing workflow in a sort of monitoring web site. So the next step is to add the ExecutionStatus of each activity to the image. The following image is an example of the result.
 
 
This can be done using an IDesignerGlyphProvider in the WorkflowView type. The WorkflowView is already equipped with a IDesignerGlyphProviderService service to with we need to add our IDesignerGlyphProvider implementations. As we need to use the protected GetService to get a reference to the IDesignerGlyphProviderService we need to create a subclass of WorkflowView and add some code.
 
Imports System.Workflow.ComponentModel.Design
 
Class GlyphProvidedWorkflowView
    Inherits WorkflowView
 
    SubNew(ByVal serviceProvider As IServiceProvider)
        MyBase.New(serviceProvider)
    EndSub
 
    PublicSub AddGlyphProvider(ByVal provider As IDesignerGlyphProvider)
        Dim service As IDesignerGlyphProviderService
        service = GetService(GetType(IDesignerGlyphProviderService))
        service.AddGlyphProvider(provider)
    EndSub
EndClass
 
The next step is to create the IDesignerGlyphProvider implementation itself. Again no big deal. In this example I decided to use the Workflow SqlTrackingQuery to retrieve an actual SqlTrackingWorkflowInstanceinstead instead of a dummy workflow created on the spot. Using this SqlTrackingWorkflowInstance gives me the history of the activity events to display. After all that is wat we want in a monitoring web site. The class I created is DesignerGlyphProvider and it contains a function to add the activity event and the GetGlyphs as gefined by the IDesignerGlyphProvider interface. Again the code is no big deal Smile
 
Imports System.Workflow.ComponentModel.Design
Imports System.Workflow.Runtime.Tracking
Imports System.Workflow.ComponentModel
 
PublicClass DesignerGlyphProvider
    Implements IDesignerGlyphProvider
 
    Private _activityExecutionStatus AsNew Dictionary(OfString, ActivityExecutionStatus)
 
    PublicFunction GetGlyphs(ByVal activityDesigner As ActivityDesigner) As ActivityDesignerGlyphCollection Implements IDesignerGlyphProvider.GetGlyphs
        Dim result AsNew ActivityDesignerGlyphCollection()
        SyncLock _activityExecutionStatus
            If _activityExecutionStatus.ContainsKey(activityDesigner.Activity.QualifiedName) Then
                Dim status As ActivityExecutionStatus = _activityExecutionStatus(activityDesigner.Activity.QualifiedName)
                SelectCase status
                    Case ActivityExecutionStatus.Executing
                        result.Add(New ExecutingStatusGlyph())
                    Case ActivityExecutionStatus.Closed
                        result.Add(New ClosedStatusGlyph())
                    Case ActivityExecutionStatus.Faulting
                        result.Add(New FaultingStatusGlyph())
                    Case ActivityExecutionStatus.Canceling
                        result.Add(New CancelingStatusGlyph())
                EndSelect
 
            EndIf
        EndSyncLock
        Return result
    EndFunction
 
    PublicSub AddActivityEvents(ByVal trackingRecords As IList(Of ActivityTrackingRecord))
        SyncLock _activityExecutionStatus
            _activityExecutionStatus.Clear()
 
            ForEach record As ActivityTrackingRecord In trackingRecords
                If _activityExecutionStatus.ContainsKey(record.QualifiedName) Then
                    _activityExecutionStatus(record.QualifiedName) = record.ExecutionStatus
                Else
                    _activityExecutionStatus.Add(record.QualifiedName, record.ExecutionStatus)
                EndIf
            Next
        EndSyncLock
    EndSub
EndClass
 
Of course we need the glyphs to draw on the design surface. I kept things really simple and just used the Winding font to write an appropriate character for each status.
 
Imports System.Drawing
Imports System.Workflow.ComponentModel.Design
 
PublicClass StatusDesignerGlyph
    Inherits DesignerGlyph
 
    Protected _text AsString = ""
    Protected _brush As Brush = Brushes.Black
 
    ProtectedOverridesSub OnPaint(ByVal graphics As Graphics, ByVal activated AsBoolean, ByVal ambientTheme As AmbientTheme, ByVal designer As ActivityDesigner)
        Using font AsNew Font("Wingdings", 12)
            graphics.DrawString(_text, font, _brush, designer.Bounds)
        EndUsing
    EndSub
EndClass
 
 
PublicClass ClosedStatusGlyph
    Inherits StatusDesignerGlyph
 
    SubNew()
        _text = "J"
        _brush = Brushes.Green
    EndSub
EndClass
 
PublicClass ExecutingStatusGlyph
    Inherits StatusDesignerGlyph
 
    SubNew()
        _text = "F"
    EndSub
EndClass
 
 
PublicClass FaultingStatusGlyph
    Inherits StatusDesignerGlyph
 
    SubNew()
        _text = "N"
        _brush = Brushes.Red
    EndSub
EndClass
 
 
PublicClass CancelingStatusGlyph
    Inherits StatusDesignerGlyph
 
    SubNew()
        _text = "I"
        _brush = Brushes.Red
    EndSub
EndClass
 
That only leaves us with the main function that was slightly updated from yesterday. Of course I added the SqlTrackingQuery to load an actual SqlTrackingWorkflowInstance object. Next I changed the standard WorkflowView used to the custom GlyphProvidedWorkflowView type. The final addition is adding the DesignerGlyphProvider to the GlyphProvidedWorkflowView.
 
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing.Imaging
Imports System.Workflow.Activities
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Design
Imports System.Workflow.Runtime.Tracking
 
Module Module1
    Sub Main()
        Dim query AsNew SqlTrackingQuery("Data Source=.\sqlexpress;Initial Catalog=WF_Tracking;Integrated Security=True")
        Dim options AsNew SqlTrackingQueryOptions
        Dim instances As IList(Of SqlTrackingWorkflowInstance) = query.GetWorkflows(options)
        Dim instance As SqlTrackingWorkflowInstance = instances(instances.Count - 1)
        Dim workflow As Activity = instance.WorkflowDefinition
 
        Dim loader AsNew WorkflowLoader(workflow)
        Dim surface AsNew DesignSurface
        surface.BeginLoad(loader)
        Dim view AsNew GlyphProvidedWorkflowView(CType(surface, IServiceProvider))
 
        Dim glyphProvider AsNew DesignerGlyphProvider()
        glyphProvider.AddActivityEvents(instance.ActivityEvents)
        view.AddGlyphProvider(glyphProvider)
 
        view.SaveWorkflowImage("workflow.png", ImageFormat.Png)
 
        Process.Start("workflow.png")
    EndSub
EndModule
 
Enjoy!
 
Update: Continued here.
Posted by Maurice | 11 comment(s)
Filed under: , , ,
I have been experimenting a bit with hosting the workflow designer. Unfortunately the sample provided, while it works is kind of hard to get started with if you are not already familiar with the way designers work in Visual Studio. So I decided to create the minimal code to create an image of a workflow, something quite useful if you are going to with an ASP.NET site to monitor you workflows. One caveat to be aware of is that the code needs to run under a thread with an STA ApartmentState. If not you will receive errors messages that the DragDrop registration did not succeed while creating the WorkflowView.
 
The code is pretty simple. Basically it uses a standard System.ComponentModel.Design.DesignSurface and System.Workflow.ComponentModel.Design.WorkflowView type to work with the workflow. To load the workflow a custom WorkflowDesignerLoader subclass is required to do the actual loading. No big deal. If you are using a State Workflow you need to override the OnEndLoad function to load the .layout file and use the LoadDesignerLayout function to add it to the image generated.
 
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing.Imaging
Imports System.Workflow.Activities
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Design
 
Module Module1
    Sub Main()
        Dim workflow AsNew SequentialWorkflowActivity
        workflow.Activities.Add(New DelayActivity())
 
        Dim loader AsNew WorkflowLoader(workflow)
        Dim surface AsNew DesignSurface
        surface.BeginLoad(loader)
        Dim view AsNew WorkflowView(CType(surface, IServiceProvider))
        view.SaveWorkflowImage("workflow.png", ImageFormat.Png)
 
        Process.Start("workflow.png")
    EndSub
EndModule
 
 
PublicClass WorkflowLoader
    Inherits WorkflowDesignerLoader
 
    Private _workflowDefinition As Activity
 
    SubNew(ByVal workflowDefinition As Activity)
        _workflowDefinition = workflowDefinition
    EndSub
 
    ProtectedOverridesSub PerformLoad(ByVal serializationManager As IDesignerSerializationManager)
        MyBase.PerformLoad(serializationManager)
 
        Dim designerHost As IDesignerHost = Me.GetService(GetType(IDesignerHost))
        Dim allActivities As List(Of Activity) = WorkflowUtils.GetAllActivities(_workflowDefinition)
 
        ForEach item As Activity In allActivities
            designerHost.Container.Add(item, item.QualifiedName)
        Next
    EndSub
 
    PublicOverridesReadOnlyProperty FileName() AsString
        Get
            Return""
        EndGet
    EndProperty
 
    PublicOverridesFunction GetFileReader(ByVal filePath AsString) As System.IO.TextReader
        ThrowNew NotSupportedException()
    EndFunction
 
    PublicOverridesFunction GetFileWriter(ByVal filePath AsString) As System.IO.TextWriter
        ThrowNew NotSupportedException()
    EndFunction
EndClass
 
Enjoy!
 
Update: Continued here.
 
Posted by Maurice | 10 comment(s)
Filed under: , , ,
If you are interested in the future of VB, or .NET in general because this is equally true for C#, you might want to read the blog post by Scott Wisniewski. In this blog post he describes how extension methods will work in VB 9 and what the benefit for the average developer will be. Of course extension methods are also a big part of LINQ so if you want to understand how LINQ works you need to understand extension methods too.
 
Its and interesting blog post you can find here.
 
Enjoy!
 
Posted by Maurice | with no comments
Filed under: , ,
I was tagged by Alex Thissen so I guess its my turn to tell 5 things you may not know about me.
 
  1. I never used computers much back in high school or in university. In fact I trained as an officer in the merchant navy and spend 5 years at sea. Most of this was spend working supply/anchor handing tugs for the offshore and oil industry. Had a great with lots of horror stories but its not the kind of job to do until you retire.
  2. I really love troubleshooting issues. I see it as a challenge to figure out what is going on deep down under the hood and getting stuff to work. And not just software. The only problem is that it sometimes takes a lot of time. This is also the reason for my company name ABL - The Problem Solver.
  3. ABL used to stand for Automatiserings Bureau Leiden. A real lame name I left behind when I moved out of Leiden. Just kept the initials for no good reason.
  4. I like doing extreme things. So I went skydiving, scuba diving, drive a motor bike (well used to, it hasn't moved much last year) and go paragliding. I crashed my paraglider last year breaking a vertebrae so I guess I will be taking it easy for some time to come :-(
  5. I love to travel and meat people. Amongst my favorite places to go are Cuba and Syria. Both leave a bit to be desired on the political front but the people are real hospitable. Some years ago I bought a single way ticket to the Middle East and just went backpacking for over a month and when the time was up got myself a ticket back home. Turns out I was in Jordan :-)
 
Guess its my turn to tag some other people. They are Yag, Jackie Goldstein, Matt Winkler, Arie Leeuwesteijn and Miguel de Icaza.
 
Posted by Maurice | 1 comment(s)
If you are using the VBC command line compiler for visual basic, for example when building ASP.NET web sites, you may want to download this hotfix.
 
 
Enjoy!
 
Posted by Maurice | 1 comment(s)
Filed under:
One thing I really dislike is instable development tools Sad. Now I do quite a bit of work with beta software and in that case it is to be expected. However when using production software it should just work and not throw random errors around. Not only does it mean I am not nearly as productive as I should be but if it happens to often I might just stop using a perfectly good piece of technology because the lack of good tooling.

One place I have been receiving a fair number of errors inside of Visual Studio 2005 is Windows Workflow Foundation. Now most errors seem to occur when working in Visual Basic Sad, switching to C# seems to produce better results.

However one error that crops up both in VB and C# is “Error HRESULT E_FAIL has been returned from a call to a COM component” while trying to open a Expression condition in a state workflow. This error seems to appear pretty randomly and most of the time just closing all windows and reopening the workflow is enough to solve it and continue work. There are times when that isn’t enough though and I need to restart VS.

Now the problem is I cannot reproduce this error on demand and to report it I really need to. So if you have any clue to the cause please let me know so we can report this as a bug and with any luck get it fixed.
 
 
Maurice de Beijer

Posted by Maurice | with no comments
Filed under: , ,
This is my first blog post in 2007 so lets start by wishing everyone a good a prosperous 2007 Smile
 
This Dutch language screen cast shows how to get started using Windows Workflow Foundation. In this first screen cast I cover starting a workflow, adding parameters and returning the result.
 
 
Enjoy!
 
Posted by Maurice | 5 comment(s)
Filed under: , , , ,