April 2008 - Posts

A few days ago I blogged about the "Publish as Web Service" feature not working for me with VS2008. It turns out this is another case if Vista and VS2008 not being quite compatible Sad.

I was running VS2008 normally and I have User Account Control (UAC) enabled. Not that I am a big fan of UAC but I believe it is a useful step along the security road and people should leave it turned on. And I do as I preach.

But if you start VS2008 with administrator privileges, ie right click and select "Run as administrator", the "Publish as Web Service" feature works just fine.

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

I am unsure if this is a problem with my PC but when I am building a workflow using the WebServiceInputActivity and choose "Publish as Web Service" from the context menu I get a real helpfull error message Sad

image

No other messages appear so that is less that helpfull.

Fortunatly it isn't all that had to publish the workflow manually. Just add a web service project to the solution and add an ASMX file with the following content:

<%@ WebService Class="WebServiceInput.Workflow1_WebService" %>

The workflow class is named "WebServiceInput.Workflow1" and just add the "_WebService" suffix to it. Next add a reference from the web service project to the assembly containing the workflow.

Don't forget to also add refrences to the System.Workflow.Activities, System.Workflow.ComponentModel and System.Workflow.Runtime assemblies used at runtime.

Next create a WorkflowRuntime config section like so:

        <section name="WorkflowRuntime" 
             type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, 
                   System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
                   PublicKeyToken=31bf3856ad364e35"/>

 

and

    <WorkflowRuntime Name="WorkflowRuntime">
        <Services>
            <add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, 
                 System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
                 PublicKeyToken=31bf3856ad364e35"/>
            <add type="System.Workflow.Runtime.Hosting.DefaultWorkflowCommitWorkBatchService, 
                 System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
                 PublicKeyToken=31bf3856ad364e35"/>
        </Services>
    </WorkflowRuntime>

 

Now you should be good to go Smile

 

The only thing now is adding conversation support. Right now you will het this error

"System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.InvalidOperationException: Current session has no workflow instance associated with it. Send activation message to start new instance in current session."

even after adding a CookieContainer as I previously described here. The problem is that the cookie is never added to the response as this is done by WorkflowWebHostingModule http module. So to enable conversations just add the following to the web.config.

        <httpModules>
      <add type="System.Workflow.Runtime.Hosting.WorkflowWebHostingModule, 
                 System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
                 PublicKeyToken=31bf3856ad364e35" 
           name="WorkflowHost"/>
        </httpModules>

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

Visual Studio visualizers are pretty cool and can help you quite a bit when debugging but you need to develop them and that just ads to the workload. So how about having someone else do it? Well Microsoft added a few visualizers to VS2008 and VS2008 but they are pretty much limited to text, html and XML data.

 

Luckily some people liked the idea of using visualizers and actually decided to take it to the next level with project Mole.

Its a really great viewer to inspect your data and the "Black Ops" feature that allows you to inspect all private members is awesome.

One quick tip: If you want to use the Mole with any variable use the "new WeakReference(variable)" in the watch window trick!

 

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with 1 comment(s)
Filed under: , , , , ,

Sometimes you can get these kinds of errors using the new Workflow Foundation ReceiveActivity when property binding the incoming value. So why does this happen Well it appears the validation is comparing the type of the original interface to to the type of the proxy generated. In this case because the actual type passed isn't shared between the client and the server.

But as the generated proxy type actually gets exactly the same name as the original, even though it is a different type defined in a different assembly, it appears as though comparing two the same types says they are not equal.

So is there a problem in the code?

No there isn't because the client doesn't have a reference to the original type, which is why the proxy was generated in the first place, the proxy is always used. So the error is bogus and should not be reported.

So this is a but that is going to be fixed? Well apparently not according to this bug report feedback. Apparently we just have to ignore the error Sad which sort of sucks big time. As far as I am concerned an incorrectly reported error is a serious bug and should be fixed as it is likely to waste a lot of time and might result in serious problems being ignored.

 

So if you agree that problems like this should be fixed please go here and vote for this to be fixed!

Enjoy!

with no comments
Filed under: , , , ,

I just noticed the second part of my article about developing custom Windows Workflow Foundation activities.

Read part 2 here. Just in case you missed part 1 you can find it here.

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with 1 comment(s)
Filed under: , , ,

As I mentioned previously I was working in a Workflow Persistence Service using SQL Server Compact as the back end store. Now this might not be the best persistence store to use in every application but it has a number of advantages.

