How to resolve "TypeError: Failed to fetch" error on Blazor? - asp.net-core

I am trying to send an HTTP request from my Blazor app to my ASP.NET Core API. I have breakpoints everywhere. The application gives an exception right after the action method on the API controller returns. I am familiar with .NET overall, however, I could not decipher the error message.
Blazor http call:
var response = await _httpClient.GetStreamAsync($"Customer/GetAllCustomers");
ASP.NET Core API Controller action:
[HttpGet]
[Route("GetAllCustomers")]
public async Task<IEnumerable<Customer>> GetAllCustomersAsync()
{
return await _service.GetAllCustomersAsync();
}
Error stack:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: TypeError: Failed to fetch
WebAssembly.JSException: TypeError: Failed to fetch
at System.Net.Http.WebAssemblyHttpHandler.doFetch (System.Threading.Tasks.TaskCompletionSource`1[TResult] tcs, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x301ab40 + 0x00a30> in <filename unknown>:0
at System.Net.Http.WebAssemblyHttpHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2ff3590 + 0x00174> in <filename unknown>:0
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2ff1e98 + 0x00160> in <filename unknown>:0
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2fc8a98 + 0x00182> in <filename unknown>:0
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x301ff08 + 0x00134> in <filename unknown>:0
at System.Net.Http.HttpClient.FinishGetStreamAsync (System.Threading.Tasks.Task`1[TResult] getTask) <0x2ffa720 + 0x000cc> in <filename unknown>:0
at WebClient.Services.LectureVideoService.GetAllLectureVideos (Content.Data.Enums.LessonType lessonType) [0x00040] in D:\AlbidersSoftware\CSharp\Albiders Content MS\Albiders\WebClient\Services\LectureVideoService.cs:21
at WebClient.Pages.MathAccList.OnInitializedAsync () [0x00026] in D:\AlbidersSoftware\CSharp\Albiders Content MS\Albiders\WebClient\Pages\MathAccList.razor:18
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x2bed718 + 0x0013a> in <filename unknown>:0
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask (System.Threading.Tasks.Task taskToHandle) <0x2e3a0b0 + 0x000b6> in <filename unknown>:0

Unhandled exception rendering component: TypeError: Failed to fetch
WebAssembly.JSException: TypeError: Failed to fetch
I did a test to make request(s) from my Blazor WebAssembly app to action method with testing data, which works well on my side.
[Route("[controller]")]
[ApiController]
public class CustomerController : ControllerBase
{
[HttpGet]
[Route("GetAllCustomers")]
public async Task<IEnumerable<Customer>> GetAllCustomersAsync()
{
//for testing purpose
return new List<Customer> { new Customer { Id = 1, Name = "Test1" }, new Customer { Id = 2, Name = "Test2" } };
//return await _service.GetAllCustomersAsync();
}
}
GetAllCustomers.razor
#page "/getallcustomers"
#using BlazorWasmApp1.Shared
#inject HttpClient _httpClient
<h3>Customer List</h3>
#if (customers == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#foreach (var customer in customers)
{
<tr>
<td>#customer.Id</td>
<td>#customer.Name</td>
</tr>
}
</tbody>
</table>
}
#code {
private Customer[] customers;
protected override async Task OnInitializedAsync()
{
//call external API
//_httpClient.BaseAddress = new Uri("https://localhost:44312/");
//your API action would return a collection of Customer
//you can try to call .GetFromJsonAsync<Customer[]>() to get the expected data
//rather than get stream
customers = await _httpClient.GetFromJsonAsync<Customer[]>($"Customer/GetAllCustomers");
}
}
Test Result
To troubleshoot the issue, please try:
check the URL of your request in browser developer tool Network tab, and make sure you are making request to correct endpoint
if your ASP.NET Core Web API project is hosting on separate site, please make sure you configured and enabled CORS to allow request(s) from your Blazor WebAssembly app, and make sure that API is running

Also check if your api is requesting from HTTP, change it to https: it will work

