{"id":25312769,"url":"https://github.com/lofcz/blazingrouter","last_synced_at":"2026-02-14T01:39:01.331Z","repository":{"id":274339519,"uuid":"922612321","full_name":"lofcz/BlazingRouter","owner":"lofcz","description":"Strongly-typed Router for Blazor / .NET Core, source-generated, AOT ready.","archived":false,"fork":false,"pushed_at":"2025-01-31T16:54:10.000Z","size":836,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-01T19:52:43.525Z","etag":null,"topics":["blazor","csharp","net-core","routing","source-gene"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lofcz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-26T17:07:53.000Z","updated_at":"2025-02-01T07:54:21.000Z","dependencies_parsed_at":"2025-01-28T11:38:11.324Z","dependency_job_id":"7d4ed576-3968-469f-a445-65c1733e3aa5","html_url":"https://github.com/lofcz/BlazingRouter","commit_stats":null,"previous_names":["lofcz/radixrouter","lofcz/blazingrouter"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/lofcz/BlazingRouter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lofcz%2FBlazingRouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lofcz%2FBlazingRouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lofcz%2FBlazingRouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lofcz%2FBlazingRouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lofcz","download_url":"https://codeload.github.com/lofcz/BlazingRouter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lofcz%2FBlazingRouter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273961555,"owners_count":25198597,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-06T02:00:13.247Z","response_time":2576,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blazor","csharp","net-core","routing","source-gene"],"created_at":"2025-02-13T15:21:18.469Z","updated_at":"2026-02-14T01:39:01.304Z","avatar_url":"https://github.com/lofcz.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![BlazingRouter](https://badgen.net/nuget/v/BlazingRouter?v=302\u0026icon=nuget\u0026label=BlazingRouter)](https://www.nuget.org/packages/BlazingRouter)\n[![BlazingRouter.CodeFix](https://badgen.net/nuget/v/BlazingRouter.CodeFix?v=302\u0026icon=nuget\u0026label=BlazingRouter.CodeFix)](https://www.nuget.org/packages/BlazingRouter.CodeFix)\n\n# BlazingRouter\n\n\u003cimg align=\"left\" width=\"128\" height=\"128\" alt=\"Te Reo Icon\" src=\"https://github.com/user-attachments/assets/2e8033f1-ad2c-4756-8224-078bd39b0afb\" /\u003e\nStrongly typed router, focused on performance and covering even the most complex routing needs. Recall the default router in .NET: \u003ccode\u003e[Authorize(Roles = \"admin,developer\")]\u003c/code\u003e. Was it really \u003ccode\u003eadmin\u003c/code\u003e? Maybe \u003ccode\u003eadministrator\u003c/code\u003e? Maybe you've introduced a constant somewhere, like \u003ccode\u003estatic class Roles { public const string Admin = \"admin\"; }\u003c/code\u003e. Is there something enforcing usage of it? Maybe you've derived your own attribute \u003ccode\u003e[AuthorizeRole(Roles role)]\u003c/code\u003e. BlazingRouter offers another approach - \u003cem\u003editch the string-based underlying structure entirely!\u003c/em\u003e\n\n\u003cbr/\u003e\u003cbr/\u003e\n\n## Getting Started\n\n1. Install the library and analyzers / code-fix providers from NuGet:\n\n```\ndotnet add package BlazingRouter\ndotnet add package BlazingRouter.CodeFix\n```\n\n2. Add a new file `Roles.cs` (name doesn't matter). Define your roles enum inside and decorate it with `[AuthRoleEnum]`:\n\n```cs\nnamespace YourProject;\n\n[AuthRoleEnum] \npublic enum MyRoles\n{\n    User,\n    Admin,\n    Developer\n}\n```\n\n3. Add the router to the services (in default Blazor template `Program.cs`):\n\n```cs\nbuilder.Services.AddBlazingRouter()\n  .Configure(ctx =\u003e\n  {\n\n  })\n  .Build();\n```\n\n4. Replace `\u003cRouter\u003e` with `\u003cRouterExt\u003e`:\n```html\n\u003cRouterExt AppAssembly=\"@typeof(App).Assembly\"\u003e\n  \u003cFound Context=\"routeData\"\u003e\n      \u003cAuthorizeRouteView RouteData=\"@routeData\" DefaultLayout=\"@typeof(MainLayout)\"\u003e\n          \u003cNotAuthorized\u003e\u003c/NotAuthorized\u003e\n          \u003cAuthorizing\u003e\u003c/Authorizing\u003e\n      \u003c/AuthorizeRouteView\u003e\n  \u003c/Found\u003e\n  \u003cNotFound\u003e\u003c/NotFound\u003e\n\u003c/RouterExt\u003e\n```\n\n5. Add folder `Pages` and place your `.razor` views in, using MVC conventions (`Controller`/`Action`). For example:\n```\n|- Program.cs\n|- Pages\n   |- Home\n      |- Index.razor\n      |- About.razor\n```\n\n_There's no need to add `@page \"\"` directives in the `.razor` files, the routing will work automatically. However, `@page` can still be used to define extra routes._\n\n6. Make sure routing is set up so that `\u003cRouterExt\u003e` can act on any request. One way is to use `_Host.cshtml` fallback:\n```cs\nWebApplication app = builder.Build();\n\napp.UseHttpsRedirection();\napp.UseStaticFiles();\n\napp.UseRouting();\napp.UseAuthentication();\napp.UseAuthorization();\napp.UseMvcWithDefaultRoute();\n\napp.UseEndpoints(x =\u003e\n{\n    x.MapBlazorHub();\n    x.MapFallbackToPage(\"/_Host\");\n});\n\napp.Run();\n```\n\n_From `Host.cshtml` we load `App` component which loads `\u003cRouterExt\u003e` in the demo setup._\n\n## Reaping The Benefits\n\nNow that the basic setup is in place, we get to sew the rewards of our work.\n\n1. MVC routing works out of the box. Navigate to:\n```cs\n/           // resolves to /Home/Index\n/Home       // this too\n/Home/Index // this one as well\n/Home/About // gets us to /Home/About.razor\n```\n\n2. Actions or whole controllers can be protected with `[AuthrorizeExt]`:\n```razor\n@* About.razor *@\n@attribute [AuthorizeExt(Roles.Admin)]\n```\n\n3. To grant access to the _at least one of roles_ pattern, we can introduce another enum in `Roles.cs`:\n```cs\n[AuthRolePrefabsEnum]\npublic enum MyRolePrefabs\n{\n  /// \u003cinheritdoc cref=\"MyRolePrefabsDocs.UserOrHigher\"/\u003e \u003c-- ✨ magic documentation rendering roles to which the prefab is resolved!\n  [RolePrefab([MyRoles.User], [AdminOrHigher])]\n  UserOrHigher, // grant access to \"user\" or any role granted access by \"AdminOrHigher\" prefab\n\n  /// \u003cinheritdoc cref=\"MyRolePrefabsDocs.AdminOrHigher\"/\u003e\n  [RolePrefab(MyRoles.Admin, MyRoles.Developer)]\n  AdminOrHigher // grant access to \"admin\" or \"developer\"\n}\n```\n\n4. Now we can use prefabs in `[AuthorizeExt]`:\n```razor\n@* About.razor *@\n@attribute [AuthorizeExt(MyRolePrefabs.AdminOrHigher)]\n```\n\n5. With the implementation as above, all checks for roles silently fail and users are denied access. To fix this, we need to extend our configuration:\n```cs\nbuilder.Services.AddBlazingRouter()\n  .Configure(ctx =\u003e\n  {\n     ctx.HasRole = (principal, role) =\u003e\n     {\n         // use ClaimsPrincipal to check for the role, \"role\" is strongly typed as \"MyRoles\"!\n         return false;   \n     }\n  })\n  .Build();\n```\n\n6. The configuration can be further extended to implement:\n```cs\nctx.OnSetupAllowedUnauthorizedRoles = () =\u003e {} // which resources are available to unauthenticated users (by default none!)\nctx.OnRedirectUnauthorized = (user, route) =\u003e {} // where do we redirect the user if the resource requested is inaccessible\nctx.OnPageScanned = (type) =\u003e {} // enables associating extra routes with Pages, apart from the one picked by conventions. Great for route localization!\nctx.OnTypeDiscovered = (type) =\u003e {} // by default, only certain types are considered as Pages. Using this callback, extra types may be promoted to Pages\n```\n\n7. We can add routes at runtime:\n```cs\nRouteManager.AddRoute(\"/blog/{year:int}/{month:int}/{slug}\", typeof(MyPage)); \n```\n\n_Route syntax supports most of the features implemented by the default router, see the [docs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing) for syntax._\n\n## Benchmark\n\nThe library was measured to perform `\u003e 200 000 op/s` with `1 000` registered non-trivial routes on a `i7 8th gen` CPU. See the [benchmark](https://github.com/lofcz/BlazingRouter/tree/master/BlazingRouter/BlazingRouter.Benchmark).\n\n## License\n\nThis library is licensed under the [MIT](https://github.com/lofcz/BlazingRouter/blob/master/LICENSE) license. 💜\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flofcz%2Fblazingrouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flofcz%2Fblazingrouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flofcz%2Fblazingrouter/lists"}