Showing posts with label Dynamics CRM 2011. Show all posts
Showing posts with label Dynamics CRM 2011. Show all posts

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, 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

Wednesday, 1 October 2014

Dynamics CRM: Create ServiceAppointment

A service appointment represents an appointment for service. The schema name for this entity is ServiceAppointment. The service appointment entity represents a block of time on a calendar. This entity stores the availability blocks for resources and can be used to determine resource availability and scheduling.
A service appointment can be customized independently from other activities to accommodate the customer's business requirements for service delivery. A service appointment must have a corresponding service. It can be already bound with a set of resources specified by an activity party (ActivityParty) list.
Following code can be used to create a Service Activity.

                // Create the ActivityParty. Resource can be a system user and user's Calendar will be booked for the duration.
                var resource = new ActivityParty
                {
                    PartyId = new EntityReference(SystemUser.EntityLogicalName, _userId)
                };

                // Create and instance of ServiceAppointment
                var appointment = new ServiceAppointment
                {
                    Subject = "Test Service Appointment",
                    ServiceId =
                        new EntityReference(Service.EntityLogicalName, new Guid("B39F04D6-7C93-E111-9675-005056B41D39")),
                    ScheduledStart = DateTime.Now.AddDays(5),
                    ScheduledEnd = DateTime.Now.AddDays(15),
                    Location = "On Site",
                    Description = "Test Appointment created for testing.",
                    Resources = new ActivityParty[] { resource },
                    IsAllDayEvent = true,
                    IsBilled = true
                };

                var request = new CreateRequest {Target = appointment};
                var response = (CreateResponse) _service.Execute(request);

                var serviceAppointmentId = response.id;

P. S. Hayer

Thursday, 28 August 2014

CRM 2011: Get list of audited attributes from AuditBase table

Recently, I was asked to get all the fields and their entities which were audited in a day so that we can decide if we really need to audit all of those fields and disable auditing where its not required.

As we know there is no Filtered view for audit entity and even advance find don't support Audit search, so it is bit difficult to get the list of fields audited. But Kelvin's blog put me on right path to write this query and get desired result.

-- Declaring Variable and Temp Tables
DECLARE @AttributeMask VARCHAR(MAX), @ObjectTypeCode INT, @EntityName VARCHAR(100), @LogDATETIME DATETIME
DECLARE @CurrentAttribute VARCHAR(MAX)
DECLARE @Audit Table(AttributeMask VARCHAR(MAX), ObjectTypeCode INT, EntityName VARCHAR(100), LogDATETIME DATETIME);                               
DECLARE @Result Table (AttributeId INT, ObjectTypeCode INT, EntityName VARCHAR(100), LogDATETIME DATETIME);
DECLARE @todaysdate DATETIME;

-- Set the date to bring all the fields Audited today
SET @todaysdate = CAST(GETDATE() AS DATE);

-- Get all todays records from AuditBase; You can remove where clause to get everything
INSERT INTO @Audit
SELECT a.AttributeMask, a.ObjectTypeCode, e.Name, a.CreatedOn FROM Audit AS a
INNER JOIN MetadataSchema.Entity e on a.ObjectTypeCode = e.ObjectTypeCode
WHERE CAST(a.CreatedOn AS DATE) = @todaysdate;

-- Using Cursor to go through each and every record in @Audit Table
DECLARE DataAuditCursor CURSOR FOR
SELECT * FROM @Audit

OPEN DataAuditCursor

FETCH NEXT FROM DataAuditCursor
INTO @AttributeMask, @ObjectTypeCode, @EntityName, @LogDATETIME

WHILE @@FETCH_STATUS = 0
BEGIN
      -- Run while Attribute mask have comma(s) in it
      WHILE CHARINDEX(',',@AttributeMask,0) <> 0
    BEGIN
            SELECT
            @CurrentAttribute=RTRIM(LTRIM(SUBSTRING(@AttributeMask,1,CHARINDEX(',',@AttributeMask,0)-1))),
            @AttributeMask=RTRIM(LTRIM(SUBSTRING(@AttributeMask,CHARINDEX(',',@AttributeMask,0)+1,LEN(@AttributeMask))))
           
        IF LEN(@CurrentAttribute) > 0
        INSERT INTO @Result Values(@CurrentAttribute, @ObjectTypeCode, @EntityName, @LogDATETIME)
    END
   
    INSERT INTO @Result VALUES((CASE WHEN ISNULL(@AttributeMask, '') = '' THEN NULL ELSE @AttributeMask END),
                                                @ObjectTypeCode, @EntityName, @LogDATETIME)
   
    FETCH NEXT FROM DataAuditCursor
    INTO @AttributeMask, @ObjectTypeCode, @EntityName, @LogDATETIME
END

CLOSE DataAuditCursor;
DEALLOCATE DataAuditCursor;

-- Select Distinct to get all the Attributes and their entities
SELECT DISTINCT
    r.EntityName
    ,(SELECT TOP 1 a.Name FROM MetadataSchema.Attribute a
            INNER JOIN MetadataSchema.Entity e ON
            a.EntityId = e.EntityId
            and a.ColumnNumber = r.AttributeId
            and e.ObjectTypeCode = r.ObjectTypeCode) 'AttributeName'
FROM @Result r;



Happy Coding

P. S. Hayer
(ਪ੍ਰੇਮਜੀਤ ਸਿੰਘ ਹੇਰ)

Please check my other (non-CRM) blog here: Programming Blogs