EDIT NOTE: I just realised that my original answer was a red-herring, so I have deleted it and replaced it. The actual cause of my error is quite different to your question, but I'll provide a summary of resolution here because it was the first post that came up with this error message and it might help someone else troubleshoot it.
I am building a Web Assembly Hosted project, but with multiple clients and have been trialing combining AddMicrosoftIdentityWebApi and AddMicrosoftIdentityWebApp in my Server project as per following.
Program.cs (Server Project)
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
Everything worked fine with just AddMicrosoftIdentityWebApi. However, when I added AddMicrosoftIdentityWebApp and tried to call my api from the client, I got the error that you identified.
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: TypeError: Failed to fetch
System.Net.Http.HttpRequestException: TypeError: Failed to fetch
---> System.Runtime.InteropServices.JavaScript.JSException: TypeError: Failed to fetch
at System.Net.Http.BrowserHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.BrowserHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[BlazorApp14.Shared.WeatherForecast[], BlazorApp14.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at BlazorApp14.Client.Pages.FetchData.OnInitializedAsync() in C:\Temp\BlazorApp14\BlazorApp14\Client\Pages\FetchData.razor:line 50
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
If I had looked more closely, I would have seen that my error is not quite the same as yours, but anyway.....
I then noticed that there was an additional error showing in Dev Tools on the browser.
Access to fetch at 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=0e5f2876-c...................
redirected from 'https://localhost:5001/WeatherForecast') from origin 'https://localhost:5001' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
This sent me down another rabbit-hole and I setup Cors etc. on my WebApi project, which did not help.
I then thought that perhaps using the same registered AzureAD application in the AddMicrosoftIdentityWebApi and AddMicrosoftIdentityWebApp calls. However, this was not the problem either.
It turns out that the [Authorize] attribute on my controller couldn't choose which Authentication scheme to use and chose the "wrong" one. The simple fix to my error was to explicitly call out the Authentication Scheme in the Authorize attribute as shown following.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}

Related

Blazor WASM controller: read request body causes the IIS process to crash

