Row Update After SharePoint File Upload

A common requirement is to update the record row in Dataverse table after a file has been uploaded to SharePoint. This small post documents the steps and expressions for it. For demonstration, I m using “Account” table and have created “URL” a custom column in it. After file uploads, I will update the row and safe URL in this field.

Summary

This post do not cover the steps required to configure SharePoint for document storage with Model-Driven App. Follow this link for integration details). Cloud flow triggers when a file is uploaded from Model Driven App and created in the SharePoint document library.

  1. Create a cloud flow and add “When a file is created (properties only)” trigger. Configure the following properties:
    • Site Address
    • Library Name

2. To upload Dataverse row, we need GUID. Unfortunately it is not available as plain text, though we can drive it from trigger’s Folder path property.

Its value will be similar to account/test_67B9406FCBB7EB118236000D3A6A4A8A/

we need to extract GUID from it. Expression which I have used uses three functions and here is complete expression:

replace(last(split(triggerOutputs()?[‘body/{Path}’],’_’)),’/’,”)

Need explanation ?

split(triggerOutputs()?[‘body/{Path}’],’_’) will divide account/test_67B9406FCBB7EB118236000D3A6A4A8A/ into two from ‘_’. Wrapping it under last function will return 67B9406FCBB7EB118236000D3A6A4A8A/ only. I have used replace function to remove last ‘/’.

3. In step 2, we have got the GUID but it is not in format that we can used to fetch or update row. Instead of

67B9406FCBB7EB118236000D3A6A4A8A

we need it in 67B9406F-CBB7-EB11-8236-000D3A6A4A8A format.

Here is expression that will do this:

concat(substring(variables(‘StringGUID’),0,8),’-‘,substring(variables(‘StringGUID’),8,4),’-‘,substring(variables(‘StringGUID’),12,4),’-‘,substring(variables(‘StringGUID’),16,4),’-‘,substring(variables(‘StringGUID’),20,12),”)

In this post I have explain this expression.

4. Last steps is to use FormatedGUID and update record. For demo I have created a custom field “URL” and populating document URL in it.

Lets test the Flow after turning it on.

Let’s Connect

 twIcon lnIcon fbicon

Convert SharePoint Uploaded Word File to Pdf

Did you ever receive a requirement that a Word file uploaded through a model-driven app in SharePoint should be converted and saved as Pdf? I had this requirement in multiple projects. Recently I have used cloud flow to achieve this. It was a model-driven app that has integration with SharePoint for document storage. In this post, I m documenting steps.

Summary

The app has SharePoint integration enabled for the “Account” table (this post does not cover how to integrate SharePoint with Model Driven Apps, follow this link for integration details). Flow triggers when a file is uploaded from Model Driven App and created in SharePoint document library. It then uses that uploaded Word file and creates Pdf copy, and finally delete the Word version. For explaining steps, I will use the following document URL, this file was uploaded by my model-driven app:

https://mydomain.sharepoint.com/sites/Documents/account/test_67B9406FCBB7EB118236000D3A6A4A8A/vr.docx

Steps

  1. Create a cloud flow and add “When a file is created (properties only)” trigger. Configure the following properties:
    • Site Address
    • Library Name

We don’t want to trigger this flow on any file upload; rather, we want to trigger it only when a word file is created. Configure “Trigger Conditions” for word file extensions “.doc” and “docx”.

Here are expressions:

@contains(triggerBody()?[‘{FilenameWithExtension}’],’.docx’)
@contains(triggerBody()?[‘{FilenameWithExtension}’],’.doc’)

2. Initialize a string type variable “DocumentsFolderName ” to hold the subdirectory name. This is the container folder for all attachments of Model-Driven App table. Since I have configured document upload for “Account” table, its value is “account” for me. The expression in the following action will use this variable.

3. Initialize another string variable “FileNameWithPath” and use the following expression as value:

concat(replace(triggerOutputs()?[‘body/{Path}’],variables(‘DocumentsFolderName’), ”), triggerOutputs()?[‘body/{FilenameWithExtension}’])

