eerhardt commented on a change in pull request #12044:
URL: https://github.com/apache/arrow/pull/12044#discussion_r778892642



##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };
+        }
+        public IDictionary<FlightTicket, FlightInfo> flights;
+        public IDictionary<FlightTicket, List<RecordBatch>> tables;
+    }
+
+    public class InMemoryFlightServer : FlightServer
+    {
+        private FlightData _flightData;
+
+        public InMemoryFlightServer(FlightData flightData)
+        {
+            _flightData = flightData;
+        }
+
+        public override async Task DoPut(
+            FlightServerRecordBatchStreamReader requestStream,
+            IAsyncStreamWriter<FlightPutResult> responseStream,
+            ServerCallContext context
+        )
+        {
+            var newTable = new List<RecordBatch> { };
+            Int64 numRows = 0;
+
+            await foreach (var batch in 
requestStream.ReadAllAsync(context.CancellationToken))
+            {
+                newTable.Add(batch);
+                numRows += batch.Length;
+            }
+
+            var descriptor = await requestStream.FlightDescriptor;
+            var ticket = DescriptorAsTicket(descriptor);
+            var schema = await requestStream.Schema;
+
+            _flightData.flights.Add(ticket, new FlightInfo(
+                schema,
+                descriptor,
+                new List<FlightEndpoint> { GetEndpoint(ticket, 
$"http://{context.Host}";) },
+                numRows,
+                -1 // Unknown
+            ));
+            _flightData.tables.Add(ticket, newTable);
+
+            await responseStream.WriteAsync(new FlightPutResult("Table 
saved."));
+        }
+
+        public override async Task DoGet(
+            FlightTicket ticket,
+            FlightServerRecordBatchStreamWriter responseStream,
+            ServerCallContext context
+        )
+        {
+            if (!_flightData.tables.ContainsKey(ticket))
+            {
+                throw new RpcException(new Status(StatusCode.NotFound, "Flight 
not found."));
+            }
+            var table = _flightData.tables[ticket];
+
+            foreach (var batch in table) {
+                await responseStream.WriteAsync(batch);
+            }
+        }
+
+        public override async Task ListFlights(
+            FlightCriteria request,
+            IAsyncStreamWriter<FlightInfo> responseStream,
+            ServerCallContext context
+        )
+        {
+            foreach (var flight in _flightData.flights.Values)
+            {
+                await responseStream.WriteAsync(flight);
+            }
+        }
+
+        public override async Task<FlightInfo> GetFlightInfo(FlightDescriptor 
request, ServerCallContext context)

Review comment:
       ```suggestion
           public override Task<FlightInfo> GetFlightInfo(FlightDescriptor 
request, ServerCallContext context)
   ```
   
   I'm getting warnings that this method lacks an `await` call. So we can 
remove the `async` keyword.
   
   Note, since you still need to return a `Task` (because this is an override), 
you can `return Task.FromResult(_flightData.flights[key]);`

##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };
+        }
+        public IDictionary<FlightTicket, FlightInfo> flights;
+        public IDictionary<FlightTicket, List<RecordBatch>> tables;
+    }
+
+    public class InMemoryFlightServer : FlightServer
+    {
+        private FlightData _flightData;
+
+        public InMemoryFlightServer(FlightData flightData)
+        {
+            _flightData = flightData;
+        }
+
+        public override async Task DoPut(
+            FlightServerRecordBatchStreamReader requestStream,
+            IAsyncStreamWriter<FlightPutResult> responseStream,
+            ServerCallContext context
+        )
+        {
+            var newTable = new List<RecordBatch> { };
+            Int64 numRows = 0;
+
+            await foreach (var batch in 
requestStream.ReadAllAsync(context.CancellationToken))
+            {
+                newTable.Add(batch);
+                numRows += batch.Length;
+            }
+
+            var descriptor = await requestStream.FlightDescriptor;
+            var ticket = DescriptorAsTicket(descriptor);
+            var schema = await requestStream.Schema;
+
+            _flightData.flights.Add(ticket, new FlightInfo(
+                schema,
+                descriptor,
+                new List<FlightEndpoint> { GetEndpoint(ticket, 
$"http://{context.Host}";) },
+                numRows,
+                -1 // Unknown
+            ));
+            _flightData.tables.Add(ticket, newTable);
+
+            await responseStream.WriteAsync(new FlightPutResult("Table 
saved."));
+        }
+
+        public override async Task DoGet(
+            FlightTicket ticket,
+            FlightServerRecordBatchStreamWriter responseStream,
+            ServerCallContext context
+        )
+        {
+            if (!_flightData.tables.ContainsKey(ticket))
+            {
+                throw new RpcException(new Status(StatusCode.NotFound, "Flight 
not found."));
+            }
+            var table = _flightData.tables[ticket];
+
+            foreach (var batch in table) {
+                await responseStream.WriteAsync(batch);
+            }
+        }
+
+        public override async Task ListFlights(
+            FlightCriteria request,
+            IAsyncStreamWriter<FlightInfo> responseStream,
+            ServerCallContext context
+        )
+        {
+            foreach (var flight in _flightData.flights.Values)
+            {
+                await responseStream.WriteAsync(flight);
+            }
+        }
+
+        public override async Task<FlightInfo> GetFlightInfo(FlightDescriptor 
request, ServerCallContext context)
+        {
+            var key = DescriptorAsTicket(request);
+            if (_flightData.flights.ContainsKey(key))
+            {
+                return _flightData.flights[key];
+            }
+            else
+            {
+                throw new RpcException(new Status(StatusCode.NotFound, "Flight 
not found."));
+            }
+        }
+
+        public override async Task ListActions(
+            IAsyncStreamWriter<FlightActionType> responseStream, 
+            ServerCallContext context
+        )
+        {
+            await responseStream.WriteAsync(new FlightActionType("clear", 
"Clear the flights from the server"));
+        }
+
+        public override async Task DoAction(

Review comment:
       ```suggestion
           public override Task DoAction(
   ```
   
   I'm getting warnings that this method lacks an await call. So we can remove 
the async keyword.
   
   Note, since you still need to return a `Task` (because this is an override), 
you can `return Task.CompletedTask;`

##########
File path: csharp/examples/FlightClientExample/Program.cs
##########
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Tasks;
+using Grpc.Net.Client;
+using Apache.Arrow.Flight.Client;
+using Apache.Arrow.Flight;
+using Apache.Arrow;
+using System.Linq;
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+
+namespace FlightClientExample
+{
+    public class Program
+    {
+        public static async Task Main(string[] args)
+        {
+            string host = args.Length > 0 ? args[0] : "localhost";
+            string port = args.Length > 1 ? args[1] : "433";
+
+            // Create client
+            // (In production systems, you should use https not http)
+            var address = $"http://{host}:{port}";;
+            Console.WriteLine($"Connecting to: {address}");
+            var channel = GrpcChannel.ForAddress(address);
+            var client = new FlightClient(channel);
+
+            var recordBatches = new RecordBatch[] {
+                CreateTestBatch(0, 2000), CreateTestBatch(50, 9000)
+            };
+
+            // Particular flights are identified by a descriptor. This might 
be a name,
+            // a SQL query, or a path. Here, just using the name "test".
+            var descriptor = FlightDescriptor.CreateCommandDescriptor("test");
+
+            // Upload data with StartPut
+            var batchStreamingCall = client.StartPut(descriptor);
+            foreach (var batch in recordBatches) {

Review comment:
       ```suggestion
               foreach (var batch in recordBatches)
               {
   ```
   
   Use consistent bracing throughout.

##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };
+        }
+        public IDictionary<FlightTicket, FlightInfo> flights;
+        public IDictionary<FlightTicket, List<RecordBatch>> tables;
+    }
+
+    public class InMemoryFlightServer : FlightServer
+    {
+        private FlightData _flightData;
+
+        public InMemoryFlightServer(FlightData flightData)
+        {
+            _flightData = flightData;
+        }
+
+        public override async Task DoPut(
+            FlightServerRecordBatchStreamReader requestStream,
+            IAsyncStreamWriter<FlightPutResult> responseStream,
+            ServerCallContext context
+        )
+        {
+            var newTable = new List<RecordBatch> { };
+            Int64 numRows = 0;

Review comment:
       ```suggestion
               long numRows = 0;
   ```

##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };

Review comment:
       ```suggestion
               flights = new ConcurrentDictionary<FlightTicket, FlightInfo> { };
               tables = new ConcurrentDictionary<FlightTicket, 
List<RecordBatch>> { };
   ```
   
   Since `FlightData` is a Singleton service, it needs to be thread-safe.

##########
File path: csharp/examples/FlightClientExample/Program.cs
##########
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Tasks;
+using Grpc.Net.Client;
+using Apache.Arrow.Flight.Client;
+using Apache.Arrow.Flight;
+using Apache.Arrow;
+using System.Linq;
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+
+namespace FlightClientExample
+{
+    public class Program
+    {
+        public static async Task Main(string[] args)
+        {
+            string host = args.Length > 0 ? args[0] : "localhost";
+            string port = args.Length > 1 ? args[1] : "433";
+
+            // Create client
+            // (In production systems, you should use https not http)
+            var address = $"http://{host}:{port}";;
+            Console.WriteLine($"Connecting to: {address}");
+            var channel = GrpcChannel.ForAddress(address);
+            var client = new FlightClient(channel);
+
+            var recordBatches = new RecordBatch[] {
+                CreateTestBatch(0, 2000), CreateTestBatch(50, 9000)
+            };
+
+            // Particular flights are identified by a descriptor. This might 
be a name,
+            // a SQL query, or a path. Here, just using the name "test".
+            var descriptor = FlightDescriptor.CreateCommandDescriptor("test");
+
+            // Upload data with StartPut
+            var batchStreamingCall = client.StartPut(descriptor);
+            foreach (var batch in recordBatches) {
+                await batchStreamingCall.RequestStream.WriteAsync(batch);
+            }
+            // Signal we are done sending record batches
+            await batchStreamingCall.RequestStream.CompleteAsync();
+            // Retrieve final response
+            await batchStreamingCall.ResponseStream.MoveNext(default);
+            
Console.WriteLine(batchStreamingCall.ResponseStream.Current.ApplicationMetadata.ToStringUtf8());
+            Console.WriteLine($"Wrote {recordBatches.Length} batches to 
server.");
+
+            // Request information:
+            var schema = await client.GetSchema(descriptor).ResponseAsync;
+            Console.WriteLine($"Schema saved as: \n {schema.ToString()}");
+
+            var info = await client.GetInfo(descriptor).ResponseAsync;
+            Console.WriteLine($"Info provided: \n {info.ToString()}");
+
+            Console.WriteLine($"Available flights:");
+            var flights_call = client.ListFlights();
+
+            while (await flights_call.ResponseStream.MoveNext(default))
+            {   
+                Console.WriteLine("  " + 
flights_call.ResponseStream.Current.ToString());
+            }
+
+            // Download data
+            await foreach (var batch in StreamRecordBatches(info, default))
+            {
+                Console.WriteLine($"Read batch from flight server: \n 
{batch}")  ;
+            }
+
+            // See available comands on this server
+            var action_stream = client.ListActions();
+            Console.WriteLine("Actions:");
+            while (await action_stream.ResponseStream.MoveNext(default))
+            {
+                var action = action_stream.ResponseStream.Current;
+                Console.WriteLine($"  {action.Type}: {action.Description}");
+            }
+
+            // Send clear command to drop all data from the server.
+            var clear_result = client.DoAction(new FlightAction("clear"));
+            await clear_result.ResponseStream.MoveNext(default);
+        }
+
+        public static async IAsyncEnumerable<RecordBatch> StreamRecordBatches(
+            FlightInfo info, 
+            [EnumeratorCancellation] CancellationToken token
+        )
+        {
+            // There might be multiple endpoints hosting part of the data. In 
simple services,
+            // the only endpoint might be the same server we initially queried.
+            foreach (var endpoint in info.Endpoints)
+            {
+                // We may have multiple locations to choose from. Here we 
choose the first.
+                var download_channel = 
GrpcChannel.ForAddress(endpoint.Locations.First().Uri);
+                var download_client = new FlightClient(download_channel);
+
+                var stream = download_client.GetStream(endpoint.Ticket);
+
+                while (await stream.ResponseStream.MoveNext(token))
+                { 
+                    yield return stream.ResponseStream.Current;
+                }
+            }
+        }
+
+        public static RecordBatch CreateTestBatch(Int32 start, Int32 length)

Review comment:
       ```suggestion
           public static RecordBatch CreateTestBatch(int start, int length)
   ```
   
   Check out 
https://blog.paranoidcoding.com/2019/04/08/string-vs-String-is-not-about-style.html
 why to always use the C# keywords.
   

##########
File path: csharp/examples/FlightClientExample/Program.cs
##########
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Tasks;
+using Grpc.Net.Client;
+using Apache.Arrow.Flight.Client;
+using Apache.Arrow.Flight;
+using Apache.Arrow;
+using System.Linq;
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+
+namespace FlightClientExample
+{
+    public class Program
+    {
+        public static async Task Main(string[] args)
+        {
+            string host = args.Length > 0 ? args[0] : "localhost";
+            string port = args.Length > 1 ? args[1] : "433";
+
+            // Create client
+            // (In production systems, you should use https not http)
+            var address = $"http://{host}:{port}";;
+            Console.WriteLine($"Connecting to: {address}");
+            var channel = GrpcChannel.ForAddress(address);
+            var client = new FlightClient(channel);
+
+            var recordBatches = new RecordBatch[] {
+                CreateTestBatch(0, 2000), CreateTestBatch(50, 9000)
+            };
+
+            // Particular flights are identified by a descriptor. This might 
be a name,
+            // a SQL query, or a path. Here, just using the name "test".
+            var descriptor = FlightDescriptor.CreateCommandDescriptor("test");
+
+            // Upload data with StartPut
+            var batchStreamingCall = client.StartPut(descriptor);
+            foreach (var batch in recordBatches) {
+                await batchStreamingCall.RequestStream.WriteAsync(batch);
+            }
+            // Signal we are done sending record batches
+            await batchStreamingCall.RequestStream.CompleteAsync();
+            // Retrieve final response
+            await batchStreamingCall.ResponseStream.MoveNext(default);
+            
Console.WriteLine(batchStreamingCall.ResponseStream.Current.ApplicationMetadata.ToStringUtf8());
+            Console.WriteLine($"Wrote {recordBatches.Length} batches to 
server.");
+
+            // Request information:
+            var schema = await client.GetSchema(descriptor).ResponseAsync;
+            Console.WriteLine($"Schema saved as: \n {schema.ToString()}");
+
+            var info = await client.GetInfo(descriptor).ResponseAsync;
+            Console.WriteLine($"Info provided: \n {info.ToString()}");

Review comment:
       ```suggestion
               Console.WriteLine($"Schema saved as: \n {schema}");
   
               var info = await client.GetInfo(descriptor).ResponseAsync;
               Console.WriteLine($"Info provided: \n {info}");
   ```
   
   No need to call ToString here

##########
File path: csharp/examples/FlightClientExample/Program.cs
##########
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Tasks;
+using Grpc.Net.Client;
+using Apache.Arrow.Flight.Client;
+using Apache.Arrow.Flight;
+using Apache.Arrow;
+using System.Linq;
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+
+namespace FlightClientExample
+{
+    public class Program
+    {
+        public static async Task Main(string[] args)
+        {
+            string host = args.Length > 0 ? args[0] : "localhost";
+            string port = args.Length > 1 ? args[1] : "433";
+
+            // Create client
+            // (In production systems, you should use https not http)
+            var address = $"http://{host}:{port}";;
+            Console.WriteLine($"Connecting to: {address}");
+            var channel = GrpcChannel.ForAddress(address);
+            var client = new FlightClient(channel);
+
+            var recordBatches = new RecordBatch[] {
+                CreateTestBatch(0, 2000), CreateTestBatch(50, 9000)
+            };
+
+            // Particular flights are identified by a descriptor. This might 
be a name,
+            // a SQL query, or a path. Here, just using the name "test".
+            var descriptor = FlightDescriptor.CreateCommandDescriptor("test");
+
+            // Upload data with StartPut
+            var batchStreamingCall = client.StartPut(descriptor);
+            foreach (var batch in recordBatches) {
+                await batchStreamingCall.RequestStream.WriteAsync(batch);
+            }
+            // Signal we are done sending record batches
+            await batchStreamingCall.RequestStream.CompleteAsync();
+            // Retrieve final response
+            await batchStreamingCall.ResponseStream.MoveNext(default);

Review comment:
       ```suggestion
               await batchStreamingCall.ResponseStream.MoveNext();
   ```
   
   If you add `using Grpc.Core;` to the top of the file, you can remove the 
`default` values here. This works because there is an extension method in that 
namespace that doesn't take a CancellationToken. I've opened 
https://github.com/grpc/grpc/issues/28473 to suggest making this better.

##########
File path: csharp/examples/FlightClientExample/FlightClientExample.csproj
##########
@@ -0,0 +1,32 @@
+<!---
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<Project Sdk="Microsoft.NET.Sdk">
+  
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net6.0</TargetFramework>
+    <ApplicationType>Console</ApplicationType>

Review comment:
       ```suggestion
   ```
   
   I don't know what this line does. Can it be removed?

##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };
+        }
+        public IDictionary<FlightTicket, FlightInfo> flights;
+        public IDictionary<FlightTicket, List<RecordBatch>> tables;
+    }
+
+    public class InMemoryFlightServer : FlightServer
+    {
+        private FlightData _flightData;
+
+        public InMemoryFlightServer(FlightData flightData)
+        {
+            _flightData = flightData;
+        }
+
+        public override async Task DoPut(
+            FlightServerRecordBatchStreamReader requestStream,
+            IAsyncStreamWriter<FlightPutResult> responseStream,
+            ServerCallContext context
+        )
+        {
+            var newTable = new List<RecordBatch> { };
+            Int64 numRows = 0;
+
+            await foreach (var batch in 
requestStream.ReadAllAsync(context.CancellationToken))
+            {
+                newTable.Add(batch);
+                numRows += batch.Length;
+            }
+
+            var descriptor = await requestStream.FlightDescriptor;
+            var ticket = DescriptorAsTicket(descriptor);
+            var schema = await requestStream.Schema;
+
+            _flightData.flights.Add(ticket, new FlightInfo(
+                schema,
+                descriptor,
+                new List<FlightEndpoint> { GetEndpoint(ticket, 
$"http://{context.Host}";) },
+                numRows,
+                -1 // Unknown
+            ));
+            _flightData.tables.Add(ticket, newTable);
+
+            await responseStream.WriteAsync(new FlightPutResult("Table 
saved."));
+        }
+
+        public override async Task DoGet(
+            FlightTicket ticket,
+            FlightServerRecordBatchStreamWriter responseStream,
+            ServerCallContext context
+        )
+        {
+            if (!_flightData.tables.ContainsKey(ticket))
+            {
+                throw new RpcException(new Status(StatusCode.NotFound, "Flight 
not found."));
+            }
+            var table = _flightData.tables[ticket];
+
+            foreach (var batch in table) {
+                await responseStream.WriteAsync(batch);
+            }
+        }
+
+        public override async Task ListFlights(
+            FlightCriteria request,
+            IAsyncStreamWriter<FlightInfo> responseStream,
+            ServerCallContext context
+        )
+        {
+            foreach (var flight in _flightData.flights.Values)
+            {
+                await responseStream.WriteAsync(flight);
+            }
+        }
+
+        public override async Task<FlightInfo> GetFlightInfo(FlightDescriptor 
request, ServerCallContext context)
+        {
+            var key = DescriptorAsTicket(request);
+            if (_flightData.flights.ContainsKey(key))
+            {
+                return _flightData.flights[key];
+            }
+            else
+            {
+                throw new RpcException(new Status(StatusCode.NotFound, "Flight 
not found."));
+            }
+        }
+
+        public override async Task ListActions(
+            IAsyncStreamWriter<FlightActionType> responseStream, 
+            ServerCallContext context
+        )
+        {
+            await responseStream.WriteAsync(new FlightActionType("clear", 
"Clear the flights from the server"));
+        }
+
+        public override async Task DoAction(
+            FlightAction request, 
+            IAsyncStreamWriter<FlightResult> responseStream, 
+            ServerCallContext context
+        )
+        {
+            if (request.Type == "clear")
+            {
+                _flightData.flights.Clear();
+                _flightData.tables.Clear();
+            }
+            else
+            {
+                throw new RpcException(new Status(StatusCode.InvalidArgument, 
"Action does not exist."));
+            }
+        }
+
+        public override async Task<Schema> GetSchema(FlightDescriptor request, 
ServerCallContext context)
+        {
+            var info = await GetFlightInfo(request, context);
+            return info.Schema;
+        }
+
+        private FlightTicket DescriptorAsTicket(FlightDescriptor desc)
+        {
+            return new FlightTicket(desc.ToString());

Review comment:
       `FlightDescriptor` doesn't override ToString, so it just returns the 
Type name when you call `ToString()`. Is creating the same `FlightTicket`, no 
matter the instance, the correct thing here?

##########
File path: 
csharp/examples/FlightAspServerExample/Services/InMemoryFlightServer.cs
##########
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow;
+using Apache.Arrow.Flight;
+using Apache.Arrow.Flight.Server;
+using Grpc.Core;
+
+namespace FlightAspServerExample.Services
+{
+    public class FlightData
+    {
+        public FlightData()
+        {
+            flights = new Dictionary<FlightTicket, FlightInfo> { };
+            tables = new Dictionary<FlightTicket, List<RecordBatch>> { };
+        }
+        public IDictionary<FlightTicket, FlightInfo> flights;
+        public IDictionary<FlightTicket, List<RecordBatch>> tables;

Review comment:
       ```suggestion
           public IDictionary<FlightTicket, FlightInfo> Flights { get; };
           public IDictionary<FlightTicket, List<RecordBatch>> Tables { get; };
   ```
   
   Use PascalCasing for public members, and don't expose fields - instead make 
them properties.

##########
File path: csharp/examples/FlightAspServerExample/appsettings.Development.json
##########
@@ -0,0 +1,8 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"

Review comment:
       These settings are the same as `appsettings.json`. Can we just remove 
the `Development` file?

##########
File path: csharp/examples/FlightAspServerExample/Program.cs
##########
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using FlightAspServerExample.Services;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Additional configuration is required to successfully run gRPC on macOS.
+// For instructions on how to configure Kestrel and gRPC clients on macOS, 
visit https://go.microsoft.com/fwlink/?linkid=2099682
+if (builder.Environment.IsDevelopment())
+{
+    builder.WebHost.ConfigureKestrel(options =>
+    {
+        // Setup a HTTP/2 endpoint without TLS.
+        options.ListenLocalhost(5000, o => o.Protocols =

Review comment:
       Why are we listening on `5000` here, but the default in the client is 
`433`? Can these be the same by default?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscr...@arrow.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to