.NET 3.0 Middleware Technologies Day: Third Incarnation 

Third incarnation of the .NET 3.0 Middleware Technologies day went through yesterday.

Here are the deliverables:

If you did not get/notice the printed articles, here's what should put you to sleep over the weekend:

Also, the accompanying book is available here.

[1] Only available in Slovene.

Thursday, 15 February 2007 06:09:56 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 MSDN Event Presentation: Code and PPT 

I just finished presenting my talk on the October 2006 Slovenian MSDN event.

Here are the deliverables:

Code: Download
PPT: Download [Slovenian]

Solution file includes:

  1. WCF service using wsDualHttpBinding for duplex session communication scenario. WCF service hosts a workflow which computes stock tax based on the current (complex) Slovenian legislation.
  2. WF workflow named ComputeTaxWorkflow. Workflow calls out to our public ASP .NET WebServices: StockQuotes and ExchangeRates.
  3. WCF Client, which sends requests and receives responses when the workflow is done

Check it out. It's free.

Monday, 23 October 2006 11:04:56 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 .NET 3.0 Middleware Technologies Day 

We had a nice discussion throughout the day today, together with around 50 attendees. It's hard to even cover feature changes of .NET 3.0 in a day, but we managed to cover the important things of WCF and WF, spending a complete day inside the Visual Studio.

Here are the demos: Download
And the PPT slides: Download [Slovenian]

And the link to the Tom Archer's compatibility matrix for the .NET Framework 3.0 downloads.

Thanks to everyone who attended.

Categories:  .NET 3.0 - WCF | .NET 3.0 - WF | Architecture | Work
Thursday, 05 October 2006 18:03:06 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Article: Cooperation Between Workflows and Services 

Last article discusses service-workflow cooperation options in WinFX and dives into communication scenarios for Windows Workflow Foundation.

Language: Slovenian


Naslov:

Sodelovanje storitev in delovnih tokov

Sodelovanje storitev in delovnih tokov

Categories:  Articles | .NET 3.0 - WCF | .NET 3.0 - WF
Wednesday, 07 June 2006 10:29:02 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Windows Workflow Foundation: Calling WCF Services 

Having the ability to call services from inside your workflows is a good thing. Things get a little obfuscated when one wants to expose a WCF based service to Windows Workflow Foundation (WF).

What it comes down to is that currently (beta 2 build of WF) we do not have any built-in workflow activities which would allow you to communicate with the WCF advanced services (meaning WS-Security enabled, TCP based, WS-RM enabled, WS-Tx enabled, ...).

Assuming we have an OrderService exposed using the following config:

<configuration>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="Default">
          <security mode="None"/>
        </binding>
        <binding name="Secure">
          <security mode="Message">
            <message clientCredentialType="Windows"/>
          </security>
        </binding>
        <binding name="Reliable">
          <reliableSession enabled="true" ordered="true"/>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="WCFCalledByWorkflow.OrderService" >
        <endpoint address=""
                  binding="wsHttpBinding"
                  behaviorConfiguration="Default"
                  contract="WCFCalledByWorkflow.IOrderService" />
        <endpoint address="/secure"
                  binding="wsHttpBinding"
                  behaviorConfiguration="Secure"
                  contract="WCFCalledByWorkflow.IOrderService" />
        <endpoint address="/reliable"
                  binding="wsHttpBinding"
                  behaviorConfiguration="Reliable"
                  contract="WCFCalledByWorkflow.IOrderService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

This, combined with the following hosting app:

using (ServiceHost sh = new ServiceHost(typeof(OrderService),
  
new Uri("http://localhost:666/OrderService")))
{
   sh.Open();
   Console.WriteLine("Order service running..\n");
   Console.WriteLine("Listening on:");
   foreach(ServiceEndpoint se in sh.Description.Endpoints)
   {
      Console.WriteLine(se.Address.ToString());
   }
   Console.WriteLine("\nPress [Enter] to stop the service.");
   Console.ReadLine();
   sh.Close();
}

Would produce the following output when run:

Order service running..

Listening on:
http://localhost:666/OrderService
http://localhost:666/OrderService/secure
http://localhost:666/OrderService/reliable

Press [Enter] to stop the service.

Now, this is not enough. Our service exposes three different endpoints, each one has different message requirements. And what is more important, all three are based on SOAP 1.2 + WS-Addressing.