What does this expression do?

Let’s use our example document URL, which is:

https://mydomain.sharepoint.com/sites/Documents/account/test_67B9406FCBB7EB118236000D3A6A4A8A/vr.docx

this variable will hold /test_67B9406FCBB7EB118236000D3A6A4A8A/VR.docx as value to be used in next steps.

4. Initialize string variable “NewFileNameWithExtension” and assign given expression as value:

concat(triggerOutputs()?[‘body/{Name}’], ‘.pdf’)

5. Convert Word document to Pdf, use action and do the following configs:

“Location” and “Document Library” should remain same (where Word document was uploaded). Assign “FileNameWithPath” variable as value in “File”.

6. Use SharePoint Create file action and configure as below:

  • Site Address should be same SharePoint site
  • Folder Path: assign trigger’s “Folder path”
  • File Name: use “NewFileNameWithExtension” variable
  • File Content: use output from, Convert Word Document to Pdf, previous step

7. Configure SharePoint (Delete file action) to delete original Word file

Use trigger’s Identifier in “File Identifier” field.

and that’s it, this flow will convert any word document uploaded to Pdf asynchronously.

Let’s Connect

 twIcon lnIcon fbicon

Convert a string to GUID in Power Automate

Power Automate Convert a String to GUID

Convert a string to GUID in Power Automate

Suppose you need to create a new globally unique identifier (GUID). In that case, Power Automate provides guid() function which generates and returns a new GUID as string. It is a useful function, but it doesn’t create a GUID based on string we provide, the way it works in C#. This post will explain how to convert a string into GUID format with dashes (with or without curly braces).

I m making this cloud flow manually triggerable for the sake of post, initializing a variable with the GUID string.

Next, I m converting this string to GUID (with dashes) using expression and storing in a variable.

Here is expression I used, for me variable name is StringGuid, please change as per your situation.

concat(substring(variables('StringGuid'),0,8),'-',substring(variables('StringGuid'),8,4),'-',substring(variables('StringGuid'),12,4),'-',substring(variables('StringGuid'),16,4),'-',substring(variables('StringGuid'),20,12),'')

Same way to convert this string to a formated GUID with curly braces I m using this expression with a variable.

Here is expression to generate GUID with curly braces

concat('{',concat(substring(variables('StringGuid'),0,8),'-',substring(variables('StringGuid'),8,4),'-',substring(variables('StringGuid'),12,4),'-',substring(variables('StringGuid'),16,4),'-',substring(variables('StringGuid'),20,12),''),'}')

Output:

I hope you found this post helpful. If you like to see this available as a feature please vote this idea.

Let’s Connect

 twIcon lnIcon fbicon

Fiddler for Model Driven Apps

While developing ‘PowerApp Components’ and traditional ‘Web Resources’, a common challenge is that testing is not straight forward. To test a change in HTML or JS code, one needs to deploy files, which is time-consuming. There are commercial tools available for model-driven apps to make it simpler but still using Fiddler have advantages. This first post of this series will explain how it works and how to get started with it.

What is Fiddler ?

Fiddler is a web proxy debugging tool often used by web developers. Basic version which we need is free forever and can be downloaded from here.

How does it work?

First, we add a web resource shell in the model-driven app, so if it JS, a file with just function name is fine. We still need to configure that function to trigger on load or save events in form properties. From this point to on we can start using Fiddler. We code in Visual Studio, configure Fiddler and open model-driven app in a browser. Fiddler will interrupt incoming request and replace JS file coming from cloud with file open in Visual Studio. Do a code change, just refresh and see the latest JS change without deploying it in app.

Benefits

  1. We can test JS/ HTML code without deployment. Do code change in Visual Studio, refresh your browser and verify changes.
  2. One can debug or develop without affecting other developers or users. Complete your work and when done deploy for testing.

