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

d_m*_*mcg 6 asp.net routes url-routing attributerouting asp.net-mvc-5

我在重构我们的支付处理操作方法(由我们的第 3 方在线支付提供商调用)时遇到问题。我们有一个产品控制器,在类级别具有[Authorize][RoutePrefix("products")]属性,以及操作方法,包括以下内容:

  • Product(string contractNumber)具有路由属性[Route("{productCode}")]
  • MakePayment(string productCode, PaymentAmountType? amountSelection, decimal? amountValue)具有路由属性[Route("{productCode}")][HttpPost]属性
  • ProcessPayment(string productCode, string result)具有路由属性[Route("{productCode}")]

由于我们的支付网关需要能够ProcessPayment在访问者重定向到同一 URL 之前调用我们的操作,因此我们必须将其重构为不带该[Authorize]属性的单独控制器。(我们已经有防止重复记入付款的机制。)

在此重构之前,MakePayment操作方法在以下调用中正确地制定了正确的返回 URL Url.Action()

var rawCallbackUrl = Url.Action("ProcessPayment", new { productCode = productCode });
Run Code Online (Sandbox Code Playgroud)

现在,操作ProcessPayment方法已从产品控制器移出并移入新控制器 ,ExternalCallbackController该控制器没有属性(更不用说[Authorize]),以避免将 HTTP 401 响应返回给支付提供商。

现在,路线属性 onProcessPayment[Route("order-processing/{productCode}/process-payment")]为了避免与RoutePrefix产品控制器上的 发生冲突。对此更新的操作方法的所有引用均已更新以指定ExternalCallbackController.

手动浏览到该 URL 会导致内部设置的断点ProcessPayment被命中,因此该路由显然可以成功运行。

问题是MakePayment,在 中,以下调用返回null

var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });
Run Code Online (Sandbox Code Playgroud)

鉴于我指定了控制器和操作方法,为什么不在Url.Action(...)表单中返回预期的 URL order-processing/{productCode}/process-payment

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

routes.MapMvcAttributeRoutes();
Run Code Online (Sandbox Code Playgroud)

如何获得从调用返回的正确 URL Url.Action(...)

d_m*_*mcg 5

Doh - 我已经弄清楚出了什么问题。尽管对源代码中的名称(特定于我们的客户端)进行了清理,但事实证明以下调用中存在不匹配:

var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });
Run Code Online (Sandbox Code Playgroud)

以及ProcessPayment()动作方法。

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

var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productNumber = productNumber });
Run Code Online (Sandbox Code Playgroud)

尝试引用操作方法:

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

事实证明,我还可以使用相同的前缀“产品”而不是“订单处理”,因为 MVCRoute在路由表中为每个属性创建一个路由。希望能帮助其他陷入类似情况的人。