Ни один маршрут не соответствует заданным значениям - PullRequest
0 голосов
/ 27 августа 2018

Этот конкретный случай не должен быть дубликатом какого-либо другого потока - я считаю, что я проверил их все, и я не думаю, что кто-либо конкретно ссылается на этот случай.

У меня есть этот контроллер:

 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);
        }
    }
}

Вот код класса 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; }
    }
}

Вот код класса 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; }
    }
}

Я делаю следующий звонок в Почтальоне:

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"}
}

Согласно коду, ожидаемое возвращение - это Guid, который представляет недавно созданный MonitorId. Вместо этого я получаю 500 Internal Server Error без подробностей. Однако запись успешно создана в базе данных. (SQL Server 2016).

Журнал показывает это как ошибку:

[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 ---

У меня есть другой контроллер в этом проекте с очень схожим синтаксисом, и все работает хорошо с ним. Я не вижу различий между ними, которые указывали бы мне, почему этот не работает.

Что может быть причиной этой ошибки, и как запись все еще создается в базе данных?

РЕДАКТИРОВАТЬ : добавлен дополнительный код для правильного контекста, чтобы способствовать ответу, предоставленному @ anserk * ​​1033 *

1 Ответ

0 голосов
/ 28 августа 2018

CreatedAtAction возвращает URI для только что созданного объекта. В вашем контроллере вы не определили действие («GET») для получения ресурса. Вы должны добавить новое действие для него.

DTO:

public class MonitorDto 
{
    public string QueryMonitorId {get; set;},
    pubcli string SubjectId {get; set;}
}

В вашем контроллере:

...
[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 });
}

Подробнее о https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction?view=aspnetcore-2.1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...