{"id":33812,"date":"2022-01-19T07:16:58","date_gmt":"2022-01-19T12:16:58","guid":{"rendered":"https:\/\/centricconsulting.com\/?p=33812"},"modified":"2022-01-18T13:26:51","modified_gmt":"2022-01-18T18:26:51","slug":"creating-a-unified-dataverse-search-experience-in-canvas-apps","status":"publish","type":"post","link":"https:\/\/centricconsulting.com\/blog\/creating-a-unified-dataverse-search-experience-in-canvas-apps\/","title":{"rendered":"Creating a Unified Dataverse Search Experience in Canvas Apps"},"content":{"rendered":"

We walk you through how to set up a Dataverse Search API and connect it to Canvas apps in this step-by-step blog.<\/h2>\n
\n

Recently, I had a client interested in building a Power App<\/a> Canvas app for mobile devices that would take some of the more routine aspects of their Dynamics<\/a> sales process and provide their salespeople with an easier way to do some of the tasks associated with capturing customer information.<\/p>\n

However, this particular client\u2019s users didn\u2019t like using Dynamics, and they wanted to streamline this process for them without needing to use the Dynamics mobile app. Canvas apps to the rescue!<\/p>\n

One Search to Rule Them All \u2013 Using Dataverse Search<\/h2>\n

When I started this project, I admittedly didn\u2019t have a deep knowledge of Dynamics. As a part of the app, the client wanted a single search interface whereby users could search across Contacts, Accounts, Leads and Opportunities, and have those presented in one pane of glass. My immediate thought was to simply use an input control and a gallery to display the results, but with Galleries, they really want a single data schema and data source in order to display information.<\/strong><\/p>\n

With these tables, the data schema was decidedly different across each of them. After doing some digging, I realized my best option was to use the Dataverse Search (formally Dynamics Relevance) API<\/a>. With this being my first real exposure to that API, I immediately went to see if anybody else has ever done this type of work before, and I came across this blog<\/a>.<\/p>\n

This particular solution relied on using a Canvas app and then calling a Power Automate<\/a> flow to retrieve the results from the Dataverse Search API. While it certainly performed the job, what I also found was the lag between clicking the button in the Canvas and the Power Automate returning results would be unacceptable for my client. So, I figured, why not just let Power Apps query it directly?<\/p>\n

Please Mr. Postman<\/h2>\n

My first step into understanding how to query the Search API and return the results I needed was to read the documentation out on Microsoft\u2019s site<\/a>. This information provided me with the necessary syntax to query the API with a POST command. From here, I knew I wanted to test it to make sure I could get results returned.<\/strong><\/p>\n

This is where Postman comes into play. Microsoft also provides a tutorial<\/a> on how to connect to the Dataverse Search API using Postman, especially around authenticating to service, which I found invaluable. By following that tutorial, you\u2019ll be ready to try out a simple query.<\/p>\n

In my case, I had some test data with my name in Dynamics, so I did a search on it. If everything is working properly, you should see a response like the one below:<\/p>\n

\"Dataverse<\/a><\/p>\n

\u00a0{<\/strong><\/p>\n

\u00a0\u00a0\u00a0 \u201csearch\u201d: \u201cJo Karnes\u201d<\/strong><\/p>\n

}<\/strong><\/p>\n

In that search, I simply tested it with a search term query, in this case \u201cJo Karnes\u201d. This particular search would scan across all of the Dynamics tables I configured to search through Dataverse Search (see here for instructions<\/a> on how to configure tables for this), but the requirement for this app was to only return results across four specific tables. We need to specify those tables in the Body of our request. We can do that by defining those entities as shown below:<\/strong><\/p>\n

\"Dataverse<\/a><\/p>\n

\u00a0{<\/strong><\/p>\n

\u00a0\u00a0\u00a0 \u201csearch\u201d: \u201cJo Karnes\u201d,<\/strong><\/p>\n

\u00a0\u00a0\u00a0 \u201centities\u201d: [\u201caccount\u201d, \u201ccontact\u201d, \u201clead\u201d, \u201copportunity\u201d]<\/strong><\/p>\n

}<\/strong><\/p>\n

Now, my results should only return results from those four tables, and we\u2019ve successfully tested a search query to the API. Now we need to get our Canvas app to do the same thing.<\/p>\n

Creating Custom Connectors for Power Apps<\/h2>\n

Did you know that Dynamics licensing allows you to create Custom Connectors for Power Apps? Power Apps licensing can be quite confusing sometimes, but if you have certain Dynamics licensing, you can use custom connectors (unlike the Power Apps license included in Office 365)<\/strong>. The specific licenses you\u2019ll want to have for this are either a PowerApps per App or per User license or one of these Dynamics Licenses:<\/p>\n

\"Dataverse<\/a>

From Microsoft\u2019s Power Platform Licensing guide \u2013 November 2021<\/p><\/div>\n

Let\u2019s Configure Authentication First<\/h3>\n

We\u2019re ready to create the custom connector our Power App will use to connect to the Dataverse Search API. But first things first, we need to add an Azure AD app registration for the API. This will allow us to use delegated permissions to Dynamics so the logged-in user in Power Apps can pass their credentials from Power Apps to the API seamlessly.<\/p>\n

Microsoft has provided a guide for creating this app registration here<\/a>. Once you\u2019ve created the App registration, save the ClientID, DirectoryID and the Client Secret to Notepad, we\u2019ll need these values when creating the custom connector.<\/strong><\/p>\n

\"Dataverse<\/a><\/p>\n

You\u2019ll also want to get the endpoint for your Dynamics environment. This will be in this format: https:\/\/<environment&gt;.crm.dynamics.com\/<\/strong>.<\/p>\n

You can find the exact endpoint of your environment by going to https:\/\/admin.powerplatform.microsoft.com\/<\/a>, clicking on the environment where you want to search, and you\u2019ll see the Environment URL in the details:<\/p>\n

\"Dataverse<\/a><\/p>\n

Now that we have all of this information, it\u2019s time to create our custom connector. Head over to make.powerapps.com<\/a>, click on Data, and then click on \u2018Custom Connectors\u2019.<\/p>\n

\"Dataverse<\/a><\/p>\n

From here, we\u2019re going to want to \u2018Create from Blank\u2019.<\/p>\n

\"Dataverse<\/a><\/p>\n

On the General tab, you can define an icon, and a description, but the most important thing on this screen is the host url. This will be the environment name we captured above. When it\u2019s entered in, click on the Security tab.<\/p>\n

\"Dataverse<\/a><\/p>\n

For Security, we have a few things to define. First, change the authentication type to \u201cOATH 2.0\u201d, then select the Azure Active Directory Identity provider. From here, populate the ClientID, Client Secret and Resource URL. The Client ID and Secret can form our Azure AD app registration, and the Resource URL is the Environment path, but with https:\/\/<\/strong>. When complete, click on the Definition tab.<\/p>\n

\"Dataverse<\/a><\/p>\n

When we get to Definition, the first thing we want to do is to create a new Action. You can name this anything you want, I just kept mine as RelevanceSearch for the Summary, Description and Operation ID. Next, we\u2019ll want to import a sample for the Request. From here we can define what a typical request would look like. For the Verb, choose POST, for the URL, the format of the URL will be: https:\/\/<environment url>\/api\/search\/v1.0\/query<\/strong>.<\/p>\n

For the Headers, we need to add the following Headers and values into the Headers box:<\/p>\n

Content-Type application\/json<\/strong><\/p>\n

Accept application\/json<\/strong><\/p>\n

OData-Version 4.0<\/strong><\/p>\n

OData-MaxVersion 4.0<\/strong><\/p>\n

And finally, for the Body, we\u2019ll pass in an example JSON request. For this sample, I\u2019ve included the \u201centities\u201d definition, as our requirements was to limit our results to just those four tables:<\/p>\n

{\u00a0\u00a0\u00a0 \u201csearch\u201d: \u201cJo Karnes\u201d,\u00a0\u00a0\u00a0 \u201centities\u201d: [\u201caccount\u201d, \u201ccontact\u201d, \u201clead\u201d, \u201copportunity\u201d]}<\/strong><\/p>\n

When finished, click on \u201cImport\u201d.<\/p>\n

\"Dataverse<\/a><\/p>\n

Next, we\u2019ll want to define the response. This is the schema Power Apps expects to get back from the API. The easiest way to get the return schema is to copy and paste it from a response in Postman. Just copy the entire response and paste it into the \u201cImport from Sample\u201d section for the custom connector.<\/strong><\/p>\n

\"Dataverse<\/a><\/p>\n

NOTE:<\/strong> For whatever sample response you use from postman, make sure to include results from all entities you defined. This way, if you have custom fields that should be returned by these entities, they\u2019re included in the response and PowerApps will recognize them.<\/p>\n

\"Dataverse<\/a><\/p>\n

Once you\u2019ve imported the Response, you may get a validation error. You can safely ignore this, I haven\u2019t seen any impact when returning data.<\/p>\n

\"Dataverse<\/a><\/p>\n

Finally, you can choose to test the connector, of you can just click on \u201cCreate connector\u201d to save the connector.<\/p>\n

\"Dataverse<\/a><\/p>\n

NOTE:<\/strong> When you save the connector, on the Security tab, you will see the Redirect URL that has been defined for the Connector. Verify that the same Redirect URL is defined on the Azure AD App Registration, or you may encounter an authentication error.<\/p>\n

\"Dataverse<\/a><\/p>\n

\"Dataverse<\/a><\/p>\n

Let\u2019s Make an App<\/h2>\n

Now that we\u2019ve defined our custom connector, we can create a Power App to use to search. Our first step is to create a blank Canvas app and add the custom connector.<\/p>\n

\"Dataverse<\/a><\/p>\n

Next, add two controls. The first is a Text Input box and the second is a Blank Vertical Gallery. See the example below.<\/p>\n

\"Dataverse<\/a><\/p>\n

Now, we need to modify the \u201cOnChange\u201d value of the Text Input box. This way, any time we type in a search, it will communicate with the API to get our results (NOTE: the \u201cOnChange\u201d value will only execute when the Text Input box loses focus. It might be helpful to add an icon people can \u201cselect,\u201d which will then move focus off of the Input box<\/strong>). We\u2019re going to set a variable called varRelSearchResults, which will pass the Text from our Text Input box to the API and collect all of the results into a variable.<\/p>\n

\"Dataverse<\/a><\/p>\n

Change the \u201cItems\u201d property of the gallery to varRelSearchResults<\/strong>. Now you can add any controls you want to display on to the template of the Gallery to show your results.<\/p>\n

\"Dataverse<\/a><\/p>\n

Conclusion<\/h2>\n

I hope this is something you may find useful, especially if you have want to be able to connect to custom API\u2019s for Dynamics.<\/p>\n","protected":false},"excerpt":{"rendered":"

We walk you through how to set up a Dataverse Search (formally Relevance Search) API and connect it to Canvas apps in this step-by-step blog.<\/p>\n","protected":false},"author":86,"featured_media":33834,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_oasis_is_in_workflow":0,"_oasis_original":0,"_oasis_task_priority":"","_relevanssi_hide_post":"","_relevanssi_hide_content":"","_relevanssi_pin_for_all":"","_relevanssi_pin_keywords":"","_relevanssi_unpin_keywords":"","_relevanssi_related_keywords":"","_relevanssi_related_include_ids":"","_relevanssi_related_exclude_ids":"","_relevanssi_related_no_append":"","_relevanssi_related_not_related":"","_relevanssi_related_posts":"","_relevanssi_noindex_reason":"","footnotes":""},"categories":[1],"tags":[],"coauthors":[15564],"acf":[],"publishpress_future_action":{"enabled":false,"date":"2024-07-21 20:58:08","action":"change-status","newStatus":"draft","terms":[],"taxonomy":"category"},"_links":{"self":[{"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/posts\/33812"}],"collection":[{"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/users\/86"}],"replies":[{"embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/comments?post=33812"}],"version-history":[{"count":0,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/posts\/33812\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/media\/33834"}],"wp:attachment":[{"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/media?parent=33812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/categories?post=33812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/tags?post=33812"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/centricconsulting.com\/wp-json\/wp\/v2\/coauthors?post=33812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}