Closed
Description
If I make GET
request on http://localhost:5000/api/v1/values/42, then I've got the following result
{
"value": "model 42"
}
and it's ok. Bui if I make a POST
on http://localhost:5000/api/v1/values
with following body
{
"value": 42
}
I've got the following stacktrace
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLIS5H63UVVC", Request id "0HLIS5H63UVVC:00000003": An unhandled exception was thrown by the application.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNetCore.Mvc.Routing.ApiVersionRouteConstraint.Match(HttpContext httpContext, IRouter route, String routeKey, RouteValueDictionary values, RouteDirection routeDirection)
at Microsoft.AspNetCore.Routing.Template.TemplateBinder.TryProcessConstraints(HttpContext httpContext, RouteValueDictionary combinedValues, String& parameterName, IRouteConstraint& constraint)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.TryProcessTemplate(HttpContext httpContext, RouteEndpoint endpoint, RouteValueDictionary values, RouteValueDictionary ambientValues, LinkOptions options, ValueTuple`2& result)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetPathByEndpoints(List`1 endpoints, RouteValueDictionary values, RouteValueDictionary ambientValues, PathString pathBase, FragmentString fragment, LinkOptions options)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetPathByAddress[TAddress](HttpContext httpContext, TAddress address, RouteValueDictionary values, RouteValueDictionary ambientValues, Nullable`1 pathBase, FragmentString fragment, LinkOptions options)
at Microsoft.AspNetCore.Routing.LinkGeneratorRouteValuesAddressExtensions.GetPathByRouteValues(LinkGenerator generator, HttpContext httpContext, String routeName, Object values, 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 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 191.4428ms 500
I can put breakpoint inside Post
action and see that it calls correctly. The problem is somewhere inside CreatedAtAction.
Here is minimal repro
.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.0.0-beta2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="3.0.0-beta2" />
</ItemGroup>
</Project>
and Program.cs
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace ApiVersionTrouble
{
public static class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var builder = services.AddMvc();
builder.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddApiVersioning();
services.AddVersionedApiExplorer();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/values")]
[Produces("application/json")]
public class ValuesController : ControllerBase
{
[HttpGet("{settingsId:long}")]
public ValueResponse Get([FromRoute] long settingsId)
{
return new ValueResponse(settingsId);
}
[HttpPost]
public ActionResult Post([FromBody] ValueInput model)
{
var response = new ValueResponse(model.Value);
return CreatedAtAction(
nameof(Get),
new {version = "1", settingsId = model.Value},
response);
}
}
public class ValueInput
{
public long Value { get; set; }
}
public class ValueResponse
{
public ValueResponse(long id)
{
Value = "model " + id.ToString("D");
}
public string Value { get; }
}
}