AlienFruit.Astra
1.0.1
dotnet add package AlienFruit.Astra --version 1.0.1
NuGet\Install-Package AlienFruit.Astra -Version 1.0.1
<PackageReference Include="AlienFruit.Astra" Version="1.0.1" />
<PackageVersion Include="AlienFruit.Astra" Version="1.0.1" />
<PackageReference Include="AlienFruit.Astra" />
paket add AlienFruit.Astra --version 1.0.1
#r "nuget: AlienFruit.Astra, 1.0.1"
#:package AlienFruit.Astra@1.0.1
#addin nuget:?package=AlienFruit.Astra&version=1.0.1
#tool nuget:?package=AlienFruit.Astra&version=1.0.1
AlienFruit.Astra
<img src="design/logo.png" alt="AlienFruit.Astra Logo" height="64">
AlienFruit.Astra is a powerful .NET library designed to enhance ASP.NET applications (both MVC and Razor Pages) by enabling dynamic content loading and providing a seamless user experience with smooth navigation between pages without full page refreshes.
Why Astra when Blazor exists?
While Blazor offers powerful client-side capabilities, Astra provides a lightweight alternative for developers who want to enhance existing ASP.NET applications with smooth AJAX navigation without the complexity of a full SPA framework. Perfect for incrementally improving user experience in traditional server-rendered applications.
Perfect for existing MVC projects!
Already have a working ASP.NET MVC or Razor Pages application? Astra can be integrated with minimal changes to your existing codebase. Transform your traditional server-rendered pages into modern, responsive applications with AJAX navigation.
What you'll get after migration:
- ⚡ Faster page loads - No more full page refreshes
- 🎯 Better UX - Smooth transitions and loading states
- 🏗️ Preserved architecture - Keep your existing controllers, views, and business logic
- 📱 Mobile-friendly - Improved responsiveness on all devices
- 🔧 Easy maintenance - Continue using familiar ASP.NET patterns
Features
- Dynamic Content Loading: Load partial views or content blocks dynamically without reloading the entire page.
- AJAX Navigation: Navigate between pages using AJAX, improving performance and user experience.
- Nested ViewBoxes: Create hierarchical UI structures with multiple independent dynamic content areas.
- JavaScript API: Programmatically control view-boxes from client-side code for advanced interactions.
- Resource Management: Efficiently manage JavaScript and CSS resources, preventing duplicates and ensuring proper loading.
- ViewBox Integration: Integrate with the ViewBox pattern for isolated and reusable UI components.
- Highly Customizable: Easily configure the library to fit your application's specific needs.
Requirements
- .NET 7.0 or higher
- ASP.NET Core MVC or Razor Pages
Installation
Install AlienFruit.Astra via NuGet Package Manager Console:
Install-Package AlienFruit.Astra
Or using the .NET CLI:
dotnet add package AlienFruit.Astra
Usage
Basic Setup
1. Register services in your Program.cs:
var builder = WebApplication.CreateBuilder(args);
// ... service registrations ...
// Register Astra services
builder.AddAstra();
2. Add the Astra middleware to your application's request pipeline:
var app = builder.Build();
// ... other middleware configuration ...
app.UseAstra();
3. Configure View Files
Add tag helpers and AstraEngine injection to your view files:
In _ViewImports.cshtml:
@addTagHelper *, AlienFruit.Astra
What this directive does: Registers all Tag Helpers from the AlienFruit.Astra assembly, allowing you to use special HTML tags <view-box> and <view-box-link> in your Razor views to create dynamic UI components.
In _ViewStart.cshtml:
@using AlienFruit.Astra.Core
@inject AstraEngine AstraEngine
@{
@AstraEngine.IncompleteLoadCheck()
Layout = AstraEngine.RouteLayout(Context, "_Layout");
}
What these directives do:
@using AlienFruit.Astra.Core- imports the namespace for accessing Astra classes@inject AstraEngine AstraEngine- injects an AstraEngine instance into the view for managing dynamic loading@AstraEngine.IncompleteLoadCheck()- adds JavaScript code to protect against incomplete resource loading when restoring pages from browser historyLayout = AstraEngine.RouteLayout(Context, "_Layout")- dynamically determines the page layout through AstraEngine instead of static assignment
Important: The @AstraEngine.IncompleteLoadCheck() line provides protection against incomplete resource loading. This function adds JavaScript code that checks for the presence of a special meta tag after DOM loading. This is necessary in case a page is restored from history when opening the browser.
4. Add ViewBox to _Layout.cshtml
The <view-box> tag is a container for dynamic page content. It is designed to hold content that can be loaded asynchronously without a full page reload:
<view-box id="main-view-box1"
class="pb-3"
role="main"
on-timeout-after-start-loading-js-function="onTimeoutAfterStartLoading"
on-finish-loading-js-function="onFinishLoading">
@RenderBody()
</view-box>
view-box Parameters:
| Parameter | Type | Required | Description | Default Value |
|---|---|---|---|---|
id |
string |
✅ Yes | Unique identifier for the view-box container. Used to link with view-box-link elements and for JavaScript interaction | - |
connection-error-message-resource |
Resource |
❌ No | Resource containing a connection error message that will be displayed when loading problems occur. Supports EmbeddedResource and InMemoryResource resource types |
Built-in resource with message "Failed to connect to server. Please check your internet connection and try refreshing the page." |
on-start-loading-js-function |
string |
❌ No | Name of the JavaScript function that will be called when content loading starts | null |
on-timeout-after-start-loading-js-function |
string |
❌ No | Name of the JavaScript function that will be called when the timeout expires after loading starts. Can be used to display a loading indicator | null |
on-finish-loading-js-function |
string |
❌ No | Name of the JavaScript function that will be called after successful content loading completion. Can be used to perform additional actions after loading | null |
on-scripts-executed-js-function |
string |
❌ No | Name of the JavaScript function that will be called after all scripts of the loaded page have been executed | null |
start-loading-event-delay |
int |
❌ No | Delay in milliseconds before calling the loading start event | 100 |
class |
string |
❌ No | CSS classes for container styling | null |
style |
string |
❌ No | Inline CSS styles for the container | null |
role |
string |
❌ No | ARIA role for accessibility | null |
tag-name |
string |
❌ No | HTML tag name to use instead of <main> |
"main" |
changing-browser-address-enable |
bool |
❌ No | Enables/disables browser URL address change during navigation | true |
parent-view-box-id |
string |
❌ No | ID of the parent view-box container for creating hierarchy | null |
Detailed description of the connection-error-message-resource parameter:
The connection-error-message-resource parameter defines a resource containing an HTML error message that will be displayed in the view-box container when connection problems occur (for example, when internet connection is lost or the server is unavailable).
Supported resource types:
EmbeddedResource- for using embedded resources from the assembly:
connection-error-message-resource="@(new EmbeddedResource(
name: "CustomError.html",
path: "MyProject.Views.Shared.CustomError.html",
assembly: typeof(MyController).Assembly))"
EmbeddedResource parameters:
name- unique resource name for identificationpath- full path to the embedded resource in the formatNamespace.Folder.FileName.Extension(manifest resource name)assembly- assembly containing the embedded resource (usuallyAssembly.GetExecutingAssembly()ortypeof(SomeClass).Assembly)
InMemoryResource- for creating a resource directly in code:
connection-error-message-resource="@(new InMemoryResource(
"connection-error",
"<div class='alert alert-danger'>Failed to connect to server. Please check your internet connection.</div>"))"
- Custom Resource implementation - for advanced scenarios, you can create your own class inheriting from the abstract
Resourceclass:
public class DatabaseResource(string name, string query, IDbConnection connection) : Resource(name)
{
public override Stream GetStream()
{
// Get HTML from database by query
var html = GetHtmlFromDatabase(query, connection);
var bytes = Encoding.UTF8.GetBytes(html);
return new MemoryStream(bytes);
}
}
Usage recommendations:
- Use
InMemoryResourcefor simple text messages - Use
EmbeddedResourcefor complex HTML templates with styling - HTML content should be valid and secure
- It is recommended to use CSS classes for styling error messages
What @RenderBody() does: This Razor method displays the content of a specific page inside the view-box container for standard display of page content using ASP.NET MVC means. For example, when first opening a page by link in the browser or during a full page reload.
Detailed explanation of @RenderBody():
- In a standard ASP.NET MVC application,
@RenderBody()is used in layout files to display page content - In the context of AlienFruit.Astra, this method is placed inside the
<view-box>container - When a user navigates via
<view-box-link>, the target page content is loaded via AJAX request and displayed inside the view-box instead of@RenderBody() - This allows updating only part of the page (view-box content), preserving navigation, header, footer, and other static elements
- This way, smooth SPA-like navigation is achieved without reloading the entire page
4.1. Nested ViewBoxes
AlienFruit.Astra supports hierarchical view-box structures, allowing you to create nested dynamic content areas. This enables complex UI layouts where different parts of the page can be updated independently.
How nested view-boxes work:
- Child view-boxes can be placed inside parent view-boxes
- Each view-box maintains its own loading state and content
- Navigation can target specific view-boxes within the hierarchy
- Parent-child relationships are established using the
parent-view-box-idparameter
Example of nested view-boxes:
<view-box id="main-view-box1" class="pb-3" role="main">
@RenderBody()
</view-box>
<view-box id="dynamic-content-box"
parent-view-box-id="main-view-box1"
class="pb-3"
role="main"
changing-browser-address-enable="false">
<div class="alert alert-info">
<h4>Select a tab to load content</h4>
</div>
</view-box>
Benefits of nested view-boxes:
- Modular UI: Create complex interfaces with multiple independent content areas
- Selective Updates: Update specific sections without affecting others
- Tab Interfaces: Perfect for tabbed content, dashboards, and multi-panel layouts
- Independent Loading: Each view-box can show its own loading states and error messages
Using view-box-link with nested structures:
<view-box-link id="tab1-link"
default-class-name="btn btn-primary"
selected-class-name="btn btn-primary active"
view-box-id="dynamic-content-box"
uri="/DynamicContent/Tab1">
Tab 1
</view-box-link>
Important notes:
- The
parent-view-box-idparameter must reference an existing view-box ID - Child view-boxes inherit the error handling and resource management of their parent
- JavaScript functions (on-finish-loading, etc.) work independently for each view-box
- Browser address changes can be controlled per view-box using
changing-browser-address-enable
5. Add Dynamic Links to _Layout.cshtml (for example, for menu items)
To create a dynamic link that loads content without a full page refresh, use the <view-box-link> tag:
<view-box-link id="home-link"
selected-class-name="nav-link text-dark active"
default-class-name="nav-link"
view-box-id="main-view-box1"
uri="/Home">
Home
</view-box-link>
view-box-link parameters:
| Parameter | Type | Required | Description | Default Value |
|---|---|---|---|---|
id |
string |
✅ Yes | Unique identifier for the view-box-link element | - |
uri |
string |
✅ Yes | URI address of the page to navigate to | - |
view-box-id |
string |
✅ Yes | ID of the view-box container where content will be loaded | - |
style |
string |
❌ No | Inline CSS styles for the element | null |
default-class-name |
string |
❌ No | CSS classes applied by default | null |
selected-class-name |
string |
❌ No | CSS classes applied when the link matches the current URL | null |
tag-name |
string |
❌ No | HTML tag name to use instead of <a> |
"a" |
on-click-js-function |
string |
❌ No | Name of the JavaScript function to be called when the link is clicked | null |
scroll-up |
bool |
❌ No | Determines whether the page should scroll up after content loading | true |
5.1. JavaScript API for Programmatic Control
AlienFruit.Astra provides a JavaScript API that allows you to programmatically control view-boxes from your client-side code. This is useful for creating custom interactions, handling complex UI logic, or integrating with other JavaScript frameworks.
ViewBoxRegistry.sendRequest() method:
The ViewBoxRegistry.sendRequest() method allows you to dynamically load content into a specific view-box by sending an AJAX request:
ViewBoxRegistry.sendRequest(viewBoxId, uri);
Parameters:
viewBoxId(string): The ID of the target view-box containeruri(string): The URI address of the page to navigate to
Example usage in HTML:
<div id="dynamic-tab3-link"
class="btn btn-primary"
onclick="ViewBoxRegistry.sendRequest('dynamic-content-box', '/DynamicContent/Tab3');">
Test request from JS
</div>
Example usage in JavaScript:
// Load content into main view-box
ViewBoxRegistry.sendRequest('main-view-box1', '/Home/About');
// Load tab content dynamically
ViewBoxRegistry.sendRequest('dynamic-content-box', '/DynamicContent/Tab1');
ViewBoxRegistry.abortCurrentRequest() method:
Cancels the currently running request in a specific view-box:
ViewBoxRegistry.abortCurrentRequest(viewBoxId);
Parameters:
viewBoxId(string): The ID of the target view-box container
Returns:
boolean:trueif the request was successfully cancelled,falseif there was no active request
Benefits of programmatic control:
- Custom Interactions: Create complex UI behaviors that go beyond simple links
- Dynamic Content: Load content based on user actions, form submissions, or application state
- Integration: Easily integrate with other JavaScript libraries and frameworks
- Conditional Loading: Load content based on business logic or user permissions
- Request Cancellation: Ability to cancel ongoing requests when needed
Available JavaScript methods:
ViewBoxRegistry.sendRequest(viewBoxId, uri)- Load content into a view-boxViewBoxRegistry.abortCurrentRequest(viewBoxId)- Cancel current request in a view-box
Additional ViewBoxRegistry methods:
ViewBoxRegistry.create(id, specification)- Create a new ViewBox instanceViewBoxRegistry.getOrCreate(id, specification)- Get or create a ViewBox instanceViewBoxRegistry.get(id)- Get an existing ViewBox instanceViewBoxRegistry.isCreated(id)- Check if ViewBox existsViewBoxRegistry.destroy(id)- Destroy a ViewBox instanceViewBoxRegistry.destroyAll()- Destroy all ViewBox instancesViewBoxRegistry.getOrOnReady(id, callback)- Get ViewBox or call callback when ready
Important notes:
- If the view-box doesn't exist when calling
sendRequest(), it will wait for the view-box to be created before executing the request - If the view-box doesn't exist when calling
abortCurrentRequest(), the method will returnfalse - All the same loading events and error handling apply as with view-box-link elements
- JavaScript API calls respect the same configuration settings (address changes, loading delays, etc.)
5.2. ViewBox Link Groups
The <view-box-link-group> tag allows you to create groups of navigation elements that share a common visual state. This is useful for creating navigation menus, tab groups, or any collection of links where you want to apply styling to a container element when any of the associated URIs is active.
How view-box-link-group works:
- Groups multiple URIs together under a single container element
- Automatically applies CSS classes to the group container based on the current page URI
- Monitors navigation events from the associated view-box
- Updates group styling when navigation occurs via view-box-link or JavaScript API
Example usage:
<view-box-link-group id="main-nav-group"
view-box-id="main-view-box1"
default-class-name="nav-item"
selected-class-name="nav-item active"
uri-to-activete="@([
"/Home",
"/About",
"/Contact"
])">
<view-box-link id="home-link"
default-class-name="nav-link"
selected-class-name="nav-link active"
view-box-id="main-view-box1"
uri="/Home">
Home
</view-box-link>
<view-box-link id="about-link"
default-class-name="nav-link"
selected-class-name="nav-link active"
view-box-id="main-view-box1"
uri="/About">
About
</view-box-link>
<view-box-link id="contact-link"
default-class-name="nav-link"
selected-class-name="nav-link active"
view-box-id="main-view-box1"
uri="/Contact">
Contact
</view-box-link>
</view-box-link-group>
view-box-link-group parameters:
| Parameter | Type | Required | Description | Default Value |
|---|---|---|---|---|
id |
string |
✅ Yes | Unique identifier for the view-box-link-group element. Used for JavaScript interaction and specification lookup | - |
view-box-id |
string |
✅ Yes | ID of the view-box container associated with this group. The group will monitor navigation events for the specified view-box | - |
uri-to-activete |
string[] |
✅ Yes | Array of URIs that will activate the selected state for this group. When the current page URI matches any of these URIs, the SelectedClassName will be applied | - |
style |
string |
❌ No | Inline CSS styles for the group element | null |
default-class-name |
string |
❌ No | CSS classes applied by default to the group element when none of the monitored URIs are active | null |
selected-class-name |
string |
❌ No | CSS classes applied when at least one of the URIs from uri-to-activete is active | null |
tag-name |
string |
❌ No | HTML tag name to use for the group element | "div" |
Use cases for view-box-link-group:
- Navigation Menus: Highlight menu sections when any page within that section is active
- Tab Groups: Style tab containers based on which tab is currently displayed
- Breadcrumb Groups: Apply styling to breadcrumb containers for related pages
- Category Navigation: Group related pages together and style the category container
Benefits:
- Centralized Styling: Apply styles to a container element instead of managing individual links
- Automatic Updates: Group styling updates automatically when navigation occurs
- Flexible Grouping: Group any combination of URIs together, regardless of their structure
- Server-Side Rendering: Initial CSS classes are applied on the server based on the current request path
Important notes:
- The
uri-to-activeteparameter must contain at least one URI - URI matching is case-insensitive
- The group monitors navigation events from the specified view-box
- Both server-side (initial page load) and client-side (AJAX navigation) styling updates are supported
- The group element can contain any HTML content, including view-box-link elements
6. Resource Management
Resource Management - is an important part of AlienFruit.Astra that provides automatic connection and management of JavaScript and CSS resources. This is necessary for the correct operation of dynamic content loading and preventing resource conflicts.
Why is this needed:
- Automatic resource connection: Astra automatically connects the necessary JS/CSS files to the HTML page header
- Prevention of duplication: The system tracks already connected resources and avoids their re-inclusion
- Version management: Resources receive version tags for correct browser caching
- Location separation: Resources can be placed in
<head>(Header) or before the closing</body>(Body) - AJAX navigation support: When dynamically loading pages, resources are connected automatically without reloading
How to use:
@using AlienFruit.Astra.Core
@inject AstraEngine AstraEngine
<!DOCTYPE html>
<html>
<head>
@AstraEngine.RenderHeaders()
</head>
<body>
</body>
</html>
What @AstraEngine.RenderHeaders() does:
- Connects the main JavaScript file
viewbox.jsfor view-box component operation - Generates HTML
<link>tags for CSS resources - Generates HTML
<script>tags for JavaScript resources - Adds a special meta tag
<meta id="load-check">to protect against incomplete resource loading - Considers resource versioning for correct caching
7. Configuration
AlienFruit.Astra provides a flexible configuration system for optimizing resource handling and performance. Most users will find the following configuration suitable:
Recommended configuration for most projects:
{
"AstraConfiguration": {
"EnableVersioning": true,
"UseCompression": true,
"CacheMaxAge": 86400
}
}
Or programmatically:
builder.AddAstra(options =>
{
options.EnableVersioning = true;
options.UseCompression = true;
options.CacheMaxAge = 86400; // 24 hours
});
All available configuration parameters:
| Parameter | Type | Description | Default Value | Recommendation |
|---|---|---|---|---|
UseCompression |
bool |
Enables resource compression (GZIP) to reduce the size of transmitted data | true |
Keep true for production |
ResourcesRoute |
string |
Route path for serving resources (CSS/JS files) | "astra" |
Use the default value |
EnableVersioning |
bool |
Enables resource versioning for correct browser caching | false |
Set true for production |
ResourceVersion |
string? |
Fixed resource version (if not specified, content hash is used) | null |
Leave null for automatic versioning |
CacheMaxAge |
int |
Resource caching time in seconds (HTTP Cache-Control max-age) | 31536000 (1 year) |
86400 (24 hours) for development, 31536000 for production |
Parameter explanations:
EnableVersioning = true- prevents caching issues when updating resourcesUseCompression = true- reduces the size of transmitted dataCacheMaxAge = 86400- balance between performance and content freshness (24 hours)
Contributing
We welcome contributions to AlienFruit.Astra! If you have suggestions for improvements, new features, or bug fixes, please open an issue or submit a pull request on our GitHub repository.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contact & Support
For questions, support, or general discussions, please visit our GitHub Discussions or open an issue on the issue tracker.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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 is compatible. 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. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.1 | 80 | 2/13/2026 |