1

I have the following method that returns an IAsyncEnumerable<T>:

async IAsyncEnumerable<T> RunReport()
{
    var handler = new HttpClientHandler();

    var client = new HttpClient(handler);
    client.BaseAddress = new Uri("");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var settings = new JsonSerializerSettings();

    var jsonFormatter = new JsonMediaTypeFormatter() { SerializerSettings = settings };

    var requestMessage = new HttpRequestMessage(HttpMethod.Get, "api/controler");
    var response = await client.SendAsync(requestMessage);

    response.EnsureSuccessStatusCode();

    using (var stream = await response.Content.ReadAsStreamAsync())
    {
        using (var reader = new StreamReader(stream))
        {
            while (!reader.EndOfStream)
            {
                var linesJson = await reader.ReadLineAsync();
                var line = JsonConvert.DeserializeObject<List<T>>(linesJson, jsonFormatter.SerializerSettings);

                foreach (var line in lines)
                    yield return line;
            }
        }
    }
}

I would like to take that result stream it to the database, using SqlBulkCopy's WriteToServerAsync method, but cannot figure out how to turn it into an IDataReader or any other type in the WriteToServerAsync's overload list.

I'm open to using something other than bulk copy, provided it's reasonably performant.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
priehl
  • 644
  • 2
  • 9
  • 21

1 Answers1

0

using the example here, I've come up with an IDataReader that takes a IAsyncEnumerable, and implements the appropriate portion of the interface.

public class GenericDataReader<T> : IDataReader where T : class
{
    private readonly IAsyncEnumerator<T> _asychEnumerator;
    private readonly List<FieldInfo> _fields = new List<FieldInfo>();

    public GenericDataReader(IAsyncEnumerable<T> asyncEnumerable)
    {
        _asychEnumerator = asyncEnumerable.GetAsyncEnumerator();

        foreach (FieldInfo fieldinfo in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public))
        {
            _fields.Add(fieldinfo);
        }
    }

    public int FieldCount => _fields.Count;

    public void Dispose() { Close(); }

    public bool Read()
    {
        return _asycEnumerator.MoveNextAsync().Result;
    }

    public async void Close(){ await _asychEnumerator.DisposeAsync(); }

    public Type GetFieldType(int i){ return _fields[i].FieldType; }

    public string GetName(int i) { return _fields[i].Name; }

    public object GetValue(int i){ return _fields[i].GetValue(_asychEnumerator.Current); }
}   

I'm still working through the example, but am a bit leary of the Read() method's implementation.

priehl
  • 644
  • 2
  • 9
  • 21
  • Also, for what it's worth. Using https://www.nuget.org/packages/System.Linq.Async/ you can turn your IAsyncEnumerable into a IEnumerable with the ToEnumerable() method. – priehl Feb 12 '20 at 17:16