Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core Razor Page multiple path routing

I'm building a system using ASP.NET Core 2.0 Razor Pages (not MVC) and I'm having trouble adding multiple routes for pages. For example, all pages should be able to be reached by abc.com/language/segment/shop/mypage or abc.com/language/shop/mypage, where both paths point to the same page. The segment path section is optional, then the pages do stuff with the optional segment info.

The question mark syntax in the CombineTemplates markup doesn't seem to work, it seems to only work in the last section of the path. Browsing to a url without a value in the {segment?} section resulted in 404. For example:

AttributeRouteModel.CombineTemplates("{language}/{segment?}/shop", selector.AttributeRouteModel.Template);

I tried code like this below but it only appends the two paths to each other, and I need to be able to enable them both as valid.

options.Conventions.Add(new DefaultPageRouteModelConvention());
options.Conventions.Add(new SegmentPageRouteModelConvention());

In ASP.NET MVC, I could just add two different routes pointing to the same area/controller/action with two different named MapRouteWithName. Any ideas how to do this with .NET Razor Page syntax?

like image 985
Robert Corvus Avatar asked Feb 09 '18 17:02

Robert Corvus


People also ask

How do I navigate from one razor to another page?

you can do it in the client side, in javascript. Also create an anchor a set the asp-controller and asp-action and there you redirect. Or create an anchor a and hard code the path.

What is UseEndpoints in ASP.NET Core?

UseEndpoints adds endpoint execution to the middleware pipeline. It runs the delegate associated with the selected endpoint.

Can you mix razor pages and MVC?

You can add support for Pages to any ASP.NET Core MVC app by simply adding a Pages folder and adding Razor Pages files to this folder. Razor Pages use the folder structure as a convention for routing requests.


1 Answers

This code works:

Add a single convention (not two different conventions):

options.Conventions.Add(new CombinedPageRouteModelConvention());

In the new convention, add both route selectors:

private class CombinedPageRouteModelConvention : IPageRouteModelConvention
    {
        private const string BaseUrlTemplateWithoutSegment = "{language}/shop";
        private const string BaseUrlTemplateWithSegment = "{language}/{segment}/shop";
        public void Apply(PageRouteModel model)
        {
            var allSelectors = new List<SelectorModel>();
            foreach (var selector in model.Selectors)
            {
                //setup the route with segment
                allSelectors.Add(CreateSelector(selector, BaseUrlTemplateWithSegment));

                //setup the route without segment
                allSelectors.Add(CreateSelector(selector, BaseUrlTemplateWithoutSegment));
            }

            //replace the default selectors with new selectors
            model.Selectors.Clear();
            foreach (var selector in allSelectors)
            {
                model.Selectors.Add(selector);
            }
        }

        private static SelectorModel CreateSelector(SelectorModel defaultSelector, string template)
        {
            var fullTemplate = AttributeRouteModel.CombineTemplates(template, defaultSelector.AttributeRouteModel.Template);
            var newSelector = new SelectorModel(defaultSelector)
            {
                AttributeRouteModel =
                {
                    Template = fullTemplate
                }
            };
            return newSelector;
        }
    }
like image 135
Robert Corvus Avatar answered Sep 25 '22 21:09

Robert Corvus