How to log HTTP requests coming into IIS - http

I run IIS 5 on my dev machine. I have an asp.net 3.5 web service running on it which I'm calling from a different web app running on the same server. My service is returning an error 500 Internal Server error and I'm troubleshooting it. My request is being sent via a System.Net.HttpWebRequest object and it looks valid from the client's perspective.
I'd like to see the raw incoming HTTP request from the server's perspective. Since the service is being called on loopback, I can't use Wireshark to see it.
IIS Logging shows me the request header but not the post content.
Any suggestions on how I could see the full raw incoming HTTP request in IIS?
Thanks

I would think you want to add an HTTPModule for logging. Here's a pretty good article on ASP.NET modules and handlers:
That way, when you want to disable logging, you can just remove/comment it from your web.config file.

Have you tried using Fiddler? Just use your machine name instead of localhost.

Your best bet is to run each of your web apps on a different port, and then use something like Fiddler to create a proxy for the port you want to watch. This will monitor all traffic to and from your specific application.

Here is code of custom HTTP module we use to log HTTP POST request data.
using System;
using System.Web;
namespace MySolution.HttpModules
{
public class HttpPOSTLogger : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
if (sender != null && sender is HttpApplication)
{
var request = (sender as HttpApplication).Request;
var response = (sender as HttpApplication).Response;
if (request != null && response != null && request.HttpMethod.ToUpper() == "POST")
{
var body = HttpUtility.UrlDecode(request.Form.ToString());
if (!string.IsNullOrWhiteSpace(body))
response.AppendToLog(body);
}
}
}
}
}
Do not forget to register it in web.config of you application.
Use system.WebServer section for IIS Integrated Model
<system.webServer>
<modules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules" />
</modules>
</system.webServer>
Use system.web section for IIS Classic Model
<system.web>
<httpModules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules"/>
</httpModules>
</system.web>
IIS log Before applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, -,
IIS log After applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, {"model":{"Platform":"Mobile","EntityID":"420003"}},
Full article:
https://www.codeproject.com/Tips/1213108/HttpModule-for-logging-HTTP-POST-data-in-IIS-Log

I'm able to log request/response with many data (request body included for http post etc...), all http verbs included (ex: get, post) using IIS Failed Request Tracing
The request does not necessarily needs to fail to be logged as you can specify there any http status like 200, 401 etc or just all (enter 100-999).
You can also just log requests with a specific URL
I'll later implement a custom http module for more control.
Thanks

Related

How to url redirect/rewrite .asp into .aspx

