Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, 25 June 2018

Resolve Error "Unable to Login to Dynamics CRM" after v9 update




Recently we have updated our Dynamics 365 to v9 and we are updating our applications to the latest version of SDK.

As per Microsoft Guideline, approach is to update apps to .NET Framework 4.6.2 and update CRM SDK to latest v9.0 assemblies. But application was still throwing same error message ("Unable to Login to Dynamics CRM").

One of my colleague pointed to a David Branscome's Post about moving away from TLS 1.0 and 1.1 to 1.2 and it reminded me about the post I read few days back.

Because our .NET assemblies were already updated so version 4.6.2 and it should be handling the TLS Protocol issue itself. But our application was still throwing the same error so we decided to try invoke TLS1.2 manually in our application before CrmServiceClient is instantiated. Following line was added to the code:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

But it was still throwing same error and then we started looking at assembly references and app.config. In config we found that targetFramework was pointing to 4.5.2 and it worked when we changed to 4.6.2 (as shown below). Once it is updated connection will was created without any issue.


<httpRuntime targetFramework="4.6.2" />



Premjit Singh
Attendite Ltd.
Twitter

Thursday, 14 April 2016

How to retrieve SLA Pause States (On Hold Case Status) in C# code


Following code shows how to retrieve SLA Pause States from Dynamics CRM using C#. I needed code a functionality to calculate case elapsed minutes and I thought it is worth finding a way to load paused statuses from system rather than hard-coding them.


        private static string[] GetSlaPauseStates(IOrganizationService service)
        {
            QueryExpression qe = new QueryExpression("organization")
            {
ColumnSet = new ColumnSet(new string[] { "organizationid", "slapausestates" })
            };

            EntityCollection orgs = service.RetrieveMultiple(qe);

            if (orgs != null && orgs.Entities.Count > 0)
            {
                var org = orgs[0];
                var slaPauseStates = orgs[0]["slapausestates"];
                string[] states = slaPauseStates.ToString().Split(';');
                return states;
            }

            return null;
        }

In Plugin or Custom Workflow we can retrieve the OrganizationId from contact and then we can directly retrieve the Organization by Id. Following is the code to retrieve organizationId.


    IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
    IOrganizationServiceFactory serviceFactory =      executionContext.GetExtension<IOrganizationServiceFactory>();
    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

    var organizationId = context.OrganizationId;

    // Get Organization Business Closure Calendar Id
    var organization = service.Retrieve("organization", context.OrganizationId, new ColumnSet("slapausestates"));
    var slaPauseStates = organization["slapausestates"];

    string[] states = slaPauseStates.ToString().Split(';');


Happy Coding

P. S. Hayer
(ਪ੍ਰੇਮਜੀਤ ਸਿੰਘ ਹੇਰ)
Premjit Singh
Attendite Ltd.
Twitter

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

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

Monday, 23 June 2014

Dynamics CRM: How to get Business Closure Dates in Plugin


using System;
using System.Linq;
using HayerCrmPackage.Plugins.Entities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;

namespace HayerCrmPackage.Plugins
{
    public class PreCaseCreate : Plugin
    {
        public PreCaseCreate()
            : base(typeof(PreCaseCreate))
        {
            base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Create", "incident", new Action<LocalPluginContext>(ExecutePreCaseCreate)));            
        }

        protected void ExecutePreCaseCreate(LocalPluginContext localContext)
        {
            if (localContext == null)
            {
                throw new ArgumentNullException("localContext");                
            }

            var pluginContext = localContext.PluginExecutionContext;
            var service = localContext.OrganizationService;
            var context = new OrganizationServiceContext(service);

            // Get Organization Business Closure Calendar Id
            var organization = service.Retrieve("organization", context.OrganizationId, new ColumnSet("businessclosurecalendarid"));

            var query = new QueryExpression("calendar")
            {
                ColumnSet = new ColumnSet(true),
                Criteria = new FilterExpression()
            };

            // Add condition to get Get Calander where CalanderId is equal to Organization's businessclosurecalendarid
            query.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, organization["businessclosurecalendarid"].ToString()));

            // Get Calendar
            var businessClosureCalendar = service.RetrieveMultiple(query).Entities[0];

            // Get the Calendar rules
            IEnumerable<Entity> calanderRules = businessClosureCalendar != null ? businessClosureCalendar.GetAttributeValue<EntityCollection>("calendarrules").Entities : null;
        }
    }
}



To know how to add working days by calculating business closure dates and weekends, please check my blog Here.

Happy Coding

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

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