Get Linked File Handler
This page provides complete examples for implementing the Get Linked File backend handler. The getlinkedfile endpoint retrieves file data and returns it as a Base64-encoded string for small to medium-sized files.
What is Get Linked File?
getlinkedfile is the backend endpoint that:
- Receives a file identifier
- Retrieves the complete file from storage
- Encodes the file as Base64
- Returns file data with extension and size information
File Size Limit
This endpoint loads the entire file into memory and encodes it as Base64. For files larger than 10MB, use Get Linked File By Chunks instead.
Complete Get Linked File Implementation
Choose your backend language:
- C# / .NET
- PHP
Controllers/FormsPublicController.cs
public class LinkedFileRequestDto
{
public string FileId { get; set; }
}
[HttpPost("getlinkedfile")]
[AllowAnonymous]
public async Task<IActionResult> GetLinkedFile([FromBody] LinkedFileRequestDto request)
{
string tenantId = GetCurrentTenantId();
byte[] fileData = null;
string fileExt = null;
var fileStorageService = GetFileStorageService();
if (fileStorageService == null)
throw new InvalidOperationException("File storage provider not configured.");
if (!string.IsNullOrEmpty(request.FileId))
{
// Parse file identifier (format: "bucket-name:path/to/file.pdf")
string[] parts = request.FileId.Split(':');
string bucketName = parts[0];
string filePath = parts[1];
// Get file data from storage
fileData = await fileStorageService.GetFileFromBucket(
tenantId,
filePath,
bucketName
);
fileExt = Path.GetExtension(request.FileId).TrimStart('.');
}
// Build response
var response = new HandlerResponse();
response.Set(
HandlerResponse.LinkedFile,
fileData != null ? Convert.ToBase64String(fileData) : null
);
response.Set(HandlerResponse.LinkedFileExt, fileExt);
response.Set(HandlerResponse.LinkedFileSize, fileData?.Length);
return Ok(await response.Get());
}
controllers/FormsPublicController.php
<?php
class FormsPublicController {
public function getLinkedFile(Request $request) {
$fileId = $request->input('fileId');
if (empty($fileId)) {
return response()->json(['error' => 'File ID is required'], 400);
}
$tenantId = $this->getCurrentTenantId();
$fileStorageService = $this->getFileStorageService();
if (!$fileStorageService) {
throw new Exception('File storage provider not configured.');
}
$fileData = null;
$fileExt = null;
// Parse file identifier (format: "bucket-name:path/to/file.pdf")
$parts = explode(':', $fileId, 2);
if (count($parts) === 2) {
$bucketName = $parts[0];
$filePath = $parts[1];
try {
// Get file data from storage
$fileData = $fileStorageService->getFileFromBucket(
$tenantId,
$filePath,
$bucketName
);
$fileExt = pathinfo($fileId, PATHINFO_EXTENSION);
}
catch (Exception $e) {
Log::error("Failed to get linked file: {$e->getMessage()}");
return response()->json(['error' => 'File not found'], 404);
}
}
return response()->json([
'linkedFile' => $fileData ? base64_encode($fileData) : null,
'linkedFileExt' => $fileExt,
'linkedFileSize' => $fileData ? strlen($fileData) : null
]);
}
private function getCurrentTenantId() {
return session('tenant_id') ?? 'default';
}
private function getFileStorageService() {
return app('file.storage');
}
}
?>
Request Structure
{
"fileId": "bucket-name:tenant/forms/2026/01/27/document.pdf"
}
Key Fields:
- fileId - The file identifier returned from the upload endpoint
Response Structure
{
"linkedFile": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9...",
"linkedFileExt": "pdf",
"linkedFileSize": 1048576
}
Response Fields:
- linkedFile - Base64-encoded file content
- linkedFileExt - File extension without the dot
- linkedFileSize - File size in bytes
Storage Implementation Examples
S3 Storage
C# - Get File Bytes from S3
public async Task<byte[]> GetFileFromS3(
string tenantId,
string filePath,
string bucketName)
{
var s3Client = new AmazonS3Client(/* credentials */);
var getRequest = new GetObjectRequest
{
BucketName = bucketName,
Key = filePath
};
using var response = await s3Client.GetObjectAsync(getRequest);
using var memoryStream = new MemoryStream();
await response.ResponseStream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
Local File Storage
C# - Get File Bytes from Local Storage
public async Task<byte[]> GetFileFromLocal(
string tenantId,
string filePath,
string bucketName)
{
var fullPath = Path.Combine(_uploadDirectory, bucketName, filePath);
if (!File.Exists(fullPath))
throw new FileNotFoundException("File not found", fullPath);
return await File.ReadAllBytesAsync(fullPath);
}
Azure Blob Storage
C# - Get File Bytes from Azure Blob
public async Task<byte[]> GetFileFromAzure(
string tenantId,
string filePath,
string containerName)
{
var blobClient = new BlobContainerClient(
_connectionString,
containerName
);
var blob = blobClient.GetBlobClient(filePath);
if (!await blob.ExistsAsync())
throw new FileNotFoundException("Blob not found", filePath);
using var memoryStream = new MemoryStream();
await blob.DownloadToAsync(memoryStream);
return memoryStream.ToArray();
}
Memory Management
Size Limit Check
Always check file size before loading into memory:
C# - Validate File Size Limit
public async Task<IActionResult> GetLinkedFile([FromBody] LinkedFileRequestDto request)
{
const long maxFileSize = 10 * 1024 * 1024; // 10MB limit
// Get file metadata first
var metadata = await GetFileMetadata(request.FileId);
if (metadata.Size > maxFileSize)
{
return BadRequest(new {
error = "File too large",
message = $"File size ({metadata.Size} bytes) exceeds maximum ({maxFileSize} bytes). Use getlinkedfilebychunks instead."
});
}
// Proceed with download...
}
Streaming Alternative
For better memory efficiency, consider streaming:
C# - Stream File in Chunks
public async Task<byte[]> GetFileWithStreaming(string filePath, string bucket)
{
using var stream = await GetFileStreamFromBucket(filePath, bucket);
using var memoryStream = new MemoryStream();
// Copy in chunks to avoid loading entire file at once
await stream.CopyToAsync(memoryStream, 81920);
return memoryStream.ToArray();
}
Base64 Encoding Best Practices
Efficient Encoding
C# - Encode to Base64
public string EncodeToBase64(byte[] fileData)
{
// Use Base64FormattingOptions.None for compact output
return Convert.ToBase64String(fileData, Base64FormattingOptions.None);
}
Client-Side Decoding
On the frontend, decode Base64 to use the file:
TypeScript - Decode Base64 to Blob
function base64ToBlob(base64: string, mimeType: string): Blob {
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: mimeType });
}
// Usage
const fileBlob = base64ToBlob(response.linkedFile, 'application/pdf');
const fileUrl = URL.createObjectURL(fileBlob);
Use Cases
When to Use This Endpoint
- Small files (< 1MB) - Images, thumbnails, small PDFs
- Embedded content - Files to display inline in the UI
- Quick previews - Generate thumbnails or previews
- Data URIs - Convert to data URLs for
<img>tags
When NOT to Use This Endpoint
- Large files (> 10MB) - Use Get Linked File By Chunks
- Direct downloads - Use Download File Handler
- Streaming video/audio - Use chunked streaming endpoint
Error Handling
C# - Handle Errors
public async Task<IActionResult> GetLinkedFile([FromBody] LinkedFileRequestDto request)
{
try
{
if (string.IsNullOrEmpty(request.FileId))
{
return BadRequest(new { error = "File ID is required" });
}
// Check authorization
if (!await CanUserAccessFile(GetCurrentUserId(), request.FileId))
{
return Unauthorized(new { error = "Access denied" });
}
// Get file data
byte[] fileData = await GetFileData(request.FileId);
if (fileData == null)
{
return NotFound(new { error = "File not found" });
}
return Ok(new {
linkedFile = Convert.ToBase64String(fileData),
linkedFileExt = Path.GetExtension(request.FileId).TrimStart('.'),
linkedFileSize = fileData.Length
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving linked file");
return StatusCode(500, new { error = "Failed to retrieve file" });
}
}
Next Steps
- Get Linked File Meta Handler - Get file metadata without downloading
- Get Linked File By Chunks - Handle large files efficiently
- Download File Handler - Direct file downloads