question

TomBara-3658 avatar image
0 Votes"
TomBara-3658 asked ·

HttpRequestException: Request headers must contain only ASCII characters with Asp.Net Core 3.1 on Ubuntu

I have an Asp.Net Core 3.1 Web app with Angular and individual authentication. I'm developing it on Ubuntu 18.04. The database is SQL Server Express. When sending registration confirmation email with SendGrid API, I get an exception "HttpRequestException: Request headers must contain only ASCII characters". I do not see any non-ASCII characters in the header.

I had exactly the same error on Windows 10. I updated Workloads and Individual Components in my Visual Studio and that solved it. I'm not sure how to solve it on Ubuntu. I installed the 3.1 SDK according to these instructions

This is the method:

     public Task SendEmailAsync(string email, string subject, string message)
     {
         string apiKey = _config.GetValue<string>("ExternalProviders:SendGrid:ApiKey");
         return Execute(apiKey, subject, message, email);
     }

  public Task Execute(string apiKey, string subject, string message, string email)
 {
     string sender = _config.GetValue<string>("ExternalProviders:SendGrid:SenderEmail");
     string senderUser = _config.GetValue<string>("ExternalProviders:SendGrid:SenderName");
     var msg = new SendGridMessage()
     {
         From = new EmailAddress(sender, senderUser),
         Subject = subject,
         PlainTextContent = message,
         HtmlContent = message
     };
     msg.AddTo(new EmailAddress(email));
     var client = new SendGridClient(apiKey);
     return client.SendEmailAsync(msg);
 }

This is the error message:

System.Net.Http.HttpConnection.WriteStringAsync(string s)
System.Net.Http.HttpConnection.WriteHeadersAsync(HttpHeaders headers, string cookiesFromContainer)
System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
SendGrid.Helpers.Reliability.RetryDelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task<HttpResponseMessage> sendTask, HttpRequestMessage request, CancellationTokenSource cts, bool disposeCts)
SendGrid.BaseClient.MakeRequest(HttpRequestMessage request, CancellationToken cancellationToken)
SendGrid.BaseClient.RequestAsync(Method method, string requestBody, string queryParams, string urlPath, CancellationToken cancellationToken)
SendGrid.BaseClient.SendEmailAsync(SendGridMessage msg, CancellationToken cancellationToken)
NoblyAppsSite.Areas.Identity.Pages.Account.RegisterModel.OnPostAsync(string returnUrl) in Register.cshtml.cs

                     await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",

Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Convert<T>(object taskAsObject)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Execute(object receiver, object[] arguments)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g_Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g
Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g
Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g
_AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)


Here is the header:

Variable Value
:authority localhost:5001
:method POST
:path /Identity/Account/Register?returnUrl=%2Fauthentication%2Flogin
:scheme https
Accept text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding gzip, deflate, br
Accept-Language en-US,en;q=0.5
Cache-Control max-age=0
Content-Length 280
Content-Type application/x-www-form-urlencoded
Cookie .AspNetCore.Antiforgery.9dU1lrY_fgE=CfDJ8Ma-TG6aJSVPqeaMKCGLfGFJbfQKQm0lFVjSI2UwnYxEquMO8_ii1znT8IGVhFJYOdsQCKReeRKvLZxiaGwOO8gkYGhV-xYhlDw707Kf8Zj235AD3kbPE18X2wrCYP2uUd26cpjYZHYAMcLEow7KdPY
Host localhost:5001
Origin https://localhost:5001
Referer https://localhost:5001/Identity/Account/Register?returnUrl=/authentication/login
TE trailers
Upgrade-Insecure-Requests 1
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0

How can I get rid of this error?





dotnet-runtime-coredotnet-aspnet-core-webapidotnet-crossplatform-general
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

miwan2-msft avatar image
0 Votes"
miwan2-msft answered ·

Hi, @TomBara-3658

By default (and RFC) SMTP headers are US-ASCII. In order to send non-ASCII characters, you need to use Unicode escape sequences.
You could try to encode header anyway by the methods below.

Here are methods to EncodeNonAsciiCharacters and DecodeEncodedNonAsciiCharacters.

 static string EncodeNonAsciiCharacters( string value ) {
         StringBuilder sb = new StringBuilder();
         foreach( char c in value ) {
             if( c > 127 ) {
                 // This character is too big for ASCII
                 string encodedValue = "\\u" + ((int) c).ToString( "x4" );
                 sb.Append( encodedValue );
             }
             else {
                 sb.Append( c );
             }
         }
         return sb.ToString();
     }
    
     static string DecodeEncodedNonAsciiCharacters( string value ) {
         return Regex.Replace(
             value,
             @"\\u(?<Value>[a-zA-Z0-9]{4})",
             m => {
                 return ((char) int.Parse( m.Groups["Value"].Value, NumberStyles.HexNumber )).ToString();
             } );
     }



· 1 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you for your contribution. I don't think this will help my situation. Here's why. EncodeNonAsciiCharacters returns a string. The argument for client.SendEmailAsync(msg) is a SendGridMessage SendGrid accepts it and passes the results to System.Net.Http... where the error is thrown. Passing a string to client.SendEmailAsync(msg) will not work.

0 Votes 0 ·