Xeku.Sharing
0.0.0.7
dotnet add package Xeku.Sharing --version 0.0.0.7
NuGet\Install-Package Xeku.Sharing -Version 0.0.0.7
<PackageReference Include="Xeku.Sharing" Version="0.0.0.7" />
<PackageVersion Include="Xeku.Sharing" Version="0.0.0.7" />
<PackageReference Include="Xeku.Sharing" />
paket add Xeku.Sharing --version 0.0.0.7
#r "nuget: Xeku.Sharing, 0.0.0.7"
#:package Xeku.Sharing@0.0.0.7
#addin nuget:?package=Xeku.Sharing&version=0.0.0.7
#tool nuget:?package=Xeku.Sharing&version=0.0.0.7
Xeku.Sharing
A secure Magic Link module for sharing XAF business objects with external users without requiring authentication. Enables time-limited, PIN-protected, and access-tracked external sharing.
Features
- Magic Links: Generate secure, high-entropy tokens for external sharing
- Security First: Stores only SHA256 hashes, never plaintext tokens
- Flexible Access Control:
- Time-based expiration
- Optional PIN protection
- Maximum access count limits
- Manual activation/deactivation toggle
- Audit Trail: Complete access logging with IP addresses, user agents, and success/failure tracking
- IShareable Interface: Mark any business object as shareable
- UI Integration: Built-in "Share Externally" action in detail views
- Anonymous Access: Shared links work without authentication
Architecture
graph TB
classDef ui fill:#e1f5ff,stroke:#01579b
classDef service fill:#fff4e1,stroke:#ff6f00
classDef entity fill:#e8f5e9,stroke:#2e7d32
classDef external fill:#f3e5f5,stroke:#7b1fa2
subgraph "Presentation Layer"
Controller[ShareLinkController]:::ui
UI[DetailView Action]:::ui
end
subgraph "Service Layer"
SharingService[SharingService]:::service
TokenGen[Token Generator]:::service
HashFunc[SHA256 Hashing]:::service
end
subgraph "Data Layer"
SharedLink[SharedLink]:::entity
AccessLog[SharedLinkAccessLog]:::entity
IShareable[IShareable Interface]:::entity
end
subgraph "External"
AnonymousUser[Anonymous User]:::external
WebAPI[Sharing WebAPI]:::external
end
UI --> Controller
Controller --> SharingService
SharingService --> TokenGen
SharingService --> HashFunc
SharingService --> SharedLink
SharedLink --> AccessLog
AnonymousUser --> WebAPI
WebAPI --> SharingService
Installation
1. Add NuGet Package
dotnet add package Xeku.Sharing
2. Register Module
In your application module constructor:
RequiredModuleTypes.Add(typeof(Xeku.Sharing.SharingModule));
3. Configure Base URL
In appsettings.json, configure the base URL for generating full share links:
{
"Sharing": {
"BaseUrl": "https://yourapp.com"
}
}
4. Mark Business Objects as Shareable
Implement the IShareable interface on business objects you want to share externally:
using Xeku.Sharing.Interfaces;
public class Invoice : BaseObject, IShareable
{
// Your business object properties
}
Usage
Generating a Share Link (UI)
- Open the detail view of a business object that implements
IShareable - Click the "Share Externally" action button
- Configure sharing settings:
- Expiration Date: When the link will expire (optional)
- Access PIN: Additional security code (optional)
- Max Access Count: Limit number of accesses (optional)
- Click "Generate Link" to create the magic link
- Copy the generated URL and share it with external users
Programmatic Link Generation
using Xeku.Sharing.Services;
using Xeku.Sharing.BusinessObjects;
// Generate a secure token
string plaintextToken = SharingService.GenerateToken();
string tokenHash = SharingService.ComputeHash(plaintextToken);
// Create a SharedLink record
using IObjectSpace os = objectSpaceFactory.CreateObjectSpace(typeof(SharedLink));
SharedLink link = os.CreateObject<SharedLink>();
link.TokenHash = tokenHash;
link.TargetType = "MyApp.BusinessObjects.Invoice"; // Full type name
link.TargetKey = invoice.Oid.ToString(); // Primary key as string
link.ExpirationDate = DateTime.UtcNow.AddDays(7); // Expires in 7 days
link.AccessPin = "1234"; // Optional PIN
link.MaxAccessCount = 10; // Optional limit
link.CreatedBy = (Guid)SecuritySystem.CurrentUserId;
os.CommitChanges();
// Build the full URL
string shareUrl = $"https://yourapp.com/share/{plaintextToken}";
Validating and Retrieving Shared Objects
using Xeku.Sharing.Services;
var sharingService = new SharingService();
var metadata = new AccessMetadata(ipAddress, userAgent);
using IObjectSpace os = objectSpaceFactory.CreateNonSecuredObjectSpace(typeof(SharedLink));
SharingResult result = sharingService.GetSharedObject(os, plaintextToken, pin, metadata);
if (result.IsValid)
{
// Success - result.TargetObject contains the shared business object
var invoice = result.TargetObject as Invoice;
// Display or process the invoice
}
else
{
// Error - result.ErrorMessage contains the reason
Console.WriteLine($"Access denied: {result.ErrorMessage}");
}
Business Objects
SharedLink
Stores encrypted information for external sharing links.
Key Properties:
TokenHash(string): SHA256 hash of the plaintext tokenTargetType(string): Full type name of the shared business objectTargetKey(string): Primary key (Oid) of the shared objectExpirationDate(DateTime?): When the link expiresAccessPin(string?): Optional PIN for additional securityIsActive(bool): Manual enable/disable toggleMaxAccessCount(int?): Maximum number of accesses allowedAccessCount(int): Current number of successful accessesIsValid(bool): Computed property checking all validation rules
SharedLinkAccessLog
Audit log for tracking all access attempts to shared links.
Key Properties:
SharedLink(SharedLink): Associated share linkAccessTime(DateTime): When the access occurredIpAddress(string?): IP address of the visitorUserAgent(string?): Browser informationIsSuccess(bool): Whether access was successfulErrorMessage(string?): Error reason if access failed
ShareLinkParameters
Non-persistent object used in the UI for configuring share links.
Key Properties:
TargetType(string): Business object type to shareTargetKey(string): Object key/IDExpirationDate(DateTime?): Link expirationAccessPin(string?): Optional PIN codeMaxAccessCount(int?): Access limitGeneratedUrl(string?): Display the generated URL after creation
Interfaces
IShareable
Marker interface for business objects that can be shared externally.
public interface IShareable
{
}
ShareableAttribute
Attribute to mark specific properties as shareable (future enhancement).
[AttributeUsage(AttributeTargets.Property)]
public class ShareableAttribute : Attribute
{
}
Controllers
ShareLinkController
Provides the "Share Externally" action button in detail views for IShareable objects.
Features:
- Popup window for configuring share settings
- Real-time link generation
- Two-step workflow: Generate → Copy → Close
- Configuration validation and warnings
Services
SharingService
Core service for managing and validating external sharing links.
Methods:
| Method | Description |
|---|---|
GenerateToken() |
Generate a secure 64-character hex token |
ComputeHash(token) |
Compute SHA256 hash of a plaintext token |
GetSharedObject(os, token, pin, metadata) |
Validate token and retrieve shared object |
Security Considerations
Token Security
- Tokens are 64-character hexadecimal strings (256 bits of entropy)
- Only SHA256 hashes are stored in the database
- Plaintext tokens are shown only once during generation
Validation Chain
- Link Existence: Token hash must exist in database
- Active Status: Link must be manually activated
- Expiration: Current time must be before expiration date
- Access Limit: Access count must be below maximum
- PIN Verification: PIN must match if configured
Access Control
- Uses
INonSecuredObjectSpaceFactoryfor data access - No XAF security checks on shared objects
- Implement field-level control using
[Shareable]attribute (future)
Error Messages
| Error | Meaning |
|---|---|
| "Link not found." | Invalid or non-existent token |
| "Link has been disabled." | IsActive is set to false |
| "Link has expired." | Current time exceeds ExpirationDate |
| "Access limit reached." | AccessCount >= MaxAccessCount |
| "Invalid PIN code." | Provided PIN doesn't match |
| "Source type not found: {type}" | Business object type no longer exists |
| "Shared data no longer exists." | Target object was deleted |
Configuration
appsettings.json
{
"Sharing": {
"BaseUrl": "https://yourapp.com"
}
}
Required Services
This module requires IConfiguration to be available in the DI container for reading the base URL.
AI Agent Integration
Use Cases
AI agents can use the Sharing module to:
- Generate Shareable Links: Create magic links for reports, invoices, or documents
- Access Control: Set expiration times and access limits programmatically
- Audit Analysis: Query access logs to understand sharing patterns
- Link Management: Deactivate or update existing share links
API Integration Guide
See Xeku.Sharing.WebApi for REST API endpoints.
Best Practices
- Always Set Expiration: Don't create permanent links unless absolutely necessary
- Use PIN for Sensitive Data: Add PIN protection for confidential information
- Monitor Access Logs: Regularly review
SharedLinkAccessLogfor suspicious activity - Deactivate After Use: Manually set
IsActive = falsewhen link is no longer needed - Field-Level Security: Only share necessary properties (use
[Shareable]attribute)
Troubleshooting
"Warning: Sharing:BaseUrl not configured"
Solution: Add Sharing:BaseUrl to your appsettings.json:
{
"Sharing": {
"BaseUrl": "https://yourapp.com"
}
}
Share action button not visible
Possible causes:
- Business object doesn't implement
IShareableinterface - You're in a ListView (action only appears in DetailView)
- Module not registered in application
"Link not found" error
Possible causes:
- Token was copied incorrectly (case-sensitive)
- Token was modified during transmission
- Link was deleted from database
Dependencies
This module requires:
DevExpress.ExpressApp- XAF frameworkDevExpress.Persistent.BaseImpl- Base business objectsSystem.Security.Cryptography- SHA256 hashing
Related Packages
- Xeku.Sharing.Blazor - Blazor UI integration
- Xeku.Sharing.WebApi - REST API for anonymous access
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- DevExpress.ExpressApp (>= 25.2.3)
- DevExpress.ExpressApp.Security (>= 25.2.3)
- DevExpress.ExpressApp.Xpo (>= 25.2.3)
- DevExpress.Persistent.Base (>= 25.2.3)
- DevExpress.Persistent.BaseImpl.Xpo (>= 25.2.3)
- Xeku.Cache (>= 0.0.0.7)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Xeku.Sharing:
| Package | Downloads |
|---|---|
|
Xeku.Sharing.WebApi
Web API endpoints for Xeku.Sharing, supporting anonymous data retrieval. |
|
|
Xeku.Sharing.Blazor
Blazor components for Xeku.Sharing, including anonymous access pages. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.0.7 | 132 | 1/28/2026 |