diff --git a/README.md b/README.md index 702a583..ad4aa87 100755 --- a/README.md +++ b/README.md @@ -14,8 +14,9 @@ Safe Routing is a [source generator](https://docs.microsoft.com/en-us/dotnet/csh - [Extension Methods](#extension-methods) - [Getting Started](#getting-started) - [Binding Source Attributes](#binding-source-attributes) - - [Helper Attributes](#helper-attributes) + - [Bundled Attributes](#bundled-attributes) - [Areas](#areas) + - [Controller Methods with the Same Name](#controller-methods-with-the-same-name) - [Using Razor Class Libraries](#using-razor-class-libraries) - [Configuration](#configuration) - [Available Configuration Options](#available-configuration-options) @@ -29,12 +30,12 @@ Safe Routing is a [source generator](https://docs.microsoft.com/en-us/dotnet/csh Consider the following contrived example of a controller class. ```csharp -public class ProductsController : Controller +public class ProductController : Controller { [FromRoute] public int? Limit { get; set; } - [Route("/Products/Search/{name}/{Limit?}")] + [Route("/Product/Search/{name}/{Limit?}")] public IActionResult Search(string name) { // ... @@ -42,16 +43,18 @@ public class ProductsController : Controller } ``` -Ordinarily, you would need to write something like the following to redirect to the `Search` action from another controller or page: +Redirecting to the `Search` action could be rewritten as follows: + +**BEFORE:** ```csharp -return RedirectToAction("Search", "Products", new { Name = "chair" }); +return RedirectToAction("Search", "Product", new { Name = "chair" }); ``` -Instead, by using the generated code, that can be simplified to the following: +**AFTER:** ```csharp -return Routes.Controllers.Products.Search("chair").Redirect(this); +return Routes.Controllers.Product.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. @@ -71,7 +74,7 @@ public sealed class EditModel : PageModel The generated code enables you to access the URL for the `OnGetAsync` handler with the following code: ```csharp -string myUrl = Routes.Pages.Edit.Get().Url(Url); +string editUrl = Routes.Pages.Edit.Get().Url(Url); ``` ## Installation @@ -90,7 +93,7 @@ This enables `for-route` attributes to be added to ``, ``, and `
` ```html @{ - var controllerRoute = Routes.Controllers.Products.Search("chair"); + var controllerRoute = Routes.Controllers.Product.Search("chair"); var pageRoute = Routes.Pages.Edit.Post(); } @@ -106,38 +109,40 @@ This enables `for-route` attributes to be added to ``, ``, and `` ### 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. +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. + +For projects using C# 8 or 9, add `using SafeRouting.Extensions;` to your source code to access the extension methods `Redirect()` and `Url()`. Projects using C# 10 or above will automatically have access to these extension methods via a generated `global using static` directive. ## Getting Started -The following code snippet demonstrates accessing, modifying, and retrieving generated route information for the `ProductsController` class defined above. +The following code snippet demonstrates accessing, modifying, and retrieving generated route information for the `ProductController` class defined above. ```csharp -// Enable the .Redirect() and .Url() extension methods +// 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"); +// Get route information for the Search method on ProductController with a name value of "chair" +// Route: /Product/Search/chair +var route = Routes.Controllers.Product.Search("chair"); // Assign a value for the Limit property (defined on the controller class) -// Route: /Products/Search/chair/5 +// Route: /Product/Search/chair/5 route[route.Properties.Limit] = 5; // Set the value of a parameter -// Route: /Products/Search/book/5 +// Route: /Product/Search/book/5 route[route.Parameters.Name] = "book"; // Set a value using the Set method -// Route: /Products/Search/book/10 +// Route: /Product/Search/book/10 route.Set(route.Properties.Limit, 10); // Remove a route value -// Route: /Products/Search/book +// Route: /Product/Search/book route.Remove(route.Properties.Limit); // Access the URL for the route using an IUrlHelper -// Value: "/Products/Search/book" +// Value: "/Product/Search/book" string routeUrl = route.Url(Url); // Redirect from within a controller action method or a page handler method @@ -171,14 +176,49 @@ public static IndexRouteInfo Index(string standard, string fromQuery, string fro } ``` -### Helper Attributes +### Bundled 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. +A couple of included attributes 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). +### Controller Methods with the Same Name + +There are a couple of situations to be mindful of involving controllers with multiple methods of the same name. Firstly, consider the following controller: + +```csharp +public class ProductController : Controller +{ + public IActionResult Edit(int productId) + { + // ... + } + + [HttpPost] + public IActionResult Edit(int productId, [FromForm] string name) + { + // ... + } +} +``` + +Because of the way that the generated methods only include parameters which can be bound via the URL, the the above methods would both result in generated methods with the same signature. Because of this, the above code results in a compile error. To work around this, you could either rename one of the methods, or apply the `[RouteGeneratorName]` attribute to one of the methods to rename the generated method into something unique. + +The other situation to be aware of is when you have multiple overloads with different resulting signatures, the generated route values classes returned by the generated methods will be named with sequential numbers to ensure uniqueness. For example, if the above class was written without the `[FromForm]` attribute, the generated methods would be written with the following signatures: + +```csharp +Support.Controllers_Product.EditRouteValues Edit(int productId); +Support.Controllers_Product.Edit2RouteValues Edit(int productId, string name); +``` + +It is recommended that you don't directly reference the names of the classes returned by those methods, and instead use the `var` keyword if you need to capture the result into a variable. I.e.; + +```csharp +var route = Routes.Controllers.Product.Edit(1, "Blanket"); +``` + ### 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). diff --git a/src/Demo/SafeRouting.Demo.Library/Areas/MyFeature/Pages/Page1.cshtml b/src/Demo/SafeRouting.Demo.Library/Areas/MyFeature/Pages/Page1.cshtml index 144defb..5ba8a00 100644 --- a/src/Demo/SafeRouting.Demo.Library/Areas/MyFeature/Pages/Page1.cshtml +++ b/src/Demo/SafeRouting.Demo.Library/Areas/MyFeature/Pages/Page1.cshtml @@ -6,9 +6,9 @@ - Library Page1 + SafeRouting.Demo.Library Page1 -

Library Page1

+

SafeRouting.Demo.Library Page1

diff --git a/src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/SettingsController.cs b/src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/PostController.cs similarity index 74% rename from src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/SettingsController.cs rename to src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/PostController.cs index e5e8f6c..0f8e42e 100644 --- a/src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/SettingsController.cs +++ b/src/Demo/SafeRouting.Demo/Areas/Blog/Controllers/PostController.cs @@ -3,7 +3,7 @@ namespace SafeRouting.Demo.Areas.Blog.Controllers; [Area("Blog")] -public sealed class SettingsController : Controller +public sealed class PostController : Controller { public IActionResult Index() => View(); } diff --git a/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Accounts/BlogAccount.cshtml b/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Account/BlogAccount.cshtml similarity index 100% rename from src/Demo/SafeRouting.Demo/Areas/Blog/Views/Accounts/BlogAccount.cshtml rename to src/Demo/SafeRouting.Demo/Areas/Blog/Views/Account/BlogAccount.cshtml diff --git a/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Post/Index.cshtml b/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Post/Index.cshtml new file mode 100644 index 0000000..3d037bd --- /dev/null +++ b/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Post/Index.cshtml @@ -0,0 +1,5 @@ +@{ + ViewData["Title"] = "Blog Area Post Index"; +} + +

Blog Area Post Index

diff --git a/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Settings/Index.cshtml b/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Settings/Index.cshtml deleted file mode 100644 index d594430..0000000 --- a/src/Demo/SafeRouting.Demo/Areas/Blog/Views/Settings/Index.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - ViewData["Title"] = "Blog Area Settings Index"; -} - -

