Reputation: 388
I am converting an ASP.NET MVC (.NET Framework) application to ASP.NET Core MVC. This is strictly a conversion, I cannot make any breaking changes hence I cannot change any Routes or Methods. I am unable to match the same functionality in ASP.NET Core MVC.
Working ASP.NET MVC:
[HttpPut]
[Route("status")]
public async Task<IHttpActionResult> UpdateStatusByOrderGuid([FromUri] Guid orderGUID, [FromBody] POST_Status linkStatusModel)
{
}
[HttpPut]
[Route("status")]
public async Task<IHttpActionResult> UpdateStatusById([FromUri] Guid id, [FromBody] POST_Status linkStatusModel)
{
}
Not working, ASP.NET Core MVC.
I get an error:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints
Code:
[HttpPut]
[Route("status")]
public async Task<IActionResult> UpdateStatusByOrderGuid([FromQuery] Guid orderGUID, [FromBody] POST_Status statusModel)
{
}
[HttpPut]
[Route("status")]
public async Task<IActionResult> UpdateStatusById([FromQuery] Guid id, [FromBody] POST_Status statusModel)
{
}
I need to include the query parameters when it resolves which route. It should match based on whether orderGUID
or id
is in the query string.
Thanks.
Upvotes: 2
Views: 2064
Reputation: 874
Why not use a single endpoint instead? You don't need to pass Guid's, since it's a GET operation, you can pass strings and cast them later. That way you can send one parameter or the other.
[HttpPut]
[Route("status")]
public async Task<IActionResult> UpdateStatus([FromBody] POST_Status statusModel, [FromQuery] string orderGUID = null, [FromQuery] string id = null)
{
if (!string.IsNullOrEmpty(orderGUID))
{
// UpdateStatusByOrderGuid implementation here
// Guid guid = Guid.Parse(orderGUID);
}
else if (!string.IsNullOrEmpty(id))
{
// UpdateStatusById implementation here
// Guid guid = Guid.Parse(id);
}
else
{
throw new ArgumentException("No valid GUID.");
}
}
This endpoint should be compatible with both scenarios you specified.
Upvotes: 2
Reputation: 36655
You needs to custom ActionMethodSelectorAttribute
:
1.QueryStringConstraintAttribute:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class QueryStringConstraintAttribute : ActionMethodSelectorAttribute
{
public string ValueName { get; private set; }
public bool ValuePresent { get; private set; }
public QueryStringConstraintAttribute(string valueName, bool valuePresent)
{
this.ValueName = valueName;
this.ValuePresent = valuePresent;
}
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
var value = routeContext.HttpContext.Request.Query[this.ValueName];
if (this.ValuePresent)
{
return !StringValues.IsNullOrEmpty(value);
}
return StringValues.IsNullOrEmpty(value);
}
}
2.Controller:
[HttpPut]
[Route("status")]
[QueryStringConstraint("orderGUID",true)]
[QueryStringConstraint("id", false)]
public void UpdateStatusByOrderGuid([FromQuery] Guid orderGUID,[FromBody]POST_Status model)
{
}
[HttpPut]
[Route("status")]
[QueryStringConstraint("id", true)]
[QueryStringConstraint("orderGUID", false)]
public void UpdateStatusById([FromQuery] Guid id, [FromBody]POST_Status model)
{
}
3.Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Upvotes: 3