Steps

  • Add web resource to model-driven app if it is a new resource. For details about web resources see this link and links under “See Also” section of it.
  • Install Fiddler
  • From Fiddler > Tools > Options > HTTPS, do the following:
    • Ensure “Capture HTTPS CONNECTs” and “Decrypt HTTPS traffic” are checked
    • In drop down “…from browsers only” is selected
    • “Certificates generated by” has “CertEnroll engine”
    • Click “Actions > Reset Certificates” and accept all prompts

  • Under Filters tab do the following configurations, these will help in targeting only relevant requests:
    • “Use Filters” check box is checked
    • Ensure for “Hosts”, “Show only Internet Hosts” is selected
    • Add your app URLs
    • “Show only if URL contains” is checked and it has “/webresources/”
  • In “AutoResponder” tab, do the following configs. Here we are telling which web resource we are working and what is the location of development version:
    • “Enable rules” is checked
    • Click Add Rule
    • Enter regular expression with name of JS file like “regex:(?insx).+/account.js”
    • Enter path to development version of file on local disk
    • Press save button
    • Ensure rule created is enabled
  • Check “Capture Traffic” under file menu:
  • Refreshing browser Fiddler should start capturing traffic. If we open the browser’s dev tools we can see code changes reflected without deploying them.

I hope it was helpful.

Querying Audit History

Audit history is a great out of box feature in model-driven apps. However, querying audit history is a bit tricky. Unfortunately commonly used querying mechanisms like Power Automate CDS connectors, LinQ, or simply FetchXml doesn’t support it. This post will discuss options we have and sample code for it.

Options

  1. Using SDK messages, RetrieveRecordChangeHistoryRequest & RetrieveRecordChangeHistoryResponse, covered in this post 
  2. Using Kingswaysoft’s Integration Toolkit for D365 (not covering in this post)

Scenario

I will query audit history for contact entity records and read audit details for its email address attribute. Audit details are available under these four heads:

  • Changed date
  • Changed field
  • Old value
  • New value

If auditing is enabled, this code will work for almost any entity and attributes.

How it works

We need ids (GUID) of entities and using those we will query audit history. I m using a fetchxml query to retrieve ids, but it can be mechanism of your choice depending on implementation and requirement.

       var targetEntites_query = @"<fetch {0}>
                                <entity name='contact'>                               
                                 </entity>
                                 </fetch>";     

Generally we know FetchXml can return maximum 5000 entities, but this code will handle and return even if there are more then 5000 records in the result.

public List<Entity> RetrieveAllRecords(string fetch)
        {
            var moreRecords = false;
            int page = 1;
            var cookie = string.Empty;
            List<Entity> Entities = new List<Entity>();
            do
            {
                var xml = string.Format(fetch, cookie);
                var collection = CrmClient.RetrieveMultiple(new FetchExpression(xml));

                if (collection.Entities.Count >= 0) Entities.AddRange(collection.Entities);

                moreRecords = collection.MoreRecords;
                if (moreRecords)
                {
                    page++;
                    cookie = string.Format("paging-cookie='{0}' page='{1}'", System.Security.SecurityElement.Escape(collection.PagingCookie), page);
                }
            } while (moreRecords);

            return Entities;
        }

Tip: FetchXml query must have {0} if query will return more then 5000 records. Additional columns can be added in fetch if required.

Next, I m looping through these ids and read audit history for records using this code:

 public AuditDetailCollection GetAuditHistory(string entityLogicalName, Guid recordId)
        {           
            var changeRequest = new RetrieveRecordChangeHistoryRequest();
            changeRequest.Target = new EntityReference(entityLogicalName, recordId);
            var changeResponse = (RetrieveRecordChangeHistoryResponse)this.CrmClient.Execute(changeRequest);             
            return changeResponse.AuditDetailCollection;
        }

Above function returns AuditDetailCollection which has a collection of AuditDetails. One Audit detail represents one entry in audit history. Please note audit history records are in the same order as they appear in UI (descending).

Every audit details record will have a changed date, and collection of new and old values with field names which we will need to loop through and read.

