Microsoft Dynamics CRM 4.0 | Workflow Assembly

 

Microsoft CRM 4.0 Workflows helfen bei wirklich vielen Dingen. Besonders die Tatsache, dass sich zusätzliche Business-Logik in die Workflow-Engine integrieren lässt, macht die Flexibilität des Systems aus. So finden sich einige Beispiele für Workflow-Assembly über den Suchbegriff "Custom Workflow Assembly" hier im Netz, aber auch das aktuelle Microsoft CRM 4.0 SDK hält einige Beispiele für den engagierten Programmierer bereit.

Eigentlich in all meinen Projekten findet sich mindestens eine solche Workflow Assembly, um die Funktionsfähigkeit der Workflow-Engine zu erweitern. Ein typisches Beispiel aus meiner Arbeit möchte ich Euch heute hier vorstellen:

Aus der Systementität wird nach einem Suchbegriff (in meinem Fall ein Userlogin) ein bestimmter CRM Benutzer gesucht, um einen Datensatz diesem Anwender / dieser Anwenderin zuzuweisen. Was braucht es hierzu? Ich gehe mal Schritt für Schritt auf die einzelnen Passagen ein, damit diejenigen unter Euch, die ebenfalls in diese Programmierung einsteigen wollen, die erforderlichen Punkte nachvollziehen können.

Schritt 1: Wir erstellen uns in VS2005 oder VS2008 eine neues C# Klassenprojekt und fügen anschließend einige Verweise dem Projekt hinzu. Nicht zu vergessen die beiden .dlls aus dem CrmSDK.

Schritt 2: Wir sprechen die entsprechenden Verweise in unserem Code an:

using System;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk.Query;
using System.Workflow.Runtime;
using System.Data;
using System.Xml;
using System.Xml.Linq;

 

Schritt 3: Wir deklarieren unseren "namespace" und bestimmen, unter welchem Namen die Assembly in den Workflow "Schritten" zu finden sein wird. Und dann geht es auch schon daran die Input-Variable zu deklarieren.

namespace FindUserbySearchstring
{
    [CrmWorkflowActivity("Finde Systemuser zu Suchbegriff")]
 
    public class MatchUsernameBy :
 
    System.Workflow.Activities.SequenceActivity
    {
        // Input property
        public static DependencyProperty senderProperty = DependencyProperty.Register("sender", typeof(string), typeof(MatchUsernameBy));
 
        [CrmInput("Suchbegriff")]
 
        public string sender
        {
            get
            {
                return (string)base.GetValue(senderProperty);
            }
            set
            {
                base.SetValue(senderProperty, value);
            }
        }

 

Schritt 4: Wo ein Input, da auch ein Output. Also deklarieren wir auch hier unseren Output, damit an den Workflow der entsprechend gefundene Wert zurückgeliefert werden kann.

// Output property
 
        public static DependencyProperty sysuserIdProperty = DependencyProperty.Register("sysuserId", typeof(Lookup), typeof(MatchUsernameBy));
 
        [CrmOutput("sysuserId")]
        [CrmReferenceTarget("systemuser")]
 
        public Lookup sysuserId
        {
            get
            {
                return (Lookup)base.GetValue(sysuserIdProperty);
            }
            set
            {
                base.SetValue(sysuserIdProperty, value);
            }
        }

 

Schritt 5: Nun bauen wir unsere Logik auf, mit der die Routine unsere Input-Variable nutzt, um damit in der Entität "Systemuser" in einem Feld danach zu suchen. Die Suchroutine arbeitet hier mit RetrieveMultiple, was rein theoretisch mehrere Treffer zurückliefert. In unserer "Foreach"-Schleife holen wir uns jedoch nur den 1. zurückgelieferten Wert. Da in unserem Beispiel davon ausgegangen wird, das keine 2 User ein und denselben "Userlogin" in der Systementität aufweisen, wird die Suchroutine auch nur einen Wert zurückliefern.

private Guid MatchSystemuserByUserLogin(ICrmService crmService, string fromSearchString)
        {
 
            // Retrieve Systemuser from Entity with "fromSearchString"
 
 
            QueryByAttribute query = new QueryByAttribute();
            query.ColumnSet = new AllColumns();
            query.EntityName = EntityName.systemuser.ToString();
            query.Attributes = new string[] { "new_userlogin" };
            query.Values = new object[] { fromSearchString, };
 
 
            RetrieveMultipleRequest retrieveMultipleRequest = new RetrieveMultipleRequest();
            retrieveMultipleRequest.Query = query;
            retrieveMultipleRequest.ReturnDynamicEntities = true;
 
            RetrieveMultipleResponse retrieveMultipleResponse = (RetrieveMultipleResponse)crmService.Execute(retrieveMultipleRequest);
            BusinessEntityCollection retrieved = crmService.RetrieveMultiple(query);
 
            Guid systemuserId = Guid.Empty;
 
            foreach (BusinessEntity busEntity in retrieveMultipleResponse.BusinessEntityCollection.BusinessEntities)
            {
                // Pick the first systemuserid.
                systemuserId = ((Key)((DynamicEntity)busEntity)["systemuserid"]).Value;
                break;
            }
 
            return systemuserId;
 
        }

 

Schritt 6: Nun müssen wir nur noch dafür sorgen, dass unser Workflow mit dem zurückgelieferten Wert (systemuserId) etwas anfangen kann. Und damit wir überhaupt die Recherche durchführen können, müssen wir noch den CrmService ansprechen.

protected override System.Workflow.ComponentModel.ActivityExecutionStatus Execute(System.Workflow.ComponentModel.ActivityExecutionContext executionContext)
        {
 
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
 
            IWorkflowContext context = contextService.Context;
 
            // Obtain IcrmService so we can call into CRM SDK to retrieve accounts
 
            ICrmService crmService = context.CreateCrmService();
 
            // this.sender property will have the User Login that needs to be matched.
 
            Guid sysuserId = MatchSystemuserByUserLogin(crmService, this.sender);
 
            // Set the sysuserId output property to return this data
 
            // back to the calling workflow
 
            this.sysuserId = new Lookup("systemuserid", sysuserId);
 
            return ActivityExecutionStatus.Closed;
 
        }
 
    }
 
}

 

Schritt 7: Der gesamte Code wird kompiliert und mit Hilfe des Plugin-Registration-Tools (Bestandteil des SDK) registriert. Zuvor könnte man das Projekt auch noch mit einem Schlüssel versehen und es mit einem Passwort schützen. Doch darauf verzichte ich für dieses Beispiel.

Schritt 8: Nachdem die Assembly registriert wurde, steht uns bei der Erstellung der Workflows ein Schritt "Finde Systemuser zu Suchbegriff" zur Verfügung. Jetzt könnte man also Beispielsweise ein am Firmendatensatz "hängenden" User-Login als Suchbegriff nehmen und diesen mit dem Zusatzfeld "new_userlogin" in der Systementität hin abgleichen. Mit dem Resultat ließe sich der Firmendatensatz neu zuweisen.

Mehr braucht es nicht, probiert es selbst…

Wie immer hoffe ich, dass dieser Tipp dem ein oder anderen von Euch helfen wird, sich an das Thema Assembly Programmierung für CRM Workflows heran zu trauen. Ich freue mich auf Feedback.

 

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s