Getting logged in user roles in client side in Dynamics V9.0

You may be asking? Why this mundane post? After all we have been here close to 8 years since 2011 released and we have millions of time retrieved it using Xrm.Page.context.getUserRoles().

So what’s the fuss in it?

So if you are working on CRM version below 9.0, then it’s no fuss. But if you are working on V9.0 and above, may be this is an interesting read for you.

Xrm.Page is deprecated. So you should no longer be using Xrm.Page.context.getUserRoles()

So what’s the other way. Well you need to do it the V9.0 way. Below is the  code to do the same.

var userRoles = Xrm.Utility.getGlobalContext().userSettings.securityRoles;

And the userRoles variable here contains the list of GUID’s of the roles the user have. Wasn’t that easy?

Also now with the unified interface coming in, you should be very careful about every piece of Javascript you write. There are some properties which works only in UCI and some in Web

For e.g – not only you can get the security roles but also the privilege id’s for all the security roles associated with the user.

var userRolesPrivileges = Xrm.Utility.getGlobalContext().userSettings.securityRolePrivileges;

Unfortunately, the above line only works in UCI and not on the web version.

Debajit Dutta
(Dynamics MVP)
For consultation/ training visit http://www.xrmforyou.com or reach out to us at info@xrmforyou.com

Advertisements

{Solved} Call Web API from within a plugin in Dynamics 365 online

Well, this is one question I cam across countless number of times. And in a recently conducted training boot camp, i was asked the same question. To be honest after understanding OAuth and how various types of grants work in Azure Active Directory, I was thinking this should not be a very tough problem.

To my surprise, when I started searching the community I came across many links which suggested it can’t be done and many links which suggested ways but no complete guidance on how to do it.

So decided to challenge myself in it for my blog readers and came out pretty quick within couple of hours. So here we start out journey.

Before we go ahead and discuss on how to do this, let’s understand the problem faced.

The first thing that we need to connect to Web API instance is an access token. And getting an access token now is just piece of cake. You reference Active Directory Authentication Library (you can easily get this from Nuget with the keyword : ADAL) in your project and then use some 4-5 pre-defined lines to get the token.

So what’s the problem with that? The problem is when we try to run the same code in our plugins and try to access the token, we get a security exception. The problem is our online plugins runs in sandbox mode.

So the solution to this would be not to use ADAL. So what are the other options? Off-course we can use plain simple HttpRequest to get the token right? After all internally ADAL might be doing the same right? Not sure about ADAL but certainly this is harder than you think.

The first point to consider here is when the plugin is executing, we do not have the password for the user.

In my blog link – https://debajmecrm.com/2018/04/30/headless-authentication-with-dynamics-crm-online-and-external-web-app-which-requires-client-secret/ I have explained in detail on how to get the access token without using ADAL. The problem here is, I am  using the password here to get the token. In plugins I will not have that.

So how to tackle this.

If you observe carefully, there are various types of grants in Oauth and one of them “grant_type=password” I have used in the above link. Well since I can’t use that, there is another type called grant_type=client_credentials”. And this is what we are going to use here.

So let’s now jump to the solution.

Step 1:

Register an application of type WebApp/Api in your Azure active directory with proper permission to Dynamics Application and then create an application user in Dynamics with the Application ID of your registered App. Give access to your application user with proper security roles to gain necessary access to entities.

If you are not aware of registering App or the concept of Application User in Dynamics, it’s explained in great detail in the below link

https://debajmecrm.com/2018/08/16/step-by-step-guide-query-dynamics-crm-web-api-using-server-to-server-authentication-with-application-user/

Just set-up the APP and the application user. Don’t try to use the code since it will not work in plugins.

Step 2:

Plugin code

public class WebApiSample : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // getting the pipeline context.
             var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var ent = (Entity)context.InputParameters["Target"];

            var accessToken = GetTokenWithoutADAL().GetAwaiter().GetResult();
             var accountJson = RetrieveAccounts(accessToken).GetAwaiter().GetResult();

            ent["vvbv_description"] = accountJson;
        }

        private async Task<string> GetTokenWithoutADAL()
        {
            string azureAdDomain = "xrmforyou62.onmicrosoft.com";
            string loginUrl = $"
https://login.microsoftonline.com/{azureAdDomain}/oauth2/token";
             string resource = "https://xrmforyou62.crm.dynamics.com";
              string clientId = "9a3590d8-c89e-4de5-bb50-8dfa3d9796a9";
            string clientSecret = "<put your client secret here>";

            HttpClient client = new HttpClient();
            var postData = $"client_id={clientId}&client_secret={clientSecret}&resource={resource}&grant_type=client_credentials";

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, loginUrl);
            request.Content = new StringContent(postData, Encoding.UTF8);
            request.Content.Headers.Remove("Content-Type");
            request.Content.Headers.TryAddWithoutValidation("Content-Type", $"application/x-www-form-urlencoded");

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            var responseMessage = await client.SendAsync(request);
            var jsonResponseString = await responseMessage.Content.ReadAsStringAsync();

           var jsonContent = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonResponseString);

            return jsonContent["access_token"];
        }

        private async Task<string> RetrieveAccounts(string token)
        {
             string webApiUrl = "
https://xrmforyou62.api.crm.dynamics.com/api/data/v9.1";
             string url = $"{webApiUrl}/accounts?$select=name";

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
           
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            HttpResponseMessage response = await client.GetAsync(url);

            string jsonContent = await response.Content.ReadAsStringAsync();

            return jsonContent;
        }
    }

