找不到ASP.NET MVC 3 HttpPost操作方法

时间:2012-08-20 08:37:30

标签: asp.net-mvc-3 post razor url-rewriting http-status-code-404

我有一个简单的表单发布到HttpPost操作方法,该方法返回其相应的视图。我的问题是我收到404 Not Found错误。奇怪的是,如果我将action方法和action方法的属性更改为GET,那么它就可以工作并显示TestMethod视图。

我似乎错过了使用POST的内容,但我在其他控制器中的帖子工作正常(例如帐户登录和注册)。请注意,AllowAnonymous属性是一个自定义属性,可以指定允许匿名访问的控制器或操作,而不是指定(通过Authorize attr)需要授权的控制器或操作。我想没有什么是不可能的,但我认为这与我的问题没有任何关系。对错误有什么看法?

FORM:

@using (Html.BeginForm("TestMethod", "Test", FormMethod.Post, new { @id = "testForm" })) {
    <fieldset>
        <legend>Test Form</legend>
        <input type="submit" value="Submit" />
    </fieldset>
}

控制器行动:

[AllowAnonymous]
[HttpPost]
public ActionResult TestMethod() {
    return View();
}

查看:

<h2>TestMethod</h2>
<p>HttpPost method was successful.</p>

从Global.asax.cs注册路由方法:

public static void RegisterRoutes(RouteCollection routes) {
        routes.IgnoreRoute("favicon.ico");
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // About
        routes.MapRoute(
            "About", // Route name
            "about", // URL with parameters
            new { controller = "Home", action = "About" } // Parameter defaults
        );

        // Faq
        routes.MapRoute(
            "Faq", // Route name
            "faq", // URL with parameters
            new { controller = "Home", action = "Faq" } // Parameter defaults
        );

        // Glossary
        routes.MapRoute(
            "Glossary", // Route name
            "glossary", // URL with parameters
            new { controller = "Home", action = "Glossary" } // Parameter defaults
        );

        // Register
        routes.MapRoute(
            "Register", // Route name
            "register", // URL with parameters
            new { controller = "Account", action = "Register" } // Parameter defaults
        );

        // LogIn
        routes.MapRoute(
            "LogIn", // Route name
            "login/{id}", // URL with parameters
            new { controller = "Account", action = "LogOn", id = UrlParameter.Optional } // Parameter defaults
        );
        routes.MapRoute(
            "LogOn", // Route name
            "logon/{id}", // URL with parameters
            new { controller = "Account", action = "LogOn", id = UrlParameter.Optional } // Parameter defaults
        );

        // Default
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

}

AUTHORIZE ATTRIBUTE CODE:

// AllowAnonymousAttribute class
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class AllowAnonymousAttribute : Attribute { }

// GlobalAuthorize class
public sealed class GlobalAuthorize : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext) {
        bool skipAuthorization = 
            filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || 
            filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);

        if (!skipAuthorization) base.OnAuthorization(filterContext);
    }
}

// RedirectAuthorizeAttribute class
public class RedirectAuthorizeAttribute : AuthorizeAttribute {
    public string RedirectUrl { get; set; }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
        filterContext.Result = new RedirectResult(RedirectUrl);
    }
}

全球过滤器:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
    filters.Add(new RequireHttpsAttribute());
    filters.Add(new GlobalAuthorize());
    filters.Add(new HandleErrorAttribute());
}

ROUTE REWRITING RULES:

<rewrite>
  <rules>
    <!-- Block all requests made to a website that do not have the host header set. -->
    <rule name="Fail bad requests" stopProcessing="true">
      <match url=".*" />
      <conditions>
        <add input="{HTTP_HOST}" pattern="localhost" negate="true" />
      </conditions>
      <action type="AbortRequest" />
    </rule>
    <!-- Remove trailing slash from all incoming requests. -->
    <rule name="Remove trailing slash" stopProcessing="false">
      <match url="(.*)/$" />
      <conditions>
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Redirect" redirectType="Permanent" url="{R:1}" />
    </rule>
    <!-- Convert all requests to all lowercase. -->
    <rule name="Convert to lowercase" stopProcessing="false">
      <match url=".*[A-Z].*" ignoreCase="false" />
      <action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
    </rule>
    <!-- Any URL with (HTTPS == OFF) and (HTTP_HOST with colon) -> use for development testing. -->
    <rule name="Development redirect to HTTPS" enabled="true" stopProcessing="true">
      <match url=".*" ignoreCase="true" />
      <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
        <add input="{HTTPS}" pattern="^OFF$" />
        <add input="{HTTP_HOST}" pattern="([^/:]*?):[^/]*?" />
      </conditions>
      <action type="Redirect" url="https://{C:1}:44300{URL}" />
    </rule>
    <!-- Redirect any HTTP request to HTTPS. -->
    <rule name="Redirect to HTTPS" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTPS}" pattern="^OFF$" ignoreCase="true" />
      </conditions>
      <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
    </rule>
  </rules>
</rewrite>

2 个答案:

答案 0 :(得分:5)

我想我终于找到了罪魁祸首。首先,我会承认,现在知道问题是什么,这个问题的标题不是很准确。问题主要是Web.config中的规则重写。在回答别人对这个问题的评论之前,我完全忘记了规则重写,这就是为什么我没有进一步检查它们的原因。

无论如何,问题是将URL重写为全部小写的规则。我知道我的帐户注册和登录表单工作正常,所以我检查了它们并注意到他们的Html.BeginForm语句是无参数的,这显然导致生成小写url。我为我的测试方法尝试了无参数的POST请求,并且它有效。然后,我尝试在Html.BeginForm语句中使用参数for action和controller,但这次我将它们作为小写字符串输入:Html.BeginForm("testmethod", "test"...)。果然,它也工作得很好,页面源将表单操作显示为小写。

要解决我的问题,我只需设置一个与POST次请求不匹配的条件:<add input="{REQUEST_METHOD}" matchType="Pattern" pattern="POST" negate="true" />。请注意,问题不是具体的小写规则,而是重定向POST请求。我找到一个blog讨论了POST重定向被转换为GET并导致错误的问题,这是我所经历的极端情况。它已经有几年了,但显然它仍然是相关信息。

无论如何,我现在已经恢复运行了。感谢所有投入两分钱的人。

P.S。当我关闭浏览器标签并结束我的搜索时,我想我会链接到这个SO question,因为它肯定与我的问题有关。

答案 1 :(得分:0)

我刚刚测试了你的代码。我最初被重定向为不使用HTTPS,所以我禁用了这个属性,但之后你的代码工作了。

这是我的逻辑扣除......

  • 如果HTTPS出现问题,您将无法获得404。
  • 如果您未登录,则会被重定向到登录页面。

我唯一能想到的是你的控制器没有命名为“TestController”,或者你的控制器在某个区域,你忘了为这个区域提供BeginForm。这有可能是其中之一吗?