Table of Contents


Working with Document Library Files

Complete guide to creating, uploading, and managing files in the Magentrix Document Library. This guide covers file uploads, bookmarks, marketing links, snippets, and notes organized in folders.


Overview

The Magentrix Document Library provides cloud-based file storage with folder-based organization. Files are created using the Document class with content passed via the Body field or Load() method.

Key Concepts:

  • Document class stores file metadata (name, type, folder, owner)
  • Body field passes file content during creation (transient, not persisted)
  • Load() method automatically populates properties from uploaded files
  • FolderId organizes documents in folders
  • File content stored in cloud storage after creation

Document Library Features:

  • Folder-based organization with unlimited nesting
  • Social engagement (views, downloads, likes, comments)
  • Version control and file replacement
  • Public and private access controls
  • Multiple content types (files, bookmarks, snippets, notes)

File Creation Methods

There are two primary methods for creating documents with file content:

Method 1: Document.Load() (Recommended)

The Load() method automatically populates document properties from an uploaded file.

Auto-Populated Properties:

  • Type = "File"
  • Name = Original filename
  • ContentType = File's MIME type
  • Extension = File extension without dot
  • Body = Base64-encoded content (transient)
  • Size = File size in bytes

Properties You Must Set:

  • FolderId - Parent folder ID
  • UniqueName - Use Document.GetUniqueName() only if you don't use Document.Load
  • AuthorId - Typically SystemInfo.UserId

Method 2: Document with Body Field

Manually create a Document and pass Base64-encoded content via the Body field.

Required Properties:

  • Name - Display filename
  • Body = Base64-encoded file content (transient)
  • Type = "File"
  • ContentType = MIME type
  • FolderId - Parent folder ID
  • UniqueName - Use Document.GetUniqueName() only if you don't use Document.Load

Complete File Upload Workflows

Workflow 1: Basic File Upload with Load()

[HttpPost]
public ActionResponse UploadFile(HttpPostedFile file, string folderId)
{
    try
    {
        // Validate file
        if (file == null || file.ContentLength == 0)
        {
            AspxPage.AddError("Please select a file to upload.");
            return View();
        }
        
        // Use Load() to auto-populate properties
        var document = Document.Load(file);
        
        if (document == null)
        {
            AspxPage.AddError("Failed to load file.");
            return View();
        }
        
        // Set required properties
        document.FolderId = folderId;
        document.AuthorId = SystemInfo.UserId;
        document.Description = "User uploaded document";
        
        // Insert - Body content automatically stored in cloud
        Database.Insert(document);
        
        AspxPage.AddMessage($"File '{document.Name}' uploaded successfully!");
        return RedirectToAction("Details", new { id = document.Id });
    }
    catch (DatabaseException ex)
    {
        SystemInfo.Debug($"Database error: {ex.Message}");
        AspxPage.AddError("Failed to create document.");
        return View();
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Upload error: {ex.Message}");
        AspxPage.AddError("Upload failed.");
        return View();
    }
}

Workflow 2: File Upload with Body Field

[HttpPost]
public ActionResponse UploadWithBody(HttpPostedFile file, string folderId)
{
    try
    {
        if (file == null || file.ContentLength == 0)
        {
            AspxPage.AddError("Please select a file.");
            return View();
        }
        
        // Read file bytes
        var fileBytes = new byte[file.ContentLength];
        file.InputStream.Read(fileBytes, 0, file.ContentLength);
        
        // Convert to Base64
        var base64Content = Convert.ToBase64String(fileBytes);
        
        // Get extension without dot
        var extension = FileHelper.GetFileExtension(file.FileName);
        
        // Create document
        var document = new Document
        {
            Name = file.FileName,
            Body = base64Content,  // Transient - creates cloud storage
            Type = "File",
            ContentType = file.ContentType,
            Extension = extension,
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(file.FileName, extension),
            AuthorId = SystemInfo.UserId,
        };

        // After insert, document.Body is null, file is in cloud storage         
        Database.Insert(document);
        
        AspxPage.AddMessage($"File '{document.Name}' uploaded successfully!");
        return RedirectToAction("Details", new { id = document.Id });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Upload error: {ex.Message}");
        AspxPage.AddError("Upload failed.");
        return View();
    }
}

Workflow 3: File Upload with Validation

