Monday, January 14, 2008

Create Relationships in CRM 3.0 programmatically

Ever have the need to programmatically create a relationship between contacts or between a contact and an account?

I stumbled on this problem when a client requested that I import relationships from the legacy ACT! 6 database.
The field where [Lead source] and [referred by].

The relationship entity schema name is "customerrelationship".
The entity has the following important attributes:

Attribute Description
customerroledescription/partnerroledescription The description for the relationship
customerid/partnerid The Lookup for the customer and partner respectively
customerroleid/partnerroleid The lookup for the relationship role (This can be configured in the Settings section of CRM)


It is that simple, create your class than call the service.create method of the CRM 3.0 to create the relationship.

Have a great day.

Oshri Cohen

Labels: , , ,

Monday, January 7, 2008

FetchXML Query Examples

For those who don't know what Fetch in CRM 3.0 is I will briefly explain it.

Fetch is a method that CRM 3.0 uses to read data through it's API.
It is very easy to write a Fetch query.

Instead of writing a long tutorial I will try to explain how to use Fetch by examples.

The basic Fetch format:
<fetch mapping='logical'>
   <entity name='[Schema entity name]'>
      <all-attributes/>
      <filter type='and' or type='or'>
        <condition attribute='[Attribute name Case sensitive]' operator='eq' <--equals value='111038-18938-0...'/> 
     </filter>
   </entity>
</fetch>

Example 1: Fetch contacts for a particular owner
<fetch mapping='logical'>
   <entity name='contact'>
      <all-attributes/>
      <filter type='and' >
        <condition attribute='ownerid' operator='eq' value='111038-18938-0...'/> 
     </filter>
   </entity>
</fetch>
This query will retrieve the contact list for a particular owner.

Example 2: Activities for an owner that are due date
<fetch mapping='logical'>
   <entity name='activitypointer'>
      <all-attributes/>
      <filter type='and' >
        <condition attribute='ownerid' operator='eq' value='111038-18938-0...'/> 
       <condition attribute='scheduleend' operator='today'/>
     </filter>
   </entity>
</fetch>
This query gets the activities for a particular owner that are due today, the keyword today is understood by CRM 3.0 as the day of execution.

This will help you get your feet wet using Fetch.
It is easy to learn, especially with the use of an application called FetchXML Builder.

***If anyone knows the link to the website that hosts the FetchXML Builder, please send it to me.***

P.S: I accept private questions feel free to leave me a comment on the blog, I usually answer them quickly.

Have a great day.
Oshri Cohen

Labels: , , , , ,

Thursday, December 20, 2007

How to download and save email activity attachments from CRM 3.0

Ever want to get an attachment from an Email in CRM 3.0?
Well you are in luck, here is how to do it.

1) Use fetchxml to get all attachments from a specific email or for any other emails matching your query, for simplicity sake, the fetch xml will be for a single email.

2) Email attachments will be returned in the result set complete with the contents of the original file in Base64 format, you will have to decode it.

Use the following method to get a nodelist for any query

static XmlNodeList GetFetchResult(string fetchXML)

{

CrmService service = new CrmService();

service.Credentials = new System.Net.NetworkCredential("CRMAdmin", "Pa$$w0rd", "ADVWORKS");

string fetch = fetchXML;

string ret = service.Fetch(fetch);

System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();

xdoc.LoadXml(ret);

System.Xml.XmlNodeList list = xdoc.SelectNodes("resultset/result");

xdoc = null;

return list;

}

All email attachments are kept in the entity "ActivityMimeAttachment", here is the xml for the query.

Replace the "activityID" value with any email value or add your conditions.

<fetch mapping='logical'>
<entity name='activitymimeattachment'>
<all-attributes/>
<filter type='and'>
<condition attribute='activityid' operator='eq' value='{A9B5DD63-D59E-DC11-920F-0003FF612152}'/>
</filter>
</entity>
</fetch>
Call the GetFetchResult into a new Nodelist and loop through it.
XmlNodeList list = GetFetchResult("");

if (list.Count > 0)

{

foreach (XmlNode n in list)

{
string body = n["body"].InnerText;
string decoded = base64Decode(body);

}

}

Use this method to convert the body of the email into it's original format.

static string base64Decode(string data)

{

try

{

System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();

System.Text.Decoder utf8Decode = encoder.GetDecoder();

byte[] todecode_byte = Convert.FromBase64String(data);

int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);

char[] decoded_char = new char[charCount];

utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);

string result = new String(decoded_char);

return result;

}

catch (Exception e)

{

throw new Exception("Error in base64Decode" + e.Message);

}

}
From here you can save the file, the filename is in the "filename" attribute of the result set.
Have a great day.
Oshri Cohen

Labels: , , , , , , , ,

Wednesday, December 19, 2007

Get started using FetchXML

Ever want to get started using FetchXML?

