I have an ASP.NET Core 2.1 webapi running that is listening for web socket requests. I want to return this.BadRequest()
if the request isn't for a WebSocket upgrade.
[Route("api/[controller]")]
[ApiController]
public class SocketController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> Post()
{
if (!this.HttpContext.WebSockets.IsWebSocketRequest)
return this.BadRequest();
using (var webSocket = await this.HttpContext.WebSockets.AcceptWebSocketAsync())
{
using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(webSocket)))
{
jsonRpc.AddLocalRpcTarget(new SocketServer());
jsonRpc.StartListening();
await jsonRpc.Completion;
}
}
return this.Ok();
}
}
But whether it takes the success path or the failure path, the server throws an exception:
fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HLEM87126JEO", Request id "0HLEM87126JEO:00000001": An unhandled exception was thrown by the application. System.InvalidOperationException: StatusCode cannot be set because the response has already started. at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Mvc.StatusCodeResult.ExecuteResult(ActionContext context) at Microsoft.AspNetCore.Mvc.ActionResult.ExecuteResultAsync(ActionContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsyncTFilter,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.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
It works OK if I change the method to just return Task
so I don't have to provide an IActionResult
, but then I don't have a way to return a 400 response to bad requests. What is the best way to go about this?
My middleware is super simple:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// app.UseHsts();
}
// app.UseHttpsRedirection();
app.UseWebSockets();
app.UseMvc();
}