How to make XAF ViewItems accessible via direct URL with parameters in Blazor
This project demonstrates how to expose XAF ViewItems as standalone pages with URL parameter configuration, plus REST API access - all using the same component.
Traditional XAF ViewItems:
- β Only accessible after login + navigation
- β No direct URL access
- β Can't share links to specific views
- β No URL parameters
This Solution:
- β
Direct URL access:
/chat?message=Hello - β URL parameters configure ViewItem state
- β Shareable links
- β Embeddable in other apps
- β REST API for programmatic access
What: Standard XAF ViewItem embedded in application Access: Login β Navigate β View Use case: Internal business app with full XAF security
https://yourapp.com/ β Login β Navigate to "AI Chat"
What: Blazor page exposing ViewItem via direct URL Access: Direct URL with parameters Use case: Shareable links, bookmarks, QR codes, embeds
Examples:
https://yourapp.com/chat
https://yourapp.com/chat?message=Hello
https://yourapp.com/chat?message=Show order 123&context=order123
URL Parameters:
message- Pre-populate initial messagecontext- Pass context data (orderId, userId, etc.)
What: HTTP API for programmatic access Access: POST request with JSON Use case: Mobile apps, external systems, automation
Endpoint:
POST https://yourapp.com/api/chat
{
"message": "List all orders",
"context": { "userId": "123" }
}This demo uses an AI Chat component (GitHub Copilot SDK) as the ViewItem example, but the URL configuration pattern works for ANY XAF ViewItem.
The same approach can be used for:
- Order detail views β
/order?id=123 - Customer profiles β
/customer?id=456&tab=orders - Reports β
/report?type=sales&month=2026-02 - Dashboard widgets β
/dashboard?widget=sales&period=today
Traditional XAF ViewItem (secured, full XAF)
β
Shared Component
(CopilotChat.razor)
β
ββββ Standalone Page (/chat) β URL Parameters
ββββ REST API (/api/chat) β JSON Request
1. Shared ViewItem Component
XafBlazorViewItemUrlConfiguration.Blazor.Server/
βββ Editors/CopilotChatViewItem/
βββ CopilotChat.razor β Reusable component
βββ CopilotChatViewItemBlazor.cs β XAF ViewItem wrapper
2. Standalone Page with URL Parameters
XafBlazorViewItemUrlConfiguration.Blazor.Server/
βββ Pages/
βββ Chat.razor β URL-accessible page
Code snippet:
@page "/chat"
@page "/chat/{InitialMessage?}"
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "message")]
public string? InitialMessage { get; set; }
[Parameter]
[SupplyParameterFromQuery(Name = "context")]
public string? Context { get; set; }
}3. REST API Controller
XafBlazorViewItemUrlConfiguration.WebApi/
βββ Controllers/
βββ ChatController.cs β HTTP endpoint
- .NET 9.0 SDK
- DevExpress XAF license
- GitHub Copilot API key (for this demo)
git clone https://github.com/egarim/XafBlazorViewItemUrlConfiguration.git
cd XafBlazorViewItemUrlConfiguration
dotnet restore XafBlazorViewItemUrlConfiguration.slnEdit appsettings.json in both projects:
{
"GitHubCopilot": {
"ApiKey": "your-copilot-api-key",
"Model": "gpt-4o"
}
}# Terminal 1: Blazor Server (port 5001)
cd XafBlazorViewItemUrlConfiguration.Blazor.Server
dotnet run
# Terminal 2: Web API (port 5002)
cd XafBlazorViewItemUrlConfiguration.WebApi
dotnet runTraditional XAF:
https://localhost:5001
Login: Admin / (empty password)
Navigate to: "Copilot Chat"
Direct URL Access:
https://localhost:5001/chat
https://localhost:5001/chat?message=Hello
https://localhost:5001/chat?message=Show order&context=order123
REST API:
curl -X POST https://localhost:5002/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "Hello, who are you?"}'Before (XAF-only):
[ViewItem(typeof(IModelMyViewItem))]
public class MyViewItemBlazor : ViewItem
{
// XAF-specific code
}After (Reusable Component):
// 1. Create standalone component
// MyComponent.razor
<div class="my-component">
@* Your ViewItem UI *@
</div>
@code {
[Parameter]
public string? InitialData { get; set; }
}
// 2. Wrap in XAF ViewItem
public class MyViewItemBlazor : ViewItem, IComponentContentHolder
{
RenderFragment IComponentContentHolder.ComponentContent => builder =>
{
builder.OpenComponent<MyComponent>(0);
builder.CloseComponent();
};
}// Pages/MyView.razor
@page "/myview"
@page "/myview/{Id?}"
<MyComponent InitialData="@Id" />
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "id")]
public string? Id { get; set; }
}[ApiController]
[Route("api/myview")]
public class MyViewController : ControllerBase
{
[HttpPost]
public IActionResult Process([FromBody] MyRequest request)
{
// Process and return data
return Ok(new MyResponse { ... });
}
}| Feature | Traditional XAF | With URL Config |
|---|---|---|
| Login Required | β Always | βοΈ Optional |
| Direct URL Access | β No | β Yes |
| Shareable Links | β No | β Yes |
| URL Parameters | β No | β Yes |
| Embeddable | β No | β Yes |
| REST API | β No | β Yes |
| XAF Security | β Full | βοΈ Optional |
Problem: Customer calls: "Where's my order?" Solution: Send them a direct link
https://yourapp.com/order?id=12345&email=customer@example.com
Customer sees order status without login.
Problem: Want customers to access support chat Solution: Print QR code linking to chat with order context
https://yourapp.com/support?order=12345&store=downtown
Problem: Email says "Approve expense report #789" Solution: Link directly to approval view
https://yourapp.com/approve?type=expense&id=789&token=...
Problem: Mobile app needs to access XAF functionality Solution: Call REST API
var response = await httpClient.PostAsJsonAsync(
"https://yourapp.com/api/order",
new { orderId = 123 }
);Problem: Users want to query data via chat Solution: Bot calls your API
response = requests.post("https://yourapp.com/api/chat",
json={"message": "Show today's orders"})// Chat.razor - No authentication
@page "/chat"
<MyComponent />// Chat.razor - Require token
@page "/chat"
@attribute [Authorize]
<MyComponent />// ChatController.cs
[ApiKey] // Custom attribute
public class ChatController : ControllerBase
{
// ...
}// Keep XAF security for ViewItem, public for standalone
if (User.Identity?.IsAuthenticated == true)
{
// Use XAF security
}
else
{
// Limited public access
}XafBlazorViewItemUrlConfiguration/
βββ XafBlazorViewItemUrlConfiguration.Blazor.Server/
β βββ Editors/
β β βββ CopilotChatViewItem/
β β βββ CopilotChat.razor β Shared component
β β βββ CopilotChatViewItemBlazor.cs β XAF ViewItem
β βββ Pages/
β βββ Chat.razor β URL-accessible page β
β
βββ XafBlazorViewItemUrlConfiguration.WebApi/
β βββ Controllers/
β βββ ChatController.cs β REST API β
β
βββ XafBlazorViewItemUrlConfiguration.Module/
β βββ Services/
β βββ CopilotChatService.cs β Business logic
β
βββ README.md β You are here
https://localhost:5001/chat
https://localhost:5001/chat?message=List all orders
https://localhost:5001/chat?message=Show details&context=order123
https://localhost:5001/chat?message=Hello&context=user:456,order:789
// Good
var url = $"/chat?message={Uri.EscapeDataString("Show order #123")}";
// Result: /chat?message=Show%20order%20%23123
// Bad
var url = $"/chat?message=Show order #123"; // Breaks with special chars// Support both formats
@page "/order/{Id}" // /order/123
[SupplyParameterFromQuery(Name = "id")] // /order?id=123// Save state to URL when it changes
protected override void OnParametersSet()
{
NavigationManager.NavigateTo(
$"/chat?message={CurrentMessage}&context={CurrentContext}",
replace: true
);
}<button @onclick="CopyShareLink">π Copy Link</button>
@code {
async Task CopyShareLink()
{
var url = $"{NavigationManager.BaseUri}chat?message={Message}";
await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", url);
}
}This project is inspired by:
- The Day I Integrated GitHub Copilot SDK Inside My XAF App β Part 1
- The Day I Integrated GitHub Copilot SDK Inside My XAF App β Part 2
Contributions welcome! Open an issue or PR.
MIT License - see LICENSE.txt
Made with β€οΈ by Joche Ojeda
Tags: xaf, devexpress, blazor, url-configuration, viewitem, deep-linking, rest-api, copilot