You can do a better job at handling the client_id and client_secret. But this is just sample code and hence I am using this directly.

Also to parse the JSON, I have used the Newtonsoft.json dll which you need to ilmerge with the plugin assembly before uploading to the plugin registration tool. Check for the highlighted code.

And I have registered this plugin on the Pre-create of a test entity. I set the description of the field in this plugin to the account JSON and voila it works!

image

Eureka! I can see the account JSON in the description field after I create the record.

Isn’t it great guys.

Hope this helps. And hope you just had something interesting to read in CRM world today.

Debajit Dutta

(Dynamics MVP)

For consultation/ training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Xrm.Page is deprecated with Version 9.0. How do I get the Clienturl and form data in Ribbon Actions?

Simple isn’t it? After all it was so easy

All I needed to write to get the ClientUrl

var clientUrl = Xrm.Page.context.getClientUrl();

And to get value of the field on the form

var fieldValue = Xrm.Page.getAttribute(“<fieldname>”).getValue()

So what’s the fuss? Well, if your CRM version is 8.2 and below, no worries. It it perfect.

However with version 9.0 and above, the Xrm.Page has been deprecated. So it means you can use them no longer.

So how do I get the Client Url? The below code does it for you.

var globalContext = Xrm.Utility.getGlobalContext();

var clientUrl = globalContext.getClientUrl();

And how about getting the value of a field on the form?

With version 9.0 and above, you should try to access the form data using the formContext. But again the problem is, to get the formContext, you need to use ExecutionContext. So the next question lies on how to pass executionContext parameter to your Ribbon actions.

For that you need to pass the CrmParameter – Primary control to your ribbon action. Below is the code to get the data using formContext.

image

function ribbonHandler(e) {
    var formContext = e.getFormContext();

    var recordId = formContext.data.entity.getId();
    var fieldValue = formContext.getAttribute("<field_name>").getValue();
}

Just another day as a consultant and I hope this blog just adds a grain to your CRM knowledge heap.

Debajit Dutta
(Dynamics MVP)
For consultation/ corporate training visit http://www.xrmforyou.com or reach out to us at info@xrmforyou.com

Perform Retrieve using Alternate Key and SDK in Dynamics 365

Alternate keys have been implemented some time back and by now I think most of the consultants working with Microsoft Dynamics are familiar with the concept of alternate keys.

In case you are new to alternate key, you can follow the below documentation here.

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/define-alternate-keys-entity

Recently I got a request to retrieve using an alternate key. Strangely enough, there are many examples of Update/ Upsert using alternate key but not much with the retrieve using SDK.

Moreover developers coming in new gets confused whenever they try to retrieve using OrganzationService.Retrieve because the method does not have any parameter to take in an alternate key

Well the alternative to that is using the RetrieveRequest. Below is the sample code to retrieve a contact record with alternate key. The alternate key is set up on the Email (emailaddress1) field of the contact entity.

string entName = "contact";
            string alternateKeyfield = "emailaddress1";

            RetrieveRequest retrieveRequest = new RetrieveRequest();
            retrieveRequest.ColumnSet = new ColumnSet(new string[2] { "firstname", "lastname" });
            retrieveRequest.Target = new EntityReference(entName, alternateKeyfield, "test@123.com");

            RetrieveResponse resp = (RetrieveResponse)proxy.Execute(retrieveRequest);

            if(resp.Entity != null)
            {
                Console.WriteLine($"First Name: {resp.Entity.GetAttributeValue<string>("firstname")}");
                Console.WriteLine($"Last Name: {resp.Entity.GetAttributeValue<string>("lastname")}");
             }

Strangely enough the RetrieveRequest is hardly being used. The highlighted one is the line where we are trying to retrieve using Alternate key which is set on emailaddress1 field.

Please note if there is no record with the specified email address here (test@123.com), you will get an error. Your code should have appropriate try catch block to handle the same

Hope this helps next time when you try to retrieve a record using alternate key.

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

{Knowhow} Delete field from managed solution in Target environment when deleted from source environment–Dynamics 365

