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.

January 9, 2007

Best Practices for Better Performance from Your Custom Code

I found this article in the official Microsoft Dynamics CRM Team Blog:

It points out some things you should keep in mind when creating a custom code.

http://blogs.msdn.com/crm/archive/2007/01/09/best-practices-for-better-performance-from-your-custom-code.aspx

December 20, 2006

How to change status of the dynamic entity?

This feature is not well documented, so I decided to describe it here:

//Create a request object
SetStateDynamicEntityRequest stateRequest = new SetStateDynamicEntityRequest();

//Use string and not integer value for state. (For Lead use "Qualified" and not 2)
stateRequest.State = newState;
state
Request.Status = newStatus;

//Create an instance of the entity
Moniker m = new Moniker();
m.Id = entityId;
m.Name = myDynamicEntity.Name;

//Set the state. Well... set the entity.
state
Request.Entity = m;

//Send the request
SetStateDynamicEntityResponse res = (SetStateDynamicEntityResponse)_crmService.Execute(state
Request);


Pretty simple, huh?

For a complete list of state and status values take a look in the SDK. You should find an enumeration for every built-in entity state together with allowed status reasons.
The name should be State Enumeration (LeadState Enumeration). Custom entities state is "Active" or "Inactive".


Of course you can use strong typed entities: (but I prefer dynamic ones)

lead myLead = new lead();
Status statusCode = new Status();
statusCode.Value = 3;
myLead.statecode = LeadState.Qualified;
myLead.statuscode = statusCode;

December 7, 2006

CRM on PlayStation Portable

Now you can tell your boss that you use your PSP for work and not for fun.