So I am trying to simply read the body (with string content) in a Blazor WASM ApiController. My code on the server-side:
[AllowAnonymous]
[ApiController]
[Route("[controller]")]
public class SmartMeterDataController : ControllerBase
{
[HttpPost("UploadData")]
public async void UploadData()
{
string body = null;
if (Request.Body.CanRead && (Request.Method == HttpMethods.Post || Request.Method == HttpMethods.Put))
{
Request.EnableBuffering();
Request.Body.Position = 0;
body = await new StreamReader(Request.Body).ReadToEndAsync();
}
}
}
My app builder in Program.cs is pretty much out of the box:
//enable REST API controllers
var mvcBuillder = builder.Services.AddMvcCore(setupAction: options => options.EnableEndpointRouting = false).ConfigureApiBehaviorOptions(options => //activate MVC and configure error handling
{
options.InvalidModelStateResponseFactory = context => //error 400 (bad request)
{
JsonApiErrorHandler.HandleError400BadRequest(context);
return new Microsoft.AspNetCore.Mvc.BadRequestObjectResult(context.ModelState);
};
});
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
...
app.UseRouting();
app.UseMvcWithDefaultRoute();
app.MapRazorPages();
app.MapControllers();
The request body looks like this:
{"api_key":"K12345667565656", "field1":"1.10", "field2":"0.76",
"field3":"0.65", "field4":"455", "field5":"0", "field6":"1324",
"field7":"433761", "field8":"11815" }
Yes, this is JSON. No, I don't want to parse it with [FromBody] or similar.
POSTing to this endpoint causes the following exception (as seen in the Windows event viewer thingy):
Application: w3wp.exe
CoreCLR Version: 6.0.1222.56807
.NET Version: 6.0.12
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'HttpRequestStream'.
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ValidateState(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ReadAsync(Memory`1 destination, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.ReadAsync(Memory`1 destination, CancellationToken cancellationToken)
at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at System.IO.StreamReader.ReadBufferAsync(CancellationToken cancellationToken)
at System.IO.StreamReader.ReadToEndAsyncInternal()
After that, a second error is always logged. It states something like it is described here.
Note that it's usually not the first, but the second or third POST that causes this. After this, the error keeps happening with every POST and after a short while the application stops working and the Windows Server 2019 need to be rebooted.
According to the internet, the code should work. Anyone have a guess why it doesn't?
I use this HttpContext extension method to read the request body and cache it in the context in case needed later in the pipeline. It works for me.
Notice the condition around EnableBuffering. Perhaps adding that condition to your code will help.
public static async Task<string> GetRequestBodyAsStringAsync(
this HttpContext httpContext)
{
if (httpContext.Items.TryGetValue("BodyAsString", out object? value))
return (string)value!;
if (!httpContext.Request.Body.CanSeek)
{
// We only do this if the stream isn't *already* rewindable,
// as EnableBuffering will create a new stream instance
// each time it's called
httpContext.Request.EnableBuffering();
}
httpContext.Request.Body.Position = 0;
StreamReader reader = new(httpContext.Request.Body, Encoding.UTF8);
string bodyAsString = await reader.ReadToEndAsync().ConfigureAwait(false);
httpContext.Request.Body.Position = 0;
httpContext.Items["BodyAsString"] = bodyAsString;
return bodyAsString;
}
EDIT ...
Possibly, your issue could also be related to fact your controller method is returning a void instead of Task?
Finally, I found the original article I used for my extension method. Interestingly, if you that extension method for the FIRST time after model-binding then it won't work (in my project I do call it from middleware).
https://markb.uk/asp-net-core-read-raw-request-body-as-string.html
Adding:
public class EnableRequestBodyBufferingMiddleware
{
private readonly RequestDelegate _next;
public EnableRequestBodyBufferingMiddleware(RequestDelegate next) =>
_next = next;
public async Task InvokeAsync(HttpContext context)
{
context.Request.EnableBuffering();
await _next(context);
}
}
and
app.UseMiddleware<EnableRequestBodyBufferingMiddleware>();
may therefore also help.

UriFormatException getting caught in exception handler for ASP .Net Core

I've added exception handling to my Asp .Net Core application to log any unhandled exceptions. I am getting unhandled UriFormatExceptions within the middleware due to what appears to be traffic from various web crawlers targeting non-existent endpoints. I am not sure how to fix this, or at least elegantly silence it so it does not show up in my telemetry. In general, I'd like to ignore traffic hitting endpoints not defined by my application.
Exception logged
[Unhandled exception][UriString][https:///favicon.ico][Exception]
[System.UriFormatException: Invalid URI: The hostname could not be parsed.]
Stacktrace:
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions)
at System.Uri..ctor(String uriString)
at Microsoft.AspNet.OData.Routing.ODataPathRouteConstraint.Match(HttpContext httpContext, IRouter route, String routeKey, RouteValueDictionary values, RouteDirection routeDirection)
at Microsoft.AspNetCore.Routing.RouteConstraintMatcher.Match(IDictionary`2 constraints, RouteValueDictionary routeValues, HttpContext httpContext, IRouter route, RouteDirection routeDirection, ILogger logger)
at Microsoft.AspNetCore.Routing.RouteBase.RouteAsync(RouteContext context)
at Microsoft.AspNetCore.Routing.RouteCollection.RouteAsync(RouteContext context)
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)]
Exception Handler
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
IExceptionHandlerPathFeature exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
string uriString = null;
uriString = context.Request.GetEncodedUrl();
Logger.EmitLog(
"Unhandled exception",
"UriString",
uriString,
"Exception",
exceptionHandlerPathFeature?.Error);
});
});

How to authenticate the .NET core API using JWT access token with SSL enabled OpenID connect?

I've two separate .NET core API projects (OpenIDConnect and Features API) and deployed into IIS. OpenIDConnect is to authenticate the users with their credentials and it will issue accessToken if authentication succeeded. Features API will authenticate using the OpenIDConnect API with that accessToken.
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
options.DefaultForbidScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});
Everything works fine until enable mTLS in OpenIdConnect. That is, enabled SSL in OpenIdConnect API from IIS and so it requires client to include the certificate on their request.
OpenIdConnect API:
services
.AddAuthentication(o =>
{
o.DefaultScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
})
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var claims = new[]
{
new Claim(
ClaimTypes.NameIdentifier,
context.ClientCertificate.Subject,
ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(
ClaimTypes.Name,
context.ClientCertificate.Subject,
ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
return Task.CompletedTask;
}
};
})
Once enabled it, I'm able to get accessToken from OpenIdConnect API by adding certificate in Postman.
But unable to access OpenIdConnect API from Features API even though added the client certificate into Features API project like below.
services.AddOpenIddict()
.AddServer(options =>
{
options.SetIssuer(new Uri(tokenServiceBaseUrl));
options.AddSigningCertificate(signingCertificate);
})
.AddValidation(options =>
{
options.SetIssuer(tokenServiceBaseUrl);
options.UseAspNetCore();
options.UseSystemNetHttp();
options.AddEncryptionCertificate(signingCertificate);
});
Getting below exception when trying to request from Postman:
System.InvalidOperationException: IDX20803: Unable to obtain
configuration from: 'System.String'. --->
System.Text.Json.JsonException: '<' is an invalid start of a value.
Path: $ | LineNumber: 0 | BytePositionInLine: 0. --->
System.Text.Json.JsonReaderException: '<' is an invalid start of a
value. LineNumber: 0 | BytePositionInLine: 0. at
System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader&
json, ExceptionResource resource, Byte nextByte, ReadOnlySpan1 bytes) at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker) at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first) at System.Text.Json.Utf8JsonReader.ReadSingleSegment() at System.Text.Json.Utf8JsonReader.Read() at System.Text.Json.Serialization.JsonConverter1.ReadCore(Utf8JsonReader&
reader, JsonSerializerOptions options, ReadStack& state) --- End of
inner exception stack trace --- at
System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state,
JsonReaderException ex) at
System.Text.Json.Serialization.JsonConverter1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.Serialization.JsonConverter1.ReadCoreAsObject(Utf8JsonReader&
reader, JsonSerializerOptions options, ReadStack& state) at
System.Text.Json.JsonSerializer.ReadCore[TValue](JsonConverter
jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options,
ReadStack& state) at
System.Text.Json.JsonSerializer.ReadCore[TValue](JsonReaderState&
readerState, Boolean isFinalBlock, ReadOnlySpan1 buffer, JsonSerializerOptions options, ReadStack& state, JsonConverter converterBase) at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken) at System.Net.Http.Json.HttpContentJsonExtensions.ReadFromJsonAsyncCore[T](HttpContent content, Encoding sourceEncoding, JsonSerializerOptions options, CancellationToken cancellationToken) at OpenIddict.Validation.SystemNetHttp.OpenIddictValidationSystemNetHttpHandlers.ExtractJsonHttpResponse1.HandleAsync(TContext
context) at
OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext
context) at
OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext
context) at
OpenIddict.Validation.OpenIddictValidationService.<>c__DisplayClass2_0.<g__ExtractConfigurationResponseAsync|2>d.MoveNext()
--- End of stack trace from previous location --- at OpenIddict.Validation.OpenIddictValidationService.GetConfigurationAsync(Uri
address, CancellationToken cancellationToken) at
OpenIddict.Validation.OpenIddictValidationService.GetConfigurationAsync(Uri
address, CancellationToken cancellationToken) at
OpenIddict.Validation.OpenIddictValidationRetriever.Microsoft.IdentityModel.Protocols.IConfigurationRetriever<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration>.GetConfigurationAsync(String
address, IDocumentRetriever retriever, CancellationToken cancel) at
Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken cancel) --- End of inner exception stack trace --- at Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken
cancel) at
OpenIddict.Validation.OpenIddictValidationHandlers.ValidateIdentityModelToken.HandleAsync(ProcessAuthenticationContext
context) at
OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext
context) at
OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext
context) at
OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandler.HandleAuthenticateAsync()
at
Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext
context, String scheme) at
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext
context)

Kestrel error when sending a request from an emulator

When making a request to Kestrel via Fiddler, the following request succeeds.
GET http://192.168.1.148:5000/ HTTP/1.1
Host: 192.168.1.148:5000
Connection: keep-alive
When making the request thru the NETMF Emulator, the following request fails.
GET http://192.168.1.148:5000 HTTP/1.1
Host: 192.168.1.148:5000
Connection: keep-alive
This is the ASP.NET Core error message. The error appears to be about logging!
Request finished in 24788.6203ms 500
fail: Microsoft.AspNet.Server.Kestrel[13]
An unhandled exception was thrown by the application.
System.AggregateException: An error occurred while writing to logger(s).
---> System.ArgumentException: Parameter name: value
at Microsoft.AspNet.Http.PathString..ctor(String value)
at Microsoft.AspNet.Http.Internal.DefaultHttpRequest.get_Path()
at Microsoft.AspNet.Hosting.Internal.HostingLoggerExtensions
.HostingRequestStarting.ToString()
at Microsoft.Extensions.Logging.Console.ConsoleLogger.Log(
LogLevel logLevel, Int32 eventId, Object state,
Exception exception, Func`3 formatter)
at Microsoft.Extensions.Logging.Logger.Log(
LogLevel logLevel, Int32 eventId, Object state,
Exception exception, Func`3 formatter)
--- End of inner exception stack trace ---
at Microsoft.Extensions.Logging.Logger.Log(
LogLevel logLevel, Int32 eventId, Object state,
Exception exception, Func`3 formatter)
at Microsoft.AspNet.Hosting.Internal.HostingLoggerExtensions
.RequestStarting(ILogger logger, HttpContext httpContext)
at Microsoft.AspNet.Hosting.Internal.HostingEngine
.<>c__DisplayClass32_0.<<Start>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter
.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Server.Kestrel.Http.Frame
.<RequestProcessingAsync>d__79.MoveNext()
---> (Inner Exception #0) System.ArgumentException: Parameter name: value
at Microsoft.AspNet.Http.PathString..ctor(String value)
at Microsoft.AspNet.Http.Internal.DefaultHttpRequest.get_Path()
at Microsoft.AspNet.Hosting.Internal.HostingLoggerExtensions
.HostingRequestStarting.ToString()
at Microsoft.Extensions.Logging.Console.ConsoleLogger.Log(
LogLevel logLevel, Int32 eventId, Object state,
Exception exception, Func`3 formatter)
at Microsoft.Extensions.Logging.Logger.Log(
LogLevel logLevel, Int32 eventId, Object state,
Exception exception, Func`3 formatter)<---
This is the entire ASP.NET Core program.
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Logging;
namespace EmptyApplication01
{
public class Startup
{
public void Configure(
IApplicationBuilder app,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(minLevel: LogLevel.Verbose);
app.Run(async (context) =>
{
var logger = loggerFactory.CreateLogger("CatchAll");
logger.LogInformation(DateTime.Now.ToString());
await context.Response.WriteAsync("head, body");
});
}
}
}
I have figured out. Kestrel will break if the AbsoluteURL is in the path. in order to make it work this is the work around
app.Use(next => async context => {
// get the frame from kestrel and then but the path by removing the hostname
var Frame = (Microsoft.AspNet.Server.Kestrel.Http.Frame)context.Features;
var newpath = Frame.RequestUri.Replace("http://" + context.Request.Host.Value, "");
context.Request.Path = newpath;
// Invoke the rest of the pipeline.
await next(context);
});
Turning off logging fixed the problem. This is probably a bug in the ASP.NET logging implementation.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using System;
namespace EmptyApplication01
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
// no more logging!
System.Console.WriteLine(DateTime.Now.ToString());
await context.Response.WriteAsync("head, body");
});
}
}
}