Below is code to accomplish this:

             //Collection of entities for which we are going to read audit history
            var AllTargetEnteties = this.RetrieveAllRecords(targetEntites_query);


            foreach (var targetComplaint in AllTargetEnteties)
            {
                //Now pass id(guid) of record with entity name to retrieve audit history 
                var audit_history_entries = this.GetAuditHistory(targetComplaint.LogicalName, targetComplaint.Id);


                foreach (AuditDetail auditDetail in audit_history_entries.AuditDetails)
                {

                    if ((auditDetail.GetType())?.Name == "AttributeAuditDetail")                     
                    {
                        //Below code reads Changed Date
                        var changeDate = auditDetail.AuditRecord.GetAttributeValue<DateTime>("createdon");

                        var newValueEntity = ((AttributeAuditDetail)auditDetail)?.NewValue;
                        if (newValueEntity.Attributes.Count > 0)
                        {
                            {
                                foreach (var attrNewValue in newValueEntity?.Attributes)
                                {
                                    //Here we will need to match attribute name to read new value.
                                    //In this case I m reading emailaddress1
                                    if (attrNewValue.Key == "emailaddress1")
                                    {                                        
                                        var newEmailAddress = attrNewValue.Value;
                                        //Custom Logic for New Value here

                                    }
                                }
                            }
                        }


                        var oldValueEntity = ((AttributeAuditDetail)auditDetail)?.OldValue;
                        if (oldValueEntity.Attributes.Count > 0)
                        {
                            foreach (var attrOldValue in oldValueEntity?.Attributes)
                            {
                                //Here we will need to match attribute name to read old value.
                                //In this case I m reading emailaddress1
                                if (attrOldValue.Key == "emailaddress1")
                                {
                                    var oldEmailAddress = attrOldValue.Value;
                                    //Custom logic for Old value will be here

                                }
                            }

                        }

                    }
                }
            }

Let’s Connect

 twIcon lnIcon fbicon

Set Lookup Field in Java Script

Adding this post for someone who needs it and for my own reference.

In Java Script lookup can be populated in one of three ways depending on requirements:

  1. Query lookup data to set in form
  2. Get lookup details from data available in form (from other fields)
  3. Hard code lookup values

This is example using second option. It uses logged in user’s id and name to populate lookup. A lookup can be populated by providing its id (GUID) , name and entity type.

var approver = new Array();
approver[0] = new Object();
approver[0].id = Xrm.Page.context.getUserId(); // Guid as "{a004b16f-4bae-4445-9b15-438449a170d3}"; 
approver[0].name = Xrm.Utility.getGlobalContext().getUserName();
approver[0].entityType = "systemuser";
Xrm.Page.getAttribute("sofhof_approvedby").setValue(approver);

I hope it is helpful.

Let’s Connect

 twIcon lnIcon fbicon

Accessibility Resources

Accessibility is an essential consideration for a public sector or enterprise implementation. In this post I m sharing some resources generally about accessibility and also particularly about accessibility in Power Platform Projects. Some of the resources are from Microsoft and others are links to the work I have been doing in previous years. While preparing this list I m feeling very hopeful and excited, why ? because few years back there were not many resources available but now we have good collection, isn’t great 🙂

Resources

  1. Accessibility Fundamentals learning path at Microsoft Learn
  2. I presented ‘Accessibility in Power Platform Projects’ at Scottish Summit, here is link to recording
  3. Similar to above another session at our own “The Good Citizen Developers”, here is recording.
  4. In Oct 2020 I presented “Accessibility in PowerApp Projects” at Washington DC – User Group. Thanks to lovely organizers and supporters of UG Kylie KiserAiden KaskelaNelson JohnsonMike Ochs and others. I covered things like what accessibility is, why it is important and how to make a PowerApp project accessibility compliance. Here is recording https://www.youtube.com/watch?v=GdK2eV8oOLU
  5. Microsoft Accessibility Conformance Reports can be downloaded from here
  6. My blog posts on accessibility:

    “Accessibility” for D365 Projects
    “Accessibility” for D365 Projects 2
  7. Scottish Summit 2021 accessibility sessions

Let’s Connect

 twIcon lnIcon fbicon

