I am experiencing an issue with a refactoring of our payment processing action method (called by our 3rd-party online payment provider). We have a product controller with the [Authorize]
and [RoutePrefix("products")]
attributes at the class level, and action methods including the following:
Product(string contractNumber)
with routing attribute [Route("{productCode}")]
MakePayment(string productCode, PaymentAmountType? amountSelection, decimal? amountValue)
with routing attribute [Route("{productCode}")]
and [HttpPost]
attributeProcessPayment(string productCode, string result)
with routing attribute [Route("{productCode}")]
Because our payment gateway needs to be able to call our ProcessPayment
action before the visitor is redirected to that same URL, we've had to refactor that to a separate controller without the [Authorize]
attribute. (We already have mechanisms to prevent double-crediting a payment.)
Before this refactoring, the MakePayment
action method correctly formulated the correct return URL in the following call to Url.Action()
:
var rawCallbackUrl = Url.Action("ProcessPayment", new { productCode = productCode });
The ProcessPayment
action method has now been moved out of the product controller and into a new controller, ExternalCallbackController
, which has no attributes (let alone [Authorize]
), in order to avoid having an HTTP 401 response returned to the payment provider.
The route attribute on ProcessPayment
is now [Route("order-processing/{productCode}/process-payment")]
to avoid clashing with the RoutePrefix
on the product controller. All references to this updated action method are updated to specify the ExternalCallbackController
.
Manually browsing to the URL causes the breakpoint set inside ProcessPayment
to be hit, so the route apparently works successfully.
The problem is that in MakePayment
, the following call returns null
:
var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });
Given that I am specifying both the controller and action method, why is Url.Action(...)
not returning the expected URL in the form order-processing/{productCode}/process-payment
?
From Day 1, our RegisterRoutes()
method in RouteConfig
has had attribute routing properly initialised with
routes.MapMvcAttributeRoutes();
How can I get the correct URL returned from the call to Url.Action(...)
?
Doh - I've figured out what went wrong. Despite the sanitising of names in the source code (which were specific to our client), it turns out that there was a mismatch in the following call:
var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });
and the ProcessPayment()
action method.
This is akin to the following (note the use of productNumber instead of productCode):
var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productNumber = productNumber });
trying to reference the action method:
[Route("order-processing/{productCode}/process-payment")]
public ActionResult ProcessPayment(string productCode, string result)
{
...
}
It also turns out that I can also use the same prefix "products" instead of "order-processing", as MVC creates one Route
per attribute route in the routing table. Hope that helps others stuck in a similar situation.