December 14, 2007

Integration of Google maps / Live maps into CRM 3.0, 4.0

I usually don't write about third party solutions, but this one is getting its place in my blog.

A fellow CRM blogger Wolter Kreun from the Netherlands is developing a freeware plugin (Can it be true? A free and very useful plugin for CRM!!!) that fully integrates Google Maps into Microsoft CRM. Soon it will support MS Live maps.

Haven't tried it, but as far as I have seen on the videos it ROCKS!

EDIT (05. oct. 2009): I just have been informed that the link provided below does not work anymore. But you can use similar integration with virtual earth at: http://www.crmwatcher.com/2006/11/virtual-earth-3d-maps-integration-in.html

So chop chop guys and click on this link: http://mscrmgooglemaps.blogspot.com/

November 28, 2007

Computer playing random music

Another post that has absolutely nothing to do with CRM. I just gotta share this.

On channel 9 I found this link to the Microsoft's KB article:
http://support.microsoft.com/default.aspx?scid=kb;en-us;261186


I'm really thinking of installing Windows 95 and crashing the CUP fan. :)

November 22, 2007

BigInteger

I just have to share this. There is a new type of number in .NET Framework 3.5 called BigInteger [System.Numeric.BigInteger]. What is so cool here? Now you don't have to write special code to work with really really really big numbers. This type is infinite, as big as you want (until you run out of memory).

Read more here.

November 15, 2007

Workflow Changes in CRM 4.0

 

Today I'm going to compare CRM 3.0 and CRM 4.0 workflows:

The web interface is much better designed than the previous one. As I wrote in my previous post, you have more space for description and you can add notes and attach files to the workflows. Moreover you can add a comment to every step of the workflow.

I will say it again. Major improvement was on the workflows in this version. Good job CRM team.

 

Major change has been made is at the basic workflow properties. No more sales process. Now workflow equals sales process. You can select multiple triggering events for a single workflow. These events are:

  • Create
  • Status change
  • Assign
  • Attribute change (update)
  • Delete

Also you can set if this workflow can be run on demand (manually) and / or as a child workflow. For the update, you must choose which attributes trigger the workflow.

image

 

Actions are now called steps. So let's take a look at the actions ... uh err ... steps.

  • Create Activity => Create Record - Not only activities. You can create any entity you want. Set their properties in a form.
    image  image

  • Send E-mail - This action stays. Again more flexible, again a form for new email opens. Templates stay - of course.
  • Create Note => Create Record - Note is actually an entity.
    image
  • Update entity record - Of course, this action stays. In version 3.0 you could update only one attribute, in version 4.0 a form opens and you update any attribute you want.
  • Change status - Not only you can change status to a fixed value, now you can set it to a status of a related entity and even to a status of a previously created task.
  • Assign entity record - Again a major improvement here. Not just to the Manager, User or Queue. You can use any dynamic value of related entities. And there's more: You can assign related records as well. This means that you can reassign previously created task to a different user or a queue.image
  • Post URL - This action was deprecated in version 3.0. There are several reasons I won't talk about them here. No more Post URL for you guys.
  • Run Subprocess => Start Child Workflow - Still here of course, but with improvements. You can start a workflow on any related entities.
  • Stop Workflow - Previously you could define what to do with sub-workflows, but in this version you can just stop it and set the status of the workflow to Completed or Canceled. This is kinda logical, since you are starting subworkflows asynchronously and for other entities.
  • Call assembly - What happened to this guy? It is not in the list anymore... Can anyone help me with this? Can you call an external assembly from the workflow?

Some changes have been made on conditions as well:

  • Check condition - This has been divided into three sub-elements: Check condition (if), Conditional branch (else if) and Default action (else). You can add as many else-ifs as you want. And of course you can check the values from related entities as well.
  • Wait for timer - This has been mover to general wait conditions group.
  • Wait condition - As before you can wait for changes in an entity or created activities. Now you can also check related entities. What is more. You can create more wait conditions, that are similar to the if - else if conditions. This is condition is called Parallel Wait Branch. Now you can wait for different conditions to appear and then execute the first one that is met. The others are ignored.
    Timers - Create a wait condition and select Workflow - Timeout. You can use dynamic values as well.

 