There is a 'Default' endpoint which is plain vanilla SOAP 1.2 endpoint, without any security (have to mention it: WCF services are secure by default, one has to turn off security to achive this). Second endpoint uses Windows based message security and third turns on WS-RM. Security wise, second and third endpoints are the same (remember, defaults?).

As said, WF is currently not able to communicate with any of the above endpoints. What needs to be done is adding another endpoint to your service, which would expose it in ASMX compatible way.

The new config is this:

<configuration>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="Default">
          <security mode="None"/>
        </binding>
        <binding name="Secure">
          <security mode="Message">
            <message clientCredentialType="Windows"/>
          </security>
        </binding>
        <binding name="Reliable">
          <reliableSession enabled="true" ordered="true"/>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="WCFCalledByWorkflow.OrderService" >
        <endpoint address=""
                  binding="wsHttpBinding"
                  behaviorConfiguration="Default"
                  contract="WCFCalledByWorkflow.IOrderService" />
        <endpoint address="/secure"
                  binding="wsHttpBinding"
                  behaviorConfiguration="Secure"
                  contract="WCFCalledByWorkflow.IOrderService" />
        <endpoint address="/reliable"
                  binding="wsHttpBinding"
                  behaviorConfiguration="Reliable"
                  contract="WCFCalledByWorkflow.IOrderService" />
        <endpoint address="/legacy"
                  binding="basicHttpBinding"
                  contract="WCFCalledByWorkflow.IOrderService"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

So our Windows Workflow Foundation compatible endpoint is <base address>/legacy.

What this means is that you can bind all your InvokeWebService activities inside workflows to published WCF services by just adding another ASMX compatible endpoint to the WCF service.

The difference in two WCF configs is here:

<endpoint address="/legacy"
   binding="basicHttpBinding"
   contract="WCFCalledByWorkflow.IOrderService"
/>

Code sample can be downloaded here. It includes two projects, a WF and a WCF project. ServiceHost is implemented.

Categories:  .NET 3.0 - WCF | .NET 3.0 - WF
Wednesday, 31 May 2006 11:54:58 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Windows Workflow Foundation: Running Service Activated Workflows on Windows Vista and IIS7 

This post will focus on how to enable IIS7 in Windows Vista client and to use it to host a service activated Windows Workflow.

Procedure is based on the current build of Windows Vista (5381.1), which is a RC1 for Beta 2 milestone. Also, WinFX February CTP is used, which includes Windows Workflow Foundation Beta 2.

There are a couple of prerequisite steps necessary to enable hosting, first of all, installing IIS7. Go to Control Panel/Programs/Turn on or off Windows Features and enable 'Internet Information Services':

Add or remove Windows features

Installer in build 5381.1 (and 5365) is stable enough to be useful. If you're running a previous build of Vista (5308, 5342) consider installing IIS by running this monster in the command prompt:

start /w pkgmgr /l:log.etw /iu:IIS-WebServerRole;IIS-WebServer;IIS-CommonHttpFeatures;IIS-StaticContent;IIS-DefaultDocument;IIS-DirectoryBrowsing;IIS-HttpErrors;IIS-HttpRedirect;IIS-ApplicationDevelopment;IIS-ASPNET;IIS-NetFxExtensibility;IIS-ASP;IIS-CGI;IIS-ISAPIExtensions;IIS-ISAPIFilter;IIS-ServerSideIncludes;IIS-HealthAndDiagnostics;IIS-HttpLogging;IIS-LoggingLibraries;IIS-RequestMonitor;IIS-HttpTracing;IIS-CustomLogging;IIS-ODBCLogging;IIS-Security;IIS-BasicAuthentication;IIS-WindowsAuthentication;IIS-DigestAuthentication;IIS-ClientCertificateMappingAuthentication;IIS-IISCertificateMappingAuthentication;IIS-URLAuthorization;IIS-RequestFiltering;IIS-IPSecurity;IIS-Performance;IIS-HttpCompressionStatic;IIS-HttpCompressionDynamic;IIS-WebServerManagementTools;IIS-ManagementConsole;IIS-ManagementScriptingTools;IIS-ManagementService;IIS-IIS6ManagementCompatibility;IIS-Metabase;IIS-WMICompatibility;IIS-LegacyScripts;IIS-LegacySnapIn;IIS-FTPPublishingService;IIS-FTPServer;IIS-FTPManagement;WAS-WindowsActivationService;WAS-ProcessModel;WAS-NetFxEnvironment;WAS-ConfigurationAPI

