Merge pull request #1445 from jtattermusch/csharp_new_api
A new C# API based on async/awaitpull/1510/head
commit
fde356c98e
43 changed files with 1611 additions and 592 deletions
@ -0,0 +1,101 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Grpc.Core |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Return type for bidirectional streaming calls. |
||||||
|
/// </summary> |
||||||
|
public struct AsyncDuplexStreamingCall<TRequest, TResponse> |
||||||
|
{ |
||||||
|
readonly IClientStreamWriter<TRequest> requestStream; |
||||||
|
readonly IAsyncStreamReader<TResponse> responseStream; |
||||||
|
|
||||||
|
public AsyncDuplexStreamingCall(IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream) |
||||||
|
{ |
||||||
|
this.requestStream = requestStream; |
||||||
|
this.responseStream = responseStream; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Writes a request to RequestStream. |
||||||
|
/// </summary> |
||||||
|
public Task Write(TRequest message) |
||||||
|
{ |
||||||
|
return requestStream.Write(message); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Closes the RequestStream. |
||||||
|
/// </summary> |
||||||
|
public Task Close() |
||||||
|
{ |
||||||
|
return requestStream.Close(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Reads a response from ResponseStream. |
||||||
|
/// </summary> |
||||||
|
/// <returns></returns> |
||||||
|
public Task<TResponse> ReadNext() |
||||||
|
{ |
||||||
|
return responseStream.ReadNext(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Async stream to read streaming responses. |
||||||
|
/// </summary> |
||||||
|
public IAsyncStreamReader<TResponse> ResponseStream |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return responseStream; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Async stream to send streaming requests. |
||||||
|
/// </summary> |
||||||
|
public IClientStreamWriter<TRequest> RequestStream |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return requestStream; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Threading; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
internal static class DebugStats |
||||||
|
{ |
||||||
|
public static readonly AtomicCounter ActiveClientCalls = new AtomicCounter(); |
||||||
|
|
||||||
|
public static readonly AtomicCounter ActiveServerCalls = new AtomicCounter(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Grpc.Core; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
internal static class ServerCalls |
||||||
|
{ |
||||||
|
public static IServerCallHandler UnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryServerMethod<TRequest, TResponse> handler) |
||||||
|
{ |
||||||
|
return new UnaryServerCallHandler<TRequest, TResponse>(method, handler); |
||||||
|
} |
||||||
|
|
||||||
|
public static IServerCallHandler ClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, ClientStreamingServerMethod<TRequest, TResponse> handler) |
||||||
|
{ |
||||||
|
return new ClientStreamingServerCallHandler<TRequest, TResponse>(method, handler); |
||||||
|
} |
||||||
|
|
||||||
|
public static IServerCallHandler ServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, ServerStreamingServerMethod<TRequest, TResponse> handler) |
||||||
|
{ |
||||||
|
return new ServerStreamingServerCallHandler<TRequest, TResponse>(method, handler); |
||||||
|
} |
||||||
|
|
||||||
|
public static IServerCallHandler DuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, DuplexStreamingServerMethod<TRequest, TResponse> handler) |
||||||
|
{ |
||||||
|
return new DuplexStreamingServerCallHandler<TRequest, TResponse>(method, handler); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
internal class ServerRequestStream<TRequest, TResponse> : IAsyncStreamReader<TRequest> |
||||||
|
{ |
||||||
|
readonly AsyncCallServer<TRequest, TResponse> call; |
||||||
|
|
||||||
|
public ServerRequestStream(AsyncCallServer<TRequest, TResponse> call) |
||||||
|
{ |
||||||
|
this.call = call; |
||||||
|
} |
||||||
|
|
||||||
|
public Task<TRequest> ReadNext() |
||||||
|
{ |
||||||
|
var taskSource = new AsyncCompletionTaskSource<TRequest>(); |
||||||
|
call.StartReadMessage(taskSource.CompletionDelegate); |
||||||
|
return taskSource.Task; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
using Grpc.Core.Internal; |
||||||
|
|
||||||
|
namespace Grpc.Core |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Server-side handler for unary call. |
||||||
|
/// </summary> |
||||||
|
public delegate Task<TResponse> UnaryServerMethod<TRequest, TResponse>(TRequest request); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Server-side handler for client streaming call. |
||||||
|
/// </summary> |
||||||
|
public delegate Task<TResponse> ClientStreamingServerMethod<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Server-side handler for server streaming call. |
||||||
|
/// </summary> |
||||||
|
public delegate Task ServerStreamingServerMethod<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Server-side handler for bidi streaming call. |
||||||
|
/// </summary> |
||||||
|
public delegate Task DuplexStreamingServerMethod<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream); |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2015, Google Inc. |
||||||
|
// All rights reserved. |
||||||
|
// |
||||||
|
// Redistribution and use in source and binary forms, with or without |
||||||
|
// modification, are permitted provided that the following conditions are |
||||||
|
// met: |
||||||
|
// |
||||||
|
// * Redistributions of source code must retain the above copyright |
||||||
|
// notice, this list of conditions and the following disclaimer. |
||||||
|
// * Redistributions in binary form must reproduce the above |
||||||
|
// copyright notice, this list of conditions and the following disclaimer |
||||||
|
// in the documentation and/or other materials provided with the |
||||||
|
// distribution. |
||||||
|
// * Neither the name of Google Inc. nor the names of its |
||||||
|
// contributors may be used to endorse or promote products derived from |
||||||
|
// this software without specific prior written permission. |
||||||
|
// |
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Grpc.Core.Utils |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Extension methods that simplify work with gRPC streaming calls. |
||||||
|
/// </summary> |
||||||
|
public static class AsyncStreamExtensions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Reads the entire stream and executes an async action for each element. |
||||||
|
/// </summary> |
||||||
|
public static async Task ForEach<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction) |
||||||
|
where T : class
|
||||||
|
{ |
||||||
|
while (true) |
||||||
|
{ |
||||||
|
var elem = await streamReader.ReadNext(); |
||||||
|
if (elem == null) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
await asyncAction(elem); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Reads the entire stream and creates a list containing all the elements read. |
||||||
|
/// </summary> |
||||||
|
public static async Task<List<T>> ToList<T>(this IAsyncStreamReader<T> streamReader) |
||||||
|
where T : class
|
||||||
|
{ |
||||||
|
var result = new List<T>(); |
||||||
|
while (true) |
||||||
|
{ |
||||||
|
var elem = await streamReader.ReadNext(); |
||||||
|
if (elem == null) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
result.Add(elem); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Writes all elements from given enumerable to the stream. |
||||||
|
/// Closes the stream afterwards unless close = false. |
||||||
|
/// </summary> |
||||||
|
public static async Task WriteAll<T>(this IClientStreamWriter<T> streamWriter, IEnumerable<T> elements, bool close = true) |
||||||
|
where T : class
|
||||||
|
{ |
||||||
|
foreach (var element in elements) |
||||||
|
{ |
||||||
|
await streamWriter.Write(element); |
||||||
|
} |
||||||
|
if (close) |
||||||
|
{ |
||||||
|
await streamWriter.Close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Writes all elements from given enumerable to the stream. |
||||||
|
/// </summary> |
||||||
|
public static async Task WriteAll<T>(this IServerStreamWriter<T> streamWriter, IEnumerable<T> elements) |
||||||
|
where T : class
|
||||||
|
{ |
||||||
|
foreach (var element in elements) |
||||||
|
{ |
||||||
|
await streamWriter.Write(element); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue