Search code examples
c#multithreadingasynchronousasp.net-core-mvc

Creating asynchronous and parallel process for dynamic types


I have a deserialized JSON array which I want to loop through and call some queries and copy some files in OneDrive. I can loop through each manually but I also wanted to see if I could get a task awaitable version setup. I have both written out below but I run into a error for the second method:

        var parentJSON = JsonConvert.DeserializeObject<dynamic>(ParentJSON);
        var childrenJSON = JsonConvert.DeserializeObject<dynamic>(ChildrenJSON);

        using (var connection = new SqlConnection(connectionString))
        {
            foreach(var childReview in childrenJSON)
            {
                var ParentID = (int)parentJSON.ID;
                var ChildID = (int)childReview.ID;

                var queryResult = connection.QuerySingle(query, new { Parent = ParentID, Child = ChildID });
                var path = Path.Combine(fileDirectory, queryResult.CHILD_PATH);

                DriveItem FolderInfo = await oneDrive.DriveItemInfoAsync(SharedDriveID, path, "path");
                var CopiedDriveItem = await oneDrive.CopyFileAsync(SharedDriveID, path, "path", queryResult.CHILD_FILENAME, FolderInfo.Id);
            }
        }

        var tasks = childrenJSON.Select(async file => {

            var ParentID = (int)parentJSON.ID;
            var ChildID = (int)file.ID;

            using (var connection = new SqlConnection(connectionString))
            {
                var queryResult = connection.QuerySingle(query, new { Parent = ParentID, Child = ChildID });
                var path = Path.Combine(fileDirectory, queryResult.CHILD_PATH);

                DriveItem FolderInfo = await oneDrive.DriveItemInfoAsync(SharedDriveID, path, "path");
                var CopiedDriveItem = await oneDrive.CopyFileAsync(SharedDriveID, path, "path", queryResult.CHILD_FILENAME, FolderInfo.Id);
            }
        });

The error is:

CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.

If I were to bind the serialized query results to a model I know I can use this task awaitable approach however using dynamic casting from my deserialized JSON results in this error. How do I get around this? I am not sure how I should cast this and why is it so strict for dynamic types despite you can foreach loop through them.


Solution

  • The Select() method that you're trying to use is Enumerable.Select. However, the compiler will not use that, since ChildrenJSON is dynamic. Instead, the compiler assumes that this unknown dynamic object will have a Select() method at runtime. That error is not specific to using Select() - it would happen if you called any method on a dynamic with a lambda as an argument. For example, childrenJSON.Blah(i => {}) would produce the same compiler error.

    If ChildrenJSON is a JSON array, then deserialize it into IEnumerable<dynamic>:

    var childrenJSON = JsonConvert.DeserializeObject<IEnumerable<dynamic>>(ChildrenJSON);
    

    The when you call .Select() it will use Enumerable.Select.