[HttpPost]
public ActionResponse UploadWithValidation(HttpPostedFile file, string folderId)
{
    try
    {
        // Validate file exists
        if (file == null || file.ContentLength == 0)
        {
            AspxPage.AddError("Please select a file to upload.");
            return View();
        }
        
        // Validate file size (10MB limit)
        const int maxFileSize = 10 * 1024 * 1024;
        if (file.ContentLength > maxFileSize)
        {
            AspxPage.AddError("File size must be less than 10MB.");
            return View();
        }
        
        // Validate file type
        string[] allowedExtensions = { ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".png", ".jpg", ".jpeg" };
        string extension = FileHelper.GetFileExtension(file.FileName).ToLower();
        
        if (!allowedExtensions.Contains(extension))
        {
            AspxPage.AddError($"File type '{extension}' is not allowed.");
            return View();
        }
        
        // Validate content type
        string[] allowedContentTypes = {
            "application/pdf",
            "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "image/png",
            "image/jpeg"
        };
        
        if (!allowedContentTypes.Contains(file.ContentType))
        {
            AspxPage.AddError($"Content type '{file.ContentType}' is not allowed.");
            return View();
        }
        
        // Upload file
        var document = Document.Load(file);
        document.FolderId = folderId;
        document.AuthorId = SystemInfo.UserId;
        
        Database.Insert(document);
        
        AspxPage.AddMessage($"File '{document.Name}' uploaded successfully!");
        return RedirectToAction("Details", new { id = document.Id });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Upload error: {ex.Message}");
        AspxPage.AddError("Upload failed.");
        return View();
    }
}

Creating Bookmarks and URLs

Creating Bookmarks (Type = "URL")

[HttpPost]
public ActionResponse CreateBookmark(string folderId, string bookmarkName, string url)
{
    try
    {
        // Validate URL
        if (string.IsNullOrWhiteSpace(url))
        {
            AspxPage.AddError("URL is required.");
            return View();
        }
        
        if (!url.StartsWith("http://") && !url.StartsWith("https://"))
        {
            AspxPage.AddError("URL must start with http:// or https://");
            return View();
        }
        
        var bookmark = new Document
        {
            Name = bookmarkName,
            Body = url,  // URL stored in Body (transient, saved to cloud)
            Type = "URL",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(bookmarkName, "url"),
            AuthorId = SystemInfo.UserId,
            Description = "External resource link"
        };
        
        Database.Insert(bookmark);
        
        AspxPage.AddMessage($"Bookmark '{bookmarkName}' created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Bookmark error: {ex.Message}");
        AspxPage.AddError("Failed to create bookmark.");
        return View();
    }
}

Creating Marketing Links with Merge Fields

[HttpPost]
public ActionResponse CreateMarketingLink(string folderId, string linkName, string baseUrl)
{
    try
    {
        // Validate employee security role
        if (!SystemInfo.IsEmployeeUser)
        {
            AspxPage.AddError("Only employees can create marketing links.");
            return RedirectToAction("Index");
        }
        
        // Build URL with merge fields
        string trackingUrl = $"{baseUrl}?email={{!User.Email}}&userId={{!User.Id}}&campaign=portal";
        
        var marketingLink = new Document
        {
            Name = linkName,
            Body = trackingUrl,  // URL with merge fields (transient)
            Type = "Marketing Link",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(linkName, "link"),
            AuthorId = SystemInfo.UserId,
            Description = "Personalized marketing link with user tracking"
        };
        
        Database.Insert(marketingLink);
        
        AspxPage.AddMessage("Marketing link created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Marketing link error: {ex.Message}");
        AspxPage.AddError("Failed to create marketing link.");
        return View();
    }
}

Creating Snippets

