Я создал .NET Core API Controller, и в методе POST я пытаюсь использовать метод CreatedAtActionResult , чтобы включить маршрут в качестве заголовка расположения в мой ответ.
[ApiController, Route("v1/[controller]")]
public class WidgetController: ControllerBase
{
public WidgetController(IWidgetService service)
{
_service = service;
}
private readonly IWidgetService _service;
[HttpGet("{id}", Name = "GetSingle")]
public IActionResult GetSingle(Guid id)
{
var result = _service.Get(id);
return Ok(result);
}
[HttpPost]
public IActionResult Post(WidgetModel model)
{
var result = _service.Post(model);
return result == Guid.Empty
? (IActionResult) BadRequest("No changes saved.")
: CreatedAtAction(nameof(GetSingle),
new {id = result},
model);
}
}
Когда я запускаю приложение, первый вызов POST из POSTman выполняется без проблем. И объект, и URL-адрес заголовка расположения генерируются, как и ожидалось. Однако, если я попытаюсь достичь этой конечной точки во второй раз, пока код еще работает, я получаю следующую ошибку:
System.InvalidOperationException: нет службы для типа 'Microsoft.AspNetCore.Routing.IEndpointAddressScheme 1[Microsoft.AspNetCore.Routing.RouteValuesAddress]' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetEndpoints[TAddress](TAddress address)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetPathByAddress[TAddress](HttpContext httpContext, TAddress address, RouteValueDictionary values, RouteValueDictionary ambientValues, Nullable
1 pathBase, фрагмент FragmentString, параметры LinkOptions)
в Microsoft.AspNetCore.Routing.LinkGeneratorRouteValuesAddressExtensions.GetPathByRouteValues (Генератор LinkGenerator, HttpContext httpContext, String routeName, Значения объекта, Nullable 1 pathBase, FragmentString fragment, LinkOptions options)
at Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper.Action(UrlActionContext urlActionContext)
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host, String fragment)
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host)
at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at SaasKit.Multitenancy.Internal.TenantResolutionMiddleware
1.Invoke (контекст HttpContext, ITververantRol)
в Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (контекст HttpContext)
Я пытался заменить CreatedAtAction
на Ok
, и результат 200 будет возвращаться столько раз, сколько я нажимаю кнопку в POSTman.
Код внутри метода Post
успешно обрабатывается, и он переходит к методу OnActionExecuted
созданного мной фильтра. Я попытался просмотреть все свойства объекта ActionExecutedContext
и не вижу ничего необычного. Как только я выйду из этого пустого метода OnActionExecuted
, вызов возвращает код состояния 500 и приведенную выше трассировку стека на странице ошибок. У меня есть фильтр исключений, но он не затрагивается.
У кого-нибудь были проблемы с этим раньше?
Для справки, вот моя конфигурация запуска:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<AppTenant, CachingAppTenantResolver>();
services.AddAutoMapper()
.AddSingleton(ConfigureAutoMapper())
.AddMvc(options =>
{
options.Filters.Add<ValidatorActionFilter>();
options.Filters.Add<ErrorHandlingFilter>();
})
.AddFluentValidation(validation => {
validation.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
validation.ImplicitlyValidateChildProperties = true;
validation.RegisterValidatorsFromAssemblyContaining<WidgetModelValidator>();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
});
services.AddEntityFrameworkSqlServer()
.AddDbContext<MyContext>();
services.Configure<MultitenancyOptions>(configuration.GetSection("Multitenancy"));
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod();
});
});
ConfigureContainer(container);
return provider;
}