ASP.NET MVC 5特性路由:Url.Action返回null

6
我遇到了一个问题,与我们的付款处理操作方法(由第三方在线付款提供商调用)的重构有关。我们有一个产品控制器,在类级别上具有[Authorize][RoutePrefix("products")]属性,并包括以下操作方法:
  • 路由属性为[Route("{productCode}")]Product(string contractNumber)
  • 路由属性为[Route("{productCode}")][HttpPost]属性的MakePayment(string productCode, PaymentAmountType? amountSelection, decimal? amountValue)
  • 路由属性为[Route("{productCode}")]ProcessPayment(string productCode, string result)
因为我们的支付网关需要能够在访问者被重定向到同一URL之前调用我们的ProcessPayment操作,所以我们不得不将其重构为没有[Authorize]属性的单独控制器。(我们已经有机制来防止重复记账付款。)
在进行此重构之前,MakePayment操作方法正确地通过以下对Url.Action()的调用制定了正确的返回URL:
var rawCallbackUrl = Url.Action("ProcessPayment", new { productCode = productCode });
ProcessPayment 操作方法已经从产品控制器中移出,并移至一个名为 ExternalCallbackController 的新控制器中,该控制器没有任何属性(更不用说 [Authorize] 了),以避免向支付提供商返回 HTTP 401 响应。 ProcessPayment 上的路由属性现在是 [Route("order-processing/{productCode}/process-payment")],以避免与产品控制器上的 RoutePrefix 冲突。所有对该更新后的操作方法的引用都需要更新为指定 ExternalCallbackController
手动浏览到该 URL 会导致在 ProcessPayment 中设置的断点被命中,因此路由显然成功工作。
问题在于,在 MakePayment 中,以下调用返回 null
var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });

既然我同时指定了控制器和操作方法,为什么Url.Action(...)没有返回预期的URL格式order-processing/{productCode}/process-payment

从第一天开始,我们在RouteConfig中的RegisterRoutes()方法已经正确地初始化了属性路由。

routes.MapMvcAttributeRoutes();

我该如何在调用Url.Action(...)时获得正确的URL返回?
2个回答

5

糟糕 - 我已经找出了问题所在。尽管源代码中的名称经过了清理(这些名称是针对我们的客户特定的),但事实证明以下调用存在不匹配:

var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });

这是类似于以下内容的(注意使用productNumber而不是productCode):

ProcessPayment()动作方法相关。

var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productNumber = productNumber });

尝试引用操作方法:

[Route("order-processing/{productCode}/process-payment")]
public ActionResult ProcessPayment(string productCode, string result)
{
    ...
}

同时,我还发现可以使用相同的前缀“products”代替“order-processing”,因为MVC在路由表中为每个属性路由创建一个Route。希望这能帮助其他陷入类似情况的人。

0

我遇到了这个错误:Url.Action返回null。

public async Task<IActionResult> ForgotPassword(ForgotPassword forgotPassword)
    {
        if (ModelState.IsValid)
        { 
            // Find the user by email
            var user = await userManager.FindByEmailAsync(forgotPassword.Email);
            // If the user is found AND Email is confirmed
            if (user != null && await userManager.IsEmailConfirmedAsync(user))
            {
                // Generate the reset password token
                var token = await userManager.GeneratePasswordResetTokenAsync(user);
                // Build the password reset link
                var passwordResetLink = Url.Action("ResetPassword", "Account",
                        new { email = forgotPassword.Email, token }, Request.Scheme);
                ViewBag.PRL = passwordResetLink;

                // Send the user to Forgot Password Confirmation view
                return View("ForgotPasswordConfirmation");
            }
            return View("ForgotPasswordConfirmation");
        }

        return View(forgotPassword);
    }

请在您的描述中添加更多细节,这有助于其他用户深入了解您的用途。添加您使用的版本、技术和IDE,或使用标记,以便您的问题能够引起正确队列的关注。 - Mangoski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接