Well use this simple method to retrieve a node list with the results.
By providing this method with any fetchxml query it will return the appropriate nodelist.

   static XmlNodeList GetFetchResult(string fetchXML)
{
CrmService service = new CrmService();
service.Credentials = new System.Net.NetworkCredential("CRMAdmin", "Pa$$w0rd", "ADVWORKS");
//DataSet ds = GetData("select * from systemuser ");
string fetch = fetchXML;
string ret = service.Fetch(fetch);
System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();
xdoc.LoadXml(ret);
System.Xml.XmlNodeList list = xdoc.SelectNodes("resultset/result");
xdoc = null;
return list;

}


Have a great day!

Oshri Cohen


Labels: , , , , ,

Monday, December 3, 2007

How to attach a file to any CRM 3.0 entity

Introduction

Microsoft CRM 3.0 has the ability to store files as attachments for any entity that supports notes.
This article is a guide to how an article would be attached to a note (otherwise known as an annotation within CRM 3.0).
To understand how to attach a file in CRM 3.0, you need to understand CRM's file attachment architecture.
Almost all entities in the system can have notes, when manually attaching a file through the UI a reference to the file shows up in the notes section.
That is because CRM holds all file attachments that are not for activities as notes.
You will have to do the following:
1) Create or retrieve the entity that you want the file to be attached to.
2) Read the file steam and encode it to a Base64 string.
3) Create the UploadFromBase64DataAnnotationRequest object and execute it.

Using the code

I will first explain the steps and code required to attach a file to any entity.
Let's assume you want to attach a PDF file to a client's contact record in CRM programmatically.
First you will need the contactID guid of the target contact record.
Secondly, you will need to create a new note.
CRM attaches all files that are NOT activity attachments as notes.
To create a note use the following block of code:

CrmService myCRMService = new CrmService();
myCRMService.Credentials = System.Net.CredentialCache.DefaultCredentials;

//#1
annotation note = new annotation();
note.subject = "my attachment";

//#2
note.ownerid = new Owner();
note.ownerid.type = "systemuser";
note.ownerid.Value = new Guid("000-000-0000"); <-- don't use this value
note.ownerid.name = "Administrator";

//#3
note.objectid = new Lookup();
note.objectid.name = "contact name";
note.objectid.type = EntityName.contact.ToString(); <-- use the correct type
note.objectid.Value = new Guid("000-000-0000-000"); <-- use the contact's guid

//#4
note.objecttypecode = new EntityNameReference();
note.objecttypecode.Value = EntityName.contact.ToString();

Guid newNoteID = new Guid();
newNoteID = myCRMService.Create(t);

#1
A note entity is known in CRM as an Annotation.

#2
Like all other user owned entities in CRM you need to assign an owner, in this example i used the system administrator.

#3
The annotation class has what is known as the objectid it is a property of type Lookup().
You need to tell CRM where you want the note attached, by providing the name, ID and type of the target entity.

In this case I used a contact as my target.
The note.objectid.type is very important it tells CRM the type of the target entity.
In order to help reduce human error the CRM API developers included a reference Enum class called EntityName, this enum is updated if you create new custom entities and publish them.

#4
The objecttypecode property is a required field, without it CRM will throw an exception.
You have to give the target entity's type, i recommend using the EntityName Enum to prevent any errors.
This may seem a bit redundant, I am not sure why we have to set the type again, if anyone knows please let me know.

Finally you will need to create the note to get the a Guid.
The next step is to actually upload a file:

//#1
FileInfo pointer = new FileInfo( "c:/test.pdf");
FileStream fileStream = pointer.OpenRead();
byte[] byteData = new byte[(int)fileStream.Length];
fileStream.Read(byteData, 0, (int)fileStream.Length);
string encodedData = System.Convert.ToBase64String(byteData);

//#2
fileStream.Flush();
fileStream.Close();

//#3
UploadFromBase64DataAnnotationRequest upload = new UploadFromBase64DataAnnotationRequest();
upload.AnnotationId = newNoteID;
upload.FileName = "test.pdf";

//#4
upload.MimeType = "application/pdf";

//#5
upload.Base64Data = encodedData;

//#6
UploadFromBase64DataAnnotationResponse uploaded = (UploadFromBase64DataAnnotationResponse)myCRMService.Execute(upload);

#1
You will need two classes the FileInfo class and the FileStream class.

The FileInfo, because you can easily get the size of the file and the extension which will be needed at point #4 to identify the mimetype.
The FileStream class because you will need to convert the file to a base64 string (not really sure why).

#2
I don't need to state this but make sure to close the filestream.

#3
If you want to upload a file to an annotation you will need to use the UploadFromBase64DataAnnotationRequest class, this class is used ONLY for annotation attachments.

The class will accept the ID of the annotation, you will also have to provide the filename.

#4
The sticky point here is specifying the MimeType, this took me forever because you have to be very specific otherwise CRM will not deliver the file correctly when you want to upload it.
I used the following MimeType list to search for the correct value based on the file extension.

#5
In this step you provide the upload request with the encoded Base64 string.

#6
Finally you upload the file by calling the crmService.Execute method and passing it the upload request.

If you have a large file to upload and many other tasks to perform afterwards, i suggest uploading the file Asynchroniously by calling the crmService.ExecuteAsync method.

I hope you this article has helped you.

Labels: , , , , ,