Blog Area Settings Index

\ No newline at end of file diff --git a/src/Demo/SafeRouting.Demo/Controllers/AccountsController.cs b/src/Demo/SafeRouting.Demo/Controllers/AccountController.cs similarity index 77% rename from src/Demo/SafeRouting.Demo/Controllers/AccountsController.cs rename to src/Demo/SafeRouting.Demo/Controllers/AccountController.cs index 3551d0b..138784d 100644 --- a/src/Demo/SafeRouting.Demo/Controllers/AccountsController.cs +++ b/src/Demo/SafeRouting.Demo/Controllers/AccountController.cs @@ -2,14 +2,14 @@ namespace SafeRouting.Demo.Controllers; -public sealed class AccountsController : Controller +public sealed class AccountController : Controller { public IActionResult Index() => View(); - public IActionResult RedirectToController() => Routes.Areas.Blog.Controllers.Settings.Index().Redirect(this); + public IActionResult RedirectToController() => Routes.Areas.Blog.Controllers.Post.Index().Redirect(this); public IActionResult RedirectToPage() => Routes.Areas.Blog.Pages.Index.Get().Redirect(this); [Area("Blog")] public IActionResult BlogAccount() => View(); -} \ No newline at end of file +} diff --git a/src/Demo/SafeRouting.Demo/Pages/Product.cshtml.cs b/src/Demo/SafeRouting.Demo/Pages/Product.cshtml.cs index a33c0a9..70c0cb8 100644 --- a/src/Demo/SafeRouting.Demo/Pages/Product.cshtml.cs +++ b/src/Demo/SafeRouting.Demo/Pages/Product.cshtml.cs @@ -7,7 +7,7 @@ public sealed class ProductModel : PageModel { public void OnGet() { } - public IActionResult OnGetRedirectToController() => Routes.Controllers.Accounts.Index().Redirect(this); + public IActionResult OnGetRedirectToController() => Routes.Controllers.Account.Index().Redirect(this); public IActionResult OnGetRedirectToPage() => Routes.Pages.Index.Get().Redirect(this); } diff --git a/src/Demo/SafeRouting.Demo/Pages/Shared/_Layout.cshtml b/src/Demo/SafeRouting.Demo/Pages/Shared/_Layout.cshtml index 36d40ae..25e264d 100644 --- a/src/Demo/SafeRouting.Demo/Pages/Shared/_Layout.cshtml +++ b/src/Demo/SafeRouting.Demo/Pages/Shared/_Layout.cshtml @@ -2,12 +2,12 @@ @{ var indexRoute = Routes.Pages.Index.Get(); var productRoute = Routes.Pages.Product.Get(); - var accountRoute = Routes.Controllers.Accounts.Index(); + var accountRoute = Routes.Controllers.Account.Index(); var blogRoute = Routes.Areas.Blog.Pages.Index.Get(); - var blogSettingsRoute = Routes.Areas.Blog.Controllers.Settings.Index(); - var blogAccountRoute = Routes.Controllers.Accounts.BlogAccount(); - var redirectControllerToControllerRoute = Routes.Controllers.Accounts.RedirectToController(); - var redirectControllerToPageRoute = Routes.Controllers.Accounts.RedirectToPage(); + var blogPostRoute = Routes.Areas.Blog.Controllers.Post.Index(); + var blogAccountRoute = Routes.Controllers.Account.BlogAccount(); + var redirectControllerToControllerRoute = Routes.Controllers.Account.RedirectToController(); + var redirectControllerToPageRoute = Routes.Controllers.Account.RedirectToPage(); var redirectPageToControllerRoute = Routes.Pages.Product.GetRedirectToController(); var redirectPageToPageRoute = Routes.Pages.Product.GetRedirectToPage(); var libraryRoute = Routes.Areas.MyFeature.Pages.Page1.Get(); @@ -25,15 +25,15 @@
@@ -41,4 +41,4 @@ @RenderBody() - \ No newline at end of file + diff --git a/src/Demo/SafeRouting.Demo/Views/Account/Index.cshtml b/src/Demo/SafeRouting.Demo/Views/Account/Index.cshtml new file mode 100644 index 0000000..9e85f53 --- /dev/null +++ b/src/Demo/SafeRouting.Demo/Views/Account/Index.cshtml @@ -0,0 +1,5 @@ +@{ + ViewData["Title"] = "AccountController Index"; +} + +

AccountController Index

diff --git a/src/Demo/SafeRouting.Demo/Views/Accounts/Index.cshtml b/src/Demo/SafeRouting.Demo/Views/Accounts/Index.cshtml deleted file mode 100644 index 6f7188a..0000000 --- a/src/Demo/SafeRouting.Demo/Views/Accounts/Index.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - ViewData["Title"] = "AccountsController Index"; -} - -

