Archive

Archive for September, 2020

Power Apps | Query Canvas App using CDS WebAPI

September 27, 2020 Leave a comment

In my Power Apps Environment I have the following ‘Hello World’ Canvas App.

When I query ‘Canvas App’ entity using Web API from same Environment, there were no Canvas App records returned.

Reason:

  • If you create a Canvas App from ‘Apps’ tab outside of solutions or imported any App to the Environment, Canvas App will not be available in CDS until its added to a solution.
  • Open any of the unmanaged solution from the Environment, use ‘Add Existing’ and select the ‘Hello World’ Canvas App from ‘Outside solutions’ tab.
  • Once added a ‘Name’ gets populated and looks as below.
  • Now query the ‘Canvas App’ entity using Web API and now we should get the ‘Hello World’ Canvas App record.

🙂

Categories: PowerApps Tags: ,

Power Platform Admin Analytics

September 27, 2020 Leave a comment

In previous Dynamics versions, with the help of Organization Insights, available as a preferred solution from AppSource, we can get the organization level insights such as No of Active Users, API Calls, etc.

Now  these analytics can be viewed right from the Power Platform Admin Center with no need of additional solutions.

Currently there are 3 types of Analytics are available.

Who can view the Analytics reports:

Admins with the following roles and a license can view the analytics:

  • Environment Admin – can view reports for the environments that the admin has access to.
  • Power Platform admin – can view reports for all environments.
  • Dynamics 365 admin – can view reports for all environments.
  • Microsoft 365 Global admin – can view reports for all environments.

Refer this article for more details

🙂

Categories: CRM, PowerApps Tags: ,

Microsoft Teams and PowerApps – Project Oakdale

September 24, 2020 Leave a comment

Project Oakdale, a new built-in low-code data platform for Teams that provides enterprise relational datastores with rich data types to Teams users, is now in public preview.

Solutions built with Power Platform can be easily published to the Teams app store and can be used off the shelf or customized for specific needs.

Lets see how to embed a Power app in Teams.

  • Connect to Office 365 portal and check if you have ‘Teams’ enabled.
  • If no Teams available, go to Teams site and sign in with Office 365 credentials.
  • Go to Teams and click on Apps->Power Apps and click ‘Add’.
  • A ‘Power Apps’ tab adds to the Teams.
  • From ‘Power Apps’ , either create a new App by clicking ‘Create an app’ or pick any of the readily available apps.
  • Once you choose existing App, select a Team’s Channel where this App needs to be available. I chose ‘Hello World’ team’s ‘General’ channel.
  • App takes few minutes to complete the setup.
  • Grant the required permissions.
  • App loads as below and ready to be used.

Notes:

  • Project Oakdale environments are automatically created for the selected team when you create a Power app in Teams for the first time or install a Power Apps app from the app catalog. See About the Project Oakdale environment.

🙂

Categories: PowerApps Tags: ,

[Code Snippet] Using Microsoft.Pfe.Xrm library

September 20, 2020 Leave a comment

Pfe.Xrm library allows us to submit a bunch of XRM requests as batches (using ExecuteMultipleRequest) and execute them in parallel.

In this article, lets see how to use Microsoft.Pfe.Xrm library with a simple ‘Retrieve Request’.

What is Microsoft.Pfe.Xrm library?

  • Contains a set of common components for building solutions using the Dynamics 365 SDK and is developed by Microsoft Premier Field Engineering (PFE) and core engineering teams.

Download Microsoft.Pfe.Xrm

  • Use ‘Tools -> Nuget package manager’ from your Visual Studio to download the Nuget package.

Building blocks of Microsoft.Pfe.Xrm library

‘Microsoft.Pfe.Library’ allows us to trigger any ‘OrganizationRequest’ in batches (i.e.,ExecuteMultipleRequest) parallelly. Lets understand the building blocks of Pfe library.

  • List<OrganizationRequest>
    • As a first step prepare your ‘RetrieveMultipleRequest’ objects and add them to a List.
  • AsBatches() method
    • Call Pfe libraries AsBatches() method by passing the List prepared in previous step.
    • ‘AsBatches()’ returns IDictionary<string, ExecuteMultipleRequest> object.
  • OrganizationServiceManager
    • Trigger ‘Microsoft.Pfe.Xrm’ OrganizationServiceManager() method to create connection object.
    • There are multiple ‘OrganizationServiceManager’ overload methods.
    • In this article, I am using the following method.
  • ParallelProxy.Execute
    • This is the final method which accepts the ‘IDictionary<string, ExecuteMultipleRequest>’ object returned by AsBatches() method which we discussed in previous sections.
    • ParallelProxy.Execute also requires OrganizationServiceManager which we created in previous step.

IDictionary<string, ExecuteMultipleResponse> batchResponses = pfeXrmConnection.ParallelProxy.Execute(batchesOrgRequest);

Code Snippet

