umbraco / Umbraco.Forms.Issues

Public issue tracker for Umbraco Forms
29 stars 0 forks source link

Issue with FileUpload field type when used in custom workflow in Umbraco Cloud #668

Open giordanop opened 2 years ago

giordanop commented 2 years ago

Brief description of the issue

Cannot retrieve an uploaded file by the FileUpload field in a custom workflow, when deployed in Umbraco Cloud (locally it works).

Specifics

Umbraco 8.16.0 Forms 8.8.0 Deploy 4.1.4

Steps to reproduce

Create a form, with inside a FileUpload field, then implement a custom workflow, where the file uploaded by the FileUpload field type is retrieved using this code: var file = record.ValueAsString("alias");

Expected result

"file" contains the right path to ...media\forms\upload... etc..

Actual result

"file" is empty when deployed in Umbraco Cloud (it contains the right path to media\forms\upload\ etc.. when executed locally).

Workaround

It seems that the issue is related to the ConvertToRecord method in FileUpload class, there is some code in that function that move the file between repositories, from a temporary repository to the media folder.

As a workaround, I created a custom field type and overrode that method (ConvertToRecord) with a custom one:

public override IEnumerable<object> ConvertToRecord(
            Field field,
            IEnumerable<object> postedValues,
            HttpContextBase context)
        {
            var processed = new List<object>();

            SetFileUploadPath(field, context);

            foreach (var postedValue in postedValues)
            {
                if (postedValue != null && !string.IsNullOrEmpty(postedValue.ToString()))
                {
                    var tempFilePathRelative = DecryptFilePath(postedValue.ToString());
                    var tempFilePathAbsolute = IOHelper.MapPath(tempFilePathRelative);

                    var filePathRelative = $"{_uploadPath}{Guid.NewGuid().ToString()}/{Path.GetFileName(tempFilePathRelative)}".ToLower(
                        CultureInfo.InvariantCulture);

                    var tempFormUploadPath = IOHelper.MapPath(Configuration.UploadTempPath);
                    if (File.Exists(tempFilePathAbsolute) && tempFilePathAbsolute.StartsWith(tempFormUploadPath))
                    {
                        var filePathAbsolute = IOHelper.MapPath(filePathRelative);
                        var directoryName = Path.GetDirectoryName(filePathAbsolute);
                        if (!string.IsNullOrWhiteSpace(directoryName) && !Directory.Exists(directoryName))
                        {
                            Directory.CreateDirectory(directoryName);
                        }

                        var fileInfo = new FileInfo(tempFilePathAbsolute);
                        if (fileInfo.Directory != null && Directory.Exists(fileInfo.Directory.FullName))
                        {
                            File.Move(tempFilePathAbsolute, filePathAbsolute);

                            processed.Add(filePathRelative);

                            try
                            {
                                File.Delete(tempFilePathAbsolute);
                                if (!Directory.EnumerateFileSystemEntries(fileInfo.Directory.FullName).Any<string>())
                                {
                                    Directory.Delete(fileInfo.Directory.FullName);
                                }
                            }
                            catch (Exception)
                            {
                                // ignored
                            }
                        }
                    }
                    else
                        processed.Add((object)tempFilePathRelative);
                }
            }

            return (IEnumerable<object>)processed;
        }

Basically I replaced the part where the file was copied using streams and IMediaFileSystem with File.Move().

Note: in this solution, mediafile system type is completely ignored.

AndyButland commented 2 years ago

Sounds you like you have this sorted for your needs, but I tried to replicate and wasn't able to see the issue you've reported here. I've got the following custom workflow - and I see the same information logged when I use the workflow locally or on Cloud. Are you able to spot anything significant that's different between my use case and yours please?

I'm using Forms 8.8.0 here.

    public class LogFileUploadedWorkflow : WorkflowType
    {
        public LogFileUploadedWorkflow()
        {
            Id = new Guid("4C40A092-0CB5-481d-96A7-A02D8E7CDB2A");
            Name = "Log File Uploaded";
        }

        public override List<Exception> ValidateSettings()
        {
            var exs = new List<Exception>();
            return exs;
        }

        public override WorkflowExecutionStatus Execute(Record record, RecordEventArgs e)
        {
            var file = record.ValueAsString("file");
            Current.Logger.Info<LogFileUploadedWorkflow>(
                $"File uploaded value: {file}");

            return WorkflowExecutionStatus.Completed;
        }
    }
giordanop commented 2 years ago

Hi @AndyButland, I don't see any relevant difference.

Could my issue be related to the media file system provider I'm using in Cloud?

In my local environment my web.config in the media folder:

  <system.webServer>
    <handlers>
      <clear />
      <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
    </handlers>
  </system.webServer>

And this is how it looks like in Umbraco Cloud:

  <system.webServer>
    <handlers>
      <add name="StaticFile" xdt:Locator="Match(name)" xdt:Transform="Remove" />
      <add name="AzureBlobStorageFile" path="*" verb="*" type="Umbraco.Cloud.StorageProviders.AzureBlob.FileHandler, Umbraco.Cloud.StorageProviders.AzureBlob"
           xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
    </handlers>
  </system.webServer>

References: https://our.umbraco.com/documentation/umbraco-cloud/Set-up/Media/ https://our.umbraco.com/Documentation/Extending/FileSystemProviders/Azure-Blob-Storage/index-v8