Document Library Folder Sharing
Programmatically control Document Library folder access and permissions to enable collaboration, content distribution, and secure file sharing. This guide covers how to configure folder sharing, manage permissions, and implement access control in code.
Overview
Folder sharing in the Document Library provides granular control over who can access folders and what actions they can perform. By default, all folders are private to the owner and administrators. Sharing must be explicitly configured to allow other users to view, upload, or manage folder content.
Key Characteristics:
- Default private access (owner and administrators only)
- Three sharing levels: private, all users, specific users/groups
- Granular permissions: Full Control, Can Upload, Can View
- Support for User Groups and Security Roles
- Public access via Guest Security Role configuration
- Programmatic sharing through ShareWithSpecificUsers() method
Access Control Layers:
- Entity Permissions - Security Role permissions on Folder (system) entity
- Folder Sharing - Specific folder access configuration
- File Publishing - Individual file public access settings
Sharing Levels
Level 1: Visible Only to Owner (Default)
The most restrictive level. Only the folder owner and administrators can access the folder.
// Default when folder is created - no additional code needed
var folder = new Folder
{
Name = "Private Folder",
ParentId = null,
OwnerId = SystemInfo.UserId
};
Database.Insert(folder);
// Folder is automatically private to owner only
Level 2: Visible to All Users
All portal users can access the folder. Guest users (non-authenticated) can access if Guest Security Role has Read permission on Folder entity.
public ActionResponse ShareWithAllUsers(string folderId)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Share with all portal users
folder.ShareWithAllUsers();
AspxPage.AddMessage("Folder shared with all users!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Level 3: Visible to Specific Users/Groups
The most flexible option. Specify exactly which users, groups, or security roles can access the folder and their permission level.
public ActionResponse ShareWithSpecificUsers(string folderId)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Define sharing permissions
var permissions = new List<FolderSharingOption>
{
new FolderSharingOption
{
RecordId = "user-id-1",
AccessLevel = "FullControl"
},
new FolderSharingOption
{
RecordId = "user-id-2",
AccessLevel = "CanUpload"
},
new FolderSharingOption
{
RecordId = "user-group-id",
AccessLevel = "CanView"
}
};
// Apply sharing
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage("Folder shared successfully!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Permission Levels
Full Control
Complete management access including editing, deleting, and managing folder permissions.
Users with Full Control can:
- View all files in the folder
- Upload new files
- Edit file properties
- Delete files
- Move or copy files
- Manage folder sharing settings
- Delete the folder
new FolderSharingOption
{
RecordId = userId,
AccessLevel = "FullControl"
}
Can Upload
Users can view files and upload new content.
Users with Can Upload can:
- View all files in the folder
- Upload new files
- Edit properties of files they uploaded
- Download files
Users with Can Upload cannot:
- Delete files uploaded by others
- Modify folder sharing settings
- Delete the folder
new FolderSharingOption
{
RecordId = userId,
AccessLevel = "CanUpload"
}
Can View
Read-only access to folder contents.
Users with Can View can:
- View all files in the folder
- Download files
Users with Can View cannot:
- Upload new files
- Edit any properties
- Delete anything
- Modify sharing settings
new FolderSharingOption
{
RecordId = userId,
AccessLevel = "CanView"
}
FolderSharingOption Class
The FolderSharingOption class defines sharing permissions for users, groups, or security roles.
Properties
| Property | Type | Required | Description |
|---|
| RecordId | string | Yes | ID of User, UserGroup, or SecurityRole to grant access |
| AccessLevel | string | Yes | Permission level: "FullControl", "CanUpload", or "CanView" |
Usage
var sharingOption = new FolderSharingOption
{
RecordId = "user-or-group-id",
AccessLevel = "FullControl" // or "CanUpload" or "CanView"
};
Sharing Methods
ShareWithAllUsers()
Share folder with all portal users.
public ActionResponse SharePublicFolder(string folderId)
{
try
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Validate user has permission to share
if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
AspxPage.AddError("You don't have permission to share this folder.");
return RedirectToAction("Index");
}
folder.ShareWithAllUsers();
AspxPage.AddMessage($"Folder '{folder.Name}' is now visible to all users!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
catch (Exception ex)
{
SystemInfo.Debug($"Share error: {ex.Message}");
AspxPage.AddError("Failed to share folder.");
return RedirectToAction("Index");
}
}
ShareWithSpecificUsers()
Share folder with specific users, groups, or security roles.
public ActionResponse ShareFolder(string folderId, List<FolderSharingOption> permissions)
{
try
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Validate ownership or admin
if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
AspxPage.AddError("Only the folder owner or administrator can share this folder.");
return RedirectToAction("Index");
}
// Apply sharing
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage("Folder sharing configured successfully!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
catch (Exception ex)
{
SystemInfo.Debug($"Share error: {ex.Message}");
AspxPage.AddError("Failed to configure folder sharing.");
return RedirectToAction("Index");
}
}
Common Sharing Scenarios
Scenario 1: Share with Team Members
public ActionResponse ShareWithTeam(string folderId, List<string> teamMemberIds)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Create permissions for team members
var permissions = teamMemberIds.Select(userId => new FolderSharingOption
{
RecordId = userId,
AccessLevel = "CanUpload"
}).ToList();
// Apply sharing
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage($"Folder shared with {teamMemberIds.Count} team members!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Scenario 2: Share with Department (User Group)
public ActionResponse ShareWithDepartment(string folderId, string userGroupId, string accessLevel)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Share with User Group
var permissions = new List<FolderSharingOption>
{
new FolderSharingOption
{
RecordId = userGroupId,
AccessLevel = accessLevel
}
};
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage("Folder shared with department!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Scenario 3: Share with Security Role
public ActionResponse ShareWithRole(string folderId, string securityRoleId)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Share with all users in a security role
var permissions = new List<FolderSharingOption>
{
new FolderSharingOption
{
RecordId = securityRoleId,
AccessLevel = "CanView"
}
};
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage("Folder shared with security role!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Scenario 4: Mixed Permission Levels
public ActionResponse ShareProjectFolder(string folderId, string managerId, string teamGroupId, string viewerRoleId)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Define different permission levels
var permissions = new List<FolderSharingOption>
{
// Project manager gets full control
new FolderSharingOption
{
RecordId = managerId,
AccessLevel = "FullControl"
},
// Team members can upload
new FolderSharingOption
{
RecordId = teamGroupId,
AccessLevel = "CanUpload"
},
// Stakeholders can only view
new FolderSharingOption
{
RecordId = viewerRoleId,
AccessLevel = "CanView"
}
};
folder.ShareWithSpecificUsers(permissions);
AspxPage.AddMessage("Project folder shared with appropriate permissions!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Public Access Configuration
Enable public access for non-authenticated users (Guest users).
Step 1: Configure Guest Security Role
// This is typically done through Setup UI, not code
// Guest Security Role must have Read permission on Folder (system) entity
Step 2: Share Folder Publicly
public ActionResponse MakeFolderPublic(string folderId)
{
try
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Share with all users (includes guest users if configured)
folder.ShareWithAllUsers();
AspxPage.AddMessage("Folder is now publicly accessible!");
// Note: Individual files must also be marked as "Published Publicly"
return RedirectToAction("FolderDetails", new { id = folderId });
}
catch (Exception ex)
{
SystemInfo.Debug($"Public share error: {ex.Message}");
AspxPage.AddError("Failed to make folder public.");
return RedirectToAction("Index");
}
}
Step 3: Publish Individual Files
public ActionResponse PublishFilesPublicly(string folderId)
{
var folder = Database.Retrieve<Folder>(folderId);
if (folder == null)
{
return PageNotFound();
}
// Get all files in folder
var documents = Database.Query<Document>()
.Where(d => d.FolderId == folderId)
.ToList();
// Mark each file as published publicly
foreach (var doc in documents)
{
doc.Published = true;
Database.Update(doc);
}
AspxPage.AddMessage($"{documents.Count} files published publicly!");
return RedirectToAction("FolderDetails", new { id = folderId });
}
Best Practices
Security
✅ Always validate ownership or admin rights
if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
AspxPage.AddError("You don't have permission to share this folder.");
return RedirectToAction("Index");
}
✅ Use least privilege principle
// Start with most restrictive access
new FolderSharingOption
{
RecordId = userId,
AccessLevel = "CanView" // Start restrictive, expand as needed
}
✅ Validate access levels
string[] validLevels = { "FullControl", "CanUpload", "CanView" };
if (!validLevels.Contains(accessLevel))
{
AspxPage.AddError("Invalid access level.");
return View();
}
Performance
✅ Use User Groups for team sharing
// Good: One permission for entire group
new FolderSharingOption
{
RecordId = userGroupId,
AccessLevel = "CanUpload"
}
// Avoid: Individual permissions for each user
// (though sometimes necessary)
Maintenance
✅ Document sharing decisions
// Create audit note when sharing
var note = new NoteAndAttachment
{
Name = "Folder Shared",
Body = $"Folder shared with {permissions.Count} users/groups by {SystemInfo.UserName}",
ReferenceId = folderId,
Type = 0
};
Database.Insert(note);
Common Pitfalls
❌ Pitfall 1: Forgetting to check ownership
// Bad: No validation
folder.ShareWithAllUsers();
// Good: Validate ownership
if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
return UnauthorizedAccessResponse();
}
❌ Pitfall 2: Public sharing without file publishing
// Bad: Folder shared but files not published
folder.ShareWithAllUsers();
// Files are not publicly accessible yet
// Good: Share folder AND publish files
folder.ShareWithAllUsers();
foreach (var doc in documents)
{
doc.Published = true;
Database.Update(doc);
}
❌ Pitfall 3: Invalid RecordId
// Bad: No validation
new FolderSharingOption
{
RecordId = userId, // Could be null or invalid
AccessLevel = "CanView"
}
// Good: Validate before sharing
if (string.IsNullOrEmpty(userId))
{
AspxPage.AddError("Invalid user ID.");
return View();
}
Related Topics