Snippets are code files and configuration content (JavaScript, C#, CSS, JSON, XML, SQL).

Creating JavaScript Snippet

[HttpPost]
public ActionResponse CreateJavaScriptSnippet(string folderId, string snippetName, string code)
{
    try
    {
        // Encode snippet code
        string base64Code = Convert.ToBase64String(Encoding.UTF8.GetBytes(code));
        
        var snippet = new Document
        {
            Name = snippetName,
            Body = base64Code,  // Base64 code (transient, saved to cloud)
            Extension = "js",
            ContentType = "Snippet",
            Type = "Snippet",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(snippetName, "js"),
            AuthorId = SystemInfo.UserId,
            Description = "JavaScript code snippet"
        };
        
        Database.Insert(snippet);
        
        AspxPage.AddMessage($"Snippet '{snippetName}' created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Snippet error: {ex.Message}");
        AspxPage.AddError("Failed to create snippet.");
        return View();
    }
}

Creating CSS Snippet

[HttpPost]
public ActionResponse CreateCSSSnippet(string folderId, string snippetName, string cssCode)
{
    try
    {
        string base64Code = Convert.ToBase64String(Encoding.UTF8.GetBytes(cssCode));
        
        var snippet = new Document
        {
            Name = snippetName,
            Body = base64Code,
            Extension = "css",
            ContentType = "Snippet",
            Type = "Snippet",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(snippetName, "css"),
            AuthorId = SystemInfo.UserId,
            Description = "CSS stylesheet snippet"
        };
        
        Database.Insert(snippet);
        
        AspxPage.AddMessage("CSS snippet created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"CSS snippet error: {ex.Message}");
        AspxPage.AddError("Failed to create snippet.");
        return View();
    }
}

Creating JSON Configuration Snippet

[HttpPost]
public ActionResponse CreateJSONSnippet(string folderId, string configName, string jsonContent)
{
    try
    {
        // Validate JSON
        try
        {
            JsonHelper.Deserialize<object>(jsonContent);
        }
        catch
        {
            AspxPage.AddError("Invalid JSON format.");
            return View();
        }
        
        string base64Content = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonContent));
        
        var snippet = new Document
        {
            Name = configName,
            Body = base64Content,
            Extension = "json",
            ContentType = "Snippet",
            Type = "Snippet",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(configName, "json"),
            AuthorId = SystemInfo.UserId,
            Description = "JSON configuration file"
        };
        
        Database.Insert(snippet);
        
        AspxPage.AddMessage("JSON configuration created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"JSON snippet error: {ex.Message}");
        AspxPage.AddError("Failed to create configuration.");
        return View();
    }
}

Creating Notes

Notes are text-based content stored in the Document Library.

[HttpPost]
public ActionResponse CreateNote(string folderId, string noteTitle, string noteContent)
{
    try
    {
        // Encode note content
        string base64Content = Convert.ToBase64String(Encoding.UTF8.GetBytes(noteContent));
        
        var note = new Document
        {
            Name = noteTitle,
            Body = base64Content,  // Note text (transient, saved to cloud)
            Type = "Note",
            ContentType = "text/plain",
            FolderId = folderId,
            UniqueName = Document.GetUniqueName(noteTitle, "txt"),
            AuthorId = SystemInfo.UserId,
            Description = "Text note"
        };
        
        Database.Insert(note);
        
        AspxPage.AddMessage($"Note '{noteTitle}' created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Note error: {ex.Message}");
        AspxPage.AddError("Failed to create note.");
        return View();
    }
}

File Download Workflows

Download File (Streaming - Recommended)

public ActionResponse DownloadFile(string documentId)
{
    try
    {
        var document = Database.Retrieve<Document>(documentId);
        
        if (document == null)
        {
            return PageNotFound();
        }
        
        // Validate user has access
        if (!UserHasAccess(document.FolderId))
        {
            return UnauthorizedAccessResponse();
        }
        
        // Stream file directly from cloud storage
        return StorageFile(document.Id, document.ContentType, document.Name);
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Download error: {ex.Message}");
        return RedirectToError("Download failed.");
    }
}

Open File Inline (View in Browser)

public ActionResponse ViewFile(string documentId)
{
    try
    {
        var document = Database.Retrieve<Document>(documentId);
        
        if (document == null)
        {
            return PageNotFound();
        }
        
        // Stream file for inline viewing
        // Fourth parameter: true = open inline in browser
        return StorageFile(document.Id, document.ContentType, document.Name, true);
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"View error: {ex.Message}");
        return RedirectToError("Unable to view file.");
    }
}

File Management Operations

Updating File Properties