Why does ToOptimizedResult throw "Requested feature is not implemented." on Mono?

I am building my ServiceStack 4.0.8 service using Visual Studio. On Windows everything works perfectly, but when I try to run on Mono 2.10.8.1 / Ubuntu 13.10 with NGINX 1.4.1 and fastcgi-server4.
I get an exception:
The requested feature is not implemented.
at System.Web.HttpContextWrapper.GetService (System.Type serviceType) [0x00000] in :0
at ServiceStack.Host.RequestPreferences.GetWorker (System.Web.HttpContextBase context) [0x00000] in :0
at ServiceStack.Host.RequestPreferences.get_HttpWorkerRequest () [0x00000]
in :0 at ServiceStack.Host.RequestPreferences.get_AcceptEncoding () [0x00000]
in :0 at ServiceStack.Host.RequestPreferences.get_AcceptsDeflate () [0x00000]
in :0 at ServiceStack.RequestExtensions.GetCompressionType (IRequest request) [0x00000]
in :0 at ServiceStack.RequestExtensions.ToOptimizedResult[List1] (IRequest request, System.Collections.Generic.List1 dto) [0x00000]
in :0 at Phase1HistoryServer.SymbolsService.Get (Phase1HistoryServer.Symbols request) [0x00000] in :0
If I return the DTO object directly I do not get errors. However if I use base.Request.ToOptimizedResult the exception occurs.
List<DataItem> data = new List<DataItem>();
data.Add(new dataItem { Data = "fake data" });
return base.Request.ToOptimizedResult<List<DataItem>>(data);
Update:
A commit to ServiceStack has been made, and version 4.0.16+ should no longer suffer from this exception.
ToOptimizedResult() works, this is not a shortcoming of ServiceStack but rather with Mono and fastcgi-server-4. There is a suitable workaround.
Mono incomplete, doesn't implement System.Web.HttpContextWrapper.GetService:
This exception is thrown because the Mono project have not yet implemented this method. As Mono is an OpenSource project they have to recreate the .NET specification themselves, and this method simply isn't done.
See here for the relevant Mono source code:
public class HttpContextWrapper : HttpContextBase
{
...
[MonoTODO]
public override object GetService (Type serviceType)
{
throw new NotImplementedException ();
}
}
Mono solution, use a Self Hosted Application:
I run ServiceStack on Mono (albeit v3.2.6) and don't have any problem using ToOptimizedResult but I don't use fastcgi-server4, which will relies on System.Web.HttpContextWrapper.
Instead I use a self hosted ServiceStack application, which is based on a pool of underlying System.Net.HttpListener, which doesn't seem to be affected by the same issue. And thus works well.
Demo App:
Below is code for a working self-hosted ServiceStack application, using your test code:
using System;
using ServiceStack;
using System.Collections.Generic;
namespace Testv4
{
class MainClass
{
public static void Main()
{
// Very basic console host
var appHost = new AppHost(500);
appHost.Init();
appHost.Start("http://*:8082/");
Console.ReadKey();
}
}
public class AppHost : AppHostHttpListenerPoolBase
{
public AppHost(int poolSize) : base("Test Service", poolSize, typeof(TestApp).Assembly) {}
public override void Configure(Funq.Container container)
{
}
}
public static class TestApp
{
public class DataItem
{
public string Data { get; set; }
}
[Route("/Test", "GET")]
public class TestRequest {}
public class TestController : Service
{
public object Get(TestRequest request)
{
var list = new List<DataItem> {
new DataItem { Data = "Fake Data" }
};
return base.Request.ToOptimizedResult(list);
}
}
}
}
You can test the application by going to localhost:8082/Test. It shouldn't throw an exception when compressing the result.
Self Hosted App Usability:
My suggestion would be to either forward requests from NGINX using it's transparent proxying abilities onto the ServiceStack application, or simply cut out NGINX and have request go directly to the application.
The AppHostHttpListenerPoolBase works well and I have had no issue using it in production environments.