Make sure you also check ASP.NET under World Wide Web Services/Application Development features, since this will install and enable ASP .NET 2.0 under all IIS7 sites. You can also do this later on using aspnet_regiis.exe, but Vista will notify you that the preferred way is using Turn on or off Windows features dialog.

Now, when you have IIS installed run the administrative console inside Administrative Tools and define a web application by right clicking on Default Web Site:

Creating application on IIS7

This will allow you to run your workflow as a service inside the default application pool. You can check and notice that default application pool uses a new integrated IIS7 mode and not ISAPI as in IIS5/6.

You're ready to deploy your workflow activated service now. use the steps described in my previous post, under Ad 1.

When you hit the service endpoint you get this:

Configuration error in IIS7

IIS7 is noticing you that your config files are not compatible with the new hosting model.

You have two options:

  • Change the configuration files
  • Change the hosting model

You can change the configuration files by running: c:\windows\system32\inetsrv\appcmd.exe migrate config "<Site name>/<VRoot name>". AppCmd.exe is a tool which automatically migrates your old config, to IIS7's new config format.

Another option is that you enable old style ISAPI hosting model inside your application pool that is running your default web site (or another site, if that's what the workflow is supposed to be running under). You can do this either by:

1. Running c:\windows\system32\inetsrv\appcmd.exe set app "<Site name>/<VRoot name>" /applicationPool: "Classic .NET AppPool". This changes the site to use another, preconfigured app pool, which uses ISAPI by default.

Here's a screenshot of the default pipeline modes for IIS7:

Application pool config in IIS7

2. Changing the hosting model on the current Default Web Site site. You can right click on Application Pools/DefaultAppPool and select Set Application Pool Defaults. Then you change the pipeline mode from Integrated to ISAPI. Here's how you do it:

Pipeline mode selection

I prefer going through route 1. Integrated mode is how you should be running your sites under IIS7, so changing the config to make IIS7 happy is the way to go. If you have specific ISAPI functionality (not limited to Workflows) you can, though run in classic mode by designing your app pool around it.

Now your service activated workflow will run and execute under IIS7. Again, beware of the caveats I described here.

Categories:  Web Services | Windows Vista | .NET 3.0 - WF
Thursday, 11 May 2006 11:15:46 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Windows Workflow Foundation: Exposing Workflows as Services 

There are currently a couple of options to expose a Windows Workflow as as service.

  1. There is a native option to publish a developed Workflow Library project as a ASP .NET Web Service (ASMX).
  2. You can host it yourself (ASMX, WCF)
  3. William Tay is doing excellent work towards hosting a workflow inside the WCF service pipeline (WCF)
  4. Roman Kiss created a static WorkflowInvoker class, which does all the heavy liting for you, if you want to host your workflow inside the WCF service method (WCF)

I'm going to focus on Ad 1 and Ad 2 in this post.

Ad 1:

There's an option to host your workflow library inside a web service by using a "Publish as a Web Service" option inside Visual Studio 2005. This creates a separate ASP .NET Web Service project inside your current solution, which you can later manually or automatically publish as a web site to your IIS of choice.

The are two major downsides to this story. The first is that this gives you practically no control over how the web service is created. Second downside, while documented, is that the current implementation of System.Workflow.Runtime.WorkflowWebHostingModule works in particular ways with the workflow persistence story.

Let's assume we have to following interface defined for this web service:

interface IServiceInterface
{
   void SendOrder(Order order);
   Order GetOrder(Guid guidOrder);
   int GetOrderStatus(Guid guidOrder);
}

What happens is (request number 1):

  1. You publish your workflow as a web service
  2. You hit the service endpoint with a browser
  3. Workflow instance gets created, is run and returns a result
  4. At this time the workflow runtime (System.Workflow.Runtime.WorkflowRuntime instance) creates a workflow instance and runs it. Since workflow completes succesfully it destroys the instance at the end of execution.
  5. Workflow runtime returns a cookie with the workflow instance back to the browser and since IE's default setting is to accept cookies, it is written to the client's disk

All good, right?

Actually, what happens during request number 2?

  1. You hit the endpoint again
  2. IE knows that the site has a persisted cookie, so it sends it bundled with the SOAP request
  3. Workflow runtime sees it and tries to load the specified workflow instance
  4. This instance is long gone, it does not exist in memory (it has been destroyed, remember?), so workflow runtime tries to rehydrate it from a persistence store. If there is a persistence store defined it goes there (most probably WorkflowPersistenceStore in SQL Server) and correctly identifies that the workflow instance is not present, so it fails with 'Workflow with id <GUID> not found in state persistence store.'. If the persistence store is not defined for this workflow it fails with 'The workflow hosting environment does not have a persistence service as required by an operation on the workflow instance <GUID>.'.

And all this is actually the expected behavior if you think hard enough. Workaround? Hit the endpoint with a newly loaded IE window. It works every time, since a cookie with an instance ID is not present.

Another thing to mention here is that this issue does not manifest itself if you hit the endpoint programatically using the web service proxy, unless you are using a CookieContainer class to cache the returning cookies.

Ad 2:

Hosting a Windows Workflow manually is another option, which gives you more flexibility towards the service detail tweeking.

You can host it using the following code:

[WebService(Namespace = "http://webservices.gama-system.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WorkflowService : System.Web.Services.WebService
{
    // workflow runtime
    private static WorkflowRuntime workflowRuntime = new WorkflowRuntime();
    
    [WebMethod]
    public void SendOrder(Order order)
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        workflowRuntime.WorkflowCompleted +=
           delegate(object sender, WorkflowCompletedEventArgs e)
        {
            waitHandle.Set();
        };
       
        workflowRuntime.WorkflowTerminated +=
           delegate(object sender, WorkflowTerminatedEventArgs e)
        {
            waitHandle.Set();
        };

        // create workflow instance with the specified parameters
        WorkflowInstance instance =
           workflowRuntime.CreateWorkflow(typeof(MyWorkflow));
        instance.Start();

        waitHandle.WaitOne();
    }   
}

An important thing in the specified sample is that the System.Workflow.Runtime.WorkflowRuntime instance is static to the service implementation class. This is a requirement, since the workflow runtime can only get loaded once per appdomain. If this is not the case you will get an exception during the second invocation of the workflow.

If you are using any additional workflow runtime services, like persistence, tracking or your own communication service to communicate with the workflow you will need to track that the services get loaded once only. Here's the example:

[WebService(Namespace = "http://webservices.gama-system.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WorkflowService : System.Web.Services.WebService
{
    // workflow runtime
    private static WorkflowRuntime workflowRuntime = new WorkflowRuntime();
   
   
// services added
    private static bool booServicesAdded = false;

    // communication service
    private static CommunicationService objComm = new CommunicationService();

    [WebMethod]
    public void SendOrder(Order order)
    {
        // add communication service
        if (!booServicesAdded)
        {
            ExternalDataExchangeService externalService =
               new ExternalDataExchangeService();
            workflowRuntime.AddService(externalService);
            externalService.AddService(objComm);
            booServiceAdded = true;
        }

        AutoResetEvent waitHandle = new AutoResetEvent(false);
        workflowRuntime.WorkflowCompleted +=
           delegate(object sender, WorkflowCompletedEventArgs e)
        {
            waitHandle.Set();
        };
       
        workflowRuntime.WorkflowTerminated +=
           delegate(object sender, WorkflowTerminatedEventArgs e)
        {
            waitHandle.Set();
        };

        // create workflow instance with the specified parameters
        WorkflowInstance instance =
           workflowRuntime.CreateWorkflow(typeof(MyWorkflow));
        instance.Start();

        waitHandle.WaitOne();
    }   
}

This adds the required services only during the first invocation of a web service. Since workflow runtime is a static class the services get persisted during all subsequent service calls. A boolean variable booServicesAdded is responsible for flag storage.

Categories:  Web Services | .NET 3.0 - WCF | .NET 3.0 - WF
Wednesday, 10 May 2006 09:55:37 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 WWF on x64 Platform 

If you are running WWF (Windows Workflow Foundation, part of WinFX) on a x64 box, and have problems debugging workflows, stop.

It's currently not supported. It should, but does not work yet. This should be fixed already, but it's not. And it will probably get fixed in the next CTP drop.

There is a workaround though:

  1. Enter Configuration Manager (Build/Configuration Manager)
  2. Select the active solution platform drop down, select New...
  3. Select x86 platform
  4. Hit OK and try debugging again

This will make sure that you are running your solution debugging under x86 mode and thus allow you to set breakpoints and debug your code.

Categories:  .NET 3.0 - General | .NET 3.0 - WF
Tuesday, 14 March 2006 23:09:15 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

Copyright © 2003-2024 , Matevž Gačnik
Recent Posts
RD / MVP
Feeds
RSS: Atom:
Archives
Categories
Blogroll
Legal

The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.

My views often change.

This blog is just a collection of bytes.

Copyright © 2003-2024
Matevž Gačnik

Send mail to the author(s) E-mail