June 4, 2007

How to debug callouts?

First, here are two points, that I would like to express:

  1. I want to debug callouts directly and not with log files.
  2. .NET 2.0 rulez

What now? Callouts use .NET 1.1 and just forget about remote debugging or something like that.

Why not create callouts that use some web service? If you have it installed on the same machine, then you can easily use impersonation etc.

So here's how I do it: I develop a web service that uses CRM web services, test it with normal win32 application and then just insert those 2 lines of code in callouts that call my web service. Use of dynamic entities is very very strongly recommended. You can serialize and deserialize them easily and if the structure of CRM entity model changes, you don't have to worry. Even callouts can have config files.

Web service is running in .NET 2.0 environment and I can debug it freely!

This is how I do it. What about you?

May 18, 2007

How to set or change the owner of the dynamic entity

First things first: The user has to have the rights to change the owner of the entity. I had some problems with the code from SDK. You can find it on two places, but only one works.

If you want to create an entity with the other owner first create the owner:

Owner owner = new Owner();
owner.type = EntityName.systemuser.ToString();
owner.Value = newEntityOwnerId;

Then add the owner to the dynamic entity properties array together with other properties and execute the request:

//Create dynamic entity
DynamicEntity entity = new DynamicEntity();
entity.Name = entityName;
entity.Properties = properties;
//Create request
TargetCreateDynamic myTarget = new TargetCreateDynamic();
myTarget.Entity = entity;
CreateRequest create = new CreateRequest();
create.Target = myTarget;
//Execute the request
CreateResponse response = (CreateResponse)_crmService.Execute(create);

In the response object you have the ID of the newly created entity.


 


If you just want to assign (change) the owner of the use this code:

// Create the SecurityPrincipal object.
SecurityPrincipal assignee = new SecurityPrincipal();

// Set the properties of the SecurityPrincipal object.'
// PrincipalId is a GUID that identifies the user or team
// that will own this record.
assignee.PrincipalId = userId;

// Create the target object for the request.
TargetOwnedDynamic target = new TargetOwnedDynamic();

// Set the properties of the target object'.
// EntityId is a GUID that identifies the dynamic entity
// Entity name is the name of the dynamic entity
// that is being assigned to the user.
target.EntityId = dynamicEntityId;
target.EntityName = dynamicEntityName;

// Create the request object.
AssignRequest assign = new AssignRequest();

// Set the properties of the request object.'
assign.Assignee = assignee;
assign.Target = target;

// Execute the request.
AssignResponse assignResponse = (AssignResponse)_crmService.Execute(assign);

March 19, 2007

Dates in CRM Queries

It's pretty simple to build query expressions from CRM web service. Until you get to dates. You have lots of different ConditionOperator types like On, OnOrAfter, OnOrBefore, ThisWeek, Last7Days etc. But what about the values?

The problem is that you can't add a DateTime object to the values array of the ConditionExpression. If you do you'll most likely get the super duper error "Server was unable to process request". And what is more! The exception data reveals us the intriguing reason: "Invalid argument." DOH!

You have to pass the DateTime as string and parse it with "s" parameter. This is language-neutral and the CRM Server should be able to parse it regardless of the regional settings.

Solution:

ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "new_duedate";
condition.Operator = ConditionOperator.OnOrAfter;
condition.Values = new string[] { DateTime.Now.ToString("s") };

 


AND YES! IT IS FINALLY SNOWING OUTSIDE!!!!!

March 13, 2007

How to copy an annotation

To copy notes wit or without attachments I have prepared this snippet.

//Copy attributes
annotation newAnnotation = new annotation();
newAnnotation.langid = sourceAnnotation.langid;
newAnnotation.notetext = sourceAnnotation.notetext;
newAnnotation.subject = sourceAnnotation.subject;
newAnnotation.objecttypecode = new EntityNameReference();
newAnnotation.objecttypecode.Value = destinationEntityName;