Stages - There is no more difference between Sales process and Workflow rules. You can insert stages into normal workflows as well, although they are not displayed in the entity's status bar.

In Sales processes you can actually look at the workflows that are running on a specific entity and see where they are or what they are waiting for. Notice the green circle.

 image image

 

The same workflow status is available of you open a workflow from the list of workflows in the Settings area and open the workflow list. Every workflow has a list of all instances that were started. Just open an instance and see the status.

 

 

This post has been written solely on my own discovery of CRM 4.0 CTP3. I'm just writing what I discovered. Maybe I missed something. Maybe it is important. Please correct me if I'm wrong.

November 13, 2007

Super duper CRM 4.0 workflows

I must say I'm pleased. A lot has been done on the workflows since version 3.

First of all workflows are now administered in a web client. This had to be done because of CRM Live. But I must say that workflow management is much easier and better.

  • File attachments - now you can attach a file to the workflow. I like it! Now I can attach a Visio diagram to the workflow, maybe some other documentation. There is a lot more space for description. And yes. There are notes too.
  • Availability - You can set the workflow to be run on demand, as well as a sub-workflow.
  • Triggering events - Now workflows support also Delete and Update events. On the Update event you can choose the actual fields that trigger the workflow.
  • Wait for ... otherwise wait for - Did you ever want to branch the workflow based on a condition. Now you can use so called "Paralel Wait Branch" and choose different wait conditions and run the first rule that matches.
  • List of workflows - Open one workflow and see status of all workflows (of this type) that were started.

 

More on workflows later. Now I have to go home.

November 8, 2007

CRM 4.0 - 4 hours after first 5 minutes

To be clear first: I still think that version 4 is a good improvement and it really is what version 3 ought to be.

 

This is a list of impressions after 4 hours of playing with new features:

Many-to-many relationships: Yeah! Finally! Yeah! No more "custom connecting relationships". Relationship editor now divides the relationships in 3 groups: 1-to-many, many-to-1 and many-to-many. Great for entities with a lot of relationships. What is missing are attributes on relations. And I couldn't find a way to start a workflow after assigning a many-to-many relationships. Is it really not possible or did I just miss it? I heard that version 5 will dealt with it.

System-to-system relationships: Yeah again! And not only that! You can have more relationships with the same entity.

Self-referential relationship: Yeah again! You can relate entity to itself.

Multi tenant support: From developers point view I thought it was different. I thought that you could manage two sites at once, but as it seems that multi tenant is almost no different than installing another version of CRM. Sites have different metadata, data, ... I admit that it is practical if you want to host CRM for others, but in my case it is almost the same as before. Oh. Another thing that is better: You can have only one login for multiple organizations. Good post about this if from Mr Dave.

Reporting architecture: Because CRM went from intranet to Internet, there is no direct access to the SQL Report server. This eases up the configuration of the servers because of the impersonation things. Now the CRM server requests the report from the SRS directly with CRMAppPool credentials (e.g. NetworkService) The SQL Report server has add-in called CRM data connector which supports use of filtered views. Then the intermediate report is sent to the CRM server, that displays the report to the user. Now it is a CRM server, who actually allows viewing the report to the user. In version 3 this was a SRS thing. A good post about this is here.

Advanced find: You can actually display columns from related entities! Now you can, let's say, see a phone number of the primary contact in the account list. Way to go!

Mail merge: Finally you don't need outlook to perform a mail merge.

Duplicate checking: I'll say better than nothing, but it could be better :)  You can define fields that are checked if there is a duplicate. You can say how many first or last letters define a duplicate and that's it. MS could actually implement some additional methods. Soundex is actually implemented in SQL server (but it is not very good). In my applications I use the following methods: Double metaphone (sounds-like algorithm better that Soundex) and Levenstein distance (detects typos). Yes. I know that you could implement it by yourself, but hey! Why not get it out of the box? First you could run a double metaphone check and then do a Levenstein difference on the results.

Import data wizard: Now supports most record types. Good thing is that it automatically maps picklist values with display values. No need to know the actual values of the picklist options. You can reuse mappings - a good thing if you have a constant import process in your company. Duplicate detection works when you are importing things. And you get an email when the job ends.