Binding CDS Data using Knockout (more tips)

This post is second in a series of querying CDS entity data and displaying it in a model-driven app web resource. A few days back, I wrote first post in this series CDS Data Binding using Knockout. Here I m answering a couple of questions and sharing a few more tips.

Though I have fetched data using WebApi and J-Query but any mechanism that returns object array will work. Yes, we can use FetchXml for querying data too.

The second thing is we can query data from multiple related entities using expand oData function. In this scenario, query returns cases with customer details. Customer can be an account or a contact:

var query = "/api/data/v9.1/incidents?$select=title&$expand=customerid_account($select=name),customerid_contact($select=fullname)";

While doing data binding a few times, I got an error:

Cannot ready property ‘name’ of undefined

The reason was in data few records don’t have customerid_account (parent object was null). To solve this, I have used if binding (Knockout offer different bindings) which checks and only bind the data if the object is not null.

<td>
<!--ko if:customerid_account -->
  <span id="accountNamee" data-bind="text:customerid_account.name"> </span>
<!--/ko-->
</td>

Knockout ‘with’ binding can also be used for this:

<td>
 <!--ko with:customerid_contact -->
         <span id="contactName" data-bind="text:fullname"></span>
 <!--/ko-->
</td>

We can do few tricks by using if and ifnot (else) bindings too. Query above is perfect example we either have customerid_account or customerid_contact not both. My requirement was to display combined data from both fields as one:

Here is complete sample code:

<!DOCTYPE html>
<html>
<head>

    https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js
    https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js
    http://../../../ClientGlobalContext.js.aspx
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">

    <script>
        $(document).ready(function () {           
            var query = "/api/data/v9.1/incidents?$select=title&$expand=customerid_account($select=name),customerid_contact($select=fullname)";
            var oDataUrl = top.Xrm.Page.context.getClientUrl() + query;
            var _data = null;

            $.getJSON(oDataUrl)
                .done(function (data) {
                    if (data != undefined && data.value.length > 0) {
                        ko.applyBindings(new AppViewModel(data));

                        debugger;
                    }
                })
                .fail(function (error) {
                    debugger;
                });

        });


        function AppViewModel(data) {


            var self = this;
            self.Results = ko.observableArray([]);

            ko.utils.arrayForEach(data.value, function (d) {

                self.Results.push(d);

            });

        }



    </script>
</head>
<body>

    <div style="overflow-x:auto;">
        <h4 class="text-center">List of Cases</h4>
        <table id="tblContainer" class="table table-sm table-striped table-hover table-borderless">
            <thead>
            <th>Title</th>
            <th>Account</th>
            <th>Contact</th>
            <th>Client</th>
            </thead>

            <tbody data-bind="foreach: Results">
                <tr>
                    <td><span id="title" data-bind="text:title"></span></td>
                    <td>
                        <!--ko if:customerid_account -->
                        <span id="accountNamee" data-bind="text:customerid_account.name"></span>
                        <!--/ko-->
                    </td>

                    <td>
                        <!--ko with:customerid_contact -->
                        <span id="contactName" data-bind="text:fullname"></span>
                        <!--/ko-->
                    </td>
                    <td>
                        <!--ko if:customerid_account -->
                        <span id="accountNamee" data-bind="text:customerid_account.name"></span>
                        <!--/ko-->
                        <!--ko with:customerid_contact -->
                        <span id="contactName" data-bind="text:fullname"></span>
                        <!--/ko-->
                    </td>


                </tr>
            </tbody>
        </table>

    </div>


</body>
</html>

I hope you find this useful.

Let’s Connect

 twIcon lnIcon fbicon

CDS Data Binding using Knockout

In this post, I am explaining how to query data from a CDS entity and use Knockout to bind it in a model-driven app web resource. It has the following advantages:

  1. It is easy don’t require a lot of efforts (less coding)
  2. We have the flexibility to do further customisation

About demo:

