MintPlayer.AspNetCore.SpaServices.Routing 1.1.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 1.1.0                
NuGet\Install-Package MintPlayer.AspNetCore.SpaServices.Routing -Version 1.1.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="1.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MintPlayer.AspNetCore.SpaServices.Routing --version 1.1.0                
#r "nuget: MintPlayer.AspNetCore.SpaServices.Routing, 1.1.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.
// Install MintPlayer.AspNetCore.SpaServices.Routing as a Cake Addin
#addin nuget:?package=MintPlayer.AspNetCore.SpaServices.Routing&version=1.1.0

// Install MintPlayer.AspNetCore.SpaServices.Routing as a Cake Tool
#tool nuget:?package=MintPlayer.AspNetCore.SpaServices.Routing&version=1.1.0                

MintPlayer.AspNetCore.SpaServices.Routing

This project facilitates server-side prerendering in ASP.NET Core.

Server-side rendering

If you haven't setup SSR yet, please consult this manual.

Installation

NuGet package manager

Open the NuGet package manager and install MintPlayer.AspNetCore.SpaServices.Routing in your project

Package manager console

Install-Package MintPlayer.AspNetCore.SpaServices.Routing

Usage

Register SPA routes

The ASP.NET Core application needs to be aware of your angular/react SPA routes. Therefor you need to provide these with the SpaRouteBuilder. For example:

public void ConfigureServices(IServiceCollection services)
{
    // Define the SPA-routes for our helper
    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")
        )
    );
}

You can define routing parameters in your paths as well.

Adding SPA prerendering middleware

To enable SPA prerendering you'd normally use the following middleware registration code:

app.UseSpa(spa =>
{
    ...

    spa.UseSpaPrerendering(options =>
    {
        options.BootModulePath = $"{spa.Options.SourcePath}/dist/server/main.js";
        options.BootModuleBuilder = env.IsDevelopment()
            ? new AngularCliBuilder(npmScript: "build:ssr")
            : null;
        options.ExcludeUrls = new[] { "/sockjs-node" };
    });

    ...
});

Supplying data

You probably want to pass data based on which url the visitor opens the first time. With this package you can easily determine which angular component is to be rendered and what data needs to be provided to the angular app.

public void Configure(IApplicationBuilder app, IHostingEnvironment 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":
                        {
                            var people = personRepository.GetPeople();
                            data["people"] = people;
                        }
                        break;
                    case "person-show":
                    case "person-edit":
                        {
                            var id = System.Convert.ToInt32(route.Parameters["id"]);
                            var person = personRepository.GetPerson(id);
                            data["person"] = person;
                        }
                        break;
                }
            };
        });
    }
}

You can't perform dependecy injection here since the SupplyData is a delegate. You can however retrieve an instance from the service-container through context.RequestServices or context.ApplicationServices.

main.server.ts

The data you passed in the SupplyData delegate is made available on the params.data object in the main.server.ts. The refactored code can look like this:

const providers: StaticProvider[] = [
  provideModuleMap(LAZY_MODULE_MAP),
  { provide: APP_BASE_HREF, useValue: params.baseUrl },
  { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
  { provide: 'MESSAGE', useValue: params.data.message }
];

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 })
}

const options = {
  document: params.data.originalHtml,
  url: params.url,
  extraProviders: providers
};

main.ts

Each key you pass in the main.server.ts must also be provided in the main.ts:

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] },
  { provide: 'MESSAGE', useValue: 'Message from the client' },
  { provide: 'PEOPLE', useValue: null },
  { provide: 'PERSON', useValue: null }
];

Use in components

You can then use this value by using dependency injection in your components:

constructor(private personService: PersonService, @Inject('PERSON') private personInj: Person, private route: ActivatedRoute) {
  if (personInj === null) {
    var id = parseInt(this.route.snapshot.paramMap.get("id"));
    this.personService.getPerson(id, true).subscribe(person => {
      this.setPerson(person);
    });
  } else {
    this.setPerson(personInj);
  }
}

Generate SPA routes

If necessary, you can generate an application URL on the server-side through c# code. Examples for this use are when using a redirect from OpenSearch straight to your ShowComponent, or when generating an XML sitemap.

To do so, there are 2 approaches:

Using a dictionary:
var parms = new Dictionary<string, object>();
parms["id"] = 5;
var route = spaRouteService.GenerateUrl("person-edit", parms);
Using an anonymous type:
var parms = new
{
    id = 5
};
var route = spaRouteService.GenerateUrl("person-edit", parms);
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  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 was computed.  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. 
.NET Core netcoreapp3.1 is compatible. 
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
9.0.0 68 11/13/2024
8.3.0 501 6/10/2024
8.2.0 3,952 11/28/2023
8.1.0 118 11/28/2023
8.0.0 114 11/14/2023
8.0.0-rc2 76 11/13/2023
8.0.0-rc1 77 11/6/2023
7.0.3 2,818 8/9/2023
7.0.2 1,927 12/6/2022
7.0.1 359 11/15/2022
7.0.0 375 11/14/2022
7.0.0-preview.1 117 10/30/2022
6.1.7 440 8/9/2023
6.1.6 3,837 12/6/2022
6.1.5 396 11/15/2022
6.1.4 588 10/28/2022
6.1.3 7,028 8/26/2022
6.1.2 435 8/26/2022
6.1.1 2,412 7/5/2022
6.1.0 481 7/5/2022
6.0.6 469 6/23/2022
6.0.5 3,242 12/27/2021
6.0.4 1,699 12/19/2021
6.0.3 346 12/8/2021
6.0.2 335 12/6/2021
6.0.1 312 12/2/2021
6.0.0 986 12/2/2021
3.1.0 363 12/2/2021
1.2.0 346 10/9/2021
1.1.5 2,518 8/20/2020
1.1.4 524 5/10/2020
1.1.3 485 5/10/2020
1.1.2 489 5/8/2020
1.1.1 487 4/29/2020
1.1.0 486 4/29/2020
1.0.5 489 2/20/2020
1.0.4 472 2/20/2020
1.0.3 475 1/17/2020
1.0.2 494 1/14/2020
1.0.1 571 12/9/2019
1.0.0 621 8/27/2019