Service Fabric Asp.net Core Kestrel HttpClient hangs with minimal load - asp.net-core

I have a barebone Service Fabric Application hosting a Asp.net Core 1.1 Web API with Azure Application Gateway as reverse proxy on a Virtual Machine scale set of 5 DS3_V2.
The API have 10 HttpClients with different URLs injected via Dependency Injection.
A simple foreach cycle in a method call 10 Httpclients in parallel:
var cts = new CancellationTokenSource();
cts.CancelAfter(600);
//Logic for asyncronously parallel calling the Call method below
public async Task<MyResponse> Call(CancellationTokenSource cts, HttpClient client, string endpoint )
{
var endpoint = "finalpartOfThendpoint";
var jsonRequest = "jsonrequest";
try
{
var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
await content.LoadIntoBufferAsync();
if (cts.Token.IsCancellationRequested)
{
return new MyResponse("Token Canceled");
}
var response = await client.PostAsync(endpoint, content, cts.Token);
if (response.IsSuccessStatusCode && ((int)response.StatusCode != 204))
{
//do something with response and return
return MyResponse("Response Ok")
}
return MyResponse("No response")
}
catch (OperationCanceledException e)
{
return new MyResponse("Timeout");
}
}
There is a single CancellationToken for all calls.
After 600ms, the still pending HttpCalls are canceled and a response is sent back anyway.
In local and in production all works perfectly, all endpoints are called and return in time, rarely one is canceled before the timeout.
But when the number of concurrent connections reach 30+, ALL calls timeout no matter what, until I reduce the load.
Does Asp.net Core have a connection limit?
This is how I create the HttpClients in a custom factory for injection in the main Controller:
public static HttpClient CreateClient(string endpoint)
{
var client = new HttpClient
{
BaseAddress = new Uri(endpoint)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
All the Httpclients are reused and static.
The same exact code works perfectly on a Asp.net Web API 2 hosted on OWIN in Service Fabric. The problem is only with Asp.net Core 1.1
I saw online to create a HttpClientHandler, but there is no parameter for concurrent connections.
What can I do to investigate further?
No exception are thrown but the OperationcanceledException and If I remove the CancellationToken the calls are stuck and the CPU goes to 100%, basically 30 connections destroy the power of 5 quad core servers.
This has something to do to the number of calls going out of Kestrel.
UPDATE
I tried with WebListener and the problem is still present, so it's not Kestrel, but Asp.net Core

I figured it out.
Asp.net core still have some HttpClient limits for the connection to the same server like the old Asp.net WebAPI.
It's poor documented but the old ServicepointManager option for maxconnections must now be passed via HttpClientHandler.
I just create HttpClient like this and the problem vanished.
var config = new HttpClientHandler()
{
MaxConnectionsPerServer = int.MaxValue
};
var client = new HttpClient(config)
{
BaseAddress = new Uri('url here')
};
Really if someone of the team is reading, this should be the default.

Related

Net Core HttpClient is disconnected after 2 minutes

I have a .NET 5 webapi application. Another .NET 5 console application is sending requests to the webapi. I have 10 seconds timeout on each request and I am sending requests one by one with a short interval. On my PC (which is very fast) I send thousands of requests and all of them succeed. But on another PC (which is pretty slow) I get few request failed, approximately every 2 minutes. First request takes a few seconds to send when the application starts because of connection estabishment to webapi.
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
await PerformPingAsync(httpClient, interval, cts.Token).ConfigureAwait(false);
private static async Task PerformPingAsync(HttpClient httpClient, int interval, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var request = new HttpRequestMessage
{
RequestUri = new Uri("http://127.0.0.1/api/service/ping"),
Method = HttpMethod.Get
};
var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
_consoleLogger.Info("Ping attempt succeed");
}
catch (Exception e)
{
_consoleLogger.Error(e);
}
await Task.Delay(TimeSpan.FromSeconds(interval), cancellationToken).ConfigureAwait(false);
}
}
Interval between requests is 1 second.
I have tried .net core 3.1, .NET 5 and 6 for my console ping application - and all of them have request timeouts (10 seconds). I have created the same console application in .net framework 4.8 and I get no timeouts. I also created a html page with JS fetch to send request and I get no timeouts.
Also what I have discovered that these timeouts can start to happen after a PC reboot. After some of reboots I might not get any timeouts but after the other reboot - I have them.
I found out that HttpClient acts a bit different in .net core/.NET 5/6 than in .net framework. And I tried to use SocketsHttpHandler:
var socketsHandler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(10),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(10)
};
return new HttpClient(socketsHandler)
{
Timeout = TimeSpan.FromSeconds(10)
};
But I have no success. Due to the official documention PooledConnectionLifetime timer should be reset after request is sent. If I have no requests for 10 minutes the connection will be closed. It's obvious that my N request is timed out because connection is being reestablished. But why it's happening, why my SocketsHttpHandler is not working? Any ideas?