Since it is demo, I have included script and link references from CDN. The focus of this post is to explain and share sample code for data binding. I m loading my web resource as a popup and have used AlertJS‘s free version for this. To keep this post short, I m not explaining how to add a button in Model-Driven App. But to summarise steps I have added JS file in my form, customised ribbon and added a button with the following code.

"use strict";
///<reference path="../mag_/js/alert.js">
var Account = (function ()
{
	return {
		LoadAccountsPopup: function (executionContext)
		{   
            Alert.showWebResource("webresource_accounts");			 
		}
	}
})();

In my web resource, I m getting data using Web API query. Data binding is done of course using Knockout and have used Bootstrap for styling. Here is code:

<!DOCTYPE html>
<html>
<head>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js" type="text/javascript"></script>
    <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">

    <script>
        $(document).ready(function () {
            var query = "/api/data/v9.1/accounts?$top=22&$select=name,telephone1,address1_city";
            var oDataUrl = parent.Xrm.Page.context.getClientUrl() + query;          

            $.getJSON(oDataUrl)
                .done(function (data) {
                    if (data != undefined && data.value.length > 0) {
                        ko.applyBindings(new AppViewModel(data));

                        debugger;
                    }
                })
                .fail(function (error) {
                    debugger;
                });

        });
        function AppViewModel(data) {
            var self = this;
            self.pingResults = ko.observableArray([]);
            ko.utils.arrayForEach(data.value, function (d) {
            self.pingResults.push(d);
            });
        }
    </script>
</head>
<body>

    <div style="overflow-x:auto;">
        <h4 class="text-center">List of Accounts</h4>
        <table id="tblContainer" class="table table-sm table-striped table-hover table-borderless">
            <thead>
            <th>Account Name</th>
            <th>Telephone</th>
            <th>City</th>

            </thead>

            <tbody data-bind="foreach: pingResults">
                <tr>
                    <td><span id="fileName" data-bind="text:name"></span></td>
                    <td><span id="fileType" data-bind="text:telephone1"></span></td>
                    <td><span id="fileType" data-bind="text:address1_city"></span></td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

I hope you find this helpful. If you have a question please leave me a comment on my blog and I will try to assist.

Enjoy your day.

Let’s Connect

 twIcon lnIcon fbicon

Power Chat with Olena Grischenko

Based in Sydney Australia Olena is a Microsoft MVP, developer and architect. She has vast experience in software development, D365 CE and Power Platform. She is a community speaker and organiser of multiple user groups.

Tell us about yourself (experience, background, industries, community service, else)

Started as a .Net developer, I’ve been working in IT for 20 years. Have worked with all versions of D365 CE and portals. As a part of my role, I do hands-on development, integration and architecture. I also do no-code development where required. Tried multiple times to give up “coding” for more manager type of roles but was always coming back. Started working as an independent consultant last October then launched a company with my partner in January. My favourite industry is higher education. Most of my projects are free community activities. I organise BizApps Women NSW, #PowerLabs and Microsoft 365 Pro-Low-No-Code Devs user groups. Also, I’m in the committee for Dynamics 365 UG NSW.

For the success of a Power App or D365 CE project, what are a few things (practices or steps) you do when kick-starting a new project?

Making sure this project is not set to failure from the beginning, and I’ve got a real power to make things happen by putting my effort and knowledge into it.

What delivery methodology you have found useful in projects?

Some people would say “it depends”. This is how I would like to answer too. But the truth is I am a true SCRUM believer. I had the opportunity to work with the most fantastic coach for SCRUM for Dynamics 365, Neil Benson, in one of the most successful implementations in my entire professional career.

What is one thing that can make a project successful or vice versa?

For me, the success of a project from the beginning of a project is very much predefined by a desire of key stakeholders and other key parties involved for the project to succeed. 

If people were forced to a change and they don’t believe this is the best way to go the rest of it is just a waste of their and your time. It’s tough to be a part of something which is doomed from the beginning. Unfortunately, it happened to my team and me before, and it’s a very traumatic experience.  

Give me two (or more) tips that will enhance the performance of my applications?

