<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kay&#039;s Technologie Backlog &#187; WF</title>
	<atom:link href="http://www.herzam.com/blog/category/wf/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.herzam.com/blog</link>
	<description>So much technology, so little time</description>
	<lastBuildDate>Thu, 11 Feb 2010 09:11:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Die RetryActivity erweitern</title>
		<link>http://www.herzam.com/blog/2009/10/05/die-retryactivity-erweitern/</link>
		<comments>http://www.herzam.com/blog/2009/10/05/die-retryactivity-erweitern/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 17:19:35 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>
		<category><![CDATA[WF-Activities]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=152</guid>
		<description><![CDATA[In mein WF Activity Toolkit gehört unter anderem die RetryActivity von Matt Milner. Wie bereits beschrieben kann mit dieser Custom Activity die Ausführung einer Sequenz wiederholt werden, falls innerhalb der Sequenz ein Fehler auftritt. Dabei können die Anzahl der erneuten Versuche und ein Intervall zwischen den Versuchen angegeben werden. Nun habe ich diese Activity noch [...]]]></description>
			<content:encoded><![CDATA[<p>In mein WF Activity Toolkit gehört unter anderem die <a href="http://www.pluralsight.com/community/blogs/matt/archive/2007/11/28/49315.aspx">RetryActivity</a> von <a href="http://www.pluralsight.com/community/blogs/matt/default.aspx">Matt Milner</a>. Wie <a href="http://www.herzam.com/blog/2009/10/01/3-nutzliche-custom-wf-activities/">bereits beschrieben</a> kann mit dieser Custom Activity die Ausführung einer Sequenz wiederholt werden, falls innerhalb der Sequenz ein Fehler auftritt. Dabei können die Anzahl der erneuten Versuche und ein Intervall zwischen den Versuchen angegeben werden. Nun habe ich diese Activity noch ein wenig erweitert, um das Intervall zwischen den Versuchen etwas flexibler konfigurieren zu können.</p>
<div id="attachment_155" class="wp-caption alignnone" style="width: 290px"><img class="size-full wp-image-155" title="Erweiterte RetryActivity" src="http://www.herzam.com/blog/wp-content/uploads/2009/09/RetryActivityEx.gif" alt="Erweiterte RetryActivity" width="280" height="117" /><p class="wp-caption-text">Erweiterte RetryActivity</p></div>
<p>Dabei werden zwischen zwei Intervall Modi unterschieden:</p>
<ul>
<li>Linear (IntervalExponential = false)<br />
Die Zeitabstände zwischen den einzelnen Intervallen sind gleichmässig, zB. immer 1 Minute.</li>
<li>Exponentiell (IntervalExponential = true)<br />
Die Zeitabstände zwischen den einzelnen Intervallen wird immer verdoppelt bis alle Versuche ausgeschöpft sind. Also wird zB. mit einer Sekunde begonnen, und das nächste Intervall dauert zwei Sekunden. Nach 10 Intervall Schritten wird bereits 512 Sekunden gewartet, also etwa achteinhalb Minuten.</li>
</ul>
<p>Dies kann nützlich sein, wenn zB. ein Aufruf an ein externes System fehlerhaft sein kann, man aber bei vielen parallelen Workflows das externe System nicht durch zahlreiche gleichzeitige Aufrufe belasten will.</p>
<p>Hier ist der der Source Code der erweiterten RetryActivity: <a href="../wp-content/uploads/2009/09/RetryActivityEx.zip">RetryActivityEx.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2009/10/05/die-retryactivity-erweitern/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>3 Nützliche Custom WF Activities</title>
		<link>http://www.herzam.com/blog/2009/10/01/3-nutzliche-custom-wf-activities/</link>
		<comments>http://www.herzam.com/blog/2009/10/01/3-nutzliche-custom-wf-activities/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 18:12:49 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>
		<category><![CDATA[WF-Activities]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=134</guid>
		<description><![CDATA[Nachdem ein grösseres Projekt nun beinahe abgeschlossen ist, komme ich auch wieder dazu, ein paar Erfahrungen der letzten Monate zu beschreiben. Die Basis Library der WF 3 enthält ja einige Activities, welche benutzt werden können, um den Ablauf zu modellieren. In einem typischen Projekt kommen dann sofort eigene Custom Activities dazu, welche sich um die [...]]]></description>
			<content:encoded><![CDATA[<p>Nachdem ein grösseres Projekt nun beinahe abgeschlossen ist, komme ich auch wieder dazu, ein paar Erfahrungen der letzten Monate zu beschreiben. Die Basis Library der WF 3 enthält ja einige Activities, welche benutzt werden können, um den Ablauf zu modellieren. In einem typischen Projekt kommen dann sofort eigene Custom Activities dazu, welche sich um die Prozess relevanten Punkte kümmern wie zB. den Zugriff auf eine externe DB.</p>
<p>Folgende 3 Custom Activities haben sich als unentbehrlich erwiesen und gehören fest in mein WF Toolkit:</p>
<h3>CallWorkflow</h3>
<p>Die InvokeWorkflowActivity der WF kann zwar auch andere Workflows ausführen, sie macht dies jedoch asynchron. Das bedeutet, sofort nach dem Aufruf kehrt die Ausführung in den aufrufenden  Workflow zurück. Die <a href="http://www.masteringbiztalk.com/blogs/jon/CommentView,guid,7be9fb53-0ddf-4633-b358-01c3e9999088.aspx">CallWorkflowActivity</a> mit dazugehörigem Runtime Service des WF Spezialisten <a href="http://www.masteringbiztalk.com/blogs/jon/default.aspx">Jon Flanders</a> bietet die synchrone Variante an. Die Ausführung im aufrufenden Workflow wartet solange, bis die aufgerufene Workflow Instanz beendet ist.</p>
<h3>Retry</h3>
<p>Die <a href="http://www.pluralsight.com/community/blogs/matt/archive/2007/11/28/49315.aspx">RetryActivity</a> von <a href="http://www.pluralsight.com/community/blogs/matt/default.aspx">Matt Milner</a> kann immer dann verwendet werden, wenn der Aufruf einer Activity fehlschlagen kann (werfen einer Exception), und man dann das ganze noch einmal ausführen lassen will. Es kann eine Anzahl der Wiederholungsversuche und ein Intervall zwischen den Versuchen angegeben werden.</p>
<div id="attachment_144" class="wp-caption alignnone" style="width: 493px"><img class="size-full wp-image-144" title="RetryActivity" src="http://www.herzam.com/blog/wp-content/uploads/2009/09/RetryActivity.gif" alt="RetryActivity" width="483" height="280" /><p class="wp-caption-text">RetryActivity</p></div>
<h3>PersistencePoint</h3>
<p>Die letzte Activity ist eine wirklich simple, aber sehr nützliche. Sie kann im Workflow eingesetzt werden, um einen Speicherpunkt im WF Store zu erzwingen auch wenn die WF dies an dieser Stelle nicht von sich aus tun würde. Wenn im Ablauf ein wichtiger Punkt erreicht wurde, kann dies in die Persitenz DB gespeichert werden, und falls der WF unterbrochen wird, fährt die Ausführung beim letzten Speicherpunkt weiter.</p>
<p>Jede Activity, welche mit dem Attribut [<a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.persistoncloseattribute.aspx">PersistOnClose</a>] ausgezeichnet wird, erreicht dieses Verhalten. Die PersistencePointActivity wird somit trivial:</p>
<pre class="brush: csharp;">
[PersistOnClose]
public partial class PersistencePointActivity : Activity
{
    public PersistencePointActivity()
    {
        InitializeComponent();
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2009/10/01/3-nutzliche-custom-wf-activities/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Setzen der Persistenz Service ID für Workflow Services</title>
		<link>http://www.herzam.com/blog/2009/09/29/setzen-der-persistenz-service-id-fur-workflow-services/</link>
		<comments>http://www.herzam.com/blog/2009/09/29/setzen-der-persistenz-service-id-fur-workflow-services/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 17:42:16 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=116</guid>
		<description><![CDATA[Gestern habe ich einen kleinen, aber nützlichen Hack gezeigt, mit welchem man die Service ID des Persistenzdienstes setzen kann. Dies funktioniert auch ganz prima, solange man nicht mit Workflow Services arbeitet.
Wie man es auch versucht, man erhält keine gültige Referenz auf den Persistenz Service.
Also was tun? Reflector zeigt uns die Interna von WorkflowService.ApplyDispatchBehavior():
static class WorkflowExtensions
...
WorkflowPersistenceService [...]]]></description>
			<content:encoded><![CDATA[<p>Gestern habe ich einen kleinen, aber nützlichen Hack gezeigt, mit welchem man die <a href="http://www.herzam.com/blog/?p=105">Service ID des Persistenzdienstes setzen</a> kann. Dies funktioniert auch ganz prima, solange man nicht mit <a href="http://msdn.microsoft.com/en-us/library/cc825354.aspx">Workflow Services</a> arbeitet.</p>
<p>Wie man es auch versucht, man erhält keine gültige Referenz auf den Persistenz Service.</p>
<p>Also was tun? Reflector zeigt uns die Interna von WorkflowService.ApplyDispatchBehavior():</p>
<pre class="brush: csharp;">static class WorkflowExtensions
...
WorkflowPersistenceService service = item.WorkflowRuntime.GetService&amp;amp;lt;WorkflowPersistenceService&amp;amp;gt;();
if (service != null)
{
    bool isStarted = item.WorkflowRuntime.IsStarted;
    if (isStarted)
    {
        item.WorkflowRuntime.StopRuntime();
    }
    item.WorkflowRuntime.RemoveService(service);
    item.WorkflowRuntime.AddService(new SkipUnloadOnFirstIdleWorkflowPersistenceService(service));
    if (isStarted)
    {
        item.WorkflowRuntime.StartRuntime();
    }
}
...
</pre>
<p>Was geschieht hier genau?<br />
Wenn via Config oder Code ein Persistenz Service hinzugefügt wurde, wird die Runtime gestoppt. Der Standard Persistenz Service wird entfernt, und ein neuer Service mit dem handlichen Namen SkipUnloadOnFirstIdleWorkflowPersistenceService wird hinzugefügt. Danach wird die Runtime wieder gestartet.<br />
Die Workflow Runtime eines Workflow Services verwendet also intern nicht den SqlWorkflowPersistenceService, sondern einen speziellen, öffentlich nicht zugänglichen und gekapselten Dienst.</p>
<p>Wie also kann nun in einem solchen Kontext die Service ID gesetzt werden?</p>
<p>Die gestern gezeigte Erweiterungsmethode kann wie folgt ergänzt werden:</p>
<pre class="brush: csharp;">static class WorkflowExtensions
{
    public static void SetServiceInstanceId(this WorkflowPersistenceService workflowPersistenceService, Guid serviceId)
    {
        Type persistenceServiceType = workflowPersistenceService.GetType();
        FieldInfo instanceIdField = persistenceServiceType.GetField(&amp;amp;quot;_serviceInstanceId&amp;amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);
        instanceIdField.SetValue(workflowPersistenceService, serviceId);
    }

    public static WorkflowRuntime GetRuntime(this WorkflowServiceHost host)
    {
        return host.Description.Behaviors.Find&amp;amp;lt;WorkflowRuntimeBehavior&amp;amp;gt;().WorkflowRuntime;
    }

    public static T GetWFService&amp;amp;lt;T&amp;amp;gt;(this WorkflowRuntime runtime) where T : class
    {
        if (typeof(T) != typeof(SqlWorkflowPersistenceService))
        {
            return runtime.GetService&amp;amp;lt;T&amp;amp;gt;();
        }
        else
        {
            WorkflowPersistenceService service = runtime.GetService&amp;amp;lt;WorkflowPersistenceService&amp;amp;gt;();
            Type sqps = service.GetType();

            FieldInfo field = (from fieldinfo in sqps.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                               where fieldinfo.FieldType == typeof (WorkflowPersistenceService)
                               select fieldinfo).First();
            return field.GetValue(service) as T;
        }
    }
}
</pre>
<p>Mit der Erweiterungsmethode GetRuntime() erhält man die WF Runtime vom WorkflowServiceHost.<br />
Mittels wfRuntime.GetWFService&lt;SqlWorkflowPersistenceService&gt;() kann danach durch den Zugriff via Reflection auf den intern als Feld gekapselten Persistenzdienst zugegriffen werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2009/09/29/setzen-der-persistenz-service-id-fur-workflow-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Workflow Ownership Probleme</title>
		<link>http://www.herzam.com/blog/2009/09/28/workflow-ownership-probleme/</link>
		<comments>http://www.herzam.com/blog/2009/09/28/workflow-ownership-probleme/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 17:00:05 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=105</guid>
		<description><![CDATA[Eines der mächtigsten Features der WF, der Persistenz Service (SqlWorkflowPersistenceService), erlaubt es einem, den aktuellen Status von Workflow Instanzen in der Workflow DB zu speichern. Microsoft stellt dabei alles, was benötigt wird, zur Verfügung, mindestens für den hauseigenen SQL Server.
Eine Applikation, die beispielsweise auf mehreren Servern gleichzeitig läuft, kann auf dieselbe WF Persistenz Datenbank zugreifen. [...]]]></description>
			<content:encoded><![CDATA[<p>Eines der mächtigsten Features der WF, der Persistenz Service <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.hosting.sqlworkflowpersistenceservice.aspx">(SqlWorkflowPersistenceService</a>), erlaubt es einem, den aktuellen Status von Workflow Instanzen in der Workflow DB zu speichern. Microsoft stellt dabei alles, was benötigt wird, zur Verfügung, mindestens für den hauseigenen SQL Server.</p>
<p>Eine Applikation, die beispielsweise auf mehreren Servern gleichzeitig läuft, kann auf dieselbe WF Persistenz Datenbank zugreifen. Dazu wurde das relativ einfache Konzept der Workflow Ownership geschaffen. Dies ist eigentlich nichts anderes als ein einfacher Lock mit einem Timeout.</p>
<p>In der WF Persistenz Datenbank dienen dazu die beiden Felder ownerId und ownedUntil der Tabelle InstanceState:</p>
<div id="attachment_108" class="wp-caption alignnone" style="width: 350px"><img class="size-full wp-image-108" title="InstanceState" src="http://www.herzam.com/blog/wp-content/uploads/2009/09/InstanceState.gif" alt="Aufbau der Tabelle InstanceState" width="340" height="220" /><p class="wp-caption-text">Aufbau der Tabelle InstanceState</p></div>
<p>Im Feld ownerId wird die GUID des Persistenz Services der jeweiligen WF Runtime eingetragen, und in ownedUntil steht (im UTC Format!), wie lange die Instanz gesperrt ist.<br />
Wenn diese beiden Felder nicht null sind, wird die entsprechende WF Instanz also gerade von einem Host bearbeitet.<br />
So wird sichergestellt, dass eine Workflow Instanz immer nur von einem Host gleichzeitig ausgeführt wird.</p>
<p>Dies funktioniert grundsätzlich auch prima, der Persistenz Service hat allerdings einige Unschönheiten.</p>
<p>Bei jedem Neustart der WorkflowRuntime wird der Persistenz Service neu initialisiert. Dabei erhält er auch immer eine neu GUID, mit welcher dann die WF Instanzen in der WF DB gelockt werden.<br />
Wenn nun zum Beispiel die Ausführung einer Workflow Instanz abgebrochen wird, bleibt der Lock bestehen.</p>
<p>Nun würde man erwarten, dass die Instanz nach dem Ablaufen des Lock Timeouts von einem anderen Host geladen und weiterbearbeitet werden kann. Leider ist dies nicht der Fall. Der Persistenz Service lädt beim Pollen nach freien Workflow Instanzen nur solche mit abgelaufenem Timer. Diejenigen mit abgelaufenem Lock werden nur beim Start des Services geladen. Solange also der Service nicht neu gestartet wird, kann die Workflow Instanz nicht mehr geladen werden.</p>
<p>Es wäre doch schön, wenn man dem Persistenz Service eine ID zuweisen könnte, damit wäre nämlich das Problem gelöst. In einer Umgebung mit mehreren Hosts, könnte jeder Service seine eigene ID erhalten.<br />
Leider ist dies nicht vorgesehen.</p>
<p>Dem kann man aber abhelfen. Nach einem kurzen Blick auf die Implementation des SqlWorkflowPersistenceService im <a href="http://www.red-gate.com/products/reflector/">Reflector</a> kann man dank der in C# 3.0 eingeführten Extension Methods den Service wie folgt erweitern:</p>
<pre class="brush: csharp;">
static class WorkflowExtensions
{
    public static void SetServiceInstanceId(this WorkflowPersistenceService workflowPersistenceService, Guid serviceId)
    {
        Type persistenceServiceType = workflowPersistenceService.GetType();
        FieldInfo instanceIdField = persistenceServiceType.GetField(&amp;quot;_serviceInstanceId&amp;quot;,
                                                                    BindingFlags.NonPublic |
                                                                    BindingFlags.Instance);
        instanceIdField.SetValue(workflowPersistenceService, serviceId);
    }
}
</pre>
<p>Die Service ID wird einfach via Reflection gesetzt. Verwendung auf eigene Gefahr, bei mir hat&#8217;s jedenfalls hervorragend funktioniert.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2009/09/28/workflow-ownership-probleme/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WF Essentials &#8211; Persistenz von Workflows &#8211; Teil 1</title>
		<link>http://www.herzam.com/blog/2008/10/29/wf-essentials-persistenz-von-workflows-teil-1/</link>
		<comments>http://www.herzam.com/blog/2008/10/29/wf-essentials-persistenz-von-workflows-teil-1/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 05:31:22 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=54</guid>
		<description><![CDATA[Dies ist der erste Teil eines mehrteiligen Artikels zu den Persistenz Mechanismen in der Windows Workflow Foundation.
Zu Beginn werden mal die Workflow Persistenz Grundlagen beleuchtet. Später geht&#8217;s dann um den Einsatz des Persistenz Services in Workflow Services und in einer Server Farm.
Die Windows Workflow Foundation stellt für die Persistenz von Workflow Instanzen den Core Dienst [...]]]></description>
			<content:encoded><![CDATA[<p>Dies ist der erste Teil eines mehrteiligen Artikels zu den Persistenz Mechanismen in der Windows Workflow Foundation.<br />
Zu Beginn werden mal die <strong>Workflow Persistenz Grundlagen</strong> beleuchtet. Später geht&#8217;s dann um den Einsatz des Persistenz Services in Workflow Services und in einer Server Farm.</p>
<p>Die Windows Workflow Foundation stellt für die Persistenz von Workflow Instanzen den Core Dienst <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.hosting.sqlworkflowpersistenceservice.aspx">SqlWorkflowPersistenceService</a> zur Verfügung. Dieser benötigt einen SQL Server, andere Datenbanken werden nicht unterstützt. Es ist allerdings möglich, einen eigenen Persistenz Dienst zu schreiben, dazu aber später mehr.</p>
<p>Wenn die WorkflowRuntime so konfiguriert wird, dass sie den SqlWorkflowPersistenceService verwenden soll, wird der aktuelle Status der Workflow Instanzen, welche sich gerade im Wartezustand befinden, in der Datenbank persistiert.</p>
<p>Wann genau wird nun eine Workflow Instanz persisitiert?</p>
<ul>
<li>Wenn sich eine Workflow Instanz sich im &#8220;Idle&#8221; Zustand befindet. Dies ist dann der Fall, wenn sie auf einen externen Event warten muss, oder eine <a href="http://msdn.microsoft.com/en-us/library/system.workflow.activities.delayactivity.aspx">DelayActivity</a> ausgeführt wird.</li>
<li>Wenn eine Workflow Instanz beendet oder terminiert wird.</li>
<li>Wenn innerhalb des Ablaufs eine <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.transactionscopeactivity.aspx">TransactionScopeActivity</a> oder eine <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.compensatabletransactionscopeactivity.aspx">CompensatableTransactionScopeActivity</a> beendet wird.</li>
<li>Wenn eine benutzerdefinierte Aktivität beendet wird, die mit dem <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.persistoncloseattribute.aspx">PersistOnClose Attribut</a> dekoriert wird.</li>
<li>oder natürlich wenn die <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.workflowinstance.unload.aspx">Unload()</a> Methode (oder auch <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.workflowinstance.tryunload.aspx">TryUnload</a>) der Workflow Instanz aufgerufen wird.</li>
</ul>
<p>Die Persistierung kann nebst dem Umstand, dass die Workflow Instanzen einen Neustart des Workflow Hosts überleben, die Skalierbarkeit einer einzelnen WorkflowRuntime erhöhen, da nicht benötigte Workflow Instanzen aus dem Speicher entfernt werden.</p>
<p><img class="alignnone size-full wp-image-59" title="SqlWorkflowPersistenceService" src="http://www.herzam.com/blog/wp-content/uploads/2008/10/workflowpersistence.png" alt="" width="500" height="250" /></p>
<p>Der SqlWorkflowPersistenceService kann via Applikations Konfigurationsfile oder via Code eingesetzt werden.</p>
<h3>Im Konfigurationsfile</h3>
<pre>
<pre class="brush: xml;">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;configuration&gt;

    &lt;configSections&gt;
        &lt;section name=&quot;WorkflowRuntimeConfiguration&quot;
                 type=&quot;System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&quot; /&gt;
    &lt;/configSections&gt;

    &lt;WorkflowRuntimeConfiguration&gt;
        &lt;CommonParameters&gt;
            &lt;add name=&quot;ConnectionString&quot;
                 value=&quot;Data Source=localhost;Initial Catalog=WFStore;User=wf;Password=wf;&quot; /&gt;
        &lt;/CommonParameters&gt;

        &lt;Services&gt;
            &lt;add type=&quot;System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&quot;
                 UnloadOnIdle=&quot;true&quot; /&gt;
        &lt;/Services&gt;

    &lt;/WorkflowRuntimeConfiguration&gt;

&lt;/configuration&gt;</pre>
</pre>
<h3>Im Code</h3>
<pre>
<pre class="brush: csharp;">// Adjust the connection string according to your environment.
var connectionString = &quot;Data Source=localhost;Initial Catalog=WFStore;User=wf;Password=wf;&quot;;

// When true, the service will persist idle workflows. The service default value is false.
bool unloadOnIdle = true;

// Specifies for how long the service will lock the instance record in the database.
// The service default value is TimeSpan.MaxValue.
TimeSpan instanceOwnershipDuration = new TimeSpan(0, 2, 0);

// The service will check for expired timers in the database this often.
// The service default value is 2 minutes
TimeSpan loadingInterval = new TimeSpan(0, 0, 5);           

var persistenceService = new SqlWorkflowPersistenceService(connectionString,
                                                           unloadOnIdle,
                                                           instanceOwnershipDuration,
                                                           loadingInterval);
workflowRuntime.AddService(persistenceService);
</pre>
</pre>
<p>Das angehängte <a href="http://www.herzam.com/blog/wp-content/uploads/2008/10/workflowpersistence.zip">Beispiel Projekt</a> für Visual Studio 2008 zeigt diese beiden Varianten. Sie benötigen zusätzlich zum Beispielprojekt eine SQL Server Datenbank. Eine SQL Server Express Installation auf dem Entwicklungsrechner reicht dabei völlig aus.</p>
<p>Die SQL Skripte für das Anlegen des DB Schemas und der benötigten Stored Procedures findet man unter</p>
<pre>C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN</pre>
<p>Beispiel Projekt: <a href="http://www.herzam.com/blog/wp-content/uploads/2008/10/workflowpersistence.zip">WorkflowPersistence.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2008/10/29/wf-essentials-persistenz-von-workflows-teil-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft kündigt erste .NET 4.0 Features an</title>
		<link>http://www.herzam.com/blog/2008/10/08/microsoft-kundigt-erste-net-40-features-an/</link>
		<comments>http://www.herzam.com/blog/2008/10/08/microsoft-kundigt-erste-net-40-features-an/#comments</comments>
		<pubDate>Wed, 08 Oct 2008 21:14:13 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WCF]]></category>
		<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=67</guid>
		<description><![CDATA[Während der Rest der (Finanz) Welt langsam zu Grunde geht, gibt Microsoft weiter Vollgas.
Normalerweise beschäftige ich mich erst im Detail mit Entwicklungstools und Technologien, wenn sie verfügbar sind. Betas, CTPs, Release Candidates und wie diese Versionen alle heissen, installiere ich schon lange nicht mehr. Die Zeit reicht einfach nicht mehr, in Projekten muss in der [...]]]></description>
			<content:encoded><![CDATA[<p>Während der Rest der (Finanz) Welt langsam zu Grunde geht, gibt Microsoft weiter Vollgas.<br />
Normalerweise beschäftige ich mich erst im Detail mit Entwicklungstools und Technologien, wenn sie verfügbar sind. Betas, CTPs, Release Candidates und wie diese Versionen alle heissen, installiere ich schon lange nicht mehr. Die Zeit reicht einfach nicht mehr, in Projekten muss in der Regel das getan werden, was der Amerikaner lapidar &#8220;get the job done&#8221; nennt.<br />
Ausserdem muss der interessierte .NET Entwickler erst mal die neuen Technologien des .NET 3.5 SP1 verdauen. Dies alles schliesst aber natürlich nicht aus, dass man sich über neue Technologien informiert.</p>
<p>So hat die am 1. Oktober von Microsoft veröffentlichte Meldung &#8220;<a href="http://www.microsoft.com/net/Dublin.aspx">Overview of WF 4.0, WCF 4.0, and Windows Server &#8220;Dublin</a>&#8221; mein Interesse geweckt:</p>
<blockquote><p><em>&#8230;Microsoft is enhancing both the .NET Framework and Windows Server. The company is adding significant functionality to the new version of Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) as part of the .NET Framework 4.0 release, including new messaging and REST capabilities in WCF, new workflow models, seamless integration between WF and WCF to support stateful and conversational services, and a new visual designer. <strong>The company is also introducing a set of enhanced Windows Server capabilities codenamed &#8220;Dublin&#8221; that will offer greater scalability and easier manageability, while extending Internet Information Services (IIS) to provide a standard host for applications that use workflow or communications.</strong> </em></p></blockquote>
<p>Im Dokument, welches <a href="http://download.microsoft.com/download/5/9/B/59B74A2A-245D-4304-802E-E0A0800FACD3/Dublin__NET_4_overview.docx">als Download zur Verfügung</a> steht, fällt mir vor allem die Erwähnung der Dublin genannten Windows Server Technologie auf, welche den IIS erweitern wird. Ein Standard Host für WCF und WF Applikationen wäre eine feine Sache.<br />
Natürlich kann man bereits jetzt mit überschaubarem Aufwand in IIS 6 + 7 die Workflow Services als zustandsorientierte, &#8220;durable&#8221; Dienste anbieten. Funktionen zur Versionierung, Überwachung und Monitoring und zum Deployment von Workflows oder WCF Diensten müssen jedoch noch selber implementiert werden.<br />
Mit Dublin könnte sich der IIS langsam zum Ernst zu nehmenden Applikationsserver mausern. Dies werde ich mal im Auge behalten, mein persönliches Technologie Backlog wird also noch länger&#8230;</p>
<p>An der <a href="http://www.microsoftpdc.com/">PDC2008</a>, die Ende dieses Monats in Los Angeles stattfindet, wird eine CTP Version der drei Technologien abgegeben. Vielleicht mache ich ja da wieder einmal eine Ausnahme und installiere sie.</p>
<p>Ich bin ebenfalls gespannt, ob die für WF 4.0 angekündigten Erweiterungen die Workfow Foundation von einem reinen Toolset für Entwickler zu einer Technologie wandeln wird, die sich vermehrt in Produkten für Endanwender wieder findet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2008/10/08/microsoft-kundigt-erste-net-40-features-an/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aktivierung von XOML Workflow Services</title>
		<link>http://www.herzam.com/blog/2008/10/07/aktivierung-von-xoml-workflow-services/</link>
		<comments>http://www.herzam.com/blog/2008/10/07/aktivierung-von-xoml-workflow-services/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 22:33:26 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WCF]]></category>
		<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=18</guid>
		<description><![CDATA[Vor der Einführung der Workflow Services mit .NET 3.5 war das Leben eines .NET WF Entwicklers etwas einfacher. Man erzeugt einfach irgendwann eine (oder entgegen der weit verbreiteten Annahme auch mehrere) WorkflowRuntime, welche dann verschiedene Overloads der CreateWorkflow() Methode zur Verfügung stellten und so die Workflow Instanzen erzeugen können.
XOML Workflow Aktivierung mit der WorkflowRuntime
Je nachdem, [...]]]></description>
			<content:encoded><![CDATA[<p>Vor der Einführung der Workflow Services mit .NET 3.5 war das Leben eines .NET WF Entwicklers etwas einfacher. Man erzeugt einfach irgendwann eine (oder entgegen der weit verbreiteten Annahme auch mehrere) <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.workflowruntime.aspx">WorkflowRuntime</a>, welche dann verschiedene Overloads der <a href="http://msdn.microsoft.com/en-us/library/system.workflow.runtime.workflowruntime.createworkflow.aspx">CreateWorkflow()</a> Methode zur Verfügung stellten und so die Workflow Instanzen erzeugen können.</p>
<h3>XOML Workflow Aktivierung mit der WorkflowRuntime</h3>
<p>Je nachdem, ob die Workflow Definitionen in einem Assembly oder in XOML vorhanden sind, wählt man den entsprechenden Overload aus.</p>
<p>Für Workflow Definitionen, welche sich in einem Assembly befinden, stehen drei Methoden Overloads zur Verfügung, welche einen Typ als Parameter erwarten:</p>
<pre>
<pre class="brush: csharp;">public WorkflowInstance CreateWorkflow(Type workflowType)

public WorkflowInstance CreateWorkflow(Type workflowType,
                                       Dictionary&lt;string, Object&gt; namedArgumentValues)

public WorkflowInstance CreateWorkflow(Type workflowType,
                                       Dictionary&lt;string, Object&gt; namedArgumentValues,
                                       Guid instanceId)</pre>
</pre>
<p>Wenn die Workflow Definitionen in XOML definiert sind, wählt man einen der anderen drei Overloads aus, welche einen XmlReader als Parameter erwarten. Der zweite XmlReader Parameter nimmt den Inhalt eines .rules files entgegen:</p>
<pre>
<pre class="brush: csharp;">public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader)

public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader,
                                                 XmlReader rulesReader,
                                                 Dictionary&lt;string, Object&gt; namedArgumentValues)

public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader,
                                                 XmlReader rulesReader,
                                                 Dictionary&lt;string, Object&gt; namedArgumentValues,
                                                 Guid instanceId)</pre>
</pre>
<p>XOML basierte Workflows haben einige Vorteile, aber auch konzeptbedingt ein paar Einschränkungen:</p>
<ul>
<li><em>Vorteil</em>: Ein Workflow kann einfacher geändert werden. Dazu muss lediglich die XOML Datei oder wenn die Definition in einer Datenbank gehalten wird, der entsprechende Eintrag angepasst werden.</li>
<li><em>Vorteil</em>: Die Regeln eines Workflows werden abenfalls in einer Datei (.rules) oder einem Record gehalten und können unabhängig vom Workflow aktualisiert werden. In Code basierten Workflows erfordert dies ein erneutes Kompilieren.</li>
<li><em>Vorteil</em>: Die Workflow Definitionen müssen nicht kompiliert werden. Dies erleichtert das Management und die Verwaltung der Workflow Definitionen.</li>
<li><em>Nachteil</em>: In den Workflow Definitionen können keine Properties definiert und keine Event Handler genutzt werden. Dies ist nur mit Code basierten Workflows möglich.</li>
</ul>
<p>Nicht nur die XOML basierten Workflows enthalten meistens auch eigene Aktivitäten, welche in einem anderen Assembly bereitgestellt sind. Während der Entwicklung der Workflows wird lediglich ein Verweis auf diese Assemblies gesetzt, danach können die dort definierten Aktivitäten im Designer genutzt werden.<br />
Wenn dieses Assembly nicht schon in der AppDomain der Workflow Runtime geladen ist, muss dies der WorkflowRuntime mitgeteilt werden. Dies erfolgt über einen <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.compiler.typeprovider.aspx">TypeProvider</a>, welcher der WorkflowRuntime als Service hinzugefügt wird:</p>
<pre>
<pre class="brush: csharp;">WorkflowRuntime workflowRuntime = new WorkflowRuntime();

// Create a type provider for types referenced in the XOML
// which are not referenced by this project
TypeProvider typeProvider = new TypeProvider(workflowRuntime);

// Load referenced assemblies into the type provider
Assembly assembly = Assembly.Load(&quot;assemblyname&quot;);
typeProvider.AddAssembly(assembly);

// OR
// typeProvider.AddAssemblyReference(@&quot;path to the assembly&quot;)

workflowRuntime.AddService(typeProvider);</pre>
</pre>
<p>Wenn dann eine Workflow Instanz mit einem der CreateWorkflow() Overloads erzeugt wird, wird die XOML basierte Workflow Definition validiert. Sollte dabei ein Problem auftreten, wird eine <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.compiler.workflowvalidationfailedexception.aspx">WorkflowValidationFailedException</a> geworfen. Dies ist in der Dokumentation nur unter den Bemerkungen zu finden, die Exception wird nicht in der Liste der anderen Ausnahmen aufgeführt.<br />
Die WorkflowValidationException besitzt ein Property Errors (Collection von <a href="http://msdn.microsoft.com/en-us/library/system.workflow.componentmodel.compiler.validationerror.aspx">ValidationError</a>), welches genau Auskunft über die Probleme bei der Validierung der Workflow Definition gibt:</p>
<pre>
<pre class="brush: csharp;">XmlReader workflowReader = XmlReader.Create(&quot;Workflow1.xoml&quot;);
WorkflowInstance workflowInstance = null;
try
{
    workflowInstance = workflowRuntime.CreateWorkflow(workflowReader);
    workflowInstance.Start();
}
catch (WorkflowValidationFailedException ex)
{
    foreach (ValidationError error in ex.Errors)
    {
        if (string.IsNullOrEmpty(error.PropertyName))
            Console.WriteLine(&quot;Validation error: {0}-{1}&quot;, error.ErrorNumber, error.ErrorText);
        else
            Console.WriteLine(&quot;Validation error for property \&quot;{2}\&quot;: {0}-{1}&quot;, error.ErrorNumber, error.ErrorText, error.PropertyName);
    }
}</pre>
</pre>
<h3>XOML Workflow Aktivierung mit Workflow Services</h3>
<p>Wie funktioniert dies nun, wenn man Workflow Services einsetzt, und ebenfalls XOML basierte Workflows aktivieren möchte? Hier stellt sich auf den ersten Blick eine Art &#8220;<a href="http://de.wikipedia.org/wiki/Henne-Ei-Problem">Huhn-Ei Problem</a>&#8220;. Der TypeProvider soll der WorkflowRuntime als Service hinzugefügt werden, diese existiert aber erst nach dem Erstellen des WorkflowServiceHosts. Man hat auch nicht direkten Zugriff auf die WorkflowRuntime, so dass nicht ohne weiteres ein Service hinzugefügt werden könnte.<br />
Der Weg führt hier über die Verwendung einer eigenen <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.activation.workflowservicehostfactory.aspx">WorkflowServiceHostFactory</a>, welche einen eigenen <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.workflowservicehost.aspx">WorkflowServiceHost</a> erzeugt. Der Konstruktor dieses WorkflowServiceHosts ist sieben Mal überladen (plus einmal protected), dabei gibt es einen <a href="http://msdn.microsoft.com/en-us/library/bb538049.aspx">Konstruktor</a>, welcher nebst dem Stream mit der Workflow Definition einen TypeProvider aufnimmt:</p>
<pre>
<pre class="brush: csharp;">public WorkflowServiceHost(Stream workflowDefinition,
                           Stream ruleDefinition,
                           ITypeProvider typeProvider,
                           params Uri[] baseAddress)</pre>
</pre>
<p>Dieser TypeProvider kann nun wie folgt dem Konstruktor übergeben werden:</p>
<pre>
<pre class="brush: csharp;">TypeProvider typeProvider = new TypeProvider(null);

// Load referenced assemblies into the type provider
Assembly assembly = Assembly.Load(&quot;assemblyname&quot;);
typeProvider.AddAssembly(assembly);

// OR
// typeProvider.AddAssemblyReference(@&quot;path to the assembly&quot;)

Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(&quot;&lt;MyXOML...&gt;&quot;));;
Uri uri = new Uri(&quot;myuri&quot;);

WorkflowServiceHost wfsh = new WorkflowServiceHost(stream, null, typeProvider, uri);</pre>
</pre>
<p>Der Konstruktor wirft nun bei Validierungsproblemen entgegen der Dokumentation ebenfalls eine WorkflowValidationFailedException, was so nicht in der Dokumentation steht, so dass man die Fehler entsprechend behandeln kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2008/10/07/aktivierung-von-xoml-workflow-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Workflow Library != Class Library</title>
		<link>http://www.herzam.com/blog/2008/10/06/workflow-library-class-library/</link>
		<comments>http://www.herzam.com/blog/2008/10/06/workflow-library-class-library/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 17:33:19 +0000</pubDate>
		<dc:creator>kay.herzam</dc:creator>
				<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://www.herzam.com/blog/?p=28</guid>
		<description><![CDATA[In Visual Studio hat man beim Anlegen eines neuen Projektes die Auswahl zwischen vielen verschiedenen Projekttypen.


Wie vielerorts empfohlen, macht es bei Workflow Projekten meistens auch Sinn, die Runtime und die Workflow Definitionen in verschiedenen Assemblies abzulegen. Wenn man dann in einer Workflow Library eine neue Workflow Definition einfügen will, sind für die Items auch entsprechende [...]]]></description>
			<content:encoded><![CDATA[<p>In Visual Studio hat man beim Anlegen eines neuen Projektes die Auswahl zwischen vielen verschiedenen Projekttypen.</p>
<p><img class="alignnone size-full wp-image-30" title="Visual Studio Projekttypen" src="http://www.herzam.com/blog/wp-content/uploads/2008/10/vs_projects.png" alt="Visual Studio Projekttypen" width="535" height="145" /></p>
<p><img class="alignnone size-full wp-image-32" title="Visual Studio WF Projekttypen" src="http://www.herzam.com/blog/wp-content/uploads/2008/10/vs_projects_wf.png" alt="Visual Studio WF Projekttypen" width="535" height="126" /></p>
<p>Wie vielerorts empfohlen, macht es bei Workflow Projekten meistens auch Sinn, die Runtime und die Workflow Definitionen in verschiedenen Assemblies abzulegen. Wenn man dann in einer Workflow Library eine neue Workflow Definition einfügen will, sind für die Items auch entsprechende Vorlagen verfügbar.</p>
<p><img class="alignnone size-full wp-image-36" title="Visual Studio WF Projekt Items" src="http://www.herzam.com/blog/wp-content/uploads/2008/10/vs_projectitems_wf.png" alt="" width="547" height="172" /></p>
<p>Wenn man aber mit einer normalen Class Library loslegt, und dann später gerne darin noch Workflow Definitionen oder eigene Activity Typen unterbringen möchte, funktioniert das nicht. Es reicht offenbar nicht aus, wenn man die entsprechenden Referenzen auf die WF Assemblies setzt.<br />
Der Workflow Designer wirft einem eine nicht allzu aufschlussreiche Fehlermeldung <strong><em>&#8220;The service &#8216;System.Workflow.ComponentModel.Design.IIdentifierCreationService&#8217; must be installed for this operation to succeed. Ensure that this service is available.&#8221;</em></strong> an den Kopf.</p>
<p>Weshalb? Eine Workflow Library ist doch nichts anderes als ein als DLL kompiliertes Assembly.<br />
Man könnte nun ein neues Workflow Library Projekt anlegen, und alle vorhandenen Dateien hinüberziehen. Es gibt aber auch einen anderen Weg.</p>
<p>Beim Vergleich von zwei Projektfiles stellt man folgendes fest: Im ansonsten völlig identischen Projektfile (.csproj)  der Workflow Library findet man die folgenden zusätzlichen Einträge:</p>
<p>In der ersten PropertyGroup:<br />
[Code language="XML"]<ProjectTypeGuids>{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>[/Code]</p>
<p>Zuunterst im Projektfile (Visual Studio 2008):</p>
<p>[Code language="XML"]<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.5\Workflow.Targets" />[/Code]</p>
<p>Für Visual Studio 2005 muss dieser Eintrag auf das .NET 3.0 Framework verweisen:</p>
<p>[Code language="XML"]<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.0\Workflow.Targets" />[/Code]</p>
<p>Man kann das Projektfile ausserhalb von Visual Studio bearbeiten, die IDE wird das Projekt automatisch aktualisieren. Danach stehen auch die WF Projektitems zur Verfügung.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.herzam.com/blog/2008/10/06/workflow-library-class-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