I'm running in the Cassini developer server inside Visual Studio 2012, and I need to redirect clients from the legacy .asp pages to .aspx pages.
Note: Ideally I would redirect clients from .asp to a friendly url, and then internally do a rewrite to .aspx
POST /ResetClock.asp
HTTP/1.1 307 Temporary Redirect
Location: //stackoverflow.us/ResetClock
And then internally:
POST /ResetClock
rewrites into /ResetClock.ashx (Yes, I changed it to .ashx; that's the virtue of url rewriting).
Like what Hanselman did
This is a lot like what Scott Hanselman did:
Request for /foo.html
gives the client a redirect to /foo
client request for /foo
is re-written into /foo.html
The attempted hack
I tried the hack solution; alter the .asp page to force a redirect to the .ashx (and live to fight with the url re-write syntax another day):
ResetClock.asp
<%
Response.Redirect("ResetClock.aspx")
Response.End
%>
Except that Cassini does not serve .asp pages at all:
This type of page is not served.
Description: The type of page you have requested is not served because it has been explicitly forbidden. The extension '.asp' may be incorrect. Please review the URL below and make sure that it is spelled correctly.
Requested URL: /WebSite/FetchTimes.asp
Which points to a related issue. The solution I end up using cannot require anything that isn't already available on the IIS7.5. And it cannot require anything that needs access to the IIS Admin tools; and must exist entirely within the web-site (e.g. the web.config).
The question
How do I re-write .asp into something more ASP.net-ish?
Edit: Changed GET to a POST to thwart nitpickers who wonder why the 307 Temporary Redirect and not 302 Found or 303 See Other.
The solution is to create an IHttpModule. HttpModules let you intercept every request, and react as you desire.
The first step is to create the plumbing of an IHttpModule:
class UrlRewriting : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(this.Application_BeginRequest);
application.EndRequest += new EventHandler(this.Application_EndRequest);
}
public void Dispose()
{
//Nothing to do here
}
private void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
}
private void Application_EndRequest(object sender, EventArgs e)
{
}
}
And then register our HttpHandler in the web.config file:
web.config:
<configuration>
<system.web>
<httpModules>
<add name="UrlRewriting" type="UrlRewriting"/>
</httpModules>
</system.web>
</configuration>
Now we have a method (Application_BeginRequest) that will run every time a request is made.
Issue client redirect if they ask for ASP page
The first order of business is redirect the client to a "clean" form. For example, a request for /File.asp is redirected to /File:
private void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
//Redirct any requests to /File.asp into a /File
if (context.Request.Url.LocalPath == VirtualPathUtility.ToAbsolute("~/File.asp"))
{
//Be sure to issue a 307 Temporary Redirect in case the client issued a POST (i.e. a non-GET)
//If we issued 302 Found, a buggy client (e.g. Chrome, IE, Firefox) might convert the POST to a GET.
//If we issued 303 See Other, the client is required to convert a POST to a GET.
//If we issued 307 Temporary Redirect, the client is required to keep the POST method
context.Response.StatusCode = (int)HttpStatusCode.TemporaryRedirect;
context.Response.RedirectLocation = VirtualPathUtility.ToAbsolute("~/File");
context.Response.End();
}
}
And then the internal rewrite
Now that the client will be asking for /File, we have to re-write that internally to an .aspx, or in my case, an .ashx file:
private void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
//Redirct any requests to /ResetClock.asp into a /File
if (context.Request.Url.LocalPath == VirtualPathUtility.ToAbsolute("~/ResetClock.asp"))
{
//Be sure to issue a 307 Temporary Redirect in case the client issued a POST (i.e. a non-GET)
//If we issued 302 Found, the buggy client might convert the POST to a GET.
//If we issued 303 See Other, the client is required to convert a POST to a GET.
//If we issued 307 Temporary Redirect, the client is required to keep the POST method
context.Response.StatusCode = (int)HttpStatusCode.TemporaryRedirect;
context.Response.RedirectLocation = VirtualPathUtility.ToAbsolute("~/ResetClock");
context.Response.End();
}
//Rewrite clean url into actual handler
if (context.Request.Url.LocalPath == VirtualPathUtility.ToAbsolute("~/ResetClock"))
{
String path = "~/ResetClock.ashx"; //no need to map the path
context.Server.Execute(path, true);
//The other page has been executed
//Do not continue or we will hit the 404 of /ResetClock not being found
context.Response.End();
}
}
IIS contains some basic url redirection
Starting with some unknown version of IIS, they added a (now mocked) form of URL Rewriting. It doesn't issuing a client redirect, only an internal re-write. But at least it could be used to solve my problem (responding to an ASP page with ASP.net content):
web.config
<configuration>
<system.web>
<urlMappings>
<add url="~/ResetClock.asp" mappedUrl="~/ResetClock.ashx"/>
</urlMappings>
</system.web>
</configuration>
The client will still appear to have found a resource at /ResetClock.asp, but the guts of the response will have come from /ResetClock.ashx.
Note: Any code is released into the public domain. No attribution required.

SignalR connection issues