//Set the destination entity ID
newAnnotation.objectid = new Lookup();
newAnnotation.objectid.type = destinationEntityName;
newAnnotation.objectid.Value = destinationEntityId;

//Create annotation
Guid newAnnotationId = _crmService.Create(newAnnotation);
if (sourceAnnotation.isdocument.Value)
{
byte[] data = GetAnnotationAttachment(sourceAnnotation.annotationid.Value);
string base64data = System.Convert.ToBase64String(data);
AddAttachment(newAnnotationId, base64data, sourceAnnotation.mimetype, sourceAnnotation.filename);
}

The code for GetAnnotationAttachment is here.

The code for AddAttachment is here.

How to add an attachment

To upload an attachment I have prepared the following function:

private void AddAttachment(Guid parentAnntotationId, string attachmentBase64Data, string mimeType, string attachmentFileName)
{
UploadFromBase64DataAnnotationRequest upload = new UploadFromBase64DataAnnotationRequest();
upload.AnnotationId = parentAnntotationId;
upload.FileName = attachmentFileName;
upload.MimeType = mimeType;
upload.Base64Data = attachmentBase64Data;

_crmService.Execute(upload);
}

How to get mime type? Previous post

Finding the file's mime type (MimeType)

I was looking for this for some time now. Simple, but beautiful solution:

public string GetMimeType(byte[] fileBytes)
{
try
{
ContentInfo info = new ContentInfo(fileBytes);
return info.ContentType.Value;
}
catch
{
return "application/octet-stream";
}
}

How to get (download) an attachment

If you want to get an attachment from a note, then you have to get it using HTTP call. The following function returns an array of bytes that can be saved into a stream or you can convert it to Base64String (System.Convert.ToBase64String(myBytes)) if you want to save it again in CRM.

private byte[] GetAnnotationAttachment(Guid annotationId)
{
Guid attachid = annotationId;
int objecttypecode = 5;
//Annotation attachment OTC
string url = _serverUrl + "Activities/Attachment/download.aspx?AttachmentType=" + objecttypecode.ToString() + "&AttachmentId=" + attachid.ToString();
System.Net.WebClient myWebClient = new System.Net.WebClient();
myWebClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
return myWebClient.DownloadData(url);
}

March 12, 2007

HTTP status 401: Unauthorized error

I wrote some callouts that use CRM web service for reading some additional data.

Man I was furious! On the test system it worked, on the production I got the 401 unauthorized error.

I Goggled a bit and then I tried the simplest solution:

  • Comment out the code: crmWebService.PreAuthenticate = true;

And it worked!

Guess what? This code was copied from Microsoft CRM 3.0 SDK.

Callout setting files

I created a callout, but I wanted to have an additional XML settings file that can be changed on live system without restarting all necessary services.

You have two options:

  • You can hardcode the full path to the file (bad solution)
  • You can read the file from the "running folder"

The default running folder is:
%windows install folder%/system32/inetsrv.

So put your XML file in this folder and read it from the callout using:

XmlDocument settings = new XmlDocument();
settings.Load(Path.GetFullPath("CalloutSettings.xml"));

That's it folks!

January 11, 2007

Optimizing the Performance of Microsoft Dynamics CRM 3.0 White Paper

Yesterday Microsoft published a white paper that describes how to optimize the performance of your CRM 3.0 system.

This white paper discusses how to optimize the performance of your Microsoft Dynamics CRM 3.0 system. You’ll learn how re-indexing, de-fragmenting, and regularly maintaining your databases can increase the speed with which Microsoft Dynamics CRM accesses your data. The white paper includes more advanced techniques as well, such as improving report performance, configuring Microsoft SQL Server, and optimizing Microsoft Internet Information Services and the .NET Framework. You’ll find complete SQL scripts that you can copy and use immediately. Finally, you’ll find links to additional information and resources, such as performance enhancements, security updates, Knowledge Base articles, and related Microsoft Dynamics CRM documentation.