Introduction
In this article we will focus on the task entity of the MS CRM 3.0. Tasks are type of activities. The scnerio is as follows:
Opportunity is created. And a task is created related to this opp. The task is searched and closed using the web services of the CRM.
Opportunity Creation
First we will create an opportunity. This opportunity will be related to an account. For this purpose we will create an opportunity. Sales > Opportunity section of the CRM provides a "New Opportunity" button to create one. When we click new opportunity we will have to fill at least subject and potential customer fields. Following is a snapshot of what we want to achieve:
Getting the Guid of Opportunity
Now we need to find the GUID of the created opportunity. The easiest way to achieve this guid is to double click on the opportunity and make it open in the internet explorer window. As you see window' s address bar shows us "edit.aspx?id={AA96EE8D-F6F0-DB11-BB67-000FEA5F83C3}" the bold part represents the GUID of the opportunity. If you can't see the address bar, press CTRL+N in order to open the opportunity in a new IE window. The new window contains the address bar, so the guid is displayed.
We will use this GUID to create a task activity related to this opportunity. A windows application will be described to create a new task and the task's state will be changed programmatically in the following sections.
Windows Project that will access MS CRM Web services
New Project>Windows Applcaition creates a new windows application. Add the MS CRM web services referance to the project lets us to utilize the CRM SDK to create and change new entities. For a MS CRM installation the web services addresses are as follows:
(1) http://<ServerName>:<PortNumber>/MSCRMServices/2006/CrmService.asmx
(2) http://<ServerName>:<PortNumber>/MSCRMServices/2006/MetadataService.asmx
First web service provides an API that is used programmatically do what we can do with the interface. Second web service provides another API that is used to get information about the entities, such as the name, type, selectable choices, ... etc.
When you add the web referances Visual Studio.Net asks you to give a namespace for that web service. First web service namespace is called CrmWS, and the second is called MetaWS. Our windows application will have the following two lines for utilization of the CrmWS web service.
CrmService crmService = new CrmService(); crmService.Credentials = new System.Net.NetworkCredential( "userName", "P@ssw0rd", "DomainName.Com" );
Above lines connects to the web service using the provided username, password and the domain name. Every user may connect to the web service using the his/her windows user credentials with the following code snippet:
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
Thus every user connects to the web service using its own windows credentials.
Creating the Task Programmatically
We will create a task programmatically using the code below. Attention! Subject and regardingobjectid fields are required fields of the task entity to create. Subject is a string field, we can assign any string to that field. However regardingobjectid is a Lookup that needs to be assigned using a picklist object. Thus we create a Lookup and then Lookup needs to be assigned the type and value. We will associate the task to an existing opportunity thus type="opportunity". Then the value field will hold the Guid of the regarding opportunities Guid that is found before we will write the guid string to a textbox field so Value = new Guid(txtOpportunityGuid.Text.Trim());
Code may be used to assign the required guid information.
task oTask = new task(); // new task object is being created. oTask.subject = "Test Task " + DateTime.Now.ToString(); oTask.regardingobjectid = new Lookup(); oTask.regardingobjectid.type = "opportunity"; oTask.regardingobjectid.Value = new Guid(txtOpportunityGuid.Text.Trim()); Guid guid = crmService.Create(oTask); // create the task. oTask.activityid = new Key(); oTask.activityid.Value = guid; // optional
Using CrmSdkHelper.cs File from the CRM SDK to Make Things Easy
CRM SDK 3.0.6 is the currently the latest sdk's version of the crm. This sdk may be reached from
http://www.microsoft.com/downloads/details.aspx?familyid=9C178B68-3A06-4898-BC83-BD14B74308C5&displaylang=en
crmsdkhelpers.cs is a helper class that is located at
crmsdk-3.0.6\sdk samples\crmsdkhelpers\crmsdkhelpers.cs
This class provides CreateLookup function that makes Lookup assignment code as easy as one line of code.
The codes below
oTask.regardingobjectid = new Lookup(); oTask.regardingobjectid.type = "opportunity"; oTask.regardingobjectid.Value = new Guid(txtOpportunityGuid.Text.Trim());
reduce to the following one line of code:
oTask.regardingobjectid = CrmTypes.CreateLookup( "opportunity", new Guid(txtOpportunityGuid.Text.Trim()) );
How to change Task's State Programmatically?
Thus we have completed to create a task. Now it's time to change the state of the task. When the task is created the state is Open. Closing a task is as simple as the following:
SetStateTaskRequest state = new SetStateTaskRequest(); state.EntityId = oTask.activityid.Value; state.TaskState = TaskState.Completed; state.TaskStatus = -1; // Let MS CRM decide this property; SetStateTaskResponse stateSet = (SetStateTaskResponse) crmService.Execute(state);
The code snippet above changes the task state to Completed, using the SetStateTaskRequest object.
How to Query CRM Database Using CRM Web Services for a Specific Entity?
Now the problem is you don't create a task in order to immediately close it. It remains open for some while. This faces us the search and find problem. How do we search for a particular entity, and update it?
QueryExpression, ConditionExpression, and FilterExpression classes provide this functionality. In our case we will try to find the open and opportunity regarding tasks that we created some time ago. Thus we will have one QueryExpression, this QueryExpression will have two ConditionExpressions.
This query will be executed CrmWS web service. Microsoft recommends all the crm operations must be done using the web services that are available in the CRM installation. However for analogy purposes having two Condition Expressions in a find query is something like the following:
SELECT activityID FROM [FilteredTask] WHERE statuscode=2 and "mailto:regardingobjectid=@oppID">regardingobjectid=@oppID
SQL1) Above select query asks the crm db for retrieving the statuscode open and
regardingobjectID specified . The regardingobjectID is the guid of our opportunity that we created at the begining of this article.
(SQL 1) may be used for fast database access, however Microsoft provides a more general interface to search and find what you are looking for using Web Services of the CRM.
In order to search using CrmWS we will first create a QueryExpression object.
QueryExpression query = new QueryExpression(); query.EntityName = "task";
EntityName is the type of the entity that will be found. In our case we are trying to find the open and specific opportunity related tasks.
Out where clause will contain two conditions:
1) 1) State = Open
2) 2) relatedOpportunityGuid = new Guid(txtOpportunityGuid.Text.Trim());
QueryExpression will containd two ConditionExpressions. Usage of the ConditionExpression object is as follows:
ConditionExpression condition1 = new ConditionExpression(); condition1.AttributeName = "ownerid"; condition1.Operator = ConditionOperator.Equal; condition1.Values = new object[] { new Guid(GuidOfOwner) };
There comes a warning! If you inspect the type of the ownerid field you will see it is an Lookup. However we have the assignment in object array as Guid, NOT Lookup. That's why CrmWS accepts only Guids for lookup fields.
condition1.Values = new object[] { /* Warning: Lookups are queried using Guids, like below!!! */ CrmTypes.CreateOwner("systemuser", new Guid(GuidOfOwner) ) };
Our second conditionExpression will contain the Open State information
ConditionExpression condition2 = new ConditionExpression(); condition2.AttributeName = "statecode"; condition2.Operator = ConditionOperator.Equal; condition2.Values = new object[] { // WARNING: type cast is a must here. (int) TaskState.Open (int) TaskState.Completed };
Below two ConditionExpressions are combined using a FilterExpression that uses the logical operator AND two join two conditions 1 and 2.
FilterExpression childFilter = new FilterExpression(); childFilter.FilterOperator = LogicalOperator.And; childFilter.Conditions = new ConditionExpression[] { condition1, condition2 };
Below code concatenates the two expressions using 'and' operator. After combining these conditions using FilterExpression QueryExpression's Criteria property may be set. QueryExpression may be executed using CrmWS web service's RetrieveMultiple method.
query.Criteria = childFilter; BusinessEntityCollection beReturned = crmService.RetrieveMultiple(query);
Since QueryExpression
method may return any type of businessEntity RetrieveMultiple
method's return value must be assigned to BusinessEntityCollection
object. BusinessEntityCollection
has BusinessEntities
indexer. So in our case we are sure that the returned BusinessEntity is a task. Following code may be written as:
if (beReturned.BusinessEntities.Length > 0) { task oTask = beReturned.BusinessEntities[0] as task; // Or following is valid too: oTask = (task) beReturned[0]; }
By querying the CRM using CrmWS we have found our task now we may change the state of the task and then update the object. As we have seen before, for changing the state of a task we use SetStateTaskRequest
.
SetStateTaskRequest state = new SetStateTaskRequest(); state.EntityId = oTask.activityid.Value; state.TaskState = TaskState.Completed; state.TaskStatus = -1; // Let MS CRM decide this property; SetStateTaskResponse stateSet =(SetStateTaskResponse) crmService.Execute(state);
Finally we have completed to change the state of the task.
Conclusion
In this article i have tried to explain the tricky parts of the CRM web service's search facility. QueryExpression may be used to query the CRM database in or der to reach a specific entity set to process. Also CRM objects may be created using crmsdkhelpers.cs helper classes, this provides short code snippets for setting crm spesific properties.
Hope you understand some key points for the CRM development and Webservices usage for search and change state purposes. Special thanks goes to :
mathematics engineer Seda YILMAZ for inspiration of this article,
computer engineer Buluç ÇELİK for editorial recomendations.
Apprendix A
Be careful when Setting the TaskStatus
When calling the setTaskState method you may get the following error message:
"0x80048408 State code is invalid or state code is valid but status code is invalid for a specified state code. Platform" This is because of inproper assignment of an status code.
"RemarksThe TaskStatus field corresponds to Status Reason in the Microsoft CRM application.
Set this field to -1 to have the platform set the appropriate value for the Microsoft CRM application. " - Quoted from CRM SDK help.