Jul 16, 2012

Disable ribbon button through onload JavaScript

CRM 2011 is giving full control of custom button through ribbon concept over ISV configuration concept of CRM 4.0. Here I have mention how to enable/disable button according to rules we define.

Here, rule is a straightforward one. For example, if we need to disable a button depending on logged in user’s team, I am still unable to address through a rule definition. Till I find it I found a way of doing it through onload JavaScript.

Ribbon item behaves according to a defined style. What I do is manipulating the style according to my need. Here I need to disable a particular button if the user is not in “Admin” team.
First I grab the id of the button. I assume you know how to do that by F12 function as shown below.


Now replace the standard style of that button by standard style of the disabled button as required.

if (!userIsInTeam("Admin"))
{
 if (window.top.document.getElementById('<ID>'))
 {
 var _id = window.top.document.getElementById('<ID>');
 var str = _id.outerHTML;
 var str1 = str.replace("ms-cui-ctl-large", "ms-cui-ctl-large ms-cui-disabled");
 _id.outerHTML = unescape(str1);
 }
}

I urge this is not the best way, but this works.
If I manage to find a way to define a rule in XML, I am publishing it. If you find first, please share it for me too.

Script error of Follow up button

When clicking the Follow up button, sometimes users see a script error as by the bottom left of corner of the browser.


This occurs since your form assistant is disabled. Obviously, this is a contradiction.  Follow up pane should get loaded in form assistant section, which is not available.

Form Assistant and Follow up
So, when you design the form, you have to think Follow up functionality together with form assistant.

1) Option 1: If you want follow up, your form assistant should be enabled
For this, go to customizations > Open relevant entity > click Forms and Views > Open Form > Open Form prosperities > Click display tab.
Then enable the Form assistant by clicking the check box.


2) Option 2: If you want form assistant to be disabled, follow up button should be removed
How to remove the button using JavaScript is discussed here.

Decide this in terms of your useability expectations.

Jul 12, 2012

Reset Time of CrmDateTime

Surprisingly, I couldn’t find straightforward post of how to reset the time portion of the CrmDateTime. So I implemented my own method which worked for me. In fact, this might not the best code, but decent enough to use.

In my previous post I gave a hint that “Value” attribute is the key to CrmDateTime modifications/conversions. See, how I have used same attribute to modify the Time portion only.

public static CrmDateTime SetTime(CrmDateTime _dateTime,string _time)
{
  // considering datetime format as 2012-07-05T11:00:00+1000
  string _crmDTvalue = Convert.ToString(_dateTime.Value);
  string _crmDTvalueP1 = _crmDTvalue.Substring(0, 11);
  string _crmDTvalueP2 = _crmDTvalue.Substring(16);
  string _crmDTvalueNewTime = string.Concat(_crmDTvalueP1, _time, _crmDTvalueP2);

  CrmDateTime _crmDataTime = new CrmDateTime();
  _crmDataTime.Value = _crmDTvalueNewTime;

  return _crmDataTime;
}

Calling part;

//8 am
SetTime(_myCrmDateTime,"08:00");
//5 pm
SetTime(_myCrmDateTime,"17:00");

Please keep in mind, this method is subjective to the date time format you use, but this approach is easily used for any format.

CrmDateTime to/from DateTime

This is a simple kind of conversion, but for some reason, I had to play around to figure it out. So I am writing it here.

When converting to/from CrmDateTime in C# key is the “Value” attribute. We can simply read it and also assign it.

CrmDateTime to DateTime

DateTime _datetime = Convert.ToDateTime(dateTime.Value)

DateTime to CrmDateTime

 CrmDateTime _crmDataTime = new CrmDateTime();
 _crmDataTime.Value = _datetime.ToString("s");

Also, we can modify date time related other attributes this way.

Jul 2, 2012

Calling WCF service within a plug-in

Calling a third party service through plug-in could be an important aspect of a CRM development. I of course had a difficult time to figure out this. At the end of the day below sequence worked for me.

1)  Adding the service to Plug-in code
This step was as same as calling a service from general web application. Add the service URL and you will see it added to the Service Reference section.


Nor difference in calling part also. Something like below...

_service = new Rate();
_service.ChannelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
 
_service.ChannelFactory.Credentials.Windows.ClientCredential.Domain = "<Domain>";
_service.ChannelFactory.Credentials.Windows.ClientCredential.UserName = "<User Name>";
_service.ChannelFactory.Credentials.Windows.ClientCredential.Password = "<Password>";

selltingRate = _service.ReturnSelltingRate(_prodId);

2) Defining the end points

Here is the tricky part. Now you got to define the endpoint of the service in the config of the CRM. You will find web.config of the CRM in C:\Program Files\Microsoft Dynamics CRM\CRMWeb. (Please make sure you get back up before modifying this file, since if it’s modified wrong, CRM will not load at all!)

Now go back to the Visual Studio project and open the app.config file of the same plug-in project. Now grab the endpoint of your service and relevant binding tag. You can select the right endpoint by searching by URL of the service. Then get the “name” attribute of particular tag and search for the Binding tag of same name.

Now paste them in the web.config file of the CRM. Under <system.serviceModel> tag you will see two sections called “client” and “bindings” Endpoint should go under client section. Binding tag should go under bindings section, within the tag either <basicHttpBinding> or <wsHttpBinding>, depending on binding type. Identifying the binding type is not hard since name attribute of binding tag contains the type.

You will find something like this in the web.config of the CRM, if you do it correctly.

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="BasicHttpBinding_IRateService" closeTimeout="00:01:00"
                        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                        maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                        useDefaultWebProxy="true">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
          maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <security mode="Transport">
        <transport clientCredentialType="Windows" proxyCredentialType="None"
            realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="https://xxxxxxxxxxxxxxxxxx/webservices/xxxxxxxxxxxxxxx/Rate.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IRateService"
            contract="BusinessServiceClient.IRateService" name="BasicHttpBinding_IRateService" />
</client>
</system.serviceModel>  

Click this to read the previous articles explained how to call a WCF from a client side. Please note some services will work fine for plug-ins but not client side due to security reasons. Only solution for that is to create your own WCF service to consume the third party service and then use your service to read values to CRM forms.