Skip to content

Commit a577735

Browse files
committed
Use await to call async Service Responses
1 parent 762bd6d commit a577735

5 files changed

Lines changed: 165 additions & 53 deletions

File tree

src/ServiceStack.Core.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceStack.Server", "Serv
5656
EndProject
5757
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceStack.Wire", "ServiceStack.Wire\ServiceStack.Wire.csproj", "{867FACE8-26A1-426C-9450-5CD30ECEF745}"
5858
EndProject
59+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreWeb.Tests", "..\tests\NetCoreWeb.Tests\NetCoreWeb.Tests.csproj", "{CF9874FE-8937-44CF-98C4-88811DF88DF4}"
60+
EndProject
5961
Global
6062
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6163
Debug|Any CPU = Debug|Any CPU
@@ -126,6 +128,10 @@ Global
126128
{867FACE8-26A1-426C-9450-5CD30ECEF745}.Debug|Any CPU.Build.0 = Debug|Any CPU
127129
{867FACE8-26A1-426C-9450-5CD30ECEF745}.Release|Any CPU.ActiveCfg = Release|Any CPU
128130
{867FACE8-26A1-426C-9450-5CD30ECEF745}.Release|Any CPU.Build.0 = Release|Any CPU
131+
{CF9874FE-8937-44CF-98C4-88811DF88DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
132+
{CF9874FE-8937-44CF-98C4-88811DF88DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
133+
{CF9874FE-8937-44CF-98C4-88811DF88DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
134+
{CF9874FE-8937-44CF-98C4-88811DF88DF4}.Release|Any CPU.Build.0 = Release|Any CPU
129135
EndGlobalSection
130136
GlobalSection(SolutionProperties) = preSolution
131137
HideSolutionNode = FALSE
@@ -134,5 +140,6 @@ Global
134140
{97002C10-48C4-4711-961B-F3E3D4FC3E4E} = {312EC6C7-3026-472C-85A1-8189207DA807}
135141
{F62296EA-27ED-46F7-8782-E84555AB4438} = {43C8BF0C-1B57-4B1F-A5D2-6010B93C791A}
136142
{0848319C-7A4C-4135-B14E-8376AD7AD7CE} = {43C8BF0C-1B57-4B1F-A5D2-6010B93C791A}
143+
{CF9874FE-8937-44CF-98C4-88811DF88DF4} = {43C8BF0C-1B57-4B1F-A5D2-6010B93C791A}
137144
EndGlobalSection
138145
EndGlobal

src/ServiceStack/Host/Handlers/ServiceStackHandlerBase.cs

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -49,66 +49,55 @@ public void UpdateResponseContentType(IRequest httpReq, object response)
4949
}
5050
}
5151

52-
public Task HandleResponse(object response, Func<object, Task> callback)
52+
public async Task HandleResponse(object response, Func<object, Task> callback)
5353
{
5454
try
5555
{
56-
var taskResponse = response as Task;
57-
if (taskResponse != null)
56+
if (response is Task taskResponse)
5857
{
5958
if (taskResponse.Status == TaskStatus.Created)
6059
{
6160
taskResponse.Start();
6261
}
6362

64-
return taskResponse
65-
.Continue(task =>
66-
{
67-
if (task.IsFaulted)
68-
return task;
69-
70-
if (task.IsCanceled)
71-
return new OperationCanceledException("The async Task operation was cancelled").AsTaskException();
72-
73-
if (task.IsCompleted)
74-
{
75-
var taskResult = task.GetResult();
76-
77-
var taskResults = taskResult as Task[];
78-
79-
if (taskResults == null)
80-
{
81-
var subTask = taskResult as Task;
82-
if (subTask != null)
83-
taskResult = subTask.GetResult();
84-
85-
return callback(taskResult);
86-
}
87-
88-
if (taskResults.Length == 0)
89-
return callback(TypeConstants.EmptyObjectArray);
90-
91-
var firstResponse = taskResults[0].GetResult();
92-
var batchedResponses = firstResponse != null
93-
? (object[])Array.CreateInstance(firstResponse.GetType(), taskResults.Length)
94-
: new object[taskResults.Length];
95-
batchedResponses[0] = firstResponse;
96-
for (var i = 1; i < taskResults.Length; i++)
97-
{
98-
batchedResponses[i] = taskResults[i].GetResult();
99-
}
100-
return callback(batchedResponses);
101-
}
102-
103-
return new InvalidOperationException("Unknown Task state").AsTaskException();
104-
});
63+
await taskResponse;
64+
var taskResult = taskResponse.GetResult();
65+
66+
if (!(taskResult is Task[] taskResults))
67+
{
68+
if (taskResult is Task subTask)
69+
taskResult = subTask.GetResult();
70+
71+
await callback(taskResult);
72+
return;
73+
}
74+
75+
if (taskResults.Length == 0)
76+
{
77+
await callback(TypeConstants.EmptyObjectArray);
78+
return;
79+
}
80+
81+
var firstResponse = taskResults[0].GetResult();
82+
var batchedResponses = firstResponse != null
83+
? (object[])Array.CreateInstance(firstResponse.GetType(), taskResults.Length)
84+
: new object[taskResults.Length];
85+
86+
batchedResponses[0] = firstResponse;
87+
for (var i = 1; i < taskResults.Length; i++)
88+
{
89+
batchedResponses[i] = taskResults[i].GetResult();
90+
}
91+
92+
await callback(batchedResponses);
93+
return;
10594
}
10695

107-
return callback(response);
96+
await callback(response);
10897
}
10998
catch (Exception ex)
11099
{
111-
return ex.AsTaskException();
100+
throw;
112101
}
113102
}
114103

src/ServiceStack/HttpResult.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Web;
1010
using ServiceStack.Host;
1111
using ServiceStack.IO;
12+
using ServiceStack.Logging;
1213
using ServiceStack.Text;
1314
using ServiceStack.Web;
1415

@@ -271,24 +272,23 @@ private async Task WriteToAsync(Stream responseStream, int paddingLength, Cancel
271272
{
272273
if (response != null)
273274
{
274-
var ms = ResponseStream as MemoryStream;
275-
if (ms != null)
275+
if (ResponseStream is MemoryStream ms)
276276
{
277277
var bytes = ms.ToArray();
278278
response.SetContentLength(bytes.Length + paddingLength);
279279

280-
responseStream.Write(bytes, 0, bytes.Length); //Write Sync to MemoryStream
280+
await responseStream.WriteAsync(bytes, 0, bytes.Length, token); //Write Sync to MemoryStream
281281
return;
282282
}
283283
}
284284

285285
await ResponseStream.CopyToAsync(responseStream, token);
286-
return;
287286
}
288287
finally
289288
{
290289
DisposeStream();
291290
}
291+
return;
292292
}
293293

294294
if (this.ResponseText != null)
@@ -305,8 +305,7 @@ private async Task WriteToAsync(Stream responseStream, int paddingLength, Cancel
305305
if (this.RequestContext == null)
306306
throw new ArgumentNullException(nameof(RequestContext));
307307

308-
var bytesResponse = this.Response as byte[];
309-
if (bytesResponse != null)
308+
if (this.Response is byte[] bytesResponse)
310309
{
311310
response?.SetContentLength(bytesResponse.Length + paddingLength);
312311

@@ -323,7 +322,7 @@ private async Task WriteToAsync(Stream responseStream, int paddingLength, Cancel
323322

324323
ResponseFilter.SerializeToStream(this.RequestContext, this.Response, responseStream);
325324
}
326-
325+
327326
public bool IsPartialRequest =>
328327
AllowsPartialResponse && RequestContext.GetHeader(HttpHeaders.Range) != null && GetContentLength() != null;
329328

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<TargetFramework>netcoreapp2.0</TargetFramework>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Folder Include="wwwroot\" />
7+
</ItemGroup>
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
10+
<ProjectReference Include="..\..\..\ServiceStack.Text\src\ServiceStack.Text\ServiceStack.Text.csproj" />
11+
<ProjectReference Include="..\..\src\ServiceStack.Interfaces\ServiceStack.Interfaces.csproj" />
12+
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj" />
13+
<ProjectReference Include="..\..\src\ServiceStack.Client\ServiceStack.Client.csproj" />
14+
<ProjectReference Include="..\..\src\ServiceStack.Common\ServiceStack.Common.csproj" />
15+
<ProjectReference Include="..\..\src\ServiceStack.Mvc\ServiceStack.Mvc.csproj" />
16+
<ProjectReference Include="..\..\src\ServiceStack.Server\ServiceStack.Server.csproj" />
17+
</ItemGroup>
18+
</Project>

tests/NetCoreWeb.Tests/Startup.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using Funq;
5+
using Microsoft.AspNetCore;
6+
using Microsoft.AspNetCore.Builder;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.AspNetCore.Http;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Microsoft.WindowsAzure.Storage;
11+
using Microsoft.WindowsAzure.Storage.Blob;
12+
using ServiceStack;
13+
using ServiceStack.Configuration;
14+
using ServiceStack.Web;
15+
16+
namespace NetCoreWeb.Tests
17+
{
18+
public class Program
19+
{
20+
public static void Main(string[] args)
21+
{
22+
BuildWebHost(args).Run();
23+
}
24+
25+
public static IWebHost BuildWebHost(string[] args)
26+
{
27+
return WebHost.CreateDefaultBuilder(args)
28+
.UseStartup<Startup>()
29+
.Build();
30+
}
31+
}
32+
33+
public class Startup
34+
{
35+
public void ConfigureServices(IServiceCollection services)
36+
{
37+
services.AddMvc();
38+
}
39+
40+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
41+
{
42+
if (env.IsDevelopment())
43+
app.UseDeveloperExceptionPage();
44+
45+
app.UseServiceStack(new AppHost());
46+
47+
app.Run(async context =>
48+
{
49+
await context.Response.WriteAsync(
50+
@"<!doctype html>
51+
<html lang=en>
52+
<head>
53+
<meta charset=utf-8>
54+
<title>ImageTest</title>
55+
</head>
56+
<body>
57+
<img src=""/img"">
58+
</body>
59+
</html>");
60+
});
61+
}
62+
}
63+
64+
public class AppHost : AppHostBase
65+
{
66+
public AppHost() : base("StreamTest", typeof(AppHost).Assembly)
67+
{
68+
AppSettings = new AppSettings();
69+
}
70+
71+
public override void Configure(Container container)
72+
{
73+
}
74+
}
75+
76+
public class ImageService : Service
77+
{
78+
private readonly CloudBlobContainer _container;
79+
80+
public ImageService()
81+
{
82+
var storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AZURE_BLOB_UBIXAR"));
83+
var storageClient = storageAccount.CreateCloudBlobClient();
84+
_container = storageClient.GetContainerReference("test");
85+
}
86+
87+
public async Task<HttpResult> Get(ImageRequest request)
88+
{
89+
var blobReference = _container.GetBlobReference("rockstars/dead/cobain/splash.jpg");
90+
var stream = await blobReference.OpenReadAsync();
91+
return new HttpResult(stream, "image/jpeg");
92+
}
93+
}
94+
95+
[Route("/img")]
96+
public class ImageRequest
97+
{
98+
}
99+
}

0 commit comments

Comments
 (0)