trying to Azure AD authentication with gRPC-Web using protobuf-net

I am trying to Azure AD authentication with gRPC-Web in a blazor webassembly app. I am using protobuf-net to help me with the serialization. I am not sure how to pass the token to have the server side recognize it. this is what I have:
var headers = new Metadata
{
{ "Authorization", $"Bearer {Token}" }
};
and, I am sending that as a parameter in the method I want to consume
var result = await Client.CreateCustomer(this.customer, headers);
This is how the service is injected:
builder.Services.AddTransient(services =>
{
var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
var channel = Grpc.Net.Client.GrpcChannel.ForAddress("****", new GrpcChannelOptions { HttpClient = httpClient });
return channel.CreateGrpcService<Application.Services.ICustomerService<ServerCallContext>>();
});
This is how the service is published:
endpoints.MapGrpcService<CustomerService>().RequireAuthorization().EnableGrpcWeb()
and, this is the implementation:
public class CustomerService : ICustomerService<ServerCallContext>
{
[Authorize]
public async ValueTask<Customer> CreateCustomer(Customer customerDTO, ServerCallContext context)
{****}
}
the error I am getting is cannot convert from 'Grpc.Core.Metadata' to 'Grpc.Core.ServerCallContext' which is kind of obvious.
The reference I have found uses Metadata but is ServerCallContext the one I am supposed to use https://learn.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/metadata so what I am missing, what I am doing wrong, how to properly use both using protobuf-net?
It looks like the problem here is that you're using ServerCallContext in the method signature; the underlying gRPC core has separate client/server context APIs, but this is not amenable to use on an agnostic interface, and as such, protobuf-net.Grpc unifies these two APIs, via CallContext. So: instead of:
async ValueTask<Customer> CreateCustomer(Customer customerDTO, ServerCallContext context)
for the signature, consider:
async ValueTask<Customer> CreateCustomer(Customer customerDTO, CallContext context)
or
async ValueTask<Customer> CreateCustomer(Customer customerDTO, CallContext context = default)
The CallContext API exposes the common server-side and client-side APIs (headers, cancellation, etc) in a single way, or you can use (for example) context.ServerCallContext to get the server-specific API if needed (this will throw an exception if used on a client-context). For client-side usage, a CallContext can be constructed from a CallOptions, which is the core gRPC client-side API, for example:
var result = await service.CreateCustomer(customer, new CallOptions(headers));
I'm open to the idea of allowing CallContext to be created directly from Metadata / CancellationToken etc (allowing var result = await service.CreateCustomer(customer, headers);) - but it doesn't seem essential.

WCF Service unable to call from .NET Core