Typing in lookup field: Now this is a neat feature. Now you can type in a value in a lookup field. After losing focus, the value is checked and if the value is OK, it becomes underlined, otherwise it turns to RED. Great functionality.

November 7, 2007

CRM 4.0 - first 5 minutes

I finally had time to take a look at it. The CTP version. Virtual PC image is almost 8GB big and needs slightly more than 1GB of RAM.

Just a quick look for 5 minutes - I'm satisfied.

Workflows are now designed in web client, they support update (you can choose columns) and delete actions.

Duplicate detection - not perfect, but still better than nothing.

User interface - better looking, but still some icons missing

Multiple languages - Cool feature for exporting and importing the published field names, attribute values, ... for translation purposes

Web services - Now you can download WSDL from web client. I'm not sure if this is really useful feature. Or is it?

Will write more later.



Update: David stressed a good point about downloading WSDL in comments: CRM Live

July 30, 2007

Black Google saves energy?

Are web pages with black backgrounds really better for the environment?

http://www.treehugger.com/files/2007/05/black_google_sa.php

June 29, 2007

Adding a reference to external .js file in your form

This code creates a new script element and inserts it into the head of the HTML document that defines the form:

st = document.createElement("<script src='http://<server>/<site>/<filename>.js' language='JavaScript'>");
h = document.getElementsByTagName('head');
h[0].insertAdjacentElement('beforeEnd',st);

Using this method to reference an external script in a production environment is unsupported because it introduces several areas for concern:

  • Transportability
  • External Site
  • Doesn't work offline
  • Future Upgrade issues
  • Possible Timing issues
  • Poor programming practice

June 27, 2007

How to set user's home page?

I got a request that all users of CRM must have their first page set to announcements.

Of course I could write a mail to all users requesting them to change their page in settings page to announcements, but this is a no no way.

So I searched the SQL database and found a user settings table in _MSCRM database. Just set the HomepageSubarea of the table UserSettingsBase to the value 'nav_news'.

So if you want to set announcements as a home page for all users just run the query:

UPDATE [UserSettingsBase] SET [HomepageSubarea] = 'nav_news', [HomepageArea] = 'Home'

Although it works in my installation, this is not a supported change, so you are doing it at your own risk. Do backup the database before messing with it. Just in case.

Renaming a (Customizable) Entity

Just changing the entity display name is not enough. There are more places where the name must be changed to fulfill customer's experience.

Areas that Need to be Changed:

  • Entity Name
  • Entity Form Labels
  • Entity View Names
  • Entity Attribute Display Names
  • System Messages
  • On-line Help Content
  • Reports

Some Areas Cannot be Changed

  • Platform error messages and messages that are displayed in Trace or the Event Log. These messages cannot be edited.
  • Strings added to the ISV configuration file.
  • User Manager component of the Microsoft CRM Deployment
    Manager tool. These strings cannot be edited.
  • Environment Diagnostics Wizard. These strings cannot be edited.

 

Basically changing the entity's name is a seven step process:

Step 1: Change Entity Name.
In the Entity Definition section, change the Name and Plural Name
to the new name.

Step 2: Edit Entity Forms and Views to Display the New Entity
Names.
Change Form Labels and View Names.

Step 3: Change Attribute Display Names for the Entity that is
Renamed.
Use Customize Entities tool to change attribute display names associated with renamed entity. This will update any other parts of the application that uses these attributes, such as View headings.

Step 4: Customize Messages and Strings Associated with
Entity that is Renamed.
Use the Customize Entities tool to customize messages and strings associated with the renamed entity.

Step 5: Publish Changes.
The Name of the entity in the Navigation Pane may not respond to the changes. The information in the SiteMap is cached on the browser. Users may need to press F5 to see the changes.

Step 6: Edit affected help Content to Display the New Entity
Name.
Manually edit entity names in help content and re-deploy the help content.

Step 7: Modify Affected Reports to Display the New Entity
Name.
Manually modify entity names in reports and re-deploy the modified reports.

June 26, 2007

Yay! I passed the exam!

Today I sucessfully passed the Microsoft exam called CRM 3.0 Applications.

The exam number is: CRM-30-423

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.

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