diff --git a/src/Nancy.Hosting.Aspnet/NancyHandler.cs b/src/Nancy.Hosting.Aspnet/NancyHandler.cs index 14a1819639..54f14e3aa1 100644 --- a/src/Nancy.Hosting.Aspnet/NancyHandler.cs +++ b/src/Nancy.Hosting.Aspnet/NancyHandler.cs @@ -37,7 +37,7 @@ public async Task ProcessRequest(HttpContextBase httpContext) using(var nancyContext = await this.engine.HandleRequest(request).ConfigureAwait(false)) { - SetNancyResponseToHttpResponse(httpContext, nancyContext.Response); + await SetNancyResponseToHttpResponse(httpContext, nancyContext.Response); } } @@ -118,7 +118,7 @@ private static long GetExpectedRequestLength(IDictionary Body { get; set; } + + public static implicit operator BodyDelegate(Func body) + { + return new BodyDelegate { Body = body }; + } + + public static implicit operator BodyDelegate(Action body) + { + return new BodyDelegate { Body = Wrap(body) }; + } + + private static Func Wrap(Action body) + { + return s => + { + body.Invoke(s); + + return Task.FromResult(new object()); + }; + } + } +} \ No newline at end of file diff --git a/src/Nancy.MSBuild/Nancy.csproj b/src/Nancy.MSBuild/Nancy.csproj index b8d76e3df6..fa25031a25 100644 --- a/src/Nancy.MSBuild/Nancy.csproj +++ b/src/Nancy.MSBuild/Nancy.csproj @@ -356,15 +356,15 @@ Helpers\ExceptionExtensions.cs - - HttpLink.cs - - - HttpLinkBuilder.cs - - - HttpLinkRelation.cs - + + HttpLink.cs + + + HttpLinkBuilder.cs + + + HttpLinkRelation.cs + IAssemblyCatalog.cs @@ -1376,6 +1376,7 @@ Routing\Route.cs + diff --git a/src/Nancy/Bootstrapper/NancyBootstrapperBase.cs b/src/Nancy/Bootstrapper/NancyBootstrapperBase.cs index 4584916cfc..83dca85505 100755 --- a/src/Nancy/Bootstrapper/NancyBootstrapperBase.cs +++ b/src/Nancy/Bootstrapper/NancyBootstrapperBase.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; + using System.IO; using System.Linq; using Nancy.Configuration; @@ -313,7 +314,7 @@ public void Initialise() { ContentType = "image/vnd.microsoft.icon", StatusCode = HttpStatusCode.OK, - Contents = s => s.Write(this.FavIcon, 0, this.FavIcon.Length) + Contents = (Action)(s => s.Write(this.FavIcon, 0, this.FavIcon.Length)) }; response.Headers["Cache-Control"] = "public, max-age=604800, must-revalidate"; diff --git a/src/Nancy/Diagnostics/DiagnosticsViewRenderer.cs b/src/Nancy/Diagnostics/DiagnosticsViewRenderer.cs index 532799feb8..a7966c153d 100644 --- a/src/Nancy/Diagnostics/DiagnosticsViewRenderer.cs +++ b/src/Nancy/Diagnostics/DiagnosticsViewRenderer.cs @@ -73,7 +73,7 @@ private static Stream GetBodyStream(string name) var stream = new MemoryStream(); - view.Contents.Invoke(stream); + view.Contents.Body.Invoke(stream).Wait(); stream.Position = 0; return stream; } diff --git a/src/Nancy/ErrorHandling/DefaultStatusCodeHandler.cs b/src/Nancy/ErrorHandling/DefaultStatusCodeHandler.cs index 365519dfbd..41ee944977 100644 --- a/src/Nancy/ErrorHandling/DefaultStatusCodeHandler.cs +++ b/src/Nancy/ErrorHandling/DefaultStatusCodeHandler.cs @@ -1,5 +1,6 @@ namespace Nancy.ErrorHandling { + using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -127,13 +128,13 @@ private void ModifyResponse(HttpStatusCode statusCode, NancyContext context, Def } context.Response.ContentType = "text/html"; - context.Response.Contents = s => + context.Response.Contents = (Action)(s => { using (var writer = new StreamWriter(new UnclosableStreamWrapper(s), Encoding.UTF8)) { writer.Write(contents); } - }; + }); } private static string LoadResource(string filename) diff --git a/src/Nancy/HeadResponse.cs b/src/Nancy/HeadResponse.cs index 3c74cc5522..983507619b 100644 --- a/src/Nancy/HeadResponse.cs +++ b/src/Nancy/HeadResponse.cs @@ -23,11 +23,11 @@ public class HeadResponse : Response public HeadResponse(Response response) { this.innerResponse = response; - this.Contents = stream => + this.Contents = (Func)(async stream => { - this.CheckAndSetContentLength(this.innerResponse); + await this.CheckAndSetContentLength(this.innerResponse); GetStringContents(string.Empty)(stream); - }; + }); this.ContentType = response.ContentType; this.Headers = response.Headers; this.StatusCode = response.StatusCode; @@ -48,7 +48,7 @@ public override Task PreExecute(NancyContext context) return this.innerResponse.PreExecute(context); } - private void CheckAndSetContentLength(Response response) + private async Task CheckAndSetContentLength(Response response) { if (this.Headers.ContainsKey(ContentLength)) { @@ -57,7 +57,7 @@ private void CheckAndSetContentLength(Response response) using (var nullStream = new NullStream()) { - response.Contents.Invoke(nullStream); + await response.Contents.Body.Invoke(nullStream); this.Headers[ContentLength] = nullStream.Length.ToString(CultureInfo.InvariantCulture); } diff --git a/src/Nancy/Jsonp.cs b/src/Nancy/Jsonp.cs index f20311ed9b..2debbb614f 100644 --- a/src/Nancy/Jsonp.cs +++ b/src/Nancy/Jsonp.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; + using System.Threading.Tasks; using Nancy.Bootstrapper; using Nancy.Configuration; using Nancy.Json; @@ -73,7 +74,7 @@ private static void PrepareJsonp(NancyContext context) // http://stackoverflow.com/questions/111302/best-content-type-to-serve-jsonp context.Response.ContentType = string.Concat("application/javascript", Encoding); - context.Response.Contents = stream => + context.Response.Contents = (Func)(async stream => { // disposing of stream is handled elsewhere var writer = new StreamWriter(stream) @@ -82,9 +83,9 @@ private static void PrepareJsonp(NancyContext context) }; writer.Write("{0}(", callback); - original(stream); + await original.Body.Invoke(stream); writer.Write(");"); - }; + }); } } } diff --git a/src/Nancy/Owin/NancyMiddleware.cs b/src/Nancy/Owin/NancyMiddleware.cs index 34a299cb71..1a919812ea 100644 --- a/src/Nancy/Owin/NancyMiddleware.cs +++ b/src/Nancy/Owin/NancyMiddleware.cs @@ -152,16 +152,15 @@ private static Task RequestComplete( .ToArray(); } - nancyResponse.Contents(owinResponseBody); + using (context) + { + return nancyResponse.Contents.Body.Invoke(owinResponseBody); + } } else { return next(environment); } - - context.Dispose(); - - return TaskHelpers.CompletedTask; } private static T Get(IDictionary env, string key) diff --git a/src/Nancy/Response.cs b/src/Nancy/Response.cs index 6511953cf7..fdc9923608 100644 --- a/src/Nancy/Response.cs +++ b/src/Nancy/Response.cs @@ -61,7 +61,7 @@ public string ContentType /// /// An delegate, containing the code that will render contents to the response stream. /// The host of Nancy will pass in the output stream after the response has been handed back to it by Nancy. - public Action Contents { get; set; } + public BodyDelegate Contents { get; set; } /// /// Gets the collection of HTTP response headers that should be sent back to the client. diff --git a/src/Nancy/Responses/EmbeddedFileResponse.cs b/src/Nancy/Responses/EmbeddedFileResponse.cs index 8bd637df9a..5b166734e2 100644 --- a/src/Nancy/Responses/EmbeddedFileResponse.cs +++ b/src/Nancy/Responses/EmbeddedFileResponse.cs @@ -7,6 +7,7 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; + using System.Threading.Tasks; /// /// Represent an HTML response with embeded file content. @@ -42,17 +43,17 @@ public EmbeddedFileResponse(Assembly assembly, string resourcePath, string name) content.Seek(0, SeekOrigin.Begin); } - this.Contents = stream => + this.Contents = (Func)(async stream => { if (content != null) { - content.CopyTo(stream); + await content.CopyToAsync(stream); } else { stream.Write(ErrorText, 0, ErrorText.Length); } - }; + }); } private Stream GetResourceContent(Assembly assembly, string resourcePath, string name) diff --git a/src/Nancy/Responses/MaterialisingResponse.cs b/src/Nancy/Responses/MaterialisingResponse.cs index fe85e4e479..99533d6b90 100644 --- a/src/Nancy/Responses/MaterialisingResponse.cs +++ b/src/Nancy/Responses/MaterialisingResponse.cs @@ -25,15 +25,16 @@ public class MaterialisingResponse : Response /// /// Task for completion/erroring /// - public override Task PreExecute(NancyContext context) + public override async Task PreExecute(NancyContext context) { using (var memoryStream = new MemoryStream()) { - this.sourceResponse.Contents.Invoke(memoryStream); + await this.sourceResponse.Contents.Body.Invoke(memoryStream); + this.oldResponseOutput = memoryStream.ToArray(); } - return base.PreExecute(context); + await base.PreExecute(context); } /// @@ -49,18 +50,18 @@ public MaterialisingResponse(Response sourceResponse) this.StatusCode = sourceResponse.StatusCode; this.ReasonPhrase = sourceResponse.ReasonPhrase; - this.Contents = WriteContents; + this.Contents = (Func)WriteContents; } - private void WriteContents(Stream stream) + private async Task WriteContents(Stream stream) { if (this.oldResponseOutput == null) { - this.sourceResponse.Contents.Invoke(stream); + await this.sourceResponse.Contents.Body.Invoke(stream); } else { - stream.Write(this.oldResponseOutput, 0, this.oldResponseOutput.Length); + await stream.WriteAsync(this.oldResponseOutput, 0, this.oldResponseOutput.Length); } } } diff --git a/src/Nancy/Responses/Negotiation/XmlProcessor.cs b/src/Nancy/Responses/Negotiation/XmlProcessor.cs index 0ad16de0c2..4f90077746 100644 --- a/src/Nancy/Responses/Negotiation/XmlProcessor.cs +++ b/src/Nancy/Responses/Negotiation/XmlProcessor.cs @@ -2,7 +2,9 @@ { using System; using System.Collections.Generic; + using System.IO; using System.Linq; + using System.Net.Mime; /// /// Processes the model for xml media types and extension. @@ -83,13 +85,13 @@ private static Response CreateResponse(dynamic model, ISerializer serializer) { return new Response { - Contents = stream => + Contents = (Action)(stream => { if (model != null) { serializer.Serialize("application/xml", model, stream); } - }, + }), ContentType = "application/xml", StatusCode = HttpStatusCode.OK }; diff --git a/src/Nancy/Responses/TextResponse.cs b/src/Nancy/Responses/TextResponse.cs index 4c998efa6e..03c468b2ae 100644 --- a/src/Nancy/Responses/TextResponse.cs +++ b/src/Nancy/Responses/TextResponse.cs @@ -1,6 +1,8 @@ namespace Nancy.Responses { + using System; using System.Collections.Generic; + using System.IO; using System.Text; using Nancy.Cookies; @@ -36,11 +38,11 @@ public TextResponse(string contents, string contentType = null, Encoding encodin if (contents != null) { - this.Contents = stream => + this.Contents = (Action)(stream => { var data = encoding.GetBytes(contents); stream.Write(data, 0, data.Length); - }; + }); } } @@ -66,11 +68,11 @@ public TextResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string conten if (contents != null) { - this.Contents = stream => + this.Contents = (Action)(stream => { var data = encoding.GetBytes(contents); stream.Write(data, 0, data.Length); - }; + }); } if (headers != null)