Skip to main content

File Attachments (Store Custom Files)

  • 7 minutes to read

XAF includes a File Attachments module and file data types for file management (upload, download, open, and save files). This module contains Property Editors and Controllers for the file data type.

Run Demo: File Attachment Properties ASP.NET Web Forms

Watch Video: XAF - Store file attachments in Dropbox instead of the database (XPO)

Supported Functionality

ASP NET Core Blazor

File Attachment Properties Blazor

FileDataPropertyEditor displays the property’s value as a link with the file name. A user can click the link to download the file. The Detail View, displays the Select File and Clear buttons. FileAttachmentController contains corresponding Actions. A user should save changes after a file is uploaded to display a link instead of a plain text file name.

FileDataPropertyEditor shows upload progress. The default maximum file size is 4 MB.

FileAttachmentsBlazorModule splits the file into chunks and uploads them to the server.

Windows Forms

IFileDataWin

Attach a File
When a user clicks the ellipsis button on the FileDataPropertyEditor, the application invokes the OpenFileDialog dialog, which you can use to select an attached file.
Save an Attached File to a Disk
The FileDataPropertyEditor context menu contains the SaveTo Action. The FileAttachmentController.SaveFileData method handles this Action’s Execute event. You can override this method in the FileAttachmentController descendant to change the default logic.
Open an Attached File
The FileDataPropertyEditor context menu contains the Open Action. The FileAttachmentController.Open method handles this Action’s Execute event. You can override this method in the FileAttachmentController descendant to change the default logic.
Detach a File
The FileDataPropertyEditor context menu contains the ClearContent Action. This Action’s Execute event handler calls the property type’s Clear method to clear file content. Override the IFileData.Clear method to implement your logic.

ASP.NET Web Forms

FileDataPropertyEditor displays the FileDataEdit control, which shows a different set of controls in View and Edit modes:

View Mode

Displays the HtmlAnchor control that allows users to download the current file.

IFileDataWebViewMode

Edit Mode

FileDataPropertyEditor shows ASPxButtons Change File and Clear buttons (xref:DevExpress.Web.ASPxButton).

IFileDataWebEditMode

XAF calls the property type’s Clear method to make the Clear button to clear property values. You can override the IFileData.Clear method to implement your logic.

The Change File button makes ASPxUploadControl visible to allow users to upload a new file.

FileDataEdit_FileDataPropertyEditor_Transparent

A user can click the HtmlAnchor control with the file name to download the file.

Default maximum file size is 4 MB.

File Attachments Module Components

The following table contains classes for different platforms:

Platform

Module Class

NuGet package

ASP.NET Core Blazor

FileAttachmentsBlazorModule

DevExpress.ExpressApp.FileAttachment.Blazor

WinForms

FileAttachmentsWindowsFormsModule

DevExpress.ExpressApp.FileAttachment.Win

ASP.NET Web Forms

FileAttachmentsAspNetModule

DevExpress.ExpressApp.FileAttachment.Web

The File Attachments Module contains the following Property Editors to display file data properties in the UI:

  • DevExpress.ExpressApp.FileAttachment.Blazor.FileDataPropertyEditor
  • DevExpress.ExpressApp.FileAttachment.Win.FileDataPropertyEditor
  • DevExpress.ExpressApp.FileAttachment.Web.FileDataPropertyEditor

Add the File Attachments Module to an XAF Application

Install the appropriate platform-specific NuGet package and use one of the following techniques to add the File Attachments Module:

Entity Framework Core-Based Application

The following additional step is required if you use Entity Framework Core:

  1. Navigate to the YourSolutionName.Module\BusinessObjects\YourSolutionNameDbContext.cs file and include the FileData entity in the data model:

    using DevExpress.Persistent.BaseImpl.EF;
    // ...
    public class YourSolutionNameEFCoreDbContext : DbContext {
        // ...
        public DbSet<FileData> FileData { get; set; }
        // ...
    }
    

Define a File Data Object and Storage

The file data object is a business class that implements the IFileData interface. You can also use the built-in FileData class (XPO: the %PROGRAMFILES%\DevExpress 23.2\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\FileData.cs file, EF Core: the %PROGRAMFILES%\DevExpress 23.2\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl.EF\FileData.cs file).