I'm getting some issues with SignalR (1.1.2) trying to create a basic realtime chat setup and after spending about a week on it (including trawling through the SignalR source) I'm sort of at the end of what I can try...
I have (I think) a rather complicated SignalR setup consisting of:
Load balanced servers
Redis message bus
Two sites on each server (ASP.NET Webforms VB.NET desktop site and MVC3 C# mobile site)
Each of the sites includes the hub of itself and the other site, so each page can send messages to each site.
Looking into the Chrome inspector (in this example on the mobile site), the hubs are both loaded, the negotiate step for mobile is successful but the connect attempt fails after 3 seconds with the error:
EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection.
which is of course our custom 500 error page after Microsoft.Owin.Host.SystemWeb has thrown:
The connection id is in the incorrect format.
Once this happens, most of the time this will then get into some sort of weird loop where it will continue to throw hundreds of these errors and send off lots of pings followed by a longPolling connect
The solution works perfectly well in my development environment (single IIS instance) but moving to the load balanced test environment is where I see the errors.
I don't know if there's anything else I can add that may help but I'm happy to add it.
I've added the following to the web.config files on both sites:
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
and
<add name="Access-Control-Allow-Origin" value="*"></add>
<add name="Access-Control-Allow-Headers" value="Content-Type" />
The global.asax files have:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
RedisScaleoutConfiguration redisConfig = new RedisScaleoutConfiguration([redisIP], [port], String.Empty, "Name");
redisConfig.Database = 9;
GlobalHost.DependencyResolver.UseRedis(redisConfig);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
HubConfiguration hubConfig = new HubConfiguration();
hubConfig.EnableCrossDomain = true;
hubConfig.EnableDetailedErrors = true;
RouteTable.Routes.MapHubs(hubConfig);
<snip>
}
The JS code I have is along the lines of:
function setUpSignalR() {
//Set up the connections
webConnection = $.hubConnection(pageInfo.webUrl);
mobConnection = $.hubConnection(pageInfo.mobUrl);
//Get the hubs for web and mobile
webHub = webConnection.createHubProxies().messagingHub;
mobHub = mobConnection.createHubProxies().messagingHub;
//Hook up the call back functions
<snip>
//Now, start it up!
mobConnection.logging = true;
mobConnection.start().done(function() {
mobHub.server.joinConversation(pageInfo.conversationGuid, "mobile").fail(function (error) { console.log('JoinConversation for mobile connection failed. Error: ' + error); });
webConnection.start().done(function() {
webHub.server.joinConversation(pageInfo.conversationGuid, "mobile").fail(function (error) { console.log('JoinConversation for web connection failed. Error: ' + error); });
});
});
}
From the SignalR troubleshooting document:
"The connection ID is in the incorrect format" or "The user identity
cannot change during an active SignalR connection" error
This error may be seen if authentication is being used, and the client
is logged out before the connection is stopped. The solution is to
stop the SignalR connection before logging the client out.

ASHX sends HttpWebRequest with Impersonation On, which works to URLs on same server but not on Remote ArcGIS server

This is a complicated issue, so bear with me.
Scenario: using a ASHX proxy to relay request to an ArcGIS server.
Trying to use ASP.NET impersonation, so that the logged in ASP.NET user credentials are used by the proxy, when sending request to the ArcGIS server.
Issue: the proxy request to ArcGIS server is refused 401, even though I know the impersonated account (sean.ryan-B + sean.ryan) does have access.
There are 4 machines:
1. machine hosting proxy page. I am logged in as: sean.ryan-B
2. a test machine. I am logged in as sean.ryan-B
3. my laptop. I am logged in as sean.ryan
4. the arcgis server.
All 4 machines are on the same domain.
web.config:
<authentication mode="Windows"/>
<identity impersonate="true" /> <!-- userName="EUROPE\sean.ryan-B" password="xxx" -->
<authorization>
<deny users="?"/>
</authorization>
Test-1. Opening a test page, in same web app as proxy, via the proxy:
http://myHost.com/sean/ProxyAsp.Net/ArcGisProxy.ashx?http://myHost.com/sean/ProxyAsp.Net
[ok on all boxes 1-3]
This looks OK - the impersonation seems look OK,
since with impersonation OFF: WindowsIdentity.GetCurrent().Name = the AppPool account
with impersonation ON: WindowsIdentity.GetCurrent().Name = EUROPE\sean.ryan or EUROPE\sean.ryan-B
Test-2. opening an image that is hosted on the same IIS (but a different site), via the proxy:
http://myHost.com/sean/ProxyAsp.Net/ArcGisProxy.ashx?http://myHost.com:10400/sites/CaSPER/SiteAssets/CaSPER.jpg
[ok on boxes 1-3]
Test-3. opening the ArcGIS map URL, via the proxy:
http://myHost.com/sean/ProxyAsp.Net/ArcGisProxy.ashx?http://mapserver1.com/ArcGIS/rest/services/Global/2D_BaseMap_SurfaceGeology/MapServer?f=json&callback=dojo.io.script.jsonp_dojoIoScript1._jsonpCallback
[fails on boxes 2,3 but succeeds on the proxy host (box 1)!]
code for the ASHX code-behind:
public partial class ArcGisProxy : IHttpHandler, IReadOnlySessionState //ASHX implements IReadOnlySessionState in order to be able to read from session
{
public void ProcessRequest(HttpContext context)
{
try
{
HttpResponse response = context.Response;
// Get the URL requested by the client (take the entire querystring at once
// to handle the case of the URL itself containing querystring parameters)
string uri = context.Request.Url.Query;
uri = uri.Substring(1); //the Substring(1) is to skip the ?, in order to get the request URL.
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)WebRequest.Create(uri);
{
req.Credentials = CredentialCache.DefaultCredentials; //this works on local box, with -B account. this is the account the web browser is running under (rather than the account logged into CaSPER with, as ASHX has separate server session).
req.ImpersonationLevel = TokenImpersonationLevel.Impersonation;
}
//to turn off caching: req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
req.Method = context.Request.HttpMethod;
req.ServicePoint.Expect100Continue = false;
req.Referer = context.Request.Headers["referer"];
// Set body of request for POST requests
req.Method = "GET";
// Send the request to the server
System.Net.WebResponse serverResponse = null;
try
{
serverResponse = req.GetResponse();
}
catch (System.Net.WebException webExc)
{
//logger.Log(GetMyUrl(), webExc, context.Request);
response.StatusCode = 500;
response.StatusDescription = webExc.Status.ToString();
response.Write(webExc.ToString());
response.Write(webExc.Response);
response.Write("Username = " + context.User.Identity.Name + " " + context.User.Identity.IsAuthenticated + " " + context.User.Identity.AuthenticationType);
response.End();
return;
}
// Set up the response to the client
....
......
response.End();
}
catch (Exception ex)
{
throw;
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
note: the following changes, meant proxy request to the map server DOES succeed:
a) set the identity in the web.config to explicitly set username, password to the sean.ryan-B account:
-OR-
b) set the App Pool account to be sean.ryan-B and turn OFF impersonation in the web.config file.
however these changes are not acceptable for Production.
The problem seems to be that:
- ASP.NET impersonation works well enough for test page + image hosted on same IIS (tests 1 and 2)
but NOT well enough for the map server.
as far as I know, the ArcGIS map server is using Negotiate, and then Kerberos authentication.
With WireShark, I monitored a successful proxy request, and found:
after 401, proxy sends GET with AUTH using SPNEGO (Kerberos)
Has anyone had similar issue with ArcGIS proxy ?
My theory is, that the impersonation on box 1 'works better', because browser is running on same box as the proxy.
Could the ArcGIS Server (or the IIS site it is using) be restricted to prevent accepting impersonation ?
Any suggestions welcome ...
p.s. had a hard time getting this post through - had to format most of it as code, as s-o is detecting it as source code !

