No route matches the supplied values
No route matches the supplied values
This particular case should not be a duplicate of any other thread - I believe I've checked them all and I don't believe any refer to this case specifically.
I have this Controller:
namespace Cantrel.Application.CantrelSearchApi.Controllers
[Route("api/[controller]")]
[Authorize]
public class MonitorsController : Controller
private readonly IMonitoringApiService monitoringService;
private readonly IClientsApiService clientsService;
private readonly ILogger<MonitorsController> logger;
public MonitorsController(IMonitoringApiService monitoringService,
IClientsApiService clientsService,
ILogger<MonitorsController> logger)
this.monitoringService = monitoringService;
this.clientsService = clientsService;
this.logger = logger;
[HttpGet("id")]
public async Task<IActionResult> Get(string id)
if (string.IsNullOrEmpty(id))
return BadRequest("No id was provided. Please provide a valid monitor id or subject id.");
try
MonitorDto monitor;
if (Guid.TryParse(id, out Guid monitorId))
monitor = await GetByMonitorId(monitorId);
else
monitor = await GetBySubjectId(id);
if (monitor == null)
return NotFound();
return Json(monitor);
catch (Exception ex)
logger.LogError($"[Request.Path.Value]: ex.ToString()");
return new StatusCodeResult(500);
[HttpPost]
public async Task<IActionResult> Post([FromBody] MonitorsPostRequest request)
//logger.LogError("We are here"); <--
if (request == null)
return BadRequest("Request could not be parsed.");
if (string.IsNullOrEmpty(request.SubjectId))
return BadRequest("SubjectId is required for a monitor.");
if (string.IsNullOrEmpty(request.Subject))
return BadRequest("Subject is required for a monitor.");
if (request.BillingCodeId == Guid.Empty)
return BadRequest("A billing code is required for a monitor.");
try
var clientId = GetClientId();
var billingCodeId = new BillingCodeId(request.BillingCodeId);
//check permissions <--
var permissions = await clientsService.AuthorizeSearchLicenseAsync(
new SearchAuthorizationRequest()
ClientId = clientId,
BillingCodeId = billingCodeId,
Categories = request.Categories?.Split(new ',', ' ' , StringSplitOptions.RemoveEmptyEntries)
);
if (!permissions.Success)
if (!permissions.BillingCodeValid)
return BadRequest($"The billing code provided is not active for the account.");
if (permissions.Licensing == null)
return BadRequest($"The User does not have access to requested functionality, please contact sales if you would like to include additional permission or if your permissions are incorrect.");
else
return BadRequest($"The User does not have access to string.Join(", ", permissions.Licensing.Select(l => l.Categories)) Categories, please contact sales if you would like to include additional permission or if your permissions are incorrect.");
var createRequest = new CreateMonitorRequest()
ClientId = clientId,
BillingCodeId = billingCodeId,
Subject = request.Subject,
SubjectId = request.SubjectId,
Categories = request.Categories?.Split(new ',', ' ' , StringSplitOptions.RemoveEmptyEntries),
NeedsTranslation = request.NeedsTranslation,
Parameters = request.Parameters
;
if (request.Schedule != null)
createRequest.StartAt = request.Schedule.StartAt;
createRequest.EndAt = request.Schedule.EndAt;
if (Enum.TryParse<ScheduleTypeId>(request.Schedule.ScheduleType, out ScheduleTypeId scheduleType))
createRequest.ScheduleType = scheduleType;
var response = await monitoringService.CreateMonitorAsync(createRequest);
if (response.Duplicate)
return BadRequest($"Subject Id [request.SubjectId] is already being monitored with monitor response.MonitorId.Id.");
else
return CreatedAtAction("Get",
new
queryMonitorId = response.MonitorId.Id,
subjectId = request.SubjectId
,
JsonConvert.SerializeObject(
new
queryMonitorId = response.MonitorId.Id,
subjectId = request.SubjectId
));
catch (RequiredFieldException rfe)
return BadRequest(rfe.Message);
catch (Exception ex)
logger.LogError($"[Request.Path.Value]: ex.ToString()");
return new StatusCodeResult(500);
private ClientId GetClientId()
var client_id = int.Parse(HttpContext.User.Claims.First(c => c.Type == TokenProviderOptions.ClientIdClaimName).Value);
return new ClientId(client_id);
private async Task<MonitorDto> GetByMonitorId(Guid monitorId)
return await monitoringService.GetMonitorByIdAsync(new MonitorId(monitorId));
private async Task<MonitorDto> GetBySubjectId(string id)
return await monitoringService.GetMonitorBySubjectIdAsync(GetClientId(), id);
Here is the CreateMonitorRequest class code:
CreateMonitorRequest
namespace Cantrel.Application.Contracts.Monitoring.Requests
[DataContract]
public class CreateMonitorRequest
public CreateMonitorRequest();
[DataMember]
public ClientId ClientId get; set;
[DataMember]
public BillingCodeId BillingCodeId get; set;
[DataMember]
public string SubjectId get; set;
[DataMember]
public ScheduleTypeId? ScheduleType get; set;
[DataMember]
public DateTime? StartAt get; set;
[DataMember]
public DateTime? EndAt get; set;
[DataMember]
public string Subject get; set;
[DataMember]
public List<string> Aliases get; set;
[DataMember]
public string Categories get; set;
[DataMember]
public bool NeedsTranslation get; set;
[DataMember]
public Dictionary<string, string> Parameters get; set;
Here is the MonitorDTO class code:
MonitorDTO
namespace Cantrel.Application.Contracts.Monitoring.Dtos
[DataContract]
public class MonitorDto
[DataMember]
public MonitorId Id get; set;
[DataMember]
public ClientId ClientId get; set;
[DataMember]
public BillingCodeId BillingCodeId get; set;
[DataMember]
public string SubjectId get; set;
[DataMember]
public DateTime CreatedAt get; set;
[DataMember]
public MonitorScheduleDto Schedule get; set;
[DataMember]
public MonitorSearchDto Search get; set;
[DataMember]
public MonitorStatus Status get; set;
[DataMember]
public string SubjectTranslated get; set;
[DataMember]
public string AliasTranslated get; set;
I make the following call in Postman:
POST: api/Monitors
Body:
"clientid":"1",
"billingcodeid":"ABCDEFGH-1234-4567-8901-ABCDEFGHIJKL",
"subject": "John Doe",
"subjectId":"Test1234",
"ScheduleType" : "1",
"Categories": "GENER",
"parameters":
"dateofbirth":"8/07/2018"
Per the code, the expected return is a Guid which represents the newly-created MonitorId. Instead, I receive a 500 Internal Server Error with no details. However, the record is successfully created in the database. (SQL Server 2016).
500 Internal Server Error
The log shows this as the error:
[ERR] Connection id ""0HLGC42CD408N"", Request id ""0HLGC42CD408N:00000004"": An unhandled exception was thrown by the application. (560e7d32)
System.InvalidOperationException: No route matches the supplied values.
at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting(ActionContext context)
at Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeResultAsync>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
I have another Controller in this project with very similar syntax and all is working well with it. I don't see any differences between the two that would indicate to me why this one doesn't work.
What could be causing this error, and how is the record still getting created in the database?
EDIT: added additional code for proper context to contribute to the answer provided by @anserk
CreatedAtAction
The above-posted error is all I'm told as far as logs go. I'm afraid I'm not well-equipped to answer your question about what CreatedAtAction does? I'm still very much a beginner at this. Any additional information you can provide so I can help you help would be greatly appreciated.
– Stpete111
Aug 27 at 18:13
1 Answer
1
The CreatedAtAction returns an URI to the entity you just created. In your controller you didn't define the action ("GET") for getting the resource. You should add a new action for it.
CreatedAtAction
DTO:
public class MonitorDto
public string QueryMonitorId get; set;,
pubcli string SubjectId get; set;
In your controller:
...
[HttpGet("queryMonitorId/subjectId", Name = "Get")]
public async Task<IActionResult> GetMonitor(string queryMonitorId, string subjectId)
...
// Your get implementation here.
Ok(new MonitorDto QueryMonitorId = queryMonitorId, SubjectId = subjectId );
More information about https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction?view=aspnetcore-2.1
it probably would have helped if I included ALL of the code for the Controller. Due to my newbie-ism, I didn't think I needed to include anything other than the piece that was related to the call I've made. There is a GET action in the Controller. I have edited my post to include the code for the entire controller (note the Get action before the Post action, as well as the GetClientId method at the end. I've also included the existing MonitorDTO class for reference. So then do you think the GET action needs to be updated along the lines of your suggestion? Thanks.
– Stpete111
Aug 28 at 1:45
You have to give your action the name
Get, see [HttpGet("queryMonitorId/subjectId", Name = "Get")]. CreatedAtAction use that name to reference the action. Make sure that you are using the right key for the GET, in your CreatedAtAction method looks like it should have a composite key: queryMonitorId = response.MonitorId.Id, subjectId = request.SubjectId– anserk
Aug 28 at 1:50
Get
[HttpGet("queryMonitorId/subjectId", Name = "Get")]
queryMonitorId = response.MonitorId.Id, subjectId = request.SubjectId
Yes, also check the route values you pass in the
CreatedAtAction. You pass both queryMonitorId and subjectId while in your GET you only expect an Id.– anserk
Aug 28 at 1:59
CreatedAtAction
queryMonitorId
subjectId
Id
To me it looks like
queryMonitorId = response.MonitorId.Id should be tyour Monitor Id.– anserk
Aug 28 at 12:19
queryMonitorId = response.MonitorId.Id
Let us continue this discussion in chat.
– anserk
Aug 28 at 14:47
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I'm assuming you've examined the logs and nothing about the error is in there? What does your
CreatedAtActiondo? It could be returning 500 without throwing anything...– Ron Beyer
Aug 27 at 17:41