I am doing something wrong and I can't figure it out ... I made .NET Framework 4 console application to communicate with SOAP Service, with use of Topshelf I deployed service on a server and with simple URL access to a method or use of Boomerang tool, I can see service is returning value
URL: http://35.231.17.237:8066/ERPCommunicationService/OriginalService/IsServiceHealthy
But now, when I try to access same service, from .NET Core project, I keep getting error:
System.ServiceModel.ProtocolException:
The remote server returned an unexpected response: (405) Method Not Allowed.
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(
SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(
String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass1_0.
<CreateGenericTask>b__0(IAsyncResult asyncResult)
--- End of stack trace from previous location where exception was thrown ---
Code is simple, I successfully used service endpoint to connect it to .NET Core project, where I can see Reference.cs autogenerated file and all methods from service are there ...
Here is service call from client side (.net core):
public async Task<bool> IsServiceHealthy()
{
try
{
string servicesUrl = $"{_iConfiguration["servicesUrl"]}/IsServiceHealthy";
//My binding setup, since ASP.NET Core apps don't use a web.config file
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
binding.MaxReceivedMessageSize = 10485760;
binding.SendTimeout = new TimeSpan(0, 0, 0, 180);
binding.ReceiveTimeout = new TimeSpan(0, 0, 0, 180);
var rsExec = new OriginalService.OriginalServiceClient(binding,
new EndpointAddress(servicesUrl));
var clientFactory = rsExec.ChannelFactory.CreateChannel();
var response = await clientFactory.IsServiceHealthyAsync();
return response;
}
catch (Exception ex)
{
logging.LogError(ex.ToString());
throw ex;
}
}
And code from server side (.NET Framework 4):
Interface:
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
Implementation:
public bool IsServiceHealthy()
{
bool serviceResult = false;
byte[] test = new byte[200];
var client = new ChannelFactory<BisWebWS.BisWebWSSOAPPortType>("BisWebWSSOAPPort")
.CreateChannel();
BisWebWS.tauthStrct auth = ServisBasic.GetAuth();
try
{
var result = client.wsTest(new BisWebWS.wsTestRequest(test));
serviceResult = result.wsTestResult;
}
catch (Exception ex)
{
logger.LogError(ex.InnerException.ToString());
}
return serviceResult;
}
When ever I google shown error, everywhere it says its server side setup, but I am kinda stuck as I installed everything there is ... I am using MS Windows Server 2012 R2 Datacenter,
Thank you for shared idea how to fix this problem
The way that we call the service by using the proxy class is an Http Post request, while there is a GET decoration on the method. It requires an Http Get request instead of Post request. This might directly cause the issue.
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
If the server host the service by using Webhttpbinding, we could directly get the result by typing the service address in the browser address bar since the default request is an Http Get request (your link is not available).
This kind of service is called Restful-style service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-web-http-programming-model
https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
The typical call is to construct an HTTP request with a request body by using HttpClient library.
We could also call the service by using the client proxy class, like what you do. However, we should keep the binding configuration consistent between the server and the client.
WCF: There was no endpoint listening at, that could accept the message
It is too complex to call the service by using client proxy class, it is better to send Http request with HttpClient when we call Restful style service.
Besides, we could also host the service by using BasicHttpBinding, this may simplify the call. There is no need to add webhttpendpoint behavior and no need to add additional [Webget] decorations.
Simply speaking, we should maintain the binding consistent between the server and the client when using client proxy.
Feel free to let me know if the problem still exists.

HTTPClient intermittently locking up server

I have a .NET Core 2.2 app which has a controller acting as a proxy to my APIs.
JS makes a fetch to the proxy, proxy forwards call onto API's and returns response.
I am experiencing intermittent lock ups on the proxy app when its awaiting the response from the HttpClient. When this happens it locks up the entire server. No more requests will be processed.
According to the logs of the API that is being proxied to it is returning fine.
To reproduce this is i have to make 100+ requests in a loop on the client through the proxy. Then i have to reload the page multiple times, reloading it whilst the 100 requests are in flight. It usually takes around 5 hits before things start slowing down.
The proxy will lock up waiting for an awaited request to resolve. Sometimes it comes back after a 4 - 5 second delay, other times after a minuet. Most of the time i haven't waited longer then 10 min before giving up and killing the proxy.
I've distilled the code down to the following block that will reproduce the issue.
I believe im following best practices, its async all the way down, im using IHttpClientFactory to enable sharing of HttpClient instances, im implementing using where i believe it is required.
The implementation was based on this: https://github.com/aspnet/AspLabs/tree/master/src/Proxy
I'm hoping im making a rather obvious mistake that others with more experience can pin point!
Any help would be greatly appreciated.
namespace Controllers
{
[Route("/proxy")]
public class ProxyController : Controller
{
private readonly IHttpClientFactory _factory;
public ProxyController(IHttpClientFactory factory)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
[HttpGet]
[Route("api")]
async public Task ProxyApi(CancellationToken requestAborted)
{
// Build API specific URI
var uri = new Uri("");
// Get headers frpm request
var headers = Request.Headers.ToDictionary(x => x.Key, y => y.Value);
headers.Add(HeaderNames.Authorization, $"Bearer {await HttpContext.GetTokenAsync("access_token")}");
// Build proxy request method. This is within a service
var message = new HttpRequestMessage();
foreach(var header in headers) {
message.Headers.Add(header.Key, header.Value.ToArray());
}
message.RequestUri = uri;
message.Headers.Host = uri.Authority;
message.Method = new HttpMethod(Request.Method);
requestAborted.ThrowIfCancellationRequested();
// Generate client and issue request
using(message)
using(var client = _factory.CreateClient())
// **Always hangs here when it does hang**
using(var result = await client.SendAsync(message, requestAborted).ConfigureAwait(false))
{
// Appy data from request onto response - Again this is within a service
Response.StatusCode = (int)result.StatusCode;
foreach (var header in result.Headers)
{
Response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
Response.Headers.Remove("transfer-encoding");
requestAborted.ThrowIfCancellationRequested();
using (var responseStream = await result.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(responseStream, 81920);
}
}
}
}
}
EDIT
So modified the code to remove the usings and return the proxied response directly as a string instead of streaming and still getting the same issues.
When running netstat i do see a lot of logs for the url of the proxied API.
4 rows mention the IP of the API being proxied to, probably about another 20 rows mentions the IP of the proxy site. Those numbers dont seem odd to me but i don't have much experience using netstat (first time ive ever fired it up).
Also i have left the proxy running for about 20 min. Its it technically still alive. Responses are coming back. Just taking a very long time between the API being proxied to returning data and the HttpClient resolving. However it wont service any new requests, they just sit there hanging.

Async REST Services using WCF WebApi

I want to know what is the opinion of you fellow Developers regarding WCF WebApi services.
In an N-tier application we can have multiple layers of services. We can have services consuming data from external services. In that scenario its worth to create Async Rest Services using WCF 4.0.
public interface IService
{
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginGetStock(string code, AsyncCallback callback, object asyncState);
//Note: There is no OperationContractAttribute for the end method.
string EndGetStock(IAsyncResult result);
}
But with the release of WCF WebApi this approach is still required? to create async services?
How to host them in IIS/WAS/Self Hosting
looking forward for suggestion and comments.
Well What i feel,In order to create asynchronous operations in the latest WCF WebAPIs (preview 6) I can still use same pattern (Begin/End), but I can also use the Task programming model to create asynchronous operations, which is a lot simpler.
One example of an asynchronous operation written using the task model is shown below.
[WebGet]
public Task<Aggregate> Aggregation()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and orders
Task<List<Contact>> contactsTask = client.GetAsync(backendAddress + "/contacts").ContinueWith<Task<List<Contact>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Contact>>();
}).Unwrap();
Task<List<Order>> ordersTask = client.GetAsync(backendAddress + "/orders").ContinueWith<Task<List<Order>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Order>>();
}).Unwrap();
// Wait for both requests to complete
return Task.Factory.ContinueWhenAll(new Task[] { contactsTask, ordersTask },
(completedTasks) =>
{
client.Dispose();
Aggregate aggregate = new Aggregate()
{
Contacts = contactsTask.Result,
Orders = ordersTask.Result
};
return aggregate;
});
}
[WebGet(UriTemplate = "contacts")]
public Task<HttpResponseMessage> Contacts()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and return task directly
return client.GetAsync(backendAddress + "/contacts");
}
WCF Web API comes with an completely async HttpClient implementation and you can host in IIS and also completely sefhost.
For a async REST "service" scenario please read "Slow REST"