One of the main advantages is ClickOnce deployment. In the case of the standard SqlWorkflowPersistenceService you need to have SQL Server installed and running and create the database, with a name of your choosing, using two scripts. Not a big problem but something that needs to be done first and is outside of the realm of what you would like to do with ClickOnce. Not so with SQL Server Compact. No with SqlCe you can just deploy a number of DLL's with your application and you are ready to go, so much easier and very ClickOnce compatible Smile Add easy installation is just what you want when you are creating sample applications.

I actually did all the data access using LINQ to SQL which fully supports SqlCe as a client. It might appear not to as there is no designer support like with SQL Server itself but runtime it works just fine Smile. using LINQ to SQL actually made the data access very easy and has an additional benefit, if you want to use the full SQL Server all you need to do is provide a different database connections string. One additional benefit of using LINQ to SQL was that is can check if the database exists and, if not, create it with a single function call. No need to mess with those tedious Create Table statements in SQL scripts!

Imports TheProblemSolver.Workflow.Hosting.Persistence

Module Module1
    Class Program
        Shared Sub Main()
            Using workflowRuntime As New WorkflowRuntime()

                Dim connectionStr As String = "Data Source=WorkflowPersistenceDatabase.sdf"
                Dim unloadOnIdle As Boolean = True
                Dim loadingInterval As TimeSpan = TimeSpan.FromSeconds(15)
                Dim persistence As New SqlCeWorkflowPersistenceService(connectionStr, _
                                                                       unloadOnIdle, _
                                                                       loadingInterval)
                workflowRuntime.AddService(persistence)

                Dim workflowInstance As WorkflowInstance
                workflowInstance = workflowRuntime.CreateWorkflow(GetType(Workflow1))
                workflowInstance.Start()

                Console.WriteLine("Press enter to stop...")
                Console.ReadLine()
            End Using
        End Sub
    End Class
End Module

Usage is real simple and pretty much the same as the standard SqlWorkflowPersistenceService type. The only extra is to set a reference to the TheProblemSolver.Workflow.Hosting.Persistence.dll that includes the SqlCeWorkflowPersistenceService type.

using System;
using System.Workflow.Runtime;
using TheProblemSolver.Workflow.Hosting.Persistence;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                string connectionStr = @"Data Source=WorkflowPersistenceDatabase.sdf";
                bool unloadOnIdle = true;
                TimeSpan loadingInterval = TimeSpan.FromSeconds(15);
                SqlCeWorkflowPersistenceService persistence = 
                    new SqlCeWorkflowPersistenceService(connectionStr, unloadOnIdle, loadingInterval);
                workflowRuntime.AddService(persistence);

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Workflow1));
                instance.Start();

                Console.WriteLine("Press enter to stop...");
                Console.ReadLine();
            }
        }
    }
}

If you want to download the SqlCeWorkflowPersistenceService you can find it here. Any feedback, hopefully good, will be appreciated!

 

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

As I previously mentioned having the LINQ DataContext create the database if it doesn't exist yet is a cool feature but it isn't perfect.

The problem I just ran into was while using the |DataDirectory| macro, something the SqlCeConnection understands and will replace with the directory specified. Well it turns out the LINQ DataContext isn't that smart when checking if the database exists. Apparently it checks if the database file exists without expanding the |DataDirectory| so it never finds the database. The result is a SqlCeException with the message: "File already exists. Try using a different database name. [ File name = C:\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\Data2.sdf ]"

Actually creating the database the first time works just fine and all other actions like querying or updating are fine to.

To reproduce the error create a console app and add a LINQ to SQL DBML file. Just add a small class with a property to server as table.

image

Add the following code:

Module Module1
    Sub Main()
        Try
            ' Cleanup any previous files
            My.Computer.FileSystem.DeleteFile("Data1.sdf")
            My.Computer.FileSystem.DeleteFile("Data2.sdf")
        Catch ex As Exception
        End Try

        For i As Integer = 1 To 2
            CreateDatabaseIfNeeded("Data Source=Data1.sdf")
            CreateDatabaseIfNeeded("Data Source=|DataDirectory|\Data2.sdf")
        Next
    End Sub

    Sub CreateDatabaseIfNeeded(ByVal connection As String)
        Dim context As New DataClasses1DataContext(connection)
        If Not context.DatabaseExists() Then
            Console.WriteLine("Creating database")
            context.CreateDatabase()
        Else
            Console.WriteLine("Database exists")
        End If
    End Sub