Don’t overthink or overcomplicate things, use the latest frameworks and SDKs which are up-to-date with security and performance updates. Make sure you understand the pros and cons of different approaches. Don’t have a solution, have more than one, understand the benefits of each.

Tell us two things (or more) which will improve the quality of deliveries?

Having a good team. Staying connected with a business and getting constant feedback.

In the context of D365 CE implementation, what does architecture means to you?

In terms of a SCRUM delivery architecture is not something predefined and one of. For me, it means it should be reviewed regularly to check if thigs we developed earlier make sense still.

What few things you consider when you are architecting or designing a solution?

Costs, licencing, maintenance and support. Scalability to a degree. I am not against “temporary” solutions, everything is temporary, but you should be aware of the price your customer is going to pay in the future.   

Tell us anything that you consider is/are the best practice(s) and everyone should follow?

There is no such thing as common sense so I can’t answer this question properly.

Share a tip of yours to boost productivity as a dev, consultant or architect?

Stay focused. Find a balance of a customer-facing and quiet time to concentrate. Both sides are crucial for a good consultant. Listen and hear.   

Tell us about a canvas app that you have built or seen which was awesome?

The most amazing ones are those built by end-users. Because they help them to solve their day to day problems.

Have you seen an impressive AI application recently, preconfigured or custom which you want to mention?

I believe that the most amazing applications are still in the future. We have to make sure it’s inclusive in all possible ways.

How you analyse and build security in projects? Any tips?

Not leaving to the very end of a project?

While doing configurations, do you follow some rules or practices?

There are too many of them.

Managed or Unmanaged?

Should I say “it depends” again “? Managed – for boxed products and unmanaged – for service projects and framework type of products. It may change or even it WILL change in the future, but for me it still the rule I follow.

Early bound or late bound?

Don’t like early bound. I know it’s a bad answer, wrong even.

LINQ, FetchXML or QueryExpression?

Can I keep them all?

Realtime vs batch?

Expectation vs reality. Batches aren’t ideal, but in some cases, we may not even have API available to integrate with. It’s not like we choose. For some areas like IoT, banking, blockchain etc you don’t even think “batches”. It depends.

No code/ low code or hardcore development?

Smart code. Saying you are pro-code or pro-nocode means you are too lazy to think of the best in each case solution. You have to learn about all possibilities and consider all options.

Generally for integration which technology and pattern is your choice?

My choice is to provide my customer with the decision-making matrix, so they know their options.

Any open-source, community development, toolbox plugin that you want someone to develop?

I want to develop a per-component backup restore for the portal packages available via Portal Record Mover in XrmToolBox. But I can’t find a time to do it, unfortunately.

If you have all the resources to improve one thing in D365 what that would be?

ALM

What is one thing in model apps you consider people are not utilising its full potential?

Not sure. It depends on the client.

If you are selling D365 just by one feature, what that feature is?

It plays nicely with Office 365.

What would you advise a girl starting in IT and working with Power Platform?

“If you don’t ask questions you look like you know stuff, if you ask questions you actually know it. Don’t look smart, be smart. It’s scary to be the only girl in a room but if it’s what you like to do then be brave and follow your dream. We all hope for a better more diverse, more inclusive world. Be a part of a good change. I love Power Platform because it allows people with no dev background to start building apps and solve business problems. It can be a great way to fall in love with technologies.”

What advice will you give your younger self who is already working as a D365 CE professional?

I’ve done well by choosing it as your career path don’t worry about stopping being a hands-on person; it will never happen.

What are a few things you do to be efficient in working?

If I can’t move faster to achieve my goals, I simply move. People don’t get the concept of time. They worry about something too late to learn or do. If you start today tomorrow, you will be much further than you were yesterday, regardless of speed.

What is the best way to keep up with technological advancements and changes?

Try to keep learning fun, do more hands-on stuff. Don’t believe in everything you see/watch/hear in social media sites. Take small steps but learn regularly.

Thanks Olena.

Let’s Connect 🙂

Let’s Connect

 twIcon lnIcon fbicon