Now lets put all the building blocks together. It becomes as the following code snippet.

    public void RetrieveUsingPFE()
    {
        // Retrieve 'Account' and 'Contact'. You can prepare your list of entities.
        var listEntities=new List<>{ "account", "contact" };
        var batchRequests = new List<OrganizationRequest>();            

        int pageNumber = 1;
        string pagingCookie = null;

        // Filter for Active records. You can prepare your required filters as below.
        var filterActive = new FilterExpression(LogicalOperator.And);
        var condActive = new ConditionExpression("statecode", ConditionOperator.Equal, 0);
        filterActive.AddCondition(condActive);

        try
        {
            foreach (var entity in listEntities)
            {
                // Prepare 'Query Expression'
                var query = new QueryExpression(entity)
                {
                    ColumnSet = new ColumnSet(true),
                    PageInfo = new PagingInfo()
                };
                query.PageInfo.Count = 5000;
                query.PageInfo.PageNumber = pageNumber;
                query.PageInfo.PagingCookie = pagingCookie;

                query.Criteria.AddFilter(filterActive);

                var request = new RetrieveMultipleRequest
                {
                    Query = query
                };

                batchRequests.Add(request);
            }

            do
            {
                // Trigger Pfe.Execute
                var batchResponses = TriggerRequests(batchRequests);
                batchRequests = new List<OrganizationRequest>();
                pageNumber++;
                foreach (var responseItem in batchResponses)
                {
                    if (responseItem.EntityCollection.Entities.Count > 0)
                    {                            
                        var currEntityName = responseItem.EntityCollection.Entities[0].LogicalName;

                        foreach (var record in responseItem.EntityCollection.Entities)
                        {
                            // 'record' is the Retreieved record
                            // Perform your desired operations
                        }
                    }

                    if (responseItem.EntityCollection.MoreRecords)
                    {
                        var query = new QueryExpression(responseItem.EntityCollection.EntityName)
                        {
                            ColumnSet = new ColumnSet(true)
                        };

                        query.Criteria.AddFilter(filterActive);

                        var request = new RetrieveMultipleRequest();
                        query.PageInfo = new PagingInfo
                        {
                            Count = 5000,
                            PageNumber = pageNumber,
                            PagingCookie = responseItem.EntityCollection.PagingCookie
                        };

                        request.Query = query;
                        batchRequests.Add(request);
                    }
                }
            } while (batchRequests.Count > 0);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error occurred, error message is {0}", ex.Message);
            throw ex;
        }            
    }

    public List<RetrieveMultipleResponse> TriggerRequests(List<OrganizationRequest> batchRequests)
    {
        var retrieveRequestBatches = batchRequests.AsBatches(recordsPerRequest);
        var batchResponses = ExecuteParallelProxy(batchRequests);            
        var listResponses = new List<RetrieveMultipleResponse>();

        foreach (var key in batchResponses.Keys)
        {
            foreach (var result in batchResponses[key].Responses)
            {
                if (retrieveRequestBatches[key].Requests[result.RequestIndex] is RetrieveMultipleRequest)
                {
                    var originalRequest = (RetrieveMultipleRequest)retrieveRequestBatches[key].Requests[result.RequestIndex];
                    // Capture failed records
                    if (result.Fault != null)
                    {
                        Console.WriteLine($" Exception : {result.Fault.Message}");
                    }
                    else if (result.Response != null && result.Response is RetrieveMultipleResponse) // Capture success records
                    {
                        var responseItem = (RetrieveMultipleResponse)result.Response;
                        listResponses.Add(responseItem);
                    }
                }                    
            }
        }

        return listResponses;
    }

    private IDictionary<string, ExecuteMultipleResponse> ExecuteParallelProxy(IDictionary<string, ExecuteMultipleRequest> retrieveRequestBatches)
    {            
        IDictionary<string, ExecuteMultipleResponse> batchResponses = null;
        try
        {
            batchResponses = CRMPfeConnection.ParallelProxy.Execute<ExecuteMultipleRequest, ExecuteMultipleResponse>(retrieveRequestBatches);                
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
            {
                Console.WriteLine($"Aggregate Error in ExecuteParallelProxy : {ex.Message.ToString()}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error in ExecuteParallelProxy : {ex.Message.ToString()}");
        }

        return batchResponses;
    }

    public static OrganizationServiceManager CRMPfeConnection
    {
        get
        {
            if (crmPfeConnection == null)
            {
                var UserName = ConfigurationManager.AppSettings["UserNameSrc"].ToString();
                var Password = ConfigurationManager.AppSettings["PasswordSrc"].ToString();
                var OrganizationUri = ConfigurationManager.AppSettings["OrganizationUriSrc"].ToString();
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
          crmPfeConnection = new OrganizationServiceManager(XrmServiceUriFactory.CreateOrganizationServiceUri(OrganizationUri), UserName, Password);
            }
            return crmPfeConnection;
        }
    }
  • Similar to ‘RetrieveRequest’, you can trigger all kinds of requests.

🙂

Power Apps | Custom connector | User does not have an entitlement to use PowerApps

September 2, 2020 Leave a comment

From the Dynamics trial instance, while registering a Custom Connector, encountered following issue.

Reason:

  • Error message states clearly, that the User who is trying to register ‘Custom Connector’ does not have ‘Power Apps’ license.
  • By default when you subscribe for trial , Dynamics only grants the ‘Dynamics 365 Customer Engagement Applications’ license which does not have ‘Power Apps’ option.
  • To check the User license, connect to Microsoft 365 Admin Center
  • Go to user’s ‘Manage product licenses’ tab.

Fix:

  • Grant the user Power Apps license to the user.
  • One option is by subscribing for the ‘Dynamics 365 Customer Engagement Plan‘ license by following below steps.
  • Connect to Microsoft 365 Admin Center
  • Go to ‘Billing -> Purchasing Services’.
  • Select ‘Dynamics 365 Customer Engagement Plan Trial’ and click on ‘Get free trial’.
  • You would get following confirmation page up on procurement.
  • Now open the User, and grant the ‘Dynamics 365 Customer Engagement Plan’ license.
    • Make sure ‘PowerApps for Dynamics 365’ is enabled.
  • You should be able to configure Custom Connector now.
  • Refer Power Apps license guide for more details.

🙂

Categories: PowerApps Tags: ,