C# Rest API 文件上传

Posted

技术标签:

【中文标题】C# Rest API 文件上传【英文标题】:C# Rest API File upload 【发布时间】:2020-05-30 07:31:33 【问题描述】:

我也在尝试通过 API 使用 C# 上传文件。

StreamUtils 不起作用,我收到错误消息:“无法将 lambda 表达式转换为类型‘字符串’,因为它不是委托类型”。

知道如何上传文件吗? 大约 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);
            

【问题讨论】:

我可以假设这一行 request.AddFile("file",s=>StreamUtils.CopyStream(fileStream, s), filename); 抛出异常,但需要澄清。 行 request.AddFile("file", s => StreamUtils.CopyStream(fileStream, s), filename) 导致问题,因为 "s => StreamUtils.CopyStream(fileStream, s)"是一个 lambda 表达式,而不是一个流。您要做的就是在函数 StreamUtils.CopyStream(Stream source, Stream target) 中按预期定义一个目标 Stream 您对request.AddFile() 的调用似乎与任何可用的方法签名都不匹配:see this link for clarification。 这有帮助吗?它提供了如何使用 RestSharp ***.com/questions/32876606/… 上传文件的答案 @rekcul 嘿,你能提供一个示例代码吗? 【参考方案1】:

所以您的代码中有两个问题 ...

1. Lambda 表达式问题

以下行导致 lambda 表达式问题

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

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

所以问题是,

s => StreamUtils.CopyStream(fileStream, s)

是一个 Lambda 表达式,您可以在其中定义 s 并将 s 作为第二个参数提供给

CopyStream(Stream source, Stream target)

但 s 不是 Stream 类型。这就是你得到异常的原因。

2。 request.AddFile 需要参数

假设您对 REST 请求使用 RestSharp NuGet 包(我假设因为这些类看起来像来自 RestSharp 的一次),您应该看看 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);

所有函数都需要几个参数。我猜你想使用第二个定义,即

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

因此,如果我们将其与您的代码中的行进行比较

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

我们看到您提供了以下参数:

“文件”作为名称 字节的函数调用(Lambda 表达式) 文件名的文件名变量

第一个和第三个参数看起来不错,但第二个参数是个问题。

我的建议:

在您的 UploadModel 中定义第二个流参数并将其传递给 CopyStream 函数:

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);

如果您仍想调用 StreamUtils.CopyStream() 来获取 request.AddFile 的第二个参数,则必须更改函数定义,因为它当前返回 void。所以而不是:

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

你必须把它改成

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

这导致我们改变了函数体本身,因为我们现在必须根据函数定义返回一个字节[](这只是一个例子,仍然需要获得我目前无法实现的真正实现要做,只是希望它给你一个印象如何去做):

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;

通过这些更改,它应该可以工作。

【讨论】:

【参考方案2】:

我认为您可以将输入文件转换为 Base64,然后发送。 另见其他教授的回答他们的想法。

【讨论】:

以上是关于C# Rest API 文件上传的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中正确使用 WCF REST API 上的 Stream 将文件(图像/视频/等)上传到服务器?

使用 Spring REST API 上传文件

通过 REST API 上传多部分文件会损坏文件并增加文件大小

在 Spring Boot REST API 中上传文件

如何使用 REST API 将文件和附件上传到 sobject 记录?

在 JAVA 中使用 Rest API 客户端上传文件