Sunday, May 14, 2017

An even more clever workaround for saving photos to SharePoint from PowerApps – using Microsoft Flow

At the time of writing there is a gap using PowerApps with SharePoint which won’t let you save a captured image from PowerApps directly to SharePoint. There are numerous posts out there about this, and Paul Culmsee wrote a post with a clever work around using Azure functions to get the image over to SharePoint.

Paul posted about this in Facebook, and cheeky me replied:
 
image

Note the (not really) at the end there, so I blame Paul entirely for making me write this post, which I think introduce an even more clever way of doing this – doable for any power user out there :D

I’ll skip all the fancy parts which Paul has to get nice random file names etc, so head over to his post for that piece of the pie.

A small note to Paul, and every one else – this will not work for the Windows desktop version of PowerApps – as it stores the captured image different compared to other devices. Instead of using the data uri notation with the full image base64 encoded, it only has a blob reference.

I’ve tested it with great success on:
  • Web
  • Windows Phone – Win10
  • iPad – iOS 10.3.1
So how do you do this? (I strongly urge you to read his post first, as it explains it all in very detail, where as I jump to the gist of things.)

First off, create a new PowerApp and add a camera control to the canvas. For the OnSelect command for the camera add the following command:

ClearCollect(PictureColl,Camera1.Photo)

When you click the image box it will grab the photo, and store it in a collection named PicureColl. As I’m using ClearCollect, the collection will always be cleared first, having one image only in the collection.

image

Next, I added a button which will send the image to SharePoint via Microsoft Flow. So let’s head over to Flow and see what the Flow looks like?

First add a collect from PowerApps actions. Then add a Create file in SharePoint action. For the file name and content, click “Ask in PowerApps”. This will generate two input variables, which we will use to pass in information from the PowerApp to the Flow.

image

Next, add a Compose step between the PowerApps action and the create file in SharePoint action. This is where we will strip away the base64 header, and convert the data to binary. You can type formulas directly into the SharePoint step as well, but I find it easier to manage this way.

The formula in the compose step is:

"@base64ToBinary(replace(triggerBody()['Createfile_FileContent'],'data:image/jpeg;base64,',''))"

"@dataUriToBinary(triggerBody()['Createfile_FileContent'])"

NOTE: It’s important to add the quotes "" before and after the expression, even though they don’t show on edit.

Next change the File Content box to retrieve the Output from the compose step instead of the collect from PowerApps as seen below.

image

And that’s it for the Flow, and head back to the PowerApp. Using PowerApps studio add a Flow to your app.

image

For the OnSelect command for the button add the following:

Saveimage.Run("test.jpg",First(PictureColl).Url)

Saveimage is the name of the Flow, which takes two parameters. The first being the filename, the second being the base64 encoded image from the Url parameter of the image. (All this is in Paul's great post.)

Fire up the app, click once on the image, and once on the button, and you should see a nice picture stored in your SharePoint library.

image

You can very well combine the OnSelect statements into either the image or button control if you want, but that’s all in how you want to have your UI. Having two controls made the demo simpler :)

19 comments:

  1. Mikael, I have followed you excellent article above to the letter and this did not work for me.

    The image gets created in the "Picture Coll" but nothing uploads to Sharepoint. What formula should I be using in the compose step?

    The code that has a strikethrough, the code below that or all of it?

    Regards

    Ian

    ReplyDelete
    Replies
    1. Do you get the flow to run? Are you seeing any errors in the log for it?

      Delete
    2. And be sure not to use the Windows version of PowerApps, as that doesn't work. Any other version is fine.

      Delete
    3. What do you mean by the Windows version of PowerApps, what other versions are there?

      Delete
    4. The error I get in in the compose section so the Flow does not run, details as follows:

      InvalidTemplate. Unable to process template language expressions in action 'Compose' inputs at line '1' and column '1549': 'The template language function 'dataUriToBinary' expects its parameter to be formatted as a valid data URI. The provided value 'blob:93427F3F-9F71-431F-8D30-2A3A8F0C1490' was not formatted correctly. Please see https://aka.ms/logicexpressions#dataUriToBinary for usage details.'.

      Delete
    5. You are using Windows :) Try using PowerApps in a web browser, on Android, iOS or WinPhone and it works. And noted at the top of the post :)

      Delete
    6. Mikael, sorry I missed the notes at the top of the post. The good news is that I no longer have an error with the compose section of the Flow. Now I am getting a permissions on the Sharepoint Create a file section as detailed below:

      Error Message.

      "status": 403, "message": "Access denied. You do not have permission to perform this action or access this resource.", "source": "https://stonarimages.sharepoint.com/sites/PowerAppDemo/_api/web/GetFolderByServerRelativeUrl('/sites...')",

      "errors": [ "-2147024891", "System.UnauthorizedAccessException"

      I am the only user in my Sharepoint tenant and I have full access to the document library in question and I get this message on every device I use the app on.

      It is driving me mad. Any ideas?

      Delete
    7. Weird... you could try to re-add the SP connection and see if that helps.

      Delete
    8. Already tried that with no success.

      Delete
    9. Can you for example create a .txt file using flow in the same or another site/lib?

      Delete
    10. Mikael, permissions issue seems to have gone on the Create file step but now the flow is giving me the following error and I have no idea what it means:

      InvalidTemplate. Unable to process template language expressions in action 'Create_file' inputs at line '1' and column '1511': 'The template language expression 'json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$connections']['shared_sharepointonline_1']['connectionId']' cannot be evaluated because property 'shared_sharepointonline_1' doesn't exist, available properties are 'shared_sharepointonline'. Please see https://aka.ms/logicexpressions for usage details.'.

      Delete
    11. Looks like the SP connection is broken of sorts. I would try to re-create the connection and the Flow and see if that works. Something is clearly saved wrong.

      Delete
    12. Mikael, thanks for your support. I think I will start again from scratch and will let you know how I get on.

      Delete
    13. Mikae,

      In the following code is it UriToBinary or UrlToBinary)

      "@dataUriToBinary(triggerBody()['Createfile_FileContent'])"

      Delete
    14. dataUriToBinary as per https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-workflow-definition-language

      Delete
  2. Hi Mikael, first of all great post on getting this done!
    Wanted to check, I have followed your post and I seem to be having an issue at the last step, adding a flow to the button.

    After adding a flow and inputting the following onselect: Saveimage.Run("test.jpg",First(PictureColl).Url)

    powerapps shows me the following error:
    Invalid number of arguements.
    Anything I am missing on, i actually copied and pasted your string exact except changed the name according to my flow name

    ReplyDelete
    Replies
    1. If your flow takes two params, and you are not using the Windows version of PowerApps it should work. When you start typing Saveimage.Run(, it should tell you what params to expect from your flow.

      Delete
  3. Mikael, that was awesome! Worked first try! I was able to prove I can save a captured image from the PowerApp to Sharepoint. What I really need to do, is to get it saved to a Item/Record in a Sharepoint List. Is there a way to modify the Flow/PowerApp to do that?

    ReplyDelete
    Replies
    1. You would need a custom azure function to save it as an attachment in a list. There is no native support for list item attachments in Flow yet afaik. And cool you got it working :) That said, native support to save images to SharePoint is underway in PowerApps.

      Delete