Wednesday, July 30, 2008

Microsoft CRM 4.0 development for on-premise, internet facing and multi tenancy

The last couple of weeks I spend to make our product "full crm 4.0 compliant". The foundation for our product was build on crm 3.0 wich was already succesfully "migrated" to crm 4.0 (i.e. all the code still accesses the 2006 (3.0) webservices). But now the product really is fully 4.0 compliant. So, what does that mean:

  • the 2006 (3.0) webservices are not used anymore
  • all callouts are replaced by plugins
  • support for both on-premise and internet facing deployments
  • support for multi tenancy
  • support for live deployment is postponed until that's available in europe
  • (full) support for the offline client is also postponed (my personal opinion is that "always online" has the future, which is made possible now with internet facing deployment)
In the coming period I want to write a number of articles about all the strugles (and solutions) we had to make it all work. Among the subjects will be:
  • what is the difference between on-premise and internet facing deployment and how does that affect your code (and other customizations)?
  • what is multi tenancy, how did Microsoft implement it in crm 4.0 and how does that affect your code (and other customizations)?
  • the beauty and pain of plugins
  • a solution for accessing filtered views in internet facing deployments
  • good resources on the web


So, keep an eye on this blog. It will be updated soon!

Monday, February 11, 2008

ACI Gold Certified Partner

Visit ACI Website (Dutch)
As of last week, the company I work for is a Microsoft Gold Certified Partner.
In relatively short time (less then one year) we achieved two competencies, a certified Microsoft CRM ISV solution and some great customer references. Yes, I can say that I am proud!

Click on the logo to visit our company's website (Dutch).

Thursday, January 24, 2008

My 1st impression of migrating to Microsoft Dynamics CRM 4.0

