Upload file with non-ASCII filename in Http request via multipart/form-data in Logic App STD

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Community Hub.

Background

For sending multipart/form-data content in Logic App, we have an official document which introduce a way to achieve it: Create workflows that call external endpoints or other workflows - Azure Logic Apps | Microsoft Learn.

But recently we found that if Content-Disposition contains non-ASCII characters (Chinese, Japanese characters) in filename section , the filename will be shown as ????.<extension> if we implement the Http action as per the document.

 

Mechanism

Via testing with CURL command, we have an alternative way to send multipart/form-data by encoding all payload as base64 encoded string, sample payload sent by CURL is following:

{ "$content-type": "multipart/form-data; boundary=------------------------boundary", "$content": "base64 encoded content" }

 

 

Decoded base64 string is a normal multipart/form-data format:

--------------------------boundary Content-Disposition: form-data; name="filename"; filename="[File name]" Content-Type: application/octet-stream File content binary --------------------------boundary--

 

 

Implementation

As per the mechanism, we can know that it is also possible to use the same format to send multipart form via using Logic App Http action, so the only road block is how to combine boundary header, file binary and boundary footer in to a single base64 string.

In most of the situation, we get file content as a separate base64 string, as we all know, multiple base64 string cannot be concatenated directly which could cause decode incorrectly.

So we have to convert all 3 parts into binary first, combine them into a single byte[], then convert to base64 string all together, which we don't have any built-in expressions/features can handle it.

As a workaround, we need to prepare 3 base64 encoded strings (boundary header, file content and boundary footer),  thencan use the new feature "C# inline" to achieve this approach, sample code is following:

// Add the required libraries #r "Newtonsoft.Json" #r "Microsoft.Azure.Workflows.Scripting" using System; using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Logging; using Microsoft.Azure.Workflows.Scripting; using Newtonsoft.Json.Linq; public static async Task<Results> Run(WorkflowContext context, ILogger log) { var fileContent = (await context.GetActionResults("FileContent").ConfigureAwait(false)).Outputs; string header = (await context.GetActionResults("BoundaryHeader").ConfigureAwait(false)).Outputs; string footer = (await context.GetActionResults("BoundaryFooter").ConfigureAwait(false)).Outputs; byte[] headerBinary = Convert.FromBase64String(header.ToString()); byte[] footerBinary = Convert.FromBase64String(footer.ToString()); byte[] fileContentBinary = Convert.FromBase64String(fileContent.ToString()); List<byte> allBytes = new List<byte>(); allBytes.AddRange(headerBinary); allBytes.AddRange(fileContentBinary); allBytes.AddRange(footerBinary); string base64Content = Convert.ToBase64String(allBytes.ToArray()); return new Results { Message = base64Content }; } public class Results { public string Message {get; set;} }

 

After we get the output from C# action, we can compose all of them in Http action

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.