4

I have a simple page where users can search for records based on start and end date, and the Reference and Client fields are optional

on the details page I have this

@page "{datestart}/{dateend}/{referenceId?}/{client?}"

on the search page I have this post handler

    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            var options = new MemoryCacheEntryOptions() { AbsoluteExpiration = DateTime.Now.AddMinutes(10) };
            ViewData["ReferenceId"] = new SelectList(_context.Referencias.AsNoTracking().FromCache(), "Id", "Name");

            return Page();
        }

        return RedirectToPage("Details", new
        {
            datestart= SearchViewModel.DateStart.ToString("dd-MM-yyyy"),
            dateend = SearchViewModel.DateEnd.ToString("dd-MM-yyyy"),
            referenceId = SearchViewModel.ReferenceId,
            client = SearchViewModel.Client
        });
    }

However everything works well except when the Reference field is null

on my details page

  public void OnGet(string datestart, string dateend, int? referenceId, int? client)

The intended result was that i would be able to go to details page if i don't supply a referenceId event if i did supply a client.

The dates are always required though.

So is there a way that i can still route even if referenceId is not supplied but client is?

All i get is this exception

InvalidOperationException: No page named 'Details' matches the supplied values. Microsoft.AspNetCore.Mvc.Infrastructure.RedirectToPageResultExecutor.ExecuteAsync(ActionContext context, RedirectToPageResult result) Microsoft.AspNetCore.Mvc.RedirectToPageResult.ExecuteResultAsync(ActionContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) NToastNotify.NtoastNotifyAjaxToastsMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass5_1+<b__1>d.MoveNext() Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Also I tried switch the order of {referenceId?} and {client?} and it worked but then it fails if i do the same for referenceId.

UPDATE

As per @Nick suggestion I tried once again with multiple routes and it except for the 2nd route, it won't route if it's the only one.

options.Conventions.AddAreaPageRoute("Production","/BackOffice/Account/Records/Details", "{datestart}/{dateend}/{client?}");
             options.Conventions.AddAreaPageRoute("Production", "/BackOffice/Account/Records/Details", "{datestart}/{dateend}/{referenceId?}");
             options.Conventions.AddAreaPageRoute("Production", "/BackOffice/Account/Records/Details", "{datestart}/{dateend}/{client?}/{referenceId?}");
7
  • 1
    i don't think so, you might need to introduce overloads Commented Aug 16, 2019 at 13:45
  • How could i achieve this? Commented Aug 16, 2019 at 13:47
  • you can create a pagemodel with those 4 parameters as properties see below : learnrazorpages.com/razor-pages/routing Commented Aug 16, 2019 at 13:50
  • Probably the best solution is to use query string values instead of route parameters. Otherwise you won't be able to disambiguate between the referenceid and clientid when one is missing. Commented Aug 16, 2019 at 15:35
  • 1
    Or you can make referenceid required and pass in 0 when there isn't one... Commented Aug 16, 2019 at 15:37

2 Answers 2

5

If you need to be able to cater for either a referenceid or a clientid, or both, you can either make the first parameter required and pass in 0, or you can use a query string. Otherwise there is no way for routing to know if the 42 on the end of /details/2019-8-15/2019-8-16/42 is a clientid or a referenceid value.

As you have discovered, as far as routing is concerned

"{datestart}/{dateend}/{client?}"

is the same as

"{datestart}/{dateend}/{referenceid?}"

and will generate an AmbiguousActionException.

If you want to make the first parameter required, the way to do that is as follows:

@page "{datestart}/{dateend}/{referenceid:int=0}/{client?}"

Any link internally generated by the tag helper will automatically populate the referenceid segment with 0 unless another value is supplied.

Sign up to request clarification or add additional context in comments.

Comments

1

Might be an odd way but you can add an addtional root by using the AddPageRoute method.

    services.AddMvc().AddRazorPagesOptions(options =>
    {
       options.Conventions.AddPageRoute("/details", "{datestart}/{dateend}/{client?}");
    });

8 Comments

This will match a route where the optional referenceid is provided but the optional clientid is not.
If you keep the current root in the razor page this should work fine.
You could try to use the AddAreaPageRoute method. learn.microsoft.com/en-us/dotnet/api/…
Did you kept the routing value in your razor page and added one using the AddPageRoute method addtionally? Because that worked fine for me.
If a referenceid is provided, but no clientid is provided, your additional route will be matched, but the referencid will be bound to the clientid parameter.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.