SafeRouting 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package SafeRouting --version 1.0.0                
NuGet\Install-Package SafeRouting -Version 1.0.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="SafeRouting" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SafeRouting --version 1.0.0                
#r "nuget: SafeRouting, 1.0.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 SafeRouting as a Cake Addin
#addin nuget:?package=SafeRouting&version=1.0.0

// Install SafeRouting as a Cake Tool
#tool nuget:?package=SafeRouting&version=1.0.0                

Safe Routing Source Generator for ASP.NET Core

SafeRouting NuGet Package

Safe Routing is a source generator which analyses a project's razor pages and MVC controllers, producing strongly-typed representations of those routes as you type. This enables you to link between pages with compile time safety instead of using the standard "stringly typed" approach.

Usage Example

Consider the following contrived example of a controller class.

public class ProductsController : Controller
{
  [FromRoute]
  public int? Limit { get; set; }

  [Route("/Products/Search/{name}/{Limit?}")]
  public IActionResult Search(string name)
  {
    // ...
  }
}

Ordinarily, you would need to write something like the following to redirect to the Search action from another controller or page:

return RedirectToAction("Search", "Products", new { Name = "chair" });

Instead, by using the generated code, that can be simplified to the following:

return Routes.Controllers.Products.Search("chair").Redirect(this);

The controller name, action name, names of action method parameters, and names of bound properties on the controller are no longer referenced with strings, and are instead referenced with C# classes, methods, parameters, and properties that offer compile time safety.

Similarly, consider the following razor page model class:

public sealed class EditModel : PageModel
{
  public Task OnGetAsync()
  {
    // ...
  }
}

The generated code enables you to access the URL for the OnGetAsync handler with the following code:

string myUrl = Routes.Pages.Edit.Get().Url(Url);

Installation

To install, simply add the SafeRouting package to your ASP.NET Core project.

Tag Helpers

To enable the included tag helpers, add the following line to _ViewImports.cshtml files where required.

@addTagHelper SafeRouting.TagHelpers.*, SafeRouting.Common

This enables for-route attributes to be added to <a>, <img>, and <form> elements, for example:

@{
  var controllerRoute = Routes.Controllers.Products.Search("chair");
  var pageRoute = Routes.Pages.Edit.Post();
}


<a for-route="controllerRoute">Search for chairs</a>


<img for-route="controllerRoute" alt="" />


<form for-route="pageRoute" method="post"></form>

Extension Methods

Add using SafeRouting.Extensions; to your source code to access the extension methods .Redirect() and .Url(). The Redirect extension methods return RedirectToActionResult or RedirectToPageResult values as appropriate for the particular route, and accept the active controller or page model as a parameter. The Url extension methods return a string with a URL for the route, accepting an IUrlHelper instance as a parameter.

Getting Started

The following code snippet demonstrates accessing, modifying, and retrieving generated route information for the ProductsController class defined above.

// Enable the .Redirect() and .Url() extension methods
using SafeRouting.Extensions;

// Get route information for the Search method on ProductsController with a name value of "chair"
// Route: /Products/Search/chair
var route = Routes.Controllers.Products.Search("chair");

// Assign a value for the Limit property (defined on the controller class)
// Route: /Products/Search/chair/5
route[route.Properties.Limit] = 5;

// Set the value of a parameter
// Route: /Products/Search/book/5
route[route.Parameters.Name] = "book";

// Set a value using the Set method
// Route: /Products/Search/book/10
route.Set(route.Properties.Limit, 10);

// Remove a route value
// Route: /Products/Search/book
route.Remove(route.Properties.Limit);

// Access the URL for the route using an IUrlHelper
// Value: "/Products/Search/book"
string routeUrl = route.Url(Url);

// Redirect from within a controller action method or a page handler method
return route.Redirect(this);

Binding Source Attributes

The generated methods will closely resemble your original controller action methods and page handler methods, but will only include parameters which can be bound via the URL. Consider the following action method:

public IActionResult Index(
  string standard,
  [FromBody] string fromBody,
  [FromForm] string fromForm,
  [FromHeader] string fromHeader,
  [FromQuery] string fromQuery,
  [FromRoute] string fromRoute,
  [FromServices] string fromServices)
{
  // ...
}

The generated route helper method omits the parameters with the attributes [FromBody], [FromForm], [FromHeader], and [FromServices] because they are not bound to any part of the URL. The generated helper method instead looks like this:

public static IndexRouteInfo Index(string standard, string fromQuery, string fromRoute)
{
  // ...
}

Helper Attributes

A couple of attributes exist which allow you to customise how the source generator interprets your code. [ExcludeFromRouteGenerator] can be applied to a class, property, method, or parameter to have it be ignored by the analyser. [RouteGeneratorName] allows you to rename any symbol (class, property, method, or parameter) in the generated code, which can help you avoid naming conflicts.

Areas

By default, the generated helper classes for controller and page routes will be added to the namespaces Routes.Controllers and Routes.Pages, respectively. Controllers adorned with the [Area] attribute, and pages within an /Areas/{area-name}/Pages/ directory structure have their helper classes added to Routes.Areas.AreaName.Controllers and Routes.Areas.AreaName.Pages respectively (replacing AreaName with the name of the area).

Using Razor Class Libraries

Route information is only generated for source code within each project which references the SafeRouting package. In order to reference routes within another library, that library must reference SafeRouting and be configured to use the public access modifier for classes (which is the default).

Configuration

This source generator can be configured via a Global AnalyzerConfig file.

Example .globalconfig file:

is_global = true

safe_routing.generated_access_modifier = internal
safe_routing.generated_namespace = Example.Namespace.Routes

Available configuration options

Option Description
safe_routing.generated_access_modifier The access modifier used for all generated classes. Can be public or internal. Defaults to public.
safe_routing.generated_namespace The namespace under which all generated route classes are created. Defaults to Routes.

Limitations

  • The including project must use C# 8 or later.
  • Pages must have a PageModel inheriting class within a .cshtml.cs file in either a Pages or Areas/{area name}/Pages directory at any depth to be discovered.
  • Multiple classes which inherit from PageModel cannot be declared in the same .cshtml.cs file.
  • Custom attributes which affect routing are unsupported and will be ignored by the source generator.
  • Using identifiers which need to be escaped with @ for names of classes, properties, or parameters is unsupported.
  • Nullable annotations on parameter and property types are respected, but attributes affecting nullability are not copied across to the generated code.
  • Generic classes, nested classes, and non-public classes which inherit from PageModel are ignored by the source generator.
  • For .NET 7, it is recommended to either continue using the [FromServices] attribute for parameters which are implicitly injected, or to replace it with [ExcludeFromRouteGenerator]. Otherwise injected parameters will be included in the method signatures of the generated route methods.

Building the NuGet Package

dotnet tool install -g dotnet-script
  • Within the project directory, run the build script with the new build number as an argument, e.g.; 1.2.3.
dotnet script build.csx -- 1.2.3
  • Review the output to ensure that the build succeeded and all tests passed.
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 netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

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.5.0 2,064 12/24/2023
1.4.0 4,144 8/27/2023
1.3.0 179 8/9/2023
1.2.3 233 6/8/2023
1.2.2 202 5/25/2023
1.2.1 462 7/31/2022
1.2.0 468 4/18/2022
1.1.1 463 4/10/2022
1.1.0 413 4/3/2022
1.0.2 457 3/26/2022
1.0.1 411 3/25/2022
1.0.0 438 3/24/2022