using DevExpress.Persistent.Base;

namespace MySolution.Module.BusinessObjects {
    [FileAttachmentAttribute(nameof(File))]
    public class MyFileAttachment : BaseObject {
        // ...
        [ExpandObjectMembers(ExpandObjectMembers.Never)]
        [FileTypeFilter("DocumentFiles", 1, "*.txt", "*.doc")]
        [FileTypeFilter("AllFiles", 2, "*.*")]
        public virtual FileData File { get; set; }
    }
    public class FileData : BaseObject, IFileData {
        // ...
    }
}

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Refer to the following help topic for more information on file data properties: File Attachment Properties.

XAF stores attached files in a database in a binary form. When you use the DevExpress.Persistent.BaseImpl.FileData type, the gzip compression is applied to a file. Maximum file size is 2 GB.

Upload and Download File Attachments Programmatically (in Code)

Call the IFileData.LoadFromStream method to upload a file in code. To obtain the file, call the IFileData.SaveToStream method. The LoadFromStream method does not require a full path to the file. This method accepts a file name as the first parameter.

Examples

View Example: How to: Store file attachments in the file system instead of the database View Example: How to: Store file attachments in Dropbox instead of the database View Example: How to: Use the File Attachment Module with a legacy database

Tip

The following example implements a business class with a file data property and a file collection property: How to: Implement File Data Properties.

Read Compressed Files in the FileData Database Table from External Non-XAF .NET Applications

XAF stores attached files in a database in a binary form. Maximum file size is 2 GB. The XPO DevExpress.Persistent.BaseImpl.FileData type compresses files when it adds them to the database and decompresses files when they are accessed in the database. The DevExpress.Persistent.Base.CompressionConverter class (a custom XPO Value Converter class from the DevExpress.Persistent.BaseImpl.Xpo assembly) applies GZIP compression to files. For more information on the GZIP compression algorithm, refer to the source code at %PROGRAMFILES%\DevExpress 23.2\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl.Xpo\CompressionUtils.cs.

Use one of the following options to read compressed files in the FileData database table from external non-XAF .NET apps:

  • If you can use XPO and FileData for data access, call the SaveToStream(Stream) method.

  • Otherwise, call the CompressionConverter.ConvertFromStorageType method as shown below:

    using DevExpress.Data.Filtering;
    using DevExpress.Xpo;
    using SolutionName.Module.BusinessObjects;
    using System;
    using System.Data.SqlClient;
    using System.IO;
    using DevExpress.Persistent.Base;
    
    namespace SolutionName {
        class Program {
            static void Main(string[] args) {
                string cons = @"Integrated Security=SSPI;Pooling=false;Data Source=(localdb)\mssqllocaldb;Initial Catalog=XafDbWithFiles";
                SqlConnection conn = new SqlConnection(cons);
                conn.Open();
                SqlCommand sqlCmd = new SqlCommand("SELECT Content, FileName FROM FileData Where oid = 'B4C546BB-807D-4951-8443-50B800B6BE2D'", conn);
                using(SqlDataReader rdr = sqlCmd.ExecuteReader()) {
                    while(rdr.Read()) {
                        byte[] column1 =(byte[]) rdr["Content"];
                        var conv = new CompressionConverter();
                        byte[] decomp = (byte[]) conv.ConvertFromStorageType(column1);
                        string column2 = rdr["FileName"].ToString();
                        using(var fs = new FileStream("c:\\test\\1ok_"+column2, FileMode.CreateNew)) {
                            fs.Write(decomp, 0, decomp.Length);
                            fs.Flush();
                        }
                    }
                }
                conn.Close();
                conn.Dispose();
            }
        }
    }
    

    If you do not want to reference the DevExpress.Persistent.BaseImpl.Xpo assembly, copy the source code of the CompressionConverter class to your external non-XAF .NET project.

  • If you do not need default file compression, you can create a custom IFileData implementation and use it instead of the DevExpress.Persistent.BaseImpl.FileData type in your application. To do this, copy the source code of the FileData.cs class. You can find it in the %PROGRAMFILES%\DevExpress 23.2\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl.Xpo folder. In the copied code, remove the [ValueConverter(typeof(CompressionConverter))] line from the Content property, and rename the class and namespaces.

See Also