From 147df8de1e5162d7adb5fb86660f6619c5d41e10 Mon Sep 17 00:00:00 2001 From: MaxDeg Date: Thu, 7 May 2020 17:37:43 +0200 Subject: [PATCH] use Kestrel for the test to ensure proper behavior of the Response buffer replace use by let, because StreamWriter.Dispose is calling flush which is not permitted in AspNet Core 3.x by default --- .paket/Paket.Restore.targets | 975 ++++++++++++++++++----------------- src/ThothSerializer.fs | 12 +- tests/ThothSerializer.fs | 24 +- 3 files changed, 510 insertions(+), 501 deletions(-) diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets index a795558..0ec2816 100644 --- a/.paket/Paket.Restore.targets +++ b/.paket/Paket.Restore.targets @@ -1,481 +1,494 @@ - - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - $(MSBuildVersion) - 15.0.0 - false - true - - true - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)..\ - $(PaketRootPath)paket-files\paket.restore.cached - $(PaketRootPath)paket.lock - classic - proj - assembly - native - /Library/Frameworks/Mono.framework/Commands/mono - mono - - - $(PaketRootPath)paket.bootstrapper.exe - $(PaketToolsPath)paket.bootstrapper.exe - $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\ - - "$(PaketBootStrapperExePath)" - $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" - - - - - true - true - - - True - - $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/')) - - - - - - - - - - - - - dotnet paket - - - - - - $(PaketRootPath)paket.exe - $(PaketToolsPath)paket.exe - $(PaketToolsPath)paket.exe - $(_PaketBootStrapperExeDir)paket.exe - paket.exe - - - $(PaketRootPath)paket - $(PaketToolsPath)paket - $(PaketToolsPath)paket - - - $(PaketRootPath)paket.exe - $(PaketToolsPath)paket.exe - - - $(PaketBootStrapperExeDir)paket.exe - - - paket - - <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) - dotnet "$(PaketExePath)" - $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" - "$(PaketExePath)" - - - - - - - - - - - - - - - - - - - - - - true - $(NoWarn);NU1603;NU1604;NU1605;NU1608 - false - true - - - - - - - - - $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) - - - - - - - $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``)) - $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``)) - - - - - %(PaketRestoreCachedKeyValue.Value) - %(PaketRestoreCachedKeyValue.Value) - - - - - true - false - true - - - - - true - - - - - - - - - - - - - - - - - - - $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached - - $(MSBuildProjectFullPath).paket.references - - $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references - - $(MSBuildProjectDirectory)\paket.references - - false - true - true - references-file-or-cache-not-found - - - - - $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) - $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) - references-file - false - - - - - false - - - - - true - target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) - - - - - - - - - - - false - true - - - - - - - - - - - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5]) - - - %(PaketReferencesFileLinesInfo.PackageVersion) - All - runtime - runtime - true - true - - - - - $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools - - - - - - - - - $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) - $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) - - - %(PaketCliToolFileLinesInfo.PackageVersion) - - - - - - - - - - false - - - - - - <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/> - - - - - - $(MSBuildProjectDirectory)/$(MSBuildProjectFile) - true - false - true - false - true - false - true - false - true - $(PaketIntermediateOutputPath)\$(Configuration) - $(PaketIntermediateOutputPath) - - - - <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/> - - - - - - - - - - - - - - - - - - - - - + + + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + $(MSBuildVersion) + 15.0.0 + false + true + + true + $(MSBuildThisFileDirectory) + $(MSBuildThisFileDirectory)..\ + $(PaketRootPath)paket-files\paket.restore.cached + $(PaketRootPath)paket.lock + classic + proj + assembly + native + /Library/Frameworks/Mono.framework/Commands/mono + mono + + + $(PaketRootPath)paket.bootstrapper.exe + $(PaketToolsPath)paket.bootstrapper.exe + $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\ + + "$(PaketBootStrapperExePath)" + $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" + + + + + true + true + + + True + + + False + + $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/')) + + + + + + + + + $(PaketRootPath)paket + $(PaketToolsPath)paket + + + + + + $(PaketRootPath)paket.exe + $(PaketToolsPath)paket.exe + + + + + + <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json")) + <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"')) + <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false + + + + + + + + + + + <_PaketCommand>dotnet paket + + + + + + $(PaketToolsPath)paket + $(PaketBootStrapperExeDir)paket + + + paket + + + + + <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) + <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)" + <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" + <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)" + + + + + + + + + + + + + + + + + + + + + true + $(NoWarn);NU1603;NU1604;NU1605;NU1608 + false + true + + + + + + + + + $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) + + + + + + + $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``)) + $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``)) + + + + + %(PaketRestoreCachedKeyValue.Value) + %(PaketRestoreCachedKeyValue.Value) + + + + + true + false + true + + + + + true + + + + + + + + + + + + + + + + + + + $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached + + $(MSBuildProjectFullPath).paket.references + + $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references + + $(MSBuildProjectDirectory)\paket.references + + false + true + true + references-file-or-cache-not-found + + + + + $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) + $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) + references-file + false + + + + + false + + + + + true + target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) + + + + + + + + + + + false + true + + + + + + + + + + + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5]) + + + %(PaketReferencesFileLinesInfo.PackageVersion) + All + runtime + runtime + true + true + + + + + $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools + + + + + + + + + $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) + $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) + + + %(PaketCliToolFileLinesInfo.PackageVersion) + + + + + + + + + + false + + + + + + <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/> + + + + + + $(MSBuildProjectDirectory)/$(MSBuildProjectFile) + true + false + true + false + true + false + true + false + true + $(PaketIntermediateOutputPath)\$(Configuration) + $(PaketIntermediateOutputPath) + + + + <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/> + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ThothSerializer.fs b/src/ThothSerializer.fs index a7239b1..3074dce 100644 --- a/src/ThothSerializer.fs +++ b/src/ThothSerializer.fs @@ -19,8 +19,8 @@ type ThothSerializer (?caseStrategy : CaseStrategy, ?extra : ExtraCoders, ?skipN fun (next: HttpFunc) (ctx: HttpContext) -> task { ctx.SetContentType "application/json; charset=utf-8" - use stream = new System.IO.StreamWriter(ctx.Response.Body, Utf8EncodingWithoutBom, DefaultBufferSize, true) - use jsonWriter = new JsonTextWriter(stream) + let stream = new System.IO.StreamWriter(ctx.Response.Body, Utf8EncodingWithoutBom, DefaultBufferSize, true) + let jsonWriter = new JsonTextWriter(stream) do! body.WriteToAsync(jsonWriter) do! jsonWriter.FlushAsync() return Some ctx @@ -37,9 +37,9 @@ type ThothSerializer (?caseStrategy : CaseStrategy, ?extra : ExtraCoders, ?skipN task { ctx.SetStatusCode 200 ctx.SetContentType "application/json; charset=utf-8" - use stream = + let stream = new System.IO.StreamWriter(ctx.Response.Body, Utf8EncodingWithoutBom, DefaultBufferSize, true) - use jsonWriter = new JsonTextWriter(stream) + let jsonWriter = new JsonTextWriter(stream) jsonWriter.WriteStartArray() for item in items do do! item.WriteToAsync(jsonWriter) @@ -125,8 +125,8 @@ type ThothSerializer (?caseStrategy : CaseStrategy, ?extra : ExtraCoders, ?skipN // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#Directives member __.SerializeToStreamAsync (o : 'T) (stream : Stream) = upcast task { - use streamWriter = new System.IO.StreamWriter(stream, Utf8EncodingWithoutBom, DefaultBufferSize, true) - use jsonWriter = new JsonTextWriter(streamWriter) + let streamWriter = new System.IO.StreamWriter(stream, Utf8EncodingWithoutBom, DefaultBufferSize, true) + let jsonWriter = new JsonTextWriter(streamWriter) let encoder = Encode.Auto.generateEncoderCached<'T>(?caseStrategy=caseStrategy, ?extra=extra, ?skipNullField=skipNullField) do! (encoder o).WriteToAsync(jsonWriter) do! jsonWriter.FlushAsync() diff --git a/tests/ThothSerializer.fs b/tests/ThothSerializer.fs index 7ba105d..01d11e4 100644 --- a/tests/ThothSerializer.fs +++ b/tests/ThothSerializer.fs @@ -1,15 +1,11 @@ module Tests.ThothSerializer open System -open System.Net open System.Net.Http -open Microsoft.AspNetCore open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Hosting -open Microsoft.AspNetCore.TestHost open Microsoft.Extensions.Hosting -open Microsoft.Extensions.Logging open Microsoft.Extensions.DependencyInjection open FSharp.Control.Tasks.V2.ContextInsensitive @@ -69,30 +65,30 @@ let createHost () = HostBuilder() .ConfigureServices(Action (fun (services : IServiceCollection) -> services.AddGiraffe() |> ignore)) - .ConfigureWebHost(fun webHost -> - webHost.UseTestServer() |> ignore + .ConfigureWebHostDefaults(fun webHost -> webHost.Configure(Action (fun app -> app.UseGiraffe(webApp) |> ignore)) |> ignore) + .Build() [] let tests = let json = "[{\"id\":1,\"name\":\"Maxime\"},{\"id\":2,\"name\":\"Thoth\"}]" testList "ThothSerializer" [ testTask "Serialization" { - let hostBuilder = createHost () - use! host = hostBuilder.StartAsync () - let client = (host :> IHost).GetTestClient() - let! (response : HttpResponseMessage) = client.GetAsync("/") + let host = createHost () + use _ = host.StartAsync () + let client = new HttpClient() + let! (response : HttpResponseMessage) = client.GetAsync("http://localhost:5000/") let! content = response.EnsureSuccessStatusCode().Content.ReadAsStringAsync() Expect.equal content json "Serialization failure" } testTask "Deserialization" { - let hostBuilder = createHost () - use! host = hostBuilder.StartAsync() - let client = (host :> IHost).GetTestClient() - let! (response : HttpResponseMessage) = client.PostAsync("/", new StringContent(json)) + let host = createHost () + use _ = host.StartAsync () + let client = new HttpClient() + let! (response : HttpResponseMessage) = client.PostAsync("http://localhost:5000/", new StringContent(json)) let! content = response.EnsureSuccessStatusCode().Content.ReadAsStringAsync() Expect.equal content json "Deserialization failure"