Prevent FormsAuthenticationModule of intercepting ASP.NET Web API responses

In ASP.NET the FormsAuthenticationModule intercepts any HTTP 401, and returns an HTTP 302 redirection to the login page. This is a pain for AJAX, since you ask for json and get the login page in html, but the status code is HTTP 200.
What is the way of avoid this interception in ASP.NET Web API ?
In ASP.NET MVC4 it is very easy to prevent this interception by ending explicitly the connection:
public class MyMvcAuthFilter:AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction)
{
filterContext.Result = new HttpStatusCodeResult(401);
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.HttpContext.Response.SuppressContent = true;
filterContext.HttpContext.Response.End();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
But in ASP.NET Web API I cannot end the connection explicitly, so even when I use this code the FormsAuthenticationModule intercepts the response and sends a redirection to the login page:
public class MyWebApiAuth: AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase)))
{
var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First();
if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
{
// this does not work either
//throw new HttpResponseException(HttpStatusCode.Unauthorized);
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
return;
}
}
base.HandleUnauthorizedRequest(actionContext);
}
}
What is the way of avoiding this behaviour in ASP.NET Web API? I have been taking a look, and I could not find a way of do it.
Regards.
PS: I cannot believe that this is 2012 and this issue is still on.
In case someone's interested in dealing with the same issue in ASP.NET MVC app using the Authorize attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class Authorize2Attribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden);
}
else
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
This way browser properly distinguishes between Forbidden and Unauthorized requests..
The release notes for MVC 4 RC imply this has been resolved since the Beta - which are you using?
http://www.asp.net/whitepapers/mvc4-release-notes
Unauthorized requests handled by ASP.NET Web API return 401 Unauthroized: Unauthorized requests handled by ASP.NET Web API now return a standard 401 Unauthorized response instead of redirecting the user agent to a login form so that the response can be handled by an Ajax client.
Looking into the source code for MVC there appears to be an functionality added via SuppressFormsAuthRedirectModule.cs
http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs.
internal static bool GetEnabled(NameValueCollection appSettings)
{
// anything but "false" will return true, which is the default behavior
So it looks this this is enabled by default and RC should fix your issue without any heroics... as a side point it looks like you can disable this new module using AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:
<appSettings>
<Add Key = "webapi:EnableSuppressRedirect" value = "false" />
</appSettings>
Edit (example and clarification)
I have now created an example for this approach on GitHub. The new redirection suppression requires that you use the two correct "Authorise" attribute's; MVC Web [System.Web.Mvc.Authorize] and Web API [System.Web.Http.Authorize] in the controllers AND/OR in the global filters Link.
This example does however draw out a limitation of the approach. It appears that the "authorisation" nodes in the web.config will always take priority over MVC routes e.g. config like this will override your rules and still redirect to login:
<system.web>
<authentication mode="Forms">
</authentication>
<authorization>
<deny users="?"/> //will deny anonymous users to all routes including WebApi
</authorization>
</system.web>
Sadly opening this up for some url routes using the Location element doesn't appear to work and the WebApi calls will continue to be intercepted and redirected to login.
Solutions
For MVC applications I am simply suggest removing the config from Web.Config and sticking with Global filters and Attributes in the code.
If you must use the authorisation nodes in Web.Config for MVC or have a Hybrid ASP.NET and WebApi application then #PilotBob - in the comments below - has found that sub folders and multiple Web.Config's can be used to have your cake and eat it.
I was able to get around the deny anonymous setting in web.config by setting the following property:
Request.RequestContext.HttpContext.SkipAuthorization = true;
I do this after some checks against the Request object in the Application_BeginRequest method in Global.asax.cs, like the RawURL property and other header information to make sure the request is accessing an area that I want to allow anonymous access to. I still perform authentication/authorization once the API action is called.

IIS 7.0 503 errors with generic handler (.ashx) implementing IHttpAsyncHandler

I'm running into some performance issues using a generic handler that implements IHttpAsyncHandler. At its simplest, the handler receives a GET request, and 20 seconds later ends the response after writing '< timeout / >' to the response.
When hammering the .ashx with 10000-20000 simultaneous requests, it fails with 503 server unavailable after precisely 5000 requests. When switching to synchronous mode, and ending the request immediately, the problem goes away.
I've tinkered with a number of settings, yet the only thing I've managed to acheive is lower the request threshold at which this error occurs.
Here's a rundown of the settings I've toyed with:
machine.config:
<configuration>
...
<system.web>
...
<processModel enable="true" requestQueueLimit="10000"/>
...
web.config:
<configuration>
...
<system.web>
...
<httpRuntime enable="true" appRequestQueueLimit="10000"/>
...
IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535
Although I can't be sure, it seems like these settings work good and fine if the requests are synchronous, but when async, I can't seem to get beyond exactly 5000 requests before the server starts telling me to go away. If I set things lower (can't remember exactly which setting that would be from the above, but I've tried them all), then the 503 count goes up accordingly, but I can never stop it happening beyond 5000 when under serious load.
It seems that there a a number of settings scattered in a myriad of places that might affect this, but the 5000 seems fairly set in stone. I see here that appRequestQueueLimit cannot exceed 5000, but can find no further info about this, and wonder if this is misinformation.
Is there any kind of "flood-control" setting in IIS that might be limiting a single host to no more than 5000 requests? How can I get IIS to handle more that 5000 concurrent asynchronous requests?
Edit2: Are there any counters or other indicators of which limit might be being exceeded, and how would I investigate further?
Edit: Here's the loadgenerator code:
using System;
using System.Net;
using System.Threading;
namespace HammerTime
{
class Program
{
private static int counter = 0;
static void Main(string[] args)
{
var limit = 5000;
ServicePointManager.DefaultConnectionLimit=limit;
for (int i = 0; i < limit;++i )
{
StartWebRequest(i.ToString());
}
Console.ReadLine();
}
private static void StartWebRequest(string channelId)
{
string uri = "http://spender2008/test/Test.ashx?channel="+channelId;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.BeginGetResponse(responseHandler, request);
}
private static void responseHandler(IAsyncResult ar)
{
try
{
HttpWebRequest state = (HttpWebRequest)ar.AsyncState;
HttpWebResponse response = (HttpWebResponse)state.EndGetResponse(ar);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.WriteLine(Interlocked.Increment(ref counter));
}
}
}
}
OK. Fixed... many thanks to this post for clearing up a few details.
To eliminate the 503 errors required 3 different config changes:
machine.config:
<configuration>
...
<system.web>
...
<processModel enable="true" requestQueueLimit="100000"/>
IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535
and finally (the missing piece of the puzzle), the command line:
appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000
The web.config setting mentioned in the main post was irrelevant.
10000 concurrent connections, no problems. Thanks for help!

Resources