Getting Started
NE.Standard is a server-driven UI framework: you write a view (a component tree) and a controller (observable state and commands), the framework compiles and renders them, and keeps the rendered page in sync in both directions. This walks through wiring that up in a new ASP.NET Core project.
Install
The framework is a pre-release, so every package needs --prerelease until the first stable release, and
every package must be installed at the same version:
dotnet add package NE.Standard.UI.Web --prerelease
dotnet add package NE.Standard.UI.Web.Renderers --prerelease
NE.Standard.UI.Web is the ASP.NET Core host (shell, SignalR channel, file transfer, the embedded
TypeScript client); NE.Standard.UI.Web.Renderers supplies the HTML renderers for the built-in components.
Everything else — the compiler, the binding model, the built-in components — arrives transitively.
Two startup classes
Configuration is split in two: one class for services and one for the application (routes, persistence, localization). Both are empty shells you fill in.
using Microsoft.Extensions.DependencyInjection;
using NE.Standard.UI.Web.Renderers.DI;
using NE.Standard.UI.Web.Startup;
internal sealed class AppWebStartup : WebStartupBase<AppStartup>
{
protected override void ConfigureServices(IServiceCollection services)
=> services.AddStandardRenderers();
}
using NE.Standard.UI.Application;
using NE.Standard.UI.Startup;
public sealed class AppStartup : UIStartupBase
{
protected override void ConfigureApplication(UIApplicationBuilder application)
=> application.Route<CounterView, CounterController>("/");
}
AddStandardRenderers() registers the renderers for the built-in components — call it once from
ConfigureServices. application.Route<TView, TController>(route) registers a page with a controller;
application.Route<TView>(route) registers one with no controller, for a page that has nothing to bind.
Program.cs
using Microsoft.AspNetCore.Builder;
using NE.Standard.UI.Web.Hosting;
using NE.Standard.UI.Web.Startup;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebStartupBuilder.Configure<AppWebStartup, AppStartup>(builder.Services);
WebApplication app = builder.Build();
// The framework maps a catch-all GET route, which matches every path — static files must be served
// (and routing added) before that map, or every static file comes back as a rendered page.
app.UseStaticFiles();
app.UseRouting();
await app.MapStandardUIWebAsync();
await app.RunAsync();
WebStartupBuilder.Configure<TWebStartup, TStartup>(services) runs both startup classes.
app.MapStandardUIWebAsync() maps the asset endpoints, the file endpoints, the SignalR hub, and the
catch-all page route — in that order, which is why UseStaticFiles/UseRouting must run first and by hand
rather than through MapStaticAssets() (its precompressed variants collide with the framework's own
response compression).
A first view and controller
A view declares the component tree; a controller holds the state a component binds to.
using NE.Standard.UI.Abstractions.Styling;
using NE.Standard.UI.Authoring.Components;
using NE.Standard.UI.Components.BuiltIns.Actions;
using NE.Standard.UI.Components.BuiltIns.Contents;
using NE.Standard.UI.Components.BuiltIns.Layouts;
using NE.Standard.UI.Authoring.Views;
internal sealed class CounterView : UIViewBase, IUIViewDefinition
{
public static string ViewKey => "counter";
protected override IVisualComponent CreateContent()
=> new ContainerComponent()
.SetPadding(new UIThickness(16))
.AddChild(new TextComponent()
.BindTitle(nameof(CounterController.Count))
.SetPlacement(1, 1, 24, 1)
)
.AddChild(new ButtonComponent()
.OnClick(nameof(CounterController.Increment))
.ConfigureDefaultContent(c => c.SetTitle("Add one"))
.SetPlacement(1, 2, 24, 1)
);
}
using NE.Standard.UI.Controllers;
using NE.Standard.UI.Primitives.Annotations;
internal sealed partial class CounterController : UIControllerBase
{
[RecursiveMember]
public partial int Count { get; set; }
[UICommand]
public void Increment() => Count++;
}
BindTitle binds TextComponent.Title to the controller's Count path; OnClick wires the button to the
Increment command by name. [RecursiveMember] generates the notifying setter for Count and the path
segment a binding resolves against; [UICommand] makes Increment callable from the client. Register the
route in AppStartup.ConfigureApplication as shown above.
Running it
dotnet run
Requires the .NET 10 SDK, and Node for the TypeScript client — the client builds as part of dotnet build,
so a client type error fails the build too (dotnet build -p:SkipWebClientBuild=true skips that step when
Node is unavailable).
Icons
Icon sets are separate packages, one per set, each with a matching NE.Standard.UI.Web.Icons.<Set> package
that plugs into the web host. Register the glyphs an application actually uses in ConfigureServices:
using NE.Standard.UI.Icons.Material;
using NE.Standard.UI.Web.Icons.Material;
protected override void ConfigureServices(IServiceCollection services)
{
services.AddStandardRenderers();
services.AddMaterialWebIcons(MaterialIconStyle.Fill | MaterialIconStyle.Outlined, MaterialIcons.Settings);
}
Only the glyphs named this way are registered — a whole style of the Material set costs megabytes, so the
call takes the names it should serve. MaterialIconStyle is a flags enum (Fill, Outlined); registering
both drawings lets a component choose per instance.
Where to go next
The counter is the whole model: a view, a controller, a route. A first real screen is three more pages away — a
list bound to a collection (Items), a form with validation and a submit
(Binding, Validation), and a sign-in page with a route behind it
(Security, Signing in); examples/TeamRoom is all three in one small application.
- Views — the component tree, placement grid, and the fluent authoring style.
- Controllers — observable state, commands, and the request lifecycle.
- Binding — paths, scopes, modes, and validation.
- Interactions and effects — client-side reactions and what a command can return.
- Routing — registering more than one route, route parameters, and filters.
- Web hosting — the ASP.NET Core host in depth, and how to extend it.
- Components — the built-in component catalogue.