title: ASP.NET MVC 5 Attribute Routing: Url.Action returns null
body: <p>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 <code>[Authorize]</code> and <code>[RoutePrefix("products")]</code> attributes at the class level, and action methods including the following:</p>
  
  <ul>
  <li><code>Product(string contractNumber)</code> with routing attribute <code>[Route("{productCode}")]</code></li>
  <li><code>MakePayment(string productCode, PaymentAmountType? amountSelection, decimal? amountValue)</code> with routing attribute <code>[Route("{productCode}")]</code> and <code>[HttpPost]</code> attribute</li>
  <li><code>ProcessPayment(string productCode, string result)</code> with routing attribute <code>[Route("{productCode}")]</code></li>
  </ul>
  
  <p>Because our payment gateway needs to be able to call our <code>ProcessPayment</code> action before the visitor is redirected to that same URL, we've had to refactor that to a separate controller without the <code>[Authorize]</code> attribute. (We already have mechanisms to prevent double-crediting a payment.)</p>
  
  <p>Before this refactoring, the <code>MakePayment</code> action method correctly formulated the correct return URL in the following call to <code>Url.Action()</code>:</p>
  
  <pre><code>var rawCallbackUrl = Url.Action("ProcessPayment", new { productCode = productCode });
  </code></pre>
  
  <p>The <code>ProcessPayment</code> action method has now been moved out of the product controller and into a new controller, <code>ExternalCallbackController</code>, which has <em>no</em> attributes (let alone <code>[Authorize]</code>), in order to avoid having an HTTP 401 response returned to the payment provider. </p>
  
  <p>The route attribute on <code>ProcessPayment</code> is now <code>[Route("order-processing/{productCode}/process-payment")]</code> to avoid clashing with the <code>RoutePrefix</code> on the product controller. All references to this updated action method are updated to specify the <code>ExternalCallbackController</code>.</p>
  
  <p>Manually browsing to the URL causes the breakpoint set inside <code>ProcessPayment</code> to be hit, so the route apparently works successfully.</p>
  
  <p>The problem is that in <code>MakePayment</code>, the following call returns <code>null</code>:</p>
  
  <pre><code>var rawCallbackUrl = Url.Action("ProcessPayment", "ExternalCallback", new { productCode = productCode });
  </code></pre>
  
  <p>Given that I am specifying both the controller and action method, why is <code>Url.Action(...)</code> not returning the expected URL in the form <code>order-processing/{productCode}/process-payment</code>?</p>
  
  <p>From Day 1, our <code>RegisterRoutes()</code> method in <code>RouteConfig</code> has had attribute routing properly initialised with</p>
  
  <pre><code>routes.MapMvcAttributeRoutes();
  </code></pre>
  
  <p>How can I get the correct URL returned from the call to <code>Url.Action(...)</code>?</p>