Html.BeginForm 在区域后自动添加子文件夹

Posted

技术标签:

【中文标题】Html.BeginForm 在区域后自动添加子文件夹【英文标题】:Html.BeginForm is automatically adding a sub-folder after the area 【发布时间】:2020-06-04 05:49:13 【问题描述】:

我在我的 ASP.NET MVC 应用程序中创建了一个名为 B2b 的区域,并且我还在该区域下创建了一个名为 Shopify 的子文件夹:

为了注册Shopify 子文件夹,我创建了一个CustomViewEngine 如下(followed this tutorial):

public class ExpandedViewEngine : RazorViewEngine 

    public ExpandedViewEngine()
    
        var extendedViews = new[] 
        
            "~/Areas/B2b/Views/Shopify/1/0.cshtml",
        ;

        var extendedPartialViews = new[]
        
            "~/Areas/B2b/Views/Shopify/Shared/0.cshtml"
        ;

        ViewLocationFormats = ViewLocationFormats.Union(extendedViews).ToArray();
        PartialViewLocationFormats = PartialViewLocationFormats.Union(extendedPartialViews).ToArray();
    

这是我的区域注册码(我使用的是lowercase-dashed-route):

public class B2bAreaRegistration : AreaRegistration

    public override string AreaName
    
        get
        
            return "B2b";
        
    

    public override void RegisterArea(AreaRegistrationContext context)
    
        // this route is for controllers and views inside Shopify sub-folder
        var shopifyDefaultRoute = new LowercaseDashedRoute(
            "B2b/Shopify/controller/action/id",
            new RouteValueDictionary(new  controller = "ProductMap", action = "Display", id = UrlParameter.Optional ),
            new DashedRouteHandler(),
            this,
            context,
            new[]  "Shopless.Web.Areas.B2b.Controllers.Shopify" 
        );
        context.Routes.Add("Shopify_default", shopifyDefaultRoute);

        // default area route which is not under Shopify subfolder
        var b2bDefaultRoute = new LowercaseDashedRoute(
            "B2b/controller/action/id",
            new RouteValueDictionary(new  action = "index", id = UrlParameter.Optional ),
            new DashedRouteHandler(),
            this,
            context,
            new[]  "Shopless.Web.Areas.B2b.Controllers" 
        );
        context.Routes.Add("B2b_default", b2bDefaultRoute);
    

我在 Global.asax 中注册了上述内容:

protected void Application_Start()


    ViewEngines.Engines.Add(new ExpandedViewEngine());
    AreaRegistration.RegisterAllAreas();
    // more code ...

一切正常,以下代码除外

@using (Html.BeginForm("update", "organisation", new  area = "B2b" , FormMethod.Post))

    <input type="text" id="name" name="name">

正在生成以下 HTML:

<form action="/b2b/shopify/organisation/update" method="post" novalidate="novalidate">
    <input type="text" id="name" name="name">
</form>

请注意,它在我的地区名称后添加了shopify B2b。上面的表格在B2b区域内,但不在shopify子文件夹下,所以不知道为什么要添加它?

【问题讨论】:

它正在打这个路由模板"B2b/Shopify/controller/action/id" @Nkosi:路由按预期工作,我的意思是,如果我将 url:B2b/Controller/Action/Id 放在浏览器中,它会命中正确的控制器......如果我把 B2b/Shopify/Controller/Action/Id 放在浏览器,它会在shopify子文件夹中执行正确的操作...但我不知道为什么Html.BeginForm总是在它生成的url中包含shopify子文件夹(当我在该区域内使用它时) 当浏览确定它会工作时,BeginForm 正在生成一个 URL,所以这是不同的。等待现在发布答案 【参考方案1】:

它映射到此路由模板"B2b/Shopify/controller/action/id",因为它还匹配在为表单生成 URL 时提供给 BeginForm 的常规值。

对于 URL 生成,两个区域路由约定相互冲突。

如果我要求路由表生成一个 URL,我给它一个 controlleractionarea。给定同一区域内的以下路线模板,哪条路线将首先匹配

B2b/Shopify/controller/action/id

B2b/controller/action/id

而且由于第一场比赛总是赢,它会映射到上面的第一场比赛,这将解释你的表格的当前体验。

如果您想使用特定路由为表单生成 URL,请使用 BeginRouteFormMethod

@using (Html.BeginRouteForm(
    routeName: "B2b_default", 
    routeValues: new  action = "update", controller = "organisation", area = "B2b" , 
    method: FormMethod.Post)
)

    <input type="text" id="name" name="name">

【讨论】:

非常感谢...我明白如何解决问题了。我不确定我是否理解你的第一句话,BeginForm 形式如何匹配这两种约定?是不是因为我在区域注册中定义了2个约定? 您的两个区域路由约定在生成 URL 时相互冲突。如果我要求生成一个 URL,并且我给路由表一个控制器、动作和区域,那么哪个路由会首先匹配? 所以它无法根据表单所在的路径找出正确的约定?这是我的假设...... @HoomanBahreini 不。它取决于你给予什么。您可能会发布到位于该区域之外的表单,因此它不会假定您的意思是在当前表单的同一位置。如果您不提供路线值,它将仅默认为当前位置。

以上是关于Html.BeginForm 在区域后自动添加子文件夹的主要内容,如果未能解决你的问题,请参考以下文章

在区域下添加子文件夹并配置视图引擎以搜索子文件夹中的视图

使用 javascript 将路由值传递给 Html.BeginForm

使用 onsubmit 属性时 request.files 返回 null

ASP.Net MVC 5 Html.BeginForm onsubmit 和具有所需属性的模型

如何在 Razor 中编写“Html.BeginForm”

MVC小系列Html.BeginForm与Ajax.BeginForm