Friday 30 October 2015

How to increase Paging Limit (Records Per Page) in Dynamics CRM 2015 Online using C#


In Dynamics CRM default paging limit is set to 50 records per page. Sometime we need to increase Paging Limit (per page) so that I can Activate/Deactivate/Edit/View more than 50 records per page. In CRM On-Premises we have an unsupported option to set it to whatever value we want by running a SQL update query on UserSettings. But with CRM 2015 Online we don’t have access to database so everything needs to be supported. 

From UI we can only set Paging Limit up to 250. ‘PagingLimit’ in UserSettings entity is valid for update so we can write some code to update Paging Limit. However even with code maximum Paging Limit we can set is 500 but it is still double than the maximum we can set through UI.

Complete Solution to update Record per page can be downloaded from CodePlex.


Following is the code to update.

using System;
using System.Linq;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;

namespace UpdatePagingLimit
{
    internal class Program
    {
        private static OrganizationServiceProxy _serviceProxy;

        private static void Main(string[] args)
        {
            using (var context = GetOrganizationServiceContext())
            {
                string firstname = "** user’s first name **";

                var userId = (from u in context.CreateQuery("systemuser")
                    where u.GetAttributeValue<string>("firstname") == firstname
                    select u.GetAttributeValue<Guid>("systemuserid")).FirstOrDefault();

                if (userId != Guid.Empty)
                {
                    var usersettingsId = (from s in context.CreateQuery("usersettings")
                        where s.GetAttributeValue<Guid>("systemuserid") == userId
                        select s.Id).FirstOrDefault();

                    if (usersettingsId != Guid.Empty)
                    {
                        var userSettingsToUpdate = new Entity("usersettings") {Id = usersettingsId};

   // 500 is the Maximum you can set
                        userSettingsToUpdate["paginglimit"] = 500;

                        var service = GetOrganizationService();
                        service.Update(userSettingsToUpdate);
                    }
                }
                else
                {
                    Console.WriteLine("Unable to find the System User");
                }
            }
            Console.ReadLine();
        }

        public static OrganizationServiceProxy GetOrganizationServiceProxy()
        {
            var organizationUri = new Uri("https://XXXXXXXX.crm4.dynamics.com/XRMServices/2011/Organization.svc");

            IServiceManagement<IOrganizationService> orgServiceManagement =
                ServiceConfigurationFactory.CreateManagement<IOrganizationService>(organizationUri);


            AuthenticationProviderType endpointType = orgServiceManagement.AuthenticationType;

            AuthenticationCredentials authCredentials = new AuthenticationCredentials();
            authCredentials.ClientCredentials.UserName.UserName = "joe.blogs@example.onmicrosoft.com";
            authCredentials.ClientCredentials.UserName.Password = "Password";
            if (endpointType == AuthenticationProviderType.OnlineFederation)
            {
                IdentityProvider provider =
                    orgServiceManagement.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName);
                if (provider != null && provider.IdentityProviderType == IdentityProviderType.LiveId)
                {
                    authCredentials.SupportingCredentials = new AuthenticationCredentials
                    {
                        ClientCredentials = Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice()
                    };
                }
            }

            _serviceProxy =
                GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, authCredentials);

            return _serviceProxy;
        }

        public static OrganizationServiceContext GetOrganizationServiceContext()
        {
            var proxy = GetOrganizationServiceProxy();
            var context = new OrganizationServiceContext(proxy);
            return context;
        }

        public static IOrganizationService GetOrganizationService()
        {
            var service = (IOrganizationService) GetOrganizationServiceProxy();
            return service;
        }

        private static TProxy GetProxy<TService, TProxy>(
            IServiceManagement<TService> serviceManagement,
            AuthenticationCredentials authCredentials)
            where TService : class
            where TProxy : ServiceProxy<TService>
        {
            Type classType = typeof (TProxy);

            if (serviceManagement.AuthenticationType !=
                AuthenticationProviderType.ActiveDirectory)
            {
                AuthenticationCredentials tokenCredentials =
                    serviceManagement.Authenticate(authCredentials);

                // Obtain organization service proxy for Federated, LiveId and OnlineFederated environments.
                // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
                return (TProxy) classType
                    .GetConstructor(new Type[] {typeof (IServiceManagement<TService>), typeof (SecurityTokenResponse)})
                    .Invoke(new object[] {serviceManagement, tokenCredentials.SecurityTokenResponse});
            }

            // Obtain discovery/organization service proxy for ActiveDirectory environment.
            // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
            return (TProxy) classType
                .GetConstructor(new Type[] {typeof (IServiceManagement<TService>), typeof (ClientCredentials)})
                .Invoke(new object[] {serviceManagement, authCredentials.ClientCredentials});
        }
    }
}

Now if you build the project you will get an error complaining about missing reference for Microsoft.Xrm.Services. To get rid of this error download CRM 2015 SDK. Go to \SDK\SampleCode\CS\HelperCode and add DeviceIdManager.cs to you. Now you will have to add System.Security assembly reference.

Your code is ready to build and run. Make sure that you have updated the credentials, Organization service Uri and user’s first name in code. I have set them to dummy data.

Happy Coding
P. S. Hayer

Friday 22 May 2015

CRM 2015 - How to change existing or add new theme



From long time customers were waiting the day Microsoft will allow them to change user interface of Dynamics CRM, so that they can have their own logo and colour theme applied to CRM to match their organization's brand. Finally the day has arrived. In spring 2015 release of CRM, Microsoft has launched a new feature to change theme. However we will not have full control like normal website, but still it is enough for customers to create a custom look and feel.

You can use your company logo instead of MS Dynamics logo and make changes to the default colors and visual elements provided in the un-customized CRM system. But themes are not included in solutions exported from CRM organization, but we can use export/import if needed, however there are only few options and it will take same amount of time to copy and paste from one CRM organization to another.

Personally I found it very useful because it allowed us to make all our CRM systems (Live, development & UAT) look different. We have selected different colours for all three different environment to eliminate the confusion. 

To change the theme, follow the steps below:

1. Go to setings > customizations in new menu. (Which is far better then the previous one, as display sub-options under the main options. Which made the life a lot easier for desktop users.)

2. Under customizations, click on Themes.


3. Under themes you will see a default theme. If you have plans to revert back to default theme then don't edit it and create a new theme or clone the existing one. In this example I am going to create a new theme instead of cloning. Upload your own logo and set all the colors as you want. Though I am using some flashy colors, please forgive me if they are not meeting usability standards, I am selected those just to test this new feature.



 4. Save and Publish the theme. you can preview it if you want. But as we have not deleted the original theme we have an option to go back to that. You can switch between existing themes by simply setting one as default.



Once you are happy with the new look, set it as default and enjoy.

P S Hayer

Friday 6 March 2015

The E-mail Router service could not run the service main background thread. The E-mail Router service cannot continue and will now shut down.

Because of some issues 'Microsoft CRM Email Router' service stopped automatically. On manual start it stopped immediately saying SystemState.xml is corrupt.

I found the actual error message (following) in event log. But most useful message was prior to this error message saying "Error accesing SystemState.xml. Restore file with last backup."

#16192 - The E-mail Router service could not run the service main background thread. The E-mail Router service cannot continue and will now shut down. System.Configuration.ConfigurationErrorsException: The E-mail router service cannot access system state file Microsoft.Crm.Tools.EmailAgent.SystemState.xml. The file may be missing or may not be accessible. The E-mail Router service cannot continue and will now shut down. ---> System.Xml.XmlException: Root element is missing.
   at System.Xml.XmlTextReaderImpl.ThrowWithoutLineInfo(String res)
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
   at System.Xml.XmlDocument.Load(XmlReader reader)
   at System.Xml.XmlDocument.Load(String filename)
   at Microsoft.Crm.Tools.Email.Providers.ConfigFileReader..ctor(String filePath, ServiceLogger serviceLogger)
   at Microsoft.Crm.Tools.Email.Providers.SystemState.Initialize(ServiceLogger serviceLogger)
   at Microsoft.Crm.Tools.Email.Agent.ServiceCore.InitializeSystemConfiguration()
   --- End of inner exception stack trace ---
   at Microsoft.Crm.Tools.Email.Agent.ServiceCore.InitializeSystemConfiguration()
   at Microsoft.Crm.Tools.Email.Agent.ServiceCore.ExecuteService()

It gave me an idea that I need to find and restore the file from backup (if there is any). File was located at C:\Program Files\Microsoft CRM Email\Service\Microsoft.Crm.Tools.EmailAgent.SystemState.xml.

But Unfortunately there was not any backup. So I just renamed the file and restarted the service. It worked and started picking up pending emails gradually. 

For future use I have taken backup of SystemState.xml and Configuration.bin as suggested by Microsoft

P.S. Hayer

How to reset Auto-numbering and where does CRM stores Prefix and Number

I Recently came across a question on a forum about how to update Auto-numbering number and where does CRM stores it in Database? I have looked in CRM tables and found that CRM stores it in [OrganizationBase] table. But as it is unsupported to update in SQL, I was not sure that if updating the number will work or not. I personally avoid doing unsupported things. But to find out the consequences I decided to give it a go in my Development environment. 

Note: To update Auto-Numbering by Supported way, have a look at How to reset Auto-numbering in Dynamics CRM Online.

Following query returned the current auto number values.

SELECT [KbPrefix]
      ,[CurrentKbNumber]
      ,[CasePrefix]
      ,[CurrentCaseNumber]
      ,[ContractPrefix]
      ,[CurrentContractNumber]
      ,[QuotePrefix]
      ,[CurrentQuoteNumber]
      ,[OrderPrefix]
      ,[CurrentOrderNumber]
      ,[InvoicePrefix]
      ,[CurrentInvoiceNumber]
      ,[UniqueSpecifierLength]     
  FROM [dbo].[OrganizationBase]

Then executed the following query to reset number:

Update [dbo].[OrganizationBase]
set [CurrentKbNumber] = 10000;

Resetting number only can cause duplication if you already have records with that number. So to avoid it I have updated the Prefix as well. 

CRM allows to update Prefix using UI but Number field is locked as shown below:

Got to Settings > Administration > Auto-numbering


Now on new Article creation, I can notice that Number has been set to 10000. Done some light testing and could not find any issues.

Note: It is not a Microsoft supported way of updating Auto-numbering, I would recommend to update Auto-Numbering Supported Way by updating the Organization using sdk.

P.S. Hayer