The last couple of days I started with investigating how to make our Microsoft Dynamics CRM 3.0 add-on(s) ready for CRM 4.0. Until now I didn't have the time to really dive into CRM 4.0 and I had only seen some demo's and read a number of articles about it. The knowledge I had made me quite optimistic about "migrating" our solution(s). But I have to confess: after studying the SDK 4.0 and playing around with some things, I'm afraid I have to change my estimates.
Untill now I encountered the following issues:

  • existing code (i.e, all of our code) which makes use of the crm webservices does not work without recompiling against the new webservices;

  • recompiling against the new webservices forces you to change your code (e.g. datatype crmFloat has changed);

  • url's are dynamically changed by the crm website, so relative references to own pages will not work anymore (e.g. custom url's in the sitemap);

  • for some reason (I still have to find out why) modified attribute values in any precallout entityXml are not saved (is the dynamic entity xml schema changed?);

  • new callouts (plugins) can only be activated (registered) by code which you have to develop yourself (unbelievable that Microsoft hasn't made a good working, complete GUI for that);

  • modifying the query (fetchxml) for lookups in JavaScript is not possible anymore;

  • the used (Generic)Identity for impersonation is not of type windowsuser anymore but some CrmIdentity type from which I don't know how to cast;


All of these issues, and probably I will walk into more, can be solved, but I am really disappointed that Microsoft has changed these kind of things without clear documentation how to solve these issues.
How am I going to tell my boss that it takes (pretty much) longer than expected to be CRM 4.0 compliant?

Saturday, January 19, 2008

Dynamically accessing the field mappings area between Opportunity Product, Quote Product, Salesorder Product and Invoice Product

In a lot of projects we do for our customers with Microsoft Dynamics CRM 3.0 I find it very usefull that, though the relationships are not existing, it is still possible to access the field mappings areas to specify mappings between Opportunity Product, Quote Product, Salesorder Product and Invoice Product. This Microsoft Support Article tells how to do this.

(Custom) mappings between those entities are wanted when custom fields are added to them. When converting an opportunity to a quote, or quote to salesorder or salesorder to invoice, you want the underlying details to be copied completely, including your own custom fields.

But, it is not that easy to do. You have to open pretty complex webpages (i.e. webservice descriptions and webservice result xml) which most (functional) consultants haven't seen before and than copy and paste guid's (who want's to deal with guids?) into the final field mappings area url to do the job. Above all, this has to be done physically on the CRM server itself (at least the first steps).
So, I decided to include the (links to the) mapping pages into our standard product settings module. Pretty easy to do. Nothing else than hyperlinks to the following url (as documented in the Microsoft Support Article):

http://crmserver:5555/tools/systemcustomization/relationships/mappings/mappinglist.aspx?mappingid={mapid}
where crmserver:5555 needs to be replaced by the correct server:port address. And {mapid} must contain the id (guid) of the specific field mapping area.

But: how to dynamically obtain the correct mapid? (Microsoft Support says in their article mentioned that those id's differ for each environment!).

The Microsoft Support Article describes how to obtain the mapid's:
  1. open a url displaying the description for webservice "EntityMap"
  2. click a hyperlink to display the webmethod "RetrieveEntityMaps"
  3. as test parameter, fill in the specific source entityname and click "Invoke"
  4. find in the displayed result xml the correct mapid and copy this
  5. (now you can paste the mapid into the final url (see above) to bring up the desired mappings area)

Step 1 to 4 can be easily automated in a C# method which returns the mapid (e.g. a webmethod which can be called from Javascript, or inside an .aspx code-behind page). Here's the code:

string getMapId(string entityFrom, string entityTo)
{
    try
    {
        //create httprequest to call the "RetrieveEntityMaps" webmethod
        string urlFromRegistry = (string)Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\MSCRM").GetValue("ServerURL");
        string uri = Path.Combine(urlFromRegistry, "entitymap.asmx/RetrieveEntityMaps");
        string data = "entityName=" + entityFrom;
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
        req.Method = WebRequestMethods.Http.Post;                
        req.UseDefaultCredentials = true;
        req.ContentLength = data.Length;
        req.ContentType = "application/x-www-form-urlencoded";
        //and add the parameter
        StreamWriter wr = new StreamWriter(req.GetRequestStream());
        wr.Write(data);
        wr.Close();
                
        //get the response
        HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
        //load it into a XmlDocument
        XmlDocument doc = new XmlDocument();
        doc.Load(resp.GetResponseStream()); 
        resp.Close();
        //Select the mapid using a Xpath expression
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
        nsmgr.AddNamespace("ns""http://schemas.microsoft.com/crm/2006/WebServices");
        string xPath = "//ns:entitymap[ns:targetentityname = '" + entityTo + "']/ns:entitymapid";
        XmlNode node = doc.SelectSingleNode(xPath, nsmgr);
        //Return the InnerText of the found node
        if (node != null) return node.InnerText;
        return "";
    }
    catch (Exception e)
    {
        //probably an authorization error...
        return "";
    }
}

Note that this code uses undocumented CRM features (at least not documented in the SDK). This makes it unsupported (but I bet it will continue working in 4.0, though I haven't tested it yet).

Saturday, January 12, 2008

Microsoft Dynamics CRM 4.0 Language Pack: Spanish & Dutch now available!

2 new language packs are available now; Dutch (my home language!) and Spanish.
Microsoft Dynamics CRM 4.0 Language Packs contain translated text, such as labels, error messages, and Help.


By installing a Language Pack on the server that is running Microsoft Dynamics CRM 4.0 and then enabling the language in the Microsoft Dynamics CRM 4.0 Web application, users can view Microsoft Dynamics CRM 4.0 in a language other than the base language of the installation.

Download page

Microsoft Dynamics CRM 4.0 SDK available!


The Microsoft Dynamics CRM 4.0 Software Development Kit (SDK) is now available.
It contains all new information about creating plug-ins, working with custom workflow activities, using the new Web services, using new data management features, and much more.

For now, only a downloadable version is available. The online version will follow soon.
Future releases will include the ISV Guide and Report Writers Guide.

Download page

Sunday, January 6, 2008

Hans's scale of supportability; is a customization supported or not?

Often I hear questions about whether some customization is supported or not.
Actually, I think it is not that clear to say what the exact definition of "supported customizations" is. When you search on the web, you can find a lot of (almost the same) definitions. In addition, I will give here my own definition:

A supported customization is a customization which uses only techniques which are documented in the SDK. This assures (when correctly implemented) that:

  • the customization will continue functioning even after an upgrade;
  • the standard CRM functionality will continue functioning (both before and after an upgrade);
  • Microsoft will give support on it when it breaks (because this would mean that their SDK is not correct).

So, does this mean that we (we, CRM developers) only have to implement solutions which meet the above criteria? No, I don't think so. Moreover, even to build a solution which meets the "Certified for Microsoft CRM" criteria you don't have to stay exactly to the SDK documentation (I know this from my own experience).
All you need to do is use your common sense.
To do that, I have made my own scale of supportability.

Class A: fully supported
These are fully supported customizations, only using techniques documented in the SDK.

Class B: fully supported with unsupported cosmetic features
These are also customizations only using techniques documented in the SDK.
But these customizations also contain some not documented tricks. Those unsupported tricks however are limited to GUI adjustments by using undocumented features in the application's HTML output. These include Javascripts which add icons/buttons or colorize fields/labels within forms and views, or Javascripts which hide items in the navigator pane. Bottom line is, to be class B (and not C or lower), that the chance of breaking functionality after an upgrade is not that big, and when it breaks it shouldn't be to difficult to repair.

Class C: smart but breakable
Class C customizations mostly are the prettiest ones. They offer a lot of extra functionality, but are not supported and will break for sure after an upgrade. These are the solutions which change (or even replace) system files of the application. Examples are modified (or completely replaced) aspx files to extend grid- and formviews, extended system Javascript files or implementation of http handlers.
These kind of modifications actually change the contents of system files and folders so they never survive any upgrading or re-installation (without using specific tools/procedures for those customizations).

Class D: bypassing the application's business logic
Don't do this! When you bypass the application's logic your customization is probably already broken when you deploy it. You just don't know it yet.
Bypassing the application's logic is done when retrieving data directly from the database tables (as opposed to filteredviews) using sql. Also (even worse) updating data in the database tables directly using sql is a guarantee for problems, sooner or later.
Another class D customization to my opinion is to overrule authorization by impersonation techniques.


Finally I want to say: don't be scared to do an unsupported customization sometimes. But: use common sense. Be aware when you do something unsupported and estimate your chances of surviving future releases... and the effort needed if not.