End Module

And run the application.

 

Want to see this fixed? The vote for it here.

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with no comments
Filed under: , , ,

LINQ to SQL has a really nice feature when making sample and demos in the ability to create the database if it doesn't exist yet. It also has a function called DatabaseExists() to check if a database exists. Both are defined on the DataContext class.

string connectionString 
    = @"Data Source=.\sqlexpress;Initial Catalog=MyNewDatabase;Integrated Security=True";

MyNewDatabase context = new MyNewDatabase(connectionString);
if (!context.DatabaseExists())
    context.CreateDatabase();

And best of all they work both for SQL Server and for SQL Compact so it is real easy to make demo's that work with both the full SQL Server as well as the lightweight SQL Compact. All you need to do is change the connection string.

connectionString = @"Data Source=MyNewDatabase.sdf";

Now I specially like the SQL Compact option for samples as there is no installation requirement, just copy the files and you are good to go Smile. In fact I have been using LINQ to SQL to create a SQL Compact Workflow persistence service but because of the very nature of LINQ to SQL I can use it just as well with the full blown SQL Server as SQL Compact.

So why do I consider the DatabaseExists() function only suitable for demo's? Well in the case of SQL Server it makes a connection to the server and sees if it can use the database. Hardly a very reliable check as it can fail for any number of reasons. And if the database exists it still doesn't mean that the schema is correct. For SQL Compact the check is even worse, it only checks if a file with the same name exists, no matter what it is.

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with 3 comment(s)
Filed under: , , ,

Sometimes you just want to be able to create a workflow in code bus save it as a XOML workflow so the end user has the opportunity to modify it.

Well it turns out to be quite easy Smile as the WorkflowMarkupSerializer class is your friend. The following code does just that. And most of the code is to create the workflow in the first place as the serialization part is just 3 lines!

using (XmlWriter writer = XmlWriter.Create("MyWorkflow.xoml"))
{
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    SequentialWorkflowActivity myWorkflow = new SequentialWorkflowActivity();

    ListenActivity listen = new ListenActivity();
    myWorkflow.Activities.Add(listen);
    EventDrivenActivity leftBranch = new EventDrivenActivity();
    leftBranch.Activities.Add(new DelayActivity("LeftDelay")
    {
        TimeoutDuration = TimeSpan.FromSeconds(5)
    });
    listen.Activities.Add(leftBranch);

    EventDrivenActivity rightBranch = new EventDrivenActivity();
    rightBranch.Activities.Add(new DelayActivity("RightDelay")
    {
        TimeoutDuration = TimeSpan.FromSeconds(5)
    });
    listen.Activities.Add(rightBranch);

    serializer.Serialize(writer, myWorkflow);
}

This produces the following XOML workflow:

<?xml version="1.0" encoding="utf-8"?>
<SequentialWorkflowActivity x:Name="SequentialWorkflowActivity"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
  <ListenActivity x:Name="listenActivity1">
    <EventDrivenActivity x:Name="eventDrivenActivity1">
      <DelayActivity TimeoutDuration="00:00:05" x:Name="LeftDelay" />
    </EventDrivenActivity>
    <EventDrivenActivity x:Name="eventDrivenActivity2">
      <DelayActivity TimeoutDuration="00:00:05" x:Name="RightDelay" />
    </EventDrivenActivity>
  </ListenActivity>
</SequentialWorkflowActivity>

image

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with no comments
Filed under: , , ,

Yep it appears you can with the Google App Engine. The figures are pretty impressive with 500Mb of disk storage and 5 million page views monthly. And the price? Well its free!That sure beats my web provider!

Ofcourse they don't support .NET yet, in fact their development platform is based on Python but they say that is just for starters. What interest me most is if this is going to be one of those moves Microsoft follows? After all they compete with Google on a number of fronts and developer mindshare is certainly one of these areas!

We certainly live in interesting times Smile

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with no comments
Filed under: ,

Both products contain 2008 in the name and come from the same vendor, Microsoft, so they must work together right? Well not quite Sad Visual Studio 2008 was actually released at the end of 2007 and SQL Server 2008 is not going to be released for some time to come. So not surpisingly VS2008 doesn't quite support SQL2008 out of the box.

But fortunatly Jackie Goldstein wrote an article showing ow to do this. You can read the article here.

 

Enjoy!

www.TheProblemSolver.nl
http://wiki.WindowsWorkflowFoundation.eu

with no comments
Filed under: ,

This is a test

 

error2