问题:.NET Core WebAPI 引发IIS应用池异常关闭
Hey there, let's break down how to diagnose and fix your IIS app pool shutdown issue with your .NET Core WebAPI. Here's a step-by-step approach tailored to your scenario:
1. First, Diagnose the Root Cause of App Pool Shutdown
Before jumping into fixes, we need to pinpoint exactly why the app pool is closing:
- Check Event Viewer & IIS Logs
- Open Event Viewer, navigate to Windows Logs > Application, and look for errors from sources like
IIS-W3SVC-WPor.NET Runtime. These entries will tell you if the shutdown is due to unhandled exceptions, memory overflow, CPU spikes, or configuration triggers. - Check your IIS site's log files (default path:
C:\inetpub\logs\LogFiles\W3SVCxxx) for unusual HTTP status codes or error traces during the 500-request burst.
- Open Event Viewer, navigate to Windows Logs > Application, and look for errors from sources like
- Enable Detailed .NET Core Logging
- Update your
appsettings.jsonto capture granular logs for URL checking logic and HTTP calls:
This will help catch unhandled exceptions (like DNS failures, timeouts, or connection leaks) that might be crashing the process.{ "Logging": { "LogLevel": { "Default": "Debug", "Microsoft.AspNetCore": "Debug", "System.Net.Http": "Debug" } } }
- Update your
- Verify App Pool Recycling Configs
- In IIS Manager, right-click your app pool > Advanced Settings:
- Check the Recycling section: Are there memory/CPU limits being hit by 500 concurrent requests? For example, a default private memory limit of 1GB might be too low.
- Check the Process Model section: Ensure "Idle Time-out" isn't set too low (though continuous SPA requests should avoid this).
- In IIS Manager, right-click your app pool > Advanced Settings:
2. Fix the Core Issue: Optimize 500 Individual Requests
The SPA's loop of 500 separate calls is putting unnecessary stress on your server. Let's fix this:
- Add a Batch URL Check Endpoint
- Create a new API endpoint that accepts an array of URLs instead of handling one per request. This cuts 500 HTTP calls down to 1:
[ApiController] [Route("api/urlcheck")] public class UrlCheckController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; private readonly SemaphoreSlim _concurrencyLimiter = new SemaphoreSlim(10); // Limit to 10 concurrent checks public UrlCheckController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } [HttpPost("batch")] public async Task<IActionResult> BatchCheckUrls([FromBody] List<string> urls) { var results = new List<UrlCheckResult>(); foreach (var url in urls) { var result = await CheckSingleUrl(url); results.Add(result); } return Ok(results); } private async Task<UrlCheckResult> CheckSingleUrl(string url) { await _concurrencyLimiter.WaitAsync(); try { var client = _httpClientFactory.CreateClient(); client.Timeout = TimeSpan.FromSeconds(10); client.MaxResponseContentBufferSize = 1024 * 1024; // Reduce memory usage var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); return new UrlCheckResult { OriginalUrl = url, FinalUrl = response.RequestMessage.RequestUri.ToString(), StatusCode = (int)response.StatusCode, Exists = response.IsSuccessStatusCode || (int)response.StatusCode is 301 or 302 }; } catch (Exception ex) { return new UrlCheckResult { OriginalUrl = url, Exists = false, ErrorMessage = ex.Message }; } finally { _concurrencyLimiter.Release(); } } } public class UrlCheckResult { public string OriginalUrl { get; set; } public string FinalUrl { get; set; } public int? StatusCode { get; set; } public bool Exists { get; set; } public string ErrorMessage { get; set; } } - Update your SPA to send the entire 500-URL list to this batch endpoint instead of looping through individual calls.
- Create a new API endpoint that accepts an array of URLs instead of handling one per request. This cuts 500 HTTP calls down to 1:
- Fix HttpClient Usage
- Stop creating a new
HttpClientper request—this causes socket connection leaks. UseIHttpClientFactory(registered inProgram.cswithbuilder.Services.AddHttpClient()) to reuse connections from a pool.
- Stop creating a new
3. Optimize IIS App Pool Settings
- Adjust Recycling Thresholds
- If memory limits are triggering shutdowns, increase the "Private Memory Limit (KB)" in app pool advanced settings (e.g., from 1GB to 2GB, based on your server's resources). You can also disable scheduled recycling if it's not needed.
- Enable "Always Running" Mode
- Set the app pool's "Start Mode" to AlwaysRunning and "Idle Time-out (Minutes)" to 0. This prevents the pool from shutting down due to inactivity and ensures it's ready to handle bursts of requests.
- Tweak Fast Fail Protection
- In app pool settings, enable logging for Fast Fail Protection to track how often the process crashes. Adjust the "Maximum Failures" and "Failure Interval" if the pool is shutting down too aggressively for transient errors.
内容的提问来源于stack exchange,提问作者MysticEarth
相关产品推荐
相关产品推荐

