Upload File Name Formats

Serenity has a unique upload system that is pretty flexible. Although it works as is, without requiring much configuration, you might want to customize it sometimes. One of the areas you might want to learn about is generated file names on disk and the format specifiers that controls them. A new feature added in recent versions is ability to use original file name on disk.

Where Files Are Stored

Uploaded files goes under App_Data/upload folder.

A setting in web.config controls the upload path:

<add key="UploadSettings" value="{ Path: '~\\App_Data\\upload\\' }" />

Default File Name Format

Unless you change the default format, Serenity generates unique filenames on disk like ProductImage/0000/00000002_4qqvi6xw25suq.png under AppData/upload when you upload a file with name MyProductImage.png for example. We'll dissect this naming scheme soon.

Where File Name is Stored

When you add a [(File/Image)UploadEditor], e.g. single file upload editor to a string field, Serenity automatically stores file name on disk, e.g. ProductImage/0000/00000002_4qqvi6xw25suq.png in that field.

How Can I Save Original Name When Using Single File Upload?

You may set OriginalNameProperty to a different field to store original file name along with disk file name, e.g.

[ImageUploadEditor(OriginalNameProperty = "MyImageName")]
public string MyImageFile { get; set; }

public string MyImageName { get; set; }

After upload, MyImageFile field will hold the file name on disk (ProductImage/0000/00000002_4qqvi6xw25suq.png) and MyImageName field will store the original file name of uploaded file (MyProductImage.png).

The Case With Multiple Upload Editors

When you use a [Multiple(File/Image)UploadEditor] it also stores file names in a string field, but this time in JSON format. You also won't need the original name property as it is also saved into same field.

[MultipleImageUploadEditor]
public string MyImageFiles { get; set;}

After upload MyImageFiles field will have content like this:

[
    {
        "FileName": "ProductImage/0000/00000002_4qqvi6xw25suq.png",
        "OriginalName": "FirstImage.png"
    },
    {
        "FileName": "ProductImage/0000/00000002_ax4qi1f435tst.png",
        "OriginalName": "SecondImage.png"
    }
]

Dissecting File Naming Scheme

Generated file name (e.g. ProductImage/0000/00000002_4qqvi6xw25suq.png) on disk has several parts:

Why We Use Such a Naming Scheme?

There are several reasons this is the default behavior:

File Name Format

The default file name format is a .NET string format specifier:

ProductImage/{1:0000}/{0:00000000}_{2}

If you look at the ProductImage field of ProductRow:

[ImageUploadEditor(FilenameFormat = "ProductImage/~", CopyToHistory = true)]
public String ProductImage
{
    get { return Fields.ProductImage[this]; }
    set { Fields.ProductImage[this] = value; }
}

You'll see that it only has "~" character after ProductImage/. This character corresponds to {1:0000}/{0:00000000}_{2} which is the default naming format.

If you don't specify any FilenameFormat, the folder name is generated based on your row class name and property name.

Format Specifiers of the Default File Name Format

Ability to Use Original Name (introduced in Serenity 2.10.2)

New format specifier ({4}) is recently added in Serenity which corresponds to original file name. Thus, you now have the option to use original name on disk as is.

But when a file with same name already exists on disk, Serenity will automatically add a suffix.

So for example if a user uploads SomeFile.docx and another also uploads SomeFile.docx, the second one will have name of *SomeFile (2).docx" on disk.

Referencing Other Row Fields in File Names (introduced in 2.4.4)

Sometimes you might want to refer some other field in same row while generating file name.

It is possible by using pipes, e.g. |OtherFieldName| in file name formats.

[ImageUploadEditor(FilenameFormat = "|SupplierId|/ProductImage/{4}")]
public String ProductImage
{
    get { return Fields.ProductImage[this]; }
    set { Fields.ProductImage[this] = value; }
}

Avoid using foreign fields as they are not available yet in new records.

Conclusion

Serenity has a very dynamic file upload name generation system that should handle most requirements.

It might not be possible to provide support for every custom need out there but Serenity also provides you flexibility of writing your own custom file upload behavior.