AccountsController Index

\ No newline at end of file diff --git a/src/README.source.md b/src/README.source.md index fa1a45a..0de4a30 100644 --- a/src/README.source.md +++ b/src/README.source.md @@ -10,12 +10,12 @@ Safe Routing is a [source generator](https://docs.microsoft.com/en-us/dotnet/csh Consider the following contrived example of a controller class. ```csharp -public class ProductsController : Controller +public class ProductController : Controller { [FromRoute] public int? Limit { get; set; } - [Route("/Products/Search/{name}/{Limit?}")] + [Route("/Product/Search/{name}/{Limit?}")] public IActionResult Search(string name) { // ... @@ -23,16 +23,18 @@ public class ProductsController : Controller } ``` -Ordinarily, you would need to write something like the following to redirect to the `Search` action from another controller or page: +Redirecting to the `Search` action could be rewritten as follows: + +**BEFORE:** ```csharp -return RedirectToAction("Search", "Products", new { Name = "chair" }); +return RedirectToAction("Search", "Product", new { Name = "chair" }); ``` -Instead, by using the generated code, that can be simplified to the following: +**AFTER:** ```csharp -return Routes.Controllers.Products.Search("chair").Redirect(this); +return Routes.Controllers.Product.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. @@ -52,7 +54,7 @@ public sealed class EditModel : PageModel The generated code enables you to access the URL for the `OnGetAsync` handler with the following code: ```csharp -string myUrl = Routes.Pages.Edit.Get().Url(Url); +string editUrl = Routes.Pages.Edit.Get().Url(Url); ``` ## Installation @@ -71,7 +73,7 @@ This enables `for-route` attributes to be added to ``, ``, and `` ```html @{ - var controllerRoute = Routes.Controllers.Products.Search("chair"); + var controllerRoute = Routes.Controllers.Product.Search("chair"); var pageRoute = Routes.Pages.Edit.Post(); } @@ -87,38 +89,40 @@ This enables `for-route` attributes to be added to ``, ``, and `` ### 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. +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. + +For projects using C# 8 or 9, add `using SafeRouting.Extensions;` to your source code to access the extension methods `Redirect()` and `Url()`. Projects using C# 10 or above will automatically have access to these extension methods via a generated `global using static` directive. ## Getting Started -The following code snippet demonstrates accessing, modifying, and retrieving generated route information for the `ProductsController` class defined above. +The following code snippet demonstrates accessing, modifying, and retrieving generated route information for the `ProductController` class defined above. ```csharp -// Enable the .Redirect() and .Url() extension methods +// 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"); +// Get route information for the Search method on ProductController with a name value of "chair" +// Route: /Product/Search/chair +var route = Routes.Controllers.Product.Search("chair"); // Assign a value for the Limit property (defined on the controller class) -// Route: /Products/Search/chair/5 +// Route: /Product/Search/chair/5 route[route.Properties.Limit] = 5; // Set the value of a parameter -// Route: /Products/Search/book/5 +// Route: /Product/Search/book/5 route[route.Parameters.Name] = "book"; // Set a value using the Set method -// Route: /Products/Search/book/10 +// Route: /Product/Search/book/10 route.Set(route.Properties.Limit, 10); // Remove a route value -// Route: /Products/Search/book +// Route: /Product/Search/book route.Remove(route.Properties.Limit); // Access the URL for the route using an IUrlHelper -// Value: "/Products/Search/book" +// Value: "/Product/Search/book" string routeUrl = route.Url(Url); // Redirect from within a controller action method or a page handler method @@ -152,14 +156,49 @@ public static IndexRouteInfo Index(string standard, string fromQuery, string fro } ``` -### Helper Attributes +### Bundled 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. +A couple of included attributes 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). +### Controller Methods with the Same Name + +There are a couple of situations to be mindful of involving controllers with multiple methods of the same name. Firstly, consider the following controller: + +```csharp +public class ProductController : Controller +{ + public IActionResult Edit(int productId) + { + // ... + } + + [HttpPost] + public IActionResult Edit(int productId, [FromForm] string name) + { + // ... + } +} +``` + +Because of the way that the generated methods only include parameters which can be bound via the URL, the the above methods would both result in generated methods with the same signature. Because of this, the above code results in a compile error. To work around this, you could either rename one of the methods, or apply the `[RouteGeneratorName]` attribute to one of the methods to rename the generated method into something unique. + +The other situation to be aware of is when you have multiple overloads with different resulting signatures, the generated route values classes returned by the generated methods will be named with sequential numbers to ensure uniqueness. For example, if the above class was written without the `[FromForm]` attribute, the generated methods would be written with the following signatures: + +```csharp +Support.Controllers_Product.EditRouteValues Edit(int productId); +Support.Controllers_Product.Edit2RouteValues Edit(int productId, string name); +``` + +It is recommended that you don't directly reference the names of the classes returned by those methods, and instead use the `var` keyword if you need to capture the result into a variable. I.e.; + +```csharp +var route = Routes.Controllers.Product.Edit(1, "Blanket"); +``` + ### 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). diff --git a/src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/SettingsController.cs b/src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/PostController.cs similarity index 75% rename from src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/SettingsController.cs rename to src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/PostController.cs index c330a37..678a0b6 100644 --- a/src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/SettingsController.cs +++ b/src/Test/SafeRouting.Tests.Integration/Areas/Blog/Controllers/PostController.cs @@ -3,7 +3,7 @@ namespace SafeRouting.Tests.Integration.Areas.Blog.Controllers; [Area("Blog")] -public sealed class SettingsController : Controller +public sealed class PostController : Controller { public IActionResult Index() => View(); } diff --git a/src/Test/SafeRouting.Tests.Integration/ControllerIntegrationTests.cs b/src/Test/SafeRouting.Tests.Integration/ControllerIntegrationTests.cs index 500b205..6187e2d 100644 --- a/src/Test/SafeRouting.Tests.Integration/ControllerIntegrationTests.cs +++ b/src/Test/SafeRouting.Tests.Integration/ControllerIntegrationTests.cs @@ -7,9 +7,9 @@ public sealed class ControllerIntegrationTests [Fact] public void AccountBlogAccountHasCorrectArea() { - var route = Routes.Controllers.Accounts.BlogAccount(); + var route = Routes.Controllers.Account.BlogAccount(); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("BlogAccount", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -23,10 +23,10 @@ public void AccountBlogAccountHasCorrectArea() [InlineData("foo")] public void AccountIndexRouteAcceptsProperty(string headerValue) { - var route = Routes.Controllers.Accounts.Index(); + var route = Routes.Controllers.Account.Index(); route[route.Properties.CustomHeader] = headerValue; - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("Index", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -42,9 +42,9 @@ public void AccountIndexRouteAcceptsProperty(string headerValue) [Fact] public void AccountIndexRouteHasExpectedValues() { - var route = Routes.Controllers.Accounts.Index(); + var route = Routes.Controllers.Account.Index(); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("Index", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -59,9 +59,9 @@ public void AccountIndexRouteHasExpectedValues() [InlineData(int.MaxValue)] public void AccountListRouteHasExpectedValues(int page) { - var route = Routes.Controllers.Accounts.List(page); + var route = Routes.Controllers.Account.List(page); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("List", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -77,9 +77,9 @@ public void AccountListRouteHasExpectedValues(int page) [Fact] public void AreasAreIncludedInRoute() { - var route = Routes.Areas.Blog.Controllers.Settings.Index(); + var route = Routes.Areas.Blog.Controllers.Post.Index(); - Assert.Equal("Settings", route.ControllerName); + Assert.Equal("Post", route.ControllerName); Assert.Equal("Index", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -92,9 +92,9 @@ public void AreasAreIncludedInRoute() public void ParameterValuesCanBeChanged() { var page = 5; - var route = Routes.Controllers.Accounts.List(page); + var route = Routes.Controllers.Account.List(page); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("List", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -109,7 +109,7 @@ public void ParameterValuesCanBeChanged() page = 10; route[route.Parameters.Page] = page; - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("List", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -126,9 +126,9 @@ public void ParameterValuesCanBeChanged() public void ParameterValuesCanBeRemoved() { var page = 5; - var route = Routes.Controllers.Accounts.List(page); + var route = Routes.Controllers.Account.List(page); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("List", route.ActionName); Assert.Collection(route.RouteValues, x => { @@ -142,7 +142,7 @@ public void ParameterValuesCanBeRemoved() route.Remove(route.Parameters.Page); - Assert.Equal("Accounts", route.ControllerName); + Assert.Equal("Account", route.ControllerName); Assert.Equal("List", route.ActionName); Assert.Collection(route.RouteValues, x => { diff --git a/src/Test/SafeRouting.Tests.Integration/Controllers/AccountsController.cs b/src/Test/SafeRouting.Tests.Integration/Controllers/AccountController.cs similarity index 85% rename from src/Test/SafeRouting.Tests.Integration/Controllers/AccountsController.cs rename to src/Test/SafeRouting.Tests.Integration/Controllers/AccountController.cs index 916eb36..710fcec 100644 --- a/src/Test/SafeRouting.Tests.Integration/Controllers/AccountsController.cs +++ b/src/Test/SafeRouting.Tests.Integration/Controllers/AccountController.cs @@ -2,7 +2,7 @@ namespace SafeRouting.Tests.Integration.Controllers; -public sealed class AccountsController : Controller +public sealed class AccountController : Controller { [FromHeader] public string? CustomHeader { get; set; }