Permalink
Browse files

Added an example of a bare async http handler

  • Loading branch information...
1 parent 9b8376f commit aa9406e61aa36806556214832ddcba65bbe179f7 @mikehadlow committed Oct 21, 2011
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TestHttpHandler")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Mike Hadlow")]
+[assembly: AssemblyProduct("TestHttpHandler")]
+[assembly: AssemblyCopyright("Copyright © Mike Hadlow 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c6ae300d-890a-4ab9-afe0-809e4f15a60a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,3 @@
+An example of the simplest possible async http handler.
+
+To play with this TestHttpHandler, configure an IIS web application with a base directory that points to this project's base directory.
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{144EF33E-90D5-41DB-83DC-F9D1B7B62876}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TestHttpHandler</RootNamespace>
+ <AssemblyName>TestHttpHandler</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Web" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="TimerHandler.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Web.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="README.txt" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
@@ -0,0 +1,41 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web;
+
+namespace TestHttpHandler
+{
+ public class TimerHandler : IHttpAsyncHandler
+ {
+ public void ProcessRequest(HttpContext context)
+ {
+ throw new InvalidOperationException("This handler cannot be called synchronously");
+ }
+
+ public bool IsReusable
+ {
+ get { return false; }
+ }
+
+ public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object state)
+ {
+ var taskCompletionSouce = new TaskCompletionSource<bool>(state);
+ var task = taskCompletionSouce.Task;
+
+ var timer = new System.Threading.Timer(timerState =>
+ {
+ context.Response.Write("OK");
+ callback(task);
+ taskCompletionSouce.SetResult(true);
+ });
+ timer.Change(1000, Timeout.Infinite);
+
+ return task;
+ }
+
+ public void EndProcessRequest(IAsyncResult result)
+ {
+ // nothing to do
+ }
+ }
+}
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <system.webServer>
+ <handlers>
+ <add name="TimerHandler" verb="GET" path="timer" type="TestHttpHandler.TimerHandler, TestHttpHandler"/>
+ </handlers>
+ </system.webServer>
+</configuration>
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebStresser.Tests", "WebStr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestTimerService", "TestTimerService\TestTimerService.csproj", "{3059387A-B33C-49B0-9526-B2A5D0A36B01}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestHttpHandler", "TestHttpHandler\TestHttpHandler.csproj", "{144EF33E-90D5-41DB-83DC-F9D1B7B62876}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -47,6 +49,16 @@ Global
{3059387A-B33C-49B0-9526-B2A5D0A36B01}.Release|Mixed Platforms.Build.0 = Release|x86
{3059387A-B33C-49B0-9526-B2A5D0A36B01}.Release|x86.ActiveCfg = Release|x86
{3059387A-B33C-49B0-9526-B2A5D0A36B01}.Release|x86.Build.0 = Release|x86
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Release|Any CPU.Build.0 = Release|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {144EF33E-90D5-41DB-83DC-F9D1B7B62876}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -0,0 +1,33 @@
+using System;
+
+namespace WebStresser.Tests
+{
+ public class RawHttpClientCallingHttpHandler
+ {
+ private static readonly Uri serviceUri = new Uri("http://timerhandler/timer");
+ private const int iterations = 100;
+ private const int intervalMilliseconds = 0;
+
+ /// <summary>
+ /// Make sure the TestHttpHandler is running before trying this test.
+ /// </summary>
+ public static void Call_TestHttpHandler()
+ {
+ var configuration = new HttpCallConfiguration
+ {
+ ServiceUri = serviceUri,
+ Method = HttpMethod.GET,
+ Iterations = iterations,
+ IntervalMilliseconds = intervalMilliseconds,
+ PrintResponse = false,
+ Expect100Continue = false,
+ UseNagleAlgorithm = false,
+ KeepAlive = true
+ };
+
+ var client = new RawHttpClient(configuration, Console.Out);
+
+ client.MakeRawHttpCall();
+ }
+ }
+}
@@ -37,6 +37,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="RawHttpClientCallingHttpHandler.cs" />
<Compile Include="RawHttpClientTests.cs" />
</ItemGroup>
<ItemGroup>
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.IO;
@@ -113,13 +114,11 @@ private void ExecuteRequests(object state)
webRequest.Timeout = configuration.TimeoutMilliseconds;
webRequest.KeepAlive = configuration.KeepAlive;
- var stopwatch = new System.Diagnostics.Stopwatch();
+ var stopwatch = new Stopwatch();
stopwatch.Start();
if (configuration.Method == HttpMethod.POST || configuration.Method == HttpMethod.PUT)
{
- // both GetRequestStream _and_ GetResponse must be aysnc, or both will be
- // called syncronously.
webRequest.BeginGetRequestStream(getRequestStreamAsyncResponse =>
{
using (var stream = webRequest.EndGetRequestStream(getRequestStreamAsyncResponse))
@@ -128,38 +127,46 @@ private void ExecuteRequests(object state)
writer.Write(configuration.PostData);
}
- webRequest.BeginGetResponse(getResponseAsyncResult =>
+ GetResponse(stopwatch, webRequest);
+ }, null);
+ }
+ else
+ {
+ GetResponse(stopwatch, webRequest);
+ }
+ }
+
+ private void GetResponse(Stopwatch stopwatch, HttpWebRequest webRequest)
+ {
+ webRequest.BeginGetResponse(getResponseAsyncResult =>
+ {
+ try
+ {
+ using (var response = webRequest.EndGetResponse(getResponseAsyncResult))
{
- try
- {
- using (var response = webRequest.EndGetResponse(getResponseAsyncResult))
- {
- ConsumeResponse(response);
-
- stopwatch.Stop();
- lock (elapsedLock)
- {
- elapsed.Add(stopwatch.ElapsedMilliseconds);
- }
- }
- }
- catch (WebException webException)
- {
- Interlocked.Increment(ref faulted);
+ ConsumeResponse(response);
- if (!webException.Message.StartsWith("The underlying connection was closed"))
- {
- ConsumeResponse(webException.Response);
- }
- }
- finally
+ stopwatch.Stop();
+ lock (elapsedLock)
{
- Interlocked.Increment(ref completed);
+ elapsed.Add(stopwatch.ElapsedMilliseconds);
}
- }, null);
+ }
+ }
+ catch (WebException webException)
+ {
+ Interlocked.Increment(ref faulted);
- }, null);
- }
+ if (!webException.Message.StartsWith("The underlying connection was closed"))
+ {
+ ConsumeResponse(webException.Response);
+ }
+ }
+ finally
+ {
+ Interlocked.Increment(ref completed);
+ }
+ }, null);
}
public void ConsumeResponse(WebResponse response)

0 comments on commit aa9406e

Please sign in to comment.