0

I am trying too upload a file with C# by an API.

The StreamUtils dont work, I am getting error: "Cannot convert lambda expression to type 'string' because it is not a delegate type".

Any idea on how to upload the file? It is around 100MB.

 public void UploadModel(string ProjectId, string filename, Stream fileStream)
        {

            string access_token_string = Read_Json_Values("access_token");
            string webstring = String.Format("https://api.test.com/v2/projects/{0}/revisions", ProjectId);

            var client = new RestClient(webstring);
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("Authorization", "Bearer " + access_token_string);
            request.AddHeader("Content-Type", "application/ifc");
            request.AddHeader("xxx-Params", "{\"callbackUri\": \"https://example.com\", \"filename\": \"mk337.ifc\", \"comment\": \"From Postman\", \"model\": \"21312312312312\"}");
            request.AddFile("file", s => StreamUtils.CopyStream(fileStream, s), filename);


            IRestResponse response = client.Execute(request);
            Console.WriteLine("Model is uploaded!");
        }
internal static class StreamUtils
        {
            private const int STREAM_BUFFER_SIZE = 128 * 1024; // 128KB

            public static void CopyStream(Stream source, Stream target)
            { CopyStream(source, target, new byte[STREAM_BUFFER_SIZE]); }

            public static void CopyStream(Stream source, Stream target, byte[] buffer)
            {
                if (source == null) throw new ArgumentNullException("source");
                if (target == null) throw new ArgumentNullException("target");

                if (buffer == null) buffer = new byte[STREAM_BUFFER_SIZE];
                int bufferLength = buffer.Length;
                int bytesRead = 0;
                while ((bytesRead = source.Read(buffer, 0, bufferLength)) > 0)
                    target.Write(buffer, 0, bytesRead);
            }
Kickdak
  • 197
  • 1
  • 3
  • 15
  • I can assume this line `request.AddFile("file",s=>StreamUtils.CopyStream(fileStream, s), filename);` throws an Exception, but clarification is needed. – Krivitskiy Grigoriy Feb 14 '20 at 13:47
  • The line request.AddFile("file", s => StreamUtils.CopyStream(fileStream, s), filename) is causing the issue because "s => StreamUtils.CopyStream(fileStream, s)" is a lambda expression and not a stream. What you have to do is to define a target Stream as expected in the function StreamUtils.CopyStream(Stream source, Stream target) – rekcul Feb 14 '20 at 13:48
  • It looks like your call to `request.AddFile()` does not match any of the method signatures available: [see this link for clarification](https://i.imgur.com/JjM93BZ.png). – Harjan Feb 14 '20 at 13:55
  • Does this help? It provides answers of how to upload a file using RestSharp https://stackoverflow.com/questions/32876606/restsharp-addfile-using-stream – Ryan Thomas Feb 14 '20 at 13:58
  • @rekcul Hey, can you provide an sample code? – Kickdak Feb 17 '20 at 07:58
  • @Kickdak please find my answer below. It's not a full working example as I am still not sure about the CopyStream() implementation, but it should give you an impression about how you can enhance your code. – rekcul Feb 18 '20 at 08:20

2 Answers2

1

So you have two issues in your code ...

1. Lambda expression issue

The following line causes the lambda expression issue

request.AddFile("file", s => StreamUtils.CopyStream(fileStream, s), filename);

// This is the function you want to call
void CopyStream(Stream source, Stream target)

So the issue is, that

s => StreamUtils.CopyStream(fileStream, s)

is a Lambda expression, where you define s and give s as second Parameter to

CopyStream(Stream source, Stream target)

but s is not of type Stream. That's why you get the exception.

2. request.AddFile needs Parameters

Assuming you use the RestSharp NuGet package for your REST request (I assume that because the classes look like the once from RestSharp) you should have a look on the different overloads of RestRequest.AddFile():

AddFile(string name, string path, string contentType = null);
AddFile(string name, byte[] bytes, string fileName, string contentType = null);
AddFile(string name, Action<Stream> writer, string fileName, long contentLength, string contentType = null);

All functions need several parameters. I guess you want to use the second definition which is

AddFile(string name, byte[] bytes, string fileName, string contentType = null);

So if we compare it with the line in your code

request.AddFile("file", s => StreamUtils.CopyStream(fileStream, s), filename);

We see that you give following Parameters:

  • "file" as the name
  • Function call (Lambda expression) for the bytes
  • Filename variable for the filename

The first and third parameters look good but second parameter is an issue.

My suggestions:

Define a secound stream parameter in your UploadModel and pass it to the CopyStream function:

public void UploadModel(string ProjectId, string filename, Stream sourceStream, Stream targetStream)
{
    // .... your code still here, just want to show the changing lines
    request.AddFile("file", StreamUtils.CopyStream(sourceStream, targetStream), filename);
}

And if you still want to call StreamUtils.CopyStream() to get the second parameter for request.AddFile, you have to change the function definition as it currently returns void. So instead of:

public static void CopyStream(Stream source, Stream target)
public static void CopyStream(Stream source, Stream target, byte[] buffer)

you have to change it to

public static byte[] CopyStream(Stream source, Stream target)
public static byte[] CopyStream(Stream source, Stream target, byte[] buffer)

which leads us to the changes in the function body itself, as we now have to return a byte[] accordingly to the functions definition (this is just an example and still needs to get the real implementation which I am currently not able to do, just hope that it gives you an impression how to do it):

public static byte[] CopyStream(Stream source, Stream target, byte[] buffer)
{
    // -> Define a byte array
    byte[] bytesToReturn;

    // -> Fill the array with data
    // ...

    // -> return the array
    return bytesToReturn;
}

With these changes it should work.

rekcul
  • 319
  • 1
  • 7
  • 18
-2

I think you can convert your input file to Base64 and then send it. See also the answers of other professors what they think.