[HttpPost]
public ActionResponse UpdateFileProperties(string documentId, string newName, string newDescription, string newKeywords)
{
    try
    {
        var document = Database.Retrieve<Document>(documentId);
        
        if (document == null)
        {
            return PageNotFound();
        }
        
        // Update properties
        document.Name = newName;
        document.Description = newDescription;
        document.Keywords = newKeywords;
        
        Database.Update(document);
        
        AspxPage.AddMessage("File properties updated successfully!");
        return RedirectToAction("Details", new { id = documentId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Update error: {ex.Message}");
        AspxPage.AddError("Update failed.");
        return View();
    }
}

Moving Files Between Folders

[HttpPost]
public ActionResponse MoveFile(string documentId, string targetFolderId)
{
    try
    {
        var document = Database.Retrieve<Document>(documentId);
        
        if (document == null)
        {
            return PageNotFound();
        }
        
        // Validate target folder exists
        var targetFolder = Database.Retrieve<Folder>(targetFolderId);
        if (targetFolder == null)
        {
            AspxPage.AddError("Target folder not found.");
            return View();
        }
        
        // Move file
        string oldFolderId = document.FolderId;
        document.FolderId = targetFolderId;
        
        Database.Update(document);
        
        AspxPage.AddMessage($"File moved successfully!");
        return RedirectToAction("FolderContents", new { folderId = targetFolderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Move error: {ex.Message}");
        AspxPage.AddError("Move operation failed.");
        return View();
    }
}

Deleting Files

[HttpPost]
public ActionResponse DeleteFile(string documentId)
{
    try
    {
        var document = Database.Retrieve<Document>(documentId);
        
        if (document == null)
        {
            return PageNotFound();
        }
        
        // Validate permissions
        if (document.AuthorId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
        {
            AspxPage.AddError("You don't have permission to delete this file.");
            return RedirectToAction("Index");
        }
        
        string folderId = document.FolderId;
        string fileName = document.Name;
        
        // Delete document record (cloud storage automatically cleaned up)
        Database.Delete(documentId);
        
        AspxPage.AddMessage($"File '{fileName}' deleted successfully.");
        return RedirectToAction("FolderContents", new { folderId = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Delete error: {ex.Message}");
        AspxPage.AddError("Delete failed.");
        return RedirectToAction("Index");
    }
}

Working with Folders

Creating Folders

public ActionResponse CreateFolder(string parentFolderId, string folderName)
{
    try
    {
        var folder = new Folder
        {
            Name = folderName,
            ParentId = parentFolderId, // null for root folder
            OwnerId = SystemInfo.UserId,
            Description = "User created folder"
        };
        
        Database.Insert(folder);
        
        AspxPage.AddMessage($"Folder '{folderName}' created successfully!");
        return RedirectToAction("FolderContents", new { folderId = folder.Id });
    }
    catch (DatabaseException ex)
    {
        AspxPage.AddError(ex.Message);
        return View();
    }
}

Sharing Folders

public ActionResponse ShareFolder(string folderId, string userId, string accessLevel)
{
    try
    {
        var folder = Database.Retrieve<Folder>(folderId);
        
        if (folder == null)
        {
            return PageNotFound();
        }
        
        // Validate ownership
        if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
        {
            AspxPage.AddError("Only the folder owner can share this folder.");
            return RedirectToAction("Index");
        }
        
        // Create sharing permissions
        var permissions = new List<FolderSharingOption>
        {
            new FolderSharingOption
            {
                RecordId = userId,
                AccessLevel = accessLevel // "CanView", "CanUpload", "FullControl"
            }
        };
        
        // Apply sharing
        folder.ShareWithSpecificUsers(permissions);
        
        AspxPage.AddMessage("Folder shared successfully!");
        return RedirectToAction("FolderContents", new { id = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Share error: {ex.Message}");
        AspxPage.AddError("Failed to share folder.");
        return View();
    }
}

Best Practices

File Upload

Always use Load() for file uploads

// Recommended
var document = Document.Load(file);
document.FolderId = folderId;
// Good
document.UniqueName = Document.GetUniqueName(document.Name, document.Extension);

// Bad - potential conflicts
document.UniqueName = document.Name;

Always set AuthorId

document.AuthorId = SystemInfo.UserId;

File Validation

Validate file size

const int maxSize = 10 * 1024 * 1024; // 10MB
if (file.ContentLength > maxSize)
{
    AspxPage.AddError("File must be less than 10MB.");
    return View();
}

Validate file types

string[] allowed = { ".pdf", ".docx", ".xlsx", ".png", ".jpg" };
string ext = FileHelper.GetFileExtension(file.FileName).ToLower();
if (!allowed.Contains(ext))
{
    AspxPage.AddError("File type not allowed.");
    return View();
}

Performance

Use StorageFile for downloads

// Good: Streams directly to browser
return StorageFile(documentId, contentType, fileName);

// Avoid: Loading entire file into memory
byte[] bytes = ReadFileBytes(documentId);
return File(bytes, contentType, fileName);

Security

Always validate folder access

if (!UserHasAccess(document.FolderId))
{
    return UnauthorizedAccessResponse();
}

Validate ownership for deletions

if (document.AuthorId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
    return UnauthorizedAccessResponse();
}

Common Pitfalls

Pitfall 1: Not setting required properties

// Bad: Missing UniqueName and AuthorId
var doc = Document.Load(file);
doc.FolderId = folderId;
Database.Insert(doc); // May cause issues

// Good: Set all required properties
var doc = Document.Load(file);
doc.FolderId = folderId;
doc.AuthorId = SystemInfo.UserId;
Database.Insert(doc);

Pitfall 2: Expecting Body to contain content after insert

// Bad: Body is null after insert
var doc = Document.Load(file);
Database.Insert(doc);
string content = doc.Body; // null - content is in cloud storage

// Good: Use download methods to retrieve content
return StorageFile(doc.Id, doc.ContentType, doc.Name);

Pitfall 3: Not validating file uploads

// Bad: No validation
var doc = Document.Load(file);
Database.Insert(doc);

// Good: Validate before processing
if (file == null || file.ContentLength == 0)
{
    AspxPage.AddError("No file selected.");
    return View();
}
if (file.ContentLength > maxSize)
{
    AspxPage.AddError("File too large.");
    return View();
}

Pitfall 4: Wrong Extension format for snippets

// Bad: Extension with dot
Extension = ".js"

// Good: Extension without dot
Extension = "js"

Related Topics

Class References

Implementation Guides

Related Topics