Dynamics CRM in the Field

Information from the Microsoft Dynamics CRM PFE team working in the field

Using a Console App to Fire a CRM 2011 Workflow

Using a Console App to Fire a CRM 2011 Workflow

Rate This
  • Comments 3

I'm not a developer - don't even play one on TV - but sometimes our internal CRM implementation needs some functionality and I'm able to cobble enough code from other places to make something work.  Since I hadn't seen anything out there for this particular use case, I thought it was worthwhile to share more broadly.

BUSINESS PROBLEM
We have had challenges at time with the waiting workflow state and the overhead associated with having all of our contracts in a waiting state, to "wait" to be marked historical automatically when the contract ends.  To avoid this, we wanted to put something in place that can run daily to check to see which contracts are about to expire or have expired.  Since I'm not really a developer, I wanted to put as much of the code in a workflow as possible, and leave the console app simple - it just reads in records for an entity and fires the appropriate workflow.  The workflow handles the sending of emails, updating records, etc.

DEVELOPMENT STEPS
These instructions may be fairly basic, but it was the exact instructions I needed in order to make this work.  These steps assume that you have Visual Studio 2010 installed on your machine, the CRM SDK and .NET 4.0.

  1. Launch Visual Studio 2010 and click on New Project
  1. Select Visual C# and choose Console Application.  Put the application in the directory of your choosing and give it an appropriate name (TriggerCRMWorkflow)
  1. Once your project is created, you will have a solution with a Solution Explorer window open on the right-hand side of the page.  Add certain references that will be required in order for your code to run successfully.  In Solution Explorer under References, right-click and choose "Add Reference" for each of these references which are likely not loaded automatically by Visual Studio:
    1. System.Net - add via the .NET tab
    1. System.ServiceModel - add via the .NET tab
    1. System.Runtime.Serialization - add via the .NET tab
    1. Microsoft.Xrm.Sdk - if you have installed the SDK on your machine, browse to the \SDK\bin folder (microsoft.xrm.sdk.dll)
    1. Microsoft.Crm.Sdk.Proxy - if you have installed the SDK on your machine, browse to the \SDK\bin folder (microsoft.crm.sdk.proxy.dll)
  1. Once the references are added to the solution, double-click on Program.cs to see your code.  Make sure the following Using statements are at the top of this file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System.ServiceModel.Description;
using System.Net;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

  1. In this example, we will connect directly to the CRM service for a particular organization, so the code below shows how to make that connection (edit your variables with your appropriate server name and organization name).  This also assumes that the code will be run under the calling user's credentials.

   

ClientCredentials Credentials = new ClientCredentials();

     Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;

     string servername = "SERVERNAME";

    string orgname = "ORGANIZATION";

 Uri OrganizationUri = new Uri("http://" + servername + "/" + orgname + "/XRMServices/2011/Organization.svc");

Uri HomeRealmUri = null;

  1. Use this statement to provide the execution context for whatever function you'd like to perform with the CRM SDK

using (OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(OrganizationUri, HomeRealmUri, Credentials, null))

  1. In this example, I'm going to fetch all of the records in a custom entity "PFE Contract" where the contract status is Active (1).  To do this, I'm going to use FetchXML and create the query in an XML format, calling the entity and then listing the attributes I want to return when I execute the query running the RetrieveMultiple command (coming up soon):

    string getContracts = @"

      <fetch mapping='logical'>

       <entity name='new_pfecontract'>

        <attribute name='new_name'/>

        <attribute name='new_pfecontractid' />

        <filter type='and'>

         <condition attribute='new_status' operator='eq' value='1' />

        </filter>

       </entity>

      </fetch> ";

  1. Now that I've got my FetchXML, I'm going to create a FetchExpression and run the RetrieveMultiple command so I can use all the rows from that query.

FetchExpression fe = new FetchExpression(getContracts);

EntityCollection results = serviceProxy.RetrieveMultiple(fe);

  1. The purpose of this console app is to run a workflow on each record returned from the above query, so I need to prepare the variables I'll be passing to the ExecuteWorkflowRequest statement.  So I need to instantiate those two variables where I'll store the GUID for the workflow I'm calling and the record from each PFE Contract.  To find the GUID of your workflow, open up the workflow in the Web editor and look at the URL - copy the part in Red out of the URL string: http://<servername>/<orgname>/sfa/workflow/edit.aspx?id=%7b93714522-439F-48D0-8148-B619436E011C%7d

var _workflowId = new Guid("fb126b05-ddc3-4f8e-8e1f-54d1e0b5fe8e");

Guid _pfecontractId;

  1. Now getting back to the records that were returned, I'm going to use a "for" statement to cycle through each record and perform an action.  In this case, I'm going to run a CRM workflow on each record that's returned.

foreach (var c in results.Entities)

{

if(c.Attributes.Contains("new_name"))

{

//System.Console.WriteLine(c.Attributes["new_name"]);

//System.Console.WriteLine(c.Attributes["new_pfecontractid"]);

 

string contractid = c.Attributes["new_pfecontractid"].ToString();

_pfecontractId = new Guid(contractid);

 // Create an ExecuteWorkflow request.

ExecuteWorkflowRequest request = new ExecuteWorkflowRequest()

{

WorkflowId = _workflowId, EntityId = _pfecontractId

};

 // Execute the workflow.

ExecuteWorkflowResponse response =

(ExecuteWorkflowResponse)serviceProxy.Execute(request);

 // System.Console.WriteLine("Successfully executed workflow");

}

  1. You can see the commented "System.Console.WriteLine" code elements are used to test the code before it's completed.  Before you try to execute the workflow, I recommend you test the code by writing the attributes out and commenting out the workflow. 
  1. Before you consider your application finished, make sure to check if any IntelliSense is showing that there's a problem with any code.  Once that is all taken care of, you can Build the solution by going to the Visual Studio menu and clicking Build > Build TriggerCRMWorkflow.  Once you build your solution, you may receive errors if the solution had incorrect code.  If it's successful, you'll see a small text in the bottom left hand corner of Visual Studio that says "Build Successful".
  2. Once your build is successful, you can run your console app.  Do this first in Visual Studio by clicking the Green Arrow near the Build menu (or click F5).  The app is now cycling through your records and performing its actions.  You should see a console window open on the screen while the app runs.

* If you received a build error related to the Target .NET Framework, you may have to change your project's default framework.  To do that, you'll need to open the Project properties and change the value to .NET Framework 4:

 

  • Please keep in mind that this will only work on the first 5000 rows. In order to loop through all records, you need to create a loop on the retrieve using the paging cookie.

  • Great Article ..

  • NullReferenceException always in EntityCollection

Page 1 of 1 (3 items)
Leave a Comment
  • Please add 3 and 1 and type the answer here:
  • Post