Displaying Entity Image in Power Apps portal with Table Permissions enforced

Recently, when working with a customer project with Power Apps portal, I bumped into a problem I was not able to solve without writing a custom plug-in. The business case was to list all contacts of the current user’s account in the portal with each contact’s Entity Image displayed.

The simplest way to do this is to simply include the entityimage field in the FetchXML query as explained in this blog post and then apply some JavaScript magic to convert the data into Base64 encoded format the HTML img tag understands.

However, in my case, I need to display multiple contacts on the same page. So my FetchXML query is a little bit different from the one used in the blog post I mentioned above:

<fetch version="1.0" mapping="logical" distinct="false">
  <entity name="contact" >
    <attribute name="fullname" />
    <attribute name="jobtitle" />
    <attribute name="emailaddress1" />
    <attribute name="telephone1" />
    <attribute name="contactid" />
    <attribute name="entityimage" />
  </entity>
</fetch>

There are two things to note about the XML above:

  • On line #1 I am using distinct=”false”. This is because not all contacts have the Entity Image defined. If I use distinct=”true” I receive a Liquid error.
  • On line #8 I am including the entityimage field as part of the result set.

So the entire working web template code is now like this:

<script>
$(window).on("load", function(){
    $("img[data-content]").each(function(){
        var content = $(this).data("content");
        var base64Content = binaryToBase64(content);
        $(this).attr("src", "data:image/png;base64, " + base64Content);
    });
});
function binaryToBase64(content) {
    if (!content) return null;
    var uarr = new Uint8Array(content.split(',').map(function (x) { return parseInt(x); }));
    return btoa(String.fromCharCode.apply(null, uarr));
}
</script>
{% fetchxml contactsQuery %}
<fetch version="1.0" mapping="logical" distinct="false">
  <entity name="contact" >
    <attribute name="fullname" />
    <attribute name="jobtitle" />
    <attribute name="emailaddress1" />
    <attribute name="telephone1" />
    <attribute name="contactid" />
    <attribute name="entityimage" />
  </entity>
</fetch>
{% endfetchxml %}
{% for result in contactsQuery.results.entities %}
    <div class="single-user-tile white-tile">
        <img data-content="{{ result.entityimage | join: ',' }}" width="70" height="70" />
        <div class="col-2">
            <div class="bolded-text">{{result.fullname}}</div>
            <div>{{result.jobtitle}}</div>
        </div>
        <div class="col-3">
            <div>{{result.role}}</div>
        </div>
        <div class="col-4">
            {{result.telephone1}}
        </div>
        <div class="col-5 bolded-text">
            {{result.emailaddress1}}
        </div>
    </div>
{% endfor %}

But one of the business requirements was to list only contacts for the current user’s account. Therefore I needed to change my Table Permissions accordingly. So I ended up with the below definition:

And that’s when the problems started! Remember I mentioned earlier that I had to use distinct=”false” attribute in FetchXML? Well, I started to receive the same error after defining the above Table Permission, even though I had that attribute defined! What?!

Now, if I examine the actual FetchXML used under the hood by outputting it on the web page with:

{{ contactsQuery.xml | h }}

And I get:

<fetch mapping="logical" version="1.0" count="5000" page="1" distinct="true"> 
    <entity name="contact"> 
        <attribute name="fullname" /> 
        <attribute name="jobtitle" /> 
        <attribute name="emailaddress1" /> 
        <attribute name="telephone1" /> 
        <attribute name="contactid" /> 
        <attribute name="entityimage" /> 
        <filter type="and"> 
            <filter type="or" hint="union"> 
                <condition attribute="parentcustomerid" operator="eq" value="1aeaaefe-dbcd-eb11-bacc-000d3adcf108" /> 
            </filter>
        </filter> 
    </entity> 
</fetch>

As you can see, server-side logic has added a filter to the query to comply with the defined Table Permissions. But what has also changed, is that the distinct attribute value has turned into true! And that’s the reason for the Liquid error. If I take the above XML and run it XrmToolBox FetchXml Builder it fails. But if I change distinct attribute’s value to false, it succeeds. Also, if I remove the entityimage from the list of fields to be fetched by the query, it succeeds (even with distinct=”true”).

For some reason, when using Account Access Type Table Permissions, the distinct attribute seems to be always forced to true!

I banged my head against a wall for quite a time there. Finally I ended up with a workaround by mimicking the solution defined here.

My final plug-in class is below.

    public class ImageToBase64 : IPlugin
    {
        private string _base64Field;
        public ImageToBase64(string unsecure)
        {
            _base64Field = unsecure;
        }
        public void Execute(IServiceProvider serviceProvider)
        {
            var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var outputCollection = (EntityCollection)context.OutputParameters["BusinessEntityCollection"];
            context.OutputParameters["BusinessEntityCollection"] = this.ModifyOutput(outputCollection, 
                ((IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory))).CreateOrganizationService(context.UserId));
        }
        public EntityCollection ModifyOutput(EntityCollection output, IOrganizationService service)
        {
            foreach (var entity in output.Entities)
            {
                var results = service.Retrieve("contact", entity.Id, new ColumnSet("entityimage"));
                if (results.Attributes.Contains("entityimage"))
                {
                    var entityImage = results.GetAttributeValue<byte[]>("entityimage");
                    entity[_base64Field] = Convert.ToBase64String(entityImage);
                }
            }
            return output;
        }
    }

Once I built and registered the assembly I added a PostOperation step for contact table.

After that I was able to simplify my Web Template code:

{% fetchxml contactsQuery %}
<fetch version="1.0" mapping="logical" distinct="false">
  <entity name="contact" >
    <attribute name="fullname" />
    <attribute name="jobtitle" />
    <attribute name="emailaddress1" />
    <attribute name="telephone1" />
    <attribute name="contactid" />
  </entity>
</fetch>
{% endfetchxml %}
{% for result in contactsQuery.results.entities %}
    <div class="single-user-tile white-tile">
        <img class="col-1" width="50" height="50" src="data:image/png;base64, {{result.cd_imagecontentbase64}}" />
        <div class="col-2">
            <div class="bolded-text">{{result.fullname}}</div>
            <div>{{result.jobtitle}}</div>
        </div>
        <div class="col-3">
            <div>{{result.role}}</div>
        </div>
        <div class="col-4">
            {{result.telephone1}}
        </div>
        <div class="col-5 bolded-text">
            {{result.emailaddress1}}
        </div>
    </div>
{% endfor %}

And the final result:

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s