I am trying to configure my .net core API in order to limit the requests.
To achieve this i modify the program.cs class like
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Limits.MaxConcurrentConnections = 2;
})
//.UseContentRoot(Directory.GetCurrentDirectory())
//.UseIISIntegration()
.UseStartup<Startup>();
});
}
but the problem is when I call my API with a console app using more threads than 2 I get the responses from all threads-calls. The API I have deployed-published it in my local IIS pc.
I consider that I must get only 2 responses and then for the other calls I will get 503 services unavailable.
what is wrong with my code?
EDIT
I have read this article How to configure concurrency in .NET Core Web API?, the problem is when I add the web.config
<configuration>
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
</configuration>
i have the warning
the element system. web has invalid child element applicationpool
and i cannot publish the api on iis or run it in iis express
Since the API will host in the IIS, so, the configuration for the Kestrel will not be used.
To set the max concurrency connections in IIS, you could Open IIS manager window. Select the site from the server node. Then, select Advance setting from the action pane. You can see the Limits under the Behavior section. Set Maximum Concurrent Connection value based on your requirement. Like this:
[Note] This setting is for all Sites.
Besides, you could also check this sample and create a custom middleware to limit the request.
Option serverOptions.Limits.MaxConcurrentConnections limits maximum number of tcp connections to Kestrel, not the number of concurrent http requests. Through each tcp connection there still might be multiple concurrent http requests. That's why in your test you can see no errors, even though there are more than 2 concurrent http requests.
In order to limit the number of concurrent http requests in .NET Core (or .NET
5+), you can use ConcurrencyLimiterMiddleware (package Microsoft.AspNetCore.ConcurrencyLimiter). Here is an example:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddStackPolicy(options =>
{
options.MaxConcurrentRequests = 2;
options.RequestQueueLimit = 25;
});
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseConcurrencyLimiter();
}
}
Related
I have a SignalR (AspNet Core 5.0) hosted in a console app using Kestrel as the web host.
I want to access the user Identity of any request in a Hub implementation, when accessing the following the Identity values are NULL.
I've looked at the available documentation on MSDN and made the following changes, but not getting the Identity populated as I expected, also not finding any examples for AspNet Core 5.0 anywhere.
Any ideas what I am doing wrong?
public class ExampleHub : Hub
{
public Task Foo()
{
*// why is name NULL?*
var name = Context.User.Identity.Name;
return Task.Completed;
}
}
I have added the following line when configuring the services as StartUp:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNeogtiate();
services.AddSignalR(options => options.EnableDetailedErrors = true);
...
}
public void Configure(IApplicationBuuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints => endpoints.MapHub<ExampleHub>("/Example"); });
}
Managed to get this working by changing to HttpSys instead of Kestrel as the host. The Context.User.Identity is now populated as WindowsIdentity.
In this case using HttpSys is preferred - an internal (corporate) network hosted in a Windows Service instead of a web server (IIS). Note IIS also uses HttpSys internally.
I have created a React Project using dotnetcore 3.1 Version. This is hosted on an IIS Server on AWS Lightsail. We use AWS Lightsail Loadbalancers. The Web Service communicates to an Microsoft SQL Server Express (64-bit) Database, version 14.0.3281.6 using Entity Framework Core.
The problem we are facing is:
We make a call to the webservice via a POST request. This runs a query on the database. This query fetches data from many related tables using Include()
For large data we have noticed that the web service return a 504 Gateway Timeout.
We have tried setting the CommandTimeout to 900 seconds as below
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var connectionString = configuration.GetConnectionString("DefaultConnection");
optionsBuilder.UseSqlServer(connectionString, sqlServerOptions => sqlServerOptions.CommandTimeout(900));
}
}
Our Connection string
"DefaultConnection": "Data Source=server_name_here,port_number_here;Initial Catalog=db_name_here;Integrated Security=False;Persist Security Info=False;User ID=user_name_here;Password=password_here
Other things we have tried:
Setting the requestTimeout="00:20:00" in the web.config
Application Pool settings screenshot
Are we missing something?
I suspect that this has something to do with the AWS loadbalancer configuration. The 504 Gateway timeout probably comes from the loadbalancer because it expects your application to answer within a certain amount of time (which it doesn't for large data).
You could try to (temporarily) disable the loadbalancer and see if you still hit the 504 Gateway Timeout error.
You could also add a new controller to test this issue:
[ApiController]
[Route("[controller]")]
public class TimeoutController : ControllerBase
{
[HttpGet]
public IActionResult Get(int timeoutInSeconds)
{
Thread.Sleep(TimeSpan.FromSeconds(timeoutInSeconds));
return Ok($"Waited for {timeoutInSeconds} seconds.");
}
}
Then you can call it with your browser on http://[server:port]/timeout?timeoutInSeconds=10
You can then gradually increase the timeout. This helps you to identify the threshold and to prove that it does not have something to do with your application code (because the controller does not do anything but wait).
We have an application running different services (c#, .NET Core) LOCAL on a Windows PC.
I now need some kind of mechanism to inform all interested services if data changed in one service (some kind of observer pattern for microservices, or some kind of MQTT (pub/sub) mechanism of c# and .NET Core microservices locally running on a windows pc).
First I want to use Sockets but the Windows documentation says use Signalr instead.
So here is what I have so far:
public class Startup
{
public Startup()
{
// empty
}
public void ConfigureServices(IServiceCollection services)
{
// Add services.
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
services.AddSignalR();
// Add the localization services to the services container.
services.AddLocalization(options => options.ResourcesPath = "Properties");
services.AddMvc()
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
// Use sessions
// The order of middleware is important.
// An InvalidOperationException exception will occur when UseSession is invoked after UseMvc.
app.UseSession();
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
//The SignalR Hubs API enables you to call methods on connected clients from the server.
//In the server code, you define methods that are called by client. In the client code, you define methods that are called from the server.
app.UseSignalR(routes =>
{
routes.MapHub<SignalRHub>("/SignalRHub");
});
app.UseMvc(
routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
For the .NET CORE Service
But I now need a client for the c# System.Web.Http.ApiController and can not find an example.
Seems some are confused by our "beautiful" architecture ;-)
I hope the following picture makes it clearer:
So, if Application 1 changes data in Microservice 2, than Application 2 has to be informed.
And again, this is all running local on a Windows PC, no clouds are involved.
Probably missing something from your description.
SignalR is fine if there are clients to report relevant information to.
In your scenario, however, it would seem that the clients are the APIs themselves and this makes little sense to me.
Maybe there's a piece missing in the middle that does the work you're saying.
In any case, you may find relevant technical information about SignalR starting from the official website.
https://learn.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-3.1&tabs=visual-studio
I'm setting up a proof of concept featuring two ASP.NET Core applications that are both instrumented with Jaeger to demonstrate how it can propagate a trace between services over the wire. Both applications are being deployed to Azure App Services.
I'm using the OpenTracing Contrib package to automatically inject the Jaeger trace context into my inter-service traffic in the form of HTTP Headers (the package is hardcoded to use that form of transmission). But it appears that those headers are going missing along the way, as the receiving application is unable to resume the tracing context.
Before deploying to Azure, I'm testing the applications locally with Docker Compose, and with that setup the context propagation works fine. It's only once the apps are in Azure that things break.
The applications communicate over HTTPS and I've disabled HSTS and HTTPS redirection in case that might be causing Azure to drop the headers, based on the answer in this previous thread.
I've also tried running both applications in Azure Container Instances, and that seems to be a non-starter - it doesn't fix the context propagation and seems to introduce more bugs around span relationships.
The two applications are nearly identical in their setup, and differ only in the API endpoints they serve.
My CreateWebHostBuild from program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureServices(services =>
{
// Registers and starts Jaeger (see Shared.JaegerServiceCollectionExtensions)
services.AddJaeger(CheckoutConfiguration.JaegerSettings.Host);
// Enables OpenTracing instrumentation for ASP.NET Core, CoreFx, EF Core
services.AddOpenTracing();
});
The contents of the AddJaeger extension method which is largely borrowed from the Contrib sample:
public static IServiceCollection AddJaeger(this IServiceCollection services, string jaegerHost = "localhost")
{
if (services == null)
throw new ArgumentNullException(nameof(services));
services.AddSingleton<ITracer>(serviceProvider =>
{
string serviceName = Assembly.GetEntryAssembly().GetName().Name;
ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
ISampler sampler = new ConstSampler(sample: true);
var reporter = new RemoteReporter.Builder()
.WithSender(new UdpSender(jaegerHost, 6831, 0))
.Build();
ITracer tracer = new Tracer.Builder(serviceName)
.WithLoggerFactory(loggerFactory)
.WithReporter(reporter)
.WithSampler(sampler)
.Build();
GlobalTracer.Register(tracer);
return tracer;
});
var jaegerUri = new Uri($"http://{jaegerHost}:14268/api/traces");
// Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger.
services.Configure<HttpHandlerDiagnosticOptions>(options =>
{
options.IgnorePatterns.Add(request => jaegerUri.IsBaseOf(request.RequestUri));
// We don't need to track Prometheus scraping requests
});
services.Configure<AspNetCoreDiagnosticOptions>(options => {
// We don't need to trace Prometheus scraping requests
options.Hosting.IgnorePatterns.Add(context => context.Request.Path.Equals("/metrics", StringComparison.OrdinalIgnoreCase));
});
return services;
}
My startup.cs configure method to show I'm not doing anything weird with the headers (the metrics extensions are for prometheus-net)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHttpMetrics();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// Do release exception handling
}
app.UseMetricServer();
app.UseMvc();
}
I expect any calls from one application to the other to propagate the active Jaeger trace context. Instead, the two applications log their traces separately and no link can be discerned between them in the Jaeger UI.
Here's a screenshot of a trace that should have spanned both services, but instead only shows spans from the first service:
Maybe you should check whether the application services which you set up in a hurry are both in the same azure resource group as the VM running the Jaeger all-in-one instance, otherwise the second application might not be able to communicate with the Jaeger instance at all.
I have a self-hosted Web API application (the server application) that uses Windows authentication.
Windows Auth is enabled in Startup.cs/Configuration by setting the following AuthenticationSchemes on System.Net.HttpListener
System.Net.HttpListener listener = (System.Net.HttpListener)appBuilder.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication
| System.Net.AuthenticationSchemes.Anonymous;
And Controllers then use the [Authorize] tag. I can then extract the Principal.Identity from the HttpRequestContext for every controller method to see who’s making the call.
It appears this is only working if the caller and server are on the same host. As soon as the calling application is on another host, all requests are blocked with a 401 unauthorized and no controller method is ever hit on the server. This is even if the calling application is executed under the same user account that the server. So is there a special config required so Windows authentication on web.api works across different machines?
Regards meisterd
In the Startup class of your WebAPI, add a call to use CORS. You may need to add Microsoft.Owin to you packages if you don't already have it. This should allow access to your api from other hosts.
It should look something like this:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
//... Your other startup code
appBuilder.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);