Dynamics CRM 2016 introduced the concept of solution segmentation, solution patching and cloning and indeed it has come a long way over the last 2-3 years. We are now exposed to CDM, flows, powerapps and what not. But CRM has some old tricks up it’s sleeve which makes you go back to the basics sometimes and I am going to pen down one such scenario here. Even experienced consultants in CRM are sometimes bamboozled by this problem and I hope this is going to benefit my blog readers.

So here is the problem

  • Source Environment (Env X) has a custom field of type Optionset – “new_FieldToBeDeleted” for Entity – Account (named it explicitly for this blog. Don’t follow such convention for stupid names Smile) . The field is Local Optionset.
  • The field is placed on the form of the account.
  • The solution from Env X is exported as managed and deployed to target environment (Env Y).
  • Because of change of requirement, the local optionset now deleted from the source and replace with a global optionset.

The question now arises. How to delete the field from the target environment? It is a managed solution. Hence if you try to delete the field, you will receive an error. Also importing the new managed solution from source won’t help in this case.

Fortunately there is one way to do so with the help of Clone Solution feature.

  • In the solution in the source environment, do all the necessary changes like removing dependencies, deleting the local optionset field, creating a global optionset and creating a new field in Account Entity to map to the global optionset.
  • Select the solution and click on Clone Solution.

image

  • Put a version number as asked for.
  • Export the solution as managed.
  • While importing the solution in the target environment, check the box – “Stage for Upgrade” and select the option – “Maintain customizations”.

image

  • Once the solution is imported click on Apply Solution Upgrade button. The field in the target would be deleted as well and you will see the new field in your target environment.

          image

Hope this helps next time you have trouble with your solution management.

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Where is “APP” permission in security role in Dynamics V9.0

Recently one of our customers upgraded to version 9.0 and suddenly and once the upgrade completed, they reported to us that they are not able to find permission for Apps under their security roles, both system and custom.

Basically in the prior versions, the permission for App used to come under Customizations tab with the Name – “APP”

image

The App entity was missing in the security role screen in the customization tab, once they upgraded to V9.0.

Honestly, I did not explore much of the customization tab in Version 9.0 and when this was reported, I was kind of out of answers as to where it have gone.

Searched with the App word in the browser screen of the security role and found one called “Model-Driven App”. But was not sure about whether this referred to the same one or is it something different.

A bit of searching and finally came across this article which verified my understanding.

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/outlook-app/deploy-dynamics-365-app-for-outlook#required-privileges

Verified with existing security roles and I can see the App permissions are rightly reflected in Model-driven App Entity

image

Hope this quick tip saves you some time

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

“Cannot read property ‘<entity name>’ of null”–Error while executing a bound action from from a WebResource in Dynamics V9.0 using Xrm.WebApi.execute

This one drove me crazy and believe these kind of things pop-up the most when you don’t expect them at all. A simple training going on and I was demoing them the wonderful Xrm.WebApi methods. Then came the turn of using Xrm.WebApi.execute to execute a bound action or entity action.

Since I worked a lot recently on Xrm.WebApi methods, was pretty confident of doing and just took this one example out of a participant wish. So here goes the requirement.

  • There is a custom entity (let’s call it Test Entity) which has N:1 relation with account. So account is a lookup on the Test Entity form.
  • There is a ribbon button on the Test Entity form which when clicked would open up a webresource which would show all the contacts related to the account in the form of HTML table.

So simple isn’t it. In the days when we moved to PowerApps and Flows, this just seems a walk in the park.

So here I started from scratch and wrote the below code onload of the HTML webresource.

var actionRequest = {};
     var crmContext = Xrm.Utility.getGlobalContext();
     var qString = crmContext.getQueryStringParameters();


    var accountId = qString.Data.replace(“}”, “”).replace(“{” ,””);


    actionRequest.StringParam = “Web Api Test”;
     actionRequest.DecimalParam = 30.43;
     actionRequest.entity = { entityType: “account”, id: accountId };


    actionRequest.getMetadata = function () {
         return {
             boundParameter: “entity”,
             operationName: “new_EntityAction”,
             operationType: 0,
             parameterTypes: {
                 “StringParam”: {
                     structuralProperty: 1,
                     typeName: “Edm.String”
                 },


                “DecimalParam”: {
                     structuralProperty: 1,
                     typeName: “Edm.Decimal”
                 },


                “entity”: {
                     structuralProperty: 5,
                     typeName: “mscrm.account”
                 }
             }
         }
     };


    Xrm.WebApi.execute(actionRequest).
         then(function (data) {
             // parsing your results here.


        },
         function (error) {
             debugger;
             console.log(error.message);
         });

Before we look at the code above, let’s find out the action.

It’s a bound action for the account entity which has two input parameters – String Parameter & Decimal Parameter

image

Button is in place and then just as i click the button and HTML webresource pops out boom! An error flashing – Cannot read property ‘account’ of null. The same would work if the webresource is embedded within the CRM Form.

For readers who are curious to know how I opened the WebResource, here is the code below.

var webResourceName = “new_/pages/spa.html”;
     var windowOptions = { height: 600, width: 800 };


    var parentAccount = Xrm.Page.getAttribute(“new_parentaccount”).getValue();


    var parentAccountId = ”;
     if (parentAccount != null) {
         parentAccountId = parentAccount[0].id;
     }


    Xrm.Navigation.openWebResource(webResourceName, windowOptions, parentAccountId);

Such an embarrassment in front of a big audience. Somehow I made this understand and they took it pretty well. If you are thinking that whether I included ClientGlobalContext.js.aspx, yeah I did. And did all whatever it takes to make it work. But none worked.

Searched the heck out of google, no luck as well.

Was not in a mood to leave. I started debugging, went inside all the system files stepping through each lines of the thousands of lines of system code.

And finally the Eureka moment. It was failing at the call of Xrm.Utility.getEntitySetName.

But let’s understand why? Well CRM relies on two arrays window.ENTITY_SET_NAMES  OR window.top.ENTITY_SET_NAMES  to get the entity set name from the logical name and window.ENTITY_PRIMARY_KEYS or window.top.ENTITY_PRIMARY_KEYS  to get the primary key property name of the entity.

Because the webresource is opening as a pop-up, both the arrays are coming as null and hence the error.

So before calling Xrm.WebApi.execute i just wrote the following lines.

var entNames = {};

entNames[“account”] = “accounts”;

window.ENTITY_SET_NAMES = JSON.stringify(entNames);


var primaryKeys = {};

primaryKeys[“account”] = “accountid”;

window.ENTITY_PRIMARY_KEYS = JSON.stringify(primaryKeys).

And this time when I run, what a relief. The code just ran fine and finally I could see my debugger being hit in the success block.

But please bear in mind this is unsupported and is never suggested. This post is more to highlight why it does not work in this scenario. May it start’s working in a future release.

However hope it saves some time or now you are aware before hand it will not work for this scenario

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com




DateTime Attribute Onchange event in Dynamics Portals

Chandana's CRM Blog

Today’s blog title sounds to be very easy but, there lies something interesting as well. Well continued to work with Dynamics Portals, starting up with entity form and entity form attributes. I have a requirement like to calculate the age on input of date field.

So I am just trying to trigger an onchange event of date field in Entity Form. DateTime Field in entity form is usually a DateTimePicker which is evident to us. My datetime attribute schema name is “new_datefield”. So i tried simply to trigger on change event like

$(‘#new_datefield’).bind(“change”, function() {  alert(“hello i am change event.”);});

Which doesn’t fire the change event. 😦 Simple but not working. After couple of observations over the datetime attribute. DateTime field on click or expand opens up a datetimepicker where actually I need to attach my event handler to it.

To add a custom event handler to datetimepicker if I…

View original post 94 more words

Multiple Control ID’s Error in Dynamics 365 Portals

Chandana's CRM Blog

Well I have started working as well as learning Dynamics 365 Portals. Seems like portals are quite interesting and bit tricky to play around. Lets move on to the scenario which I have faced.

My task is like to display a page in portal which contains account information. To achieve this I started creating a web page named “Account” which will use the entity form.

In Entity form I select account entity and account detail form to display the same on the portal. Now I am done with my changes and task as well. When I refreshed my portal to view the changes and account detail form, the portal does not show up. Indeed it throws up a weird error!!!!

Capture

I am dumbstruck, was not able to identify what actually went wrong. After some moment able to identify through error log which says like “Multiple Control ID’s…

View original post 54 more words

Show Lookup as Dropdown in Dynamics 365 Portals–Gotchas!

I have been working and providing training a lot recently on Dynamics 365 portals. And whenever I go over Metadata configuration of entity form the option – “Render Lookup as Dropdown” option excites the participants a lot.

Well, in this article I am not going to show how you can render a lookup as dropdown. Rather I would like to highlight what features you loose when you render your lookup as dropdown.

Gotcha 1 – No Values shown in DropDown

When you render your lookup as dropdown, the first thing you observe that the list is empty. Well, this may happen because there is a bit of change in this implementation. Right now the options will only show up is you enable entity permission for the entity which is shown as lookup.

For example – Primary Contact field on the account form. When you render your Primary Contact as dropdown in Portals, you need to have an entity permission for contact entity with Append privilege for the webrole the user is logged in with. The contacts will show up then.

 

Gotcha 1 – Lookup filtering not working.

Well this is something undesirable but as of the day I am writing this blog, related records filtering does not work for lookups rendered as dropdown.

 

Short article but should put you in good stead next time your customer asks for this option.

 

Debajit Dutta

(Dynamics MVP)

For consultation/ training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com