Skip to content

BeginUmbracoForm does not work correctly with custom routes/UmbracoPageController #14868

Open
@jhenkes

Description

@jhenkes

Which Umbraco version are you using? (Please write the exact version, example: 10.1.0)

11.5.0

Bug summary

When using an UmbracoPageController to submit a form to a surface controller, the surface controller action method is called but "CurrentUmbracoPage" and "RedirectToCurrentUmbracoPage" do not work as expected.

Specifics

No response

Steps to reproduce

This issue is related to #13103. I've reused the testing code and made minor modifications to showcase the issue.

Steps to reproduce:

  • Create a home page documenttype (alias homePage)
  • Create a home page node
  • Add the following code/templates:
Demo.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Common;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Website.Controllers;

namespace ToDelete5
{
    public class DemoComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.Services.Configure<UmbracoPipelineOptions>(options =>
            {
                options.AddFilter(new UmbracoPipelineFilter(nameof(DemoPageController))
                {
                    Endpoints = app => app.UseEndpoints(endpoints =>
                    {
                        endpoints.MapControllerRoute(
                            "DemoPageController",
                            "demo/{action}",
                            new { Controller = "DemoPage", Action = "Index" });

                        endpoints.MapControllerRoute(
                            "TestController",
                            "test/{action}",
                            new { Controller = "Test", Action = "Index" })
                                .ForUmbracoPage((actionExecutingContext) =>
                                {
                                    var umbracoHelper = actionExecutingContext.HttpContext.RequestServices.GetService<UmbracoHelper>();
                                    return umbracoHelper?.ContentAtRoot().First()!;
                                });
                    })
                });
            });
        }
    }

    public class TestController : UmbracoPageController
    {
        public TestController(
                    ILogger<UmbracoPageController> logger,
                    ICompositeViewEngine compositeViewEngine)
                    : base(logger, compositeViewEngine)
        { }

        [HttpGet]
        public IActionResult Index() =>
            View("~/Views/HomePage.cshtml", CurrentPage);

        [HttpGet]
        public IActionResult Subpage() =>
            View("~/Views/HomePage.cshtml", CurrentPage);
    }

    public class DemoPageController : UmbracoPageController, IVirtualPageController
    {
        private readonly UmbracoHelper _umbracoHelper;

        public DemoPageController(
            ILogger<UmbracoPageController> logger,
            ICompositeViewEngine compositeViewEngine,
            UmbracoHelper umbracoHelper) : base(logger, compositeViewEngine) =>
            _umbracoHelper = umbracoHelper;

        public IPublishedContent? FindContent(ActionExecutingContext actionExecutingContext) =>
            _umbracoHelper.ContentAtRoot().First();

        [HttpGet]
        public IActionResult Index() =>
            View("~/Views/HomePage.cshtml", CurrentPage);

        [HttpGet]
        public IActionResult Subpage() =>
            View("~/Views/HomePage.cshtml", CurrentPage);
    }

    public class DemoSurfaceController : SurfaceController
    {
        public DemoSurfaceController(
            IUmbracoContextAccessor umbracoContextAccessor,
            IUmbracoDatabaseFactory databaseFactory,
            ServiceContext services,
            AppCaches appCaches,
            IProfilingLogger profilingLogger,
            IPublishedUrlProvider publishedUrlProvider)
            : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
        { }

        [HttpPost]
        public IActionResult HandleCurrentPage(string name)
        {
            var currentPage = CurrentPage;
            ViewData["name"] = name;
            TempData["name"] = name;
            return CurrentUmbracoPage();
        }

        [HttpPost]
        public IActionResult HandleRedirectToCurrentPage(string name)
        {
            var currentPage = CurrentPage;
            ViewData["name"] = name;
            TempData["name"] = name;
            return RedirectToCurrentUmbracoPage();
        }

        [HttpPost]
        public IActionResult HandleRedirectToCurrentUrl(string name)
        {
            var currentPage = CurrentPage;
            ViewData["name"] = name;
            TempData["name"] = name;
            return RedirectToCurrentUmbracoUrl();
        }
    }
}
HomePage.cshtml
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.HomePage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
    Layout = null;
}

<h1>@ViewContext.RouteData.Values["action"]: @Model.Name</h1>

@using (Html.BeginUmbracoForm<DemoSurfaceController>("HandleCurrentPage"))
{
    @Html.TextBox("name")
    <button type="submit">Handle Current Page</button>
}

@using (Html.BeginUmbracoForm<DemoSurfaceController>("HandleRedirectToCurrentPage"))
{
    @Html.TextBox("name")
    <button type="submit">Handle Redirect To Current Page</button>
}

@using (Html.BeginUmbracoForm<DemoSurfaceController>("HandleRedirectToCurrentUrl"))
{
    @Html.TextBox("name")
    <button type="submit">Handle Redirect To Current URL</button>
}

<p>View Data: @ViewData["name"]</p>

<p>Temp Data: @TempData["name"]</p>

Call either "/demo/subpage" (= UmbracoPageController, IVirtualPageController) or "/test/subpage" (= UmbracoPageController). The "Subpage" action is called as expected. Now click on:

  1. Handle Current Page (CurrentUmbracoPage): Returns the "Index" action instead of "Subpage".
  2. Handle Redirect To Current Page (RedirectToCurrentUmbracoPage): Returns 404 instead of "Subpage".
  3. Handle Redirect To Current URL (HandleRedirectToCurrentUrl): No issue here, works as expected.

The difference between the original testing code and the modified version is the inclusion of the "{action}" for the routing pattern. Testing it with any action other than "Index" showcases N°1. N°2 is broken with or without the additional "{action}" pattern.

Expected result / actual result

Expected: "CurrentUmbracoPage" and "RedirectToCurrentUmbracoPage" returns/calls the original action where the form submit came from.
Actual: "CurrentUmbracoPage" and "RedirectToCurrentUmbracoPage" returns the "Index" action and "404" respectively.


This item has been added to our backlog AB#34096

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions