MintPlayer.AspNetCore.SpaServices.Routing 10.5.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package MintPlayer.AspNetCore.SpaServices.Routing --version 10.5.0
                    
NuGet\Install-Package MintPlayer.AspNetCore.SpaServices.Routing -Version 10.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MintPlayer.AspNetCore.SpaServices.Routing" Version="10.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MintPlayer.AspNetCore.SpaServices.Routing" Version="10.5.0" />
                    
Directory.Packages.props
<PackageReference Include="MintPlayer.AspNetCore.SpaServices.Routing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MintPlayer.AspNetCore.SpaServices.Routing --version 10.5.0
                    
#r "nuget: MintPlayer.AspNetCore.SpaServices.Routing, 10.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MintPlayer.AspNetCore.SpaServices.Routing@10.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MintPlayer.AspNetCore.SpaServices.Routing&version=10.5.0
                    
Install as a Cake Addin
#tool nuget:?package=MintPlayer.AspNetCore.SpaServices.Routing&version=10.5.0
                    
Install as a Cake Tool

MintPlayer.AspNetCore.SpaServices.Routing

NuGet Version NuGet License

This package simplifies SPA prerendering by allowing you to define your SPA routes in ASP.NET Core and determine which route is activated in the SupplyData callback.

Installation

NuGet Package Manager

Install-Package MintPlayer.AspNetCore.SpaServices.Routing

.NET CLI

dotnet add package MintPlayer.AspNetCore.SpaServices.Routing

MSBuild Integration

This package includes MintPlayer.AspNetCore.NodeServices which automatically configures your project with build targets for SPA development.

Properties

Property Default Description
EnableSpaBuilder true Master switch to disable SPA build automation
SpaRoot ClientApp\ Path to your SPA source folder
BuildServerSideRenderer true Whether to build the SSR bundle

Disabling SPA Builder

If your project doesn't have a SPA but references this package:

<PropertyGroup>
  <EnableSpaBuilder>false</EnableSpaBuilder>
</PropertyGroup>

Usage

1. Register SPA Routes

Define your SPA routes in ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSpaRoutes(routes => routes
        .Route("", "home")
        .Group("person", "person", person_routes => person_routes
            .Route("", "list")
            .Route("create", "create")
            .Route("{id}", "show")
            .Route("{id}/edit", "edit")
        )
    );
}

2. Supply Data Based on Route

Use ISpaRouteService to determine the current route and supply appropriate data:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISpaRouteService spaRouteService)
{
    app.UseSpa(spa =>
    {
        spa.UseSpaPrerendering(options =>
        {
            options.SupplyData = (context, data) =>
            {
                var route = spaRouteService.GetCurrentRoute(context);
                var personRepository = context.RequestServices.GetRequiredService<IPersonRepository>();

                switch (route?.Name)
                {
                    case "person-list":
                        data["people"] = personRepository.GetPeople();
                        break;
                    case "person-show":
                    case "person-edit":
                        var id = Convert.ToInt32(route.Parameters["id"]);
                        data["person"] = personRepository.GetPerson(id);
                        break;
                }
            };
        });
    });
}

3. Use Data in Angular (main.server.ts)

const providers: StaticProvider[] = [
    { provide: APP_BASE_HREF, useValue: params.baseUrl },
    { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
];

if ('people' in params.data) {
    providers.push({ provide: 'PEOPLE', useValue: params.data.people });
}
if ('person' in params.data) {
    providers.push({ provide: 'PERSON', useValue: params.data.person });
}

4. Generate URLs Server-Side

Generate SPA URLs from C# code (useful for redirects, sitemaps, etc.):

// Using a dictionary
var parms = new Dictionary<string, object> { ["id"] = 5 };
var url = spaRouteService.GenerateUrl("person-edit", parms);

// Using an anonymous type
var url = spaRouteService.GenerateUrl("person-edit", new { id = 5 });

Parameter values are percent-encoded, and any parameter the route template does not declare is appended as a query-string entry:

var parms = new Dictionary<string, object> { ["id"] = 5, ["tab"] = "a b" };
var url = spaRouteService.GenerateUrl("person-edit", parms);
// "/person/5/edit?tab=a%20b"

GetCurrentRoute decodes the values again, so a value containing /, &, ?, % or a space survives a generate/parse round-trip unchanged. Do not encode values yourself before passing them in, or they will be encoded twice.

Route paths are matched literally apart from {placeholders} - a route path is not a regular expression, so a . matches only a dot.

License

This project is licensed under the Apache 2.0 License.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
10.8.0-preview1 93 9/5/2026
10.7.1 94 9/5/2026
10.7.0 86 9/3/2026
10.5.0 126 8/27/2026
10.4.0 960 2/27/2026
10.3.0 150 2/1/2026
10.2.1 151 1/19/2026
10.2.0 142 1/18/2026
10.1.0 147 1/16/2026
10.0.2 143 1/12/2026
10.0.1 263 12/20/2025
10.0.0 848 11/13/2025
10.0.0-rc.6 359 11/11/2025
10.0.0-rc.5 268 11/11/2025
10.0.0-rc.4 194 11/5/2025
10.0.0-rc.3 198 11/5/2025
10.0.0-rc.2 190 11/5/2025
10.0.0-rc.1 194 10/2/2025
9.1.0 1,676 11/22/2024
9.0.0 1,374 11/13/2024
Loading failed

v 10.5.0
BREAKING CHANGES
- GenerateUrl now percent-encodes parameter values, and GetCurrentRoute now decodes them.
A generate/parse round-trip is lossless for values containing '/', '&', '?', '%' or a space.
If you were encoding values yourself before calling GenerateUrl, stop - you will now get
double-encoded output. Likewise stop decoding SpaRoute.Parameters yourself.
A '+' is NOT read as a space when decoding: a space is written as %20, so the round-trip is
symmetric without it, and doing so would corrupt a value that legitimately contains a '+'.
- Route paths are now regex-escaped. Only {placeholders} are patterns; literal text is matched
literally, so a route "a.b" no longer also matches "/axb". Route paths were never documented
as regular expressions, but a route relying on that will now return 404 instead of matching.
- Redirect now sends 301 (Moved Permanently) instead of 302. It set 301 and then let
Response.Redirect overwrite it with 302, so the permanent redirect the API always implied was
never actually sent. Browsers and CDNs cache permanent redirects.
FIXES
- The empty (root) route now parses its query string. Previously "/?a=b" lost its query while
every other route kept it.
- A repeated query key is now last-one-wins instead of throwing ArgumentException. Repeated keys
are legal in a URL.
- The query is now split at the first '?' (RFC 3986 3.4) rather than the last, so a later '?' stays
in the query instead of being captured into a route parameter.
- A null parameter value now encodes to an empty string instead of throwing NullReferenceException.
v 3.1.0
- Moved the route builder to the SpaPrerenderingService