C# RestSharp 可以在不使用多部分内容类型的情况下发送二进制数据吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10158977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 12:41:11  来源:igfitidea点击:

Can RestSharp send binary data without using a multipart content type?

c#restsharp

提问by ladenedge

I have been using AddParameterto include XML bodies in my HTTP requests:

我一直在使用AddParameter在我的 HTTP 请求中包含 XML 主体:

request.AddParameter(contentType, body, ParameterType.RequestBody);

However, this does not seem to work for non-string bodies. (RestSharp's Http.RequestBodyis a string for some reason.) I tried using AddFile(), but I can't find any way to avoid encoding the "file" as multipart/form, even if I've only supplied a single object.

但是,这似乎不适用于非字符串主体。(Http.RequestBody由于某种原因,RestSharp是一个字符串。)我尝试使用AddFile(),但我找不到任何方法来避免将“文件”编码为multipart/form,即使我只提供了一个对象。

I'm not at all opposed to underhanded reflection to solve this problem, but I'm hoping to avoid modifying the source just to send arbitrary data in an HTTP request.

我一点也不反对用不正当的反射来解决这个问题,但我希望避免修改源只是为了在 HTTP 请求中发送任意数据。

Edit:regarding the requests I'm trying to send, they just look like this:

编辑:关于我尝试发送的请求,它们看起来像这样:

PUT ... HTTP/1.1
Accept: application/vnd...
Authorization: Basic ...
Content-Type: application/octet-stream

<arbitrary bytes>

Ideally, I'd like to use the same calls to send a different content type:

理想情况下,我想使用相同的调用来发送不同的内容类型:

PUT ... HTTP/1.1
Accept: application/vnd...
Authorization: Basic ...
Content-Type: application/vnd...

<other arbitrary bytes>

采纳答案by Michael

There have been some modifications made in the latest version that allow a single file to be used without creating a multipart form request. Here is a gist that shows and example:

在最新版本中进行了一些修改,允许在不创建多部分表单请求的情况下使用单个文件。这是一个显示和示例的要点:

https://gist.github.com/hallem/5faaa6bebde50641e928

https://gist.github.com/hallem/5faaa6bebde50641e928

回答by Dresel

I ran into the same issue. I had to upload exactly one file and use a specific content type for communicating with an REST Interface. You could modify Http.RequestBody to byte[] (and all dependencies on that), but i think its easier this way:

我遇到了同样的问题。我必须只上传一个文件并使用特定的内容类型与 REST 接口进行通信。您可以将 Http.RequestBody 修改为 byte[] (以及对其的所有依赖项),但我认为这样更容易:

I modified RestSharp, so that it only use Multipart Encoding when number of Files > 1 or number of Files = 1 and there is also body or other post data set.

我修改了 RestSharp,因此它仅在文件数 > 1 或文件数 = 1 时才使用多部分编码,并且还有正文或其他后期数据集。

You have to modify Http.cs on Line 288 from

您必须从第 288 行修改 Http.cs

if(HasFiles)

to

if(Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Any())))

For Http.Sync.cs modify PreparePostData from

对于 Http.Sync.cs 修改 PreparePostData 从

private void PreparePostData(HttpWebRequest webRequest)
{
    if (HasFiles)
    {
        webRequest.ContentType = GetMultipartFormContentType();
        using (var requestStream = webRequest.GetRequestStream())
        {
            WriteMultipartFormData(requestStream);
        }
    }

    PreparePostBody(webRequest);
}

to

private void PreparePostData(HttpWebRequest webRequest)
{
    // Multiple Files or 1 file and body and / or parameters
    if (Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Any())))
    {
        webRequest.ContentType = GetMultipartFormContentType();
        using (var requestStream = webRequest.GetRequestStream())
        {
            WriteMultipartFormData(requestStream);
        }
    }
    else if (Files.Count == 1)
    {
        using (var requestStream = webRequest.GetRequestStream())
        {
            Files.Single().Writer(requestStream);
        }
    }

    PreparePostBody(webRequest);
}

If you use the async version, you have to modify the code similar to the above in Http.Async.cs.

如果使用async版本,则需要修改Http.Async.cs中类似上面的代码。

Now u can use RestSharp like this

现在你可以像这样使用 RestSharp

IRestRequest request = new RestRequest("urlpath", Method.PUT);
request.AddHeader("Content-Type", "application/zip");
request.AddFile("Testfile", "C:\File.zip");

Client.Execute(request);

AddFile also provides an overload for setting direct byte[] data instead of a path. Hope that helps.

AddFile 还提供了用于设置直接 byte[] 数据而不是路径的重载。希望有帮助。

回答by Vincent Sos

In the latest version of RestSharp at the time of writing (version 104), the modification needs to be in Http.Sync.cs , method PreparePostData, which should read as:

在撰写本文时最新版本的 RestSharp(版本 104)中,修改需要在 Http.Sync.cs 中的 PreparePostData 方法中,其应为:

    private void PreparePostData(HttpWebRequest webRequest)
    {

        // Multiple Files or 1 file and body and / or parameters
        if (Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Count>0)))
        {
            webRequest.ContentType = GetMultipartFormContentType();
            using (var requestStream = webRequest.GetRequestStream())
            {
                WriteMultipartFormData(requestStream);
            }
        }
        else if (Files.Count == 1)
        {
            using (var requestStream = webRequest.GetRequestStream())
            {
                Files[0].Writer(requestStream);
            }
        }
        PreparePostBody(webRequest);
    }

回答by Michael

Modifications to Http.Async.cs are also necessary for the RequestStreamCallback method. I'm actually working on getting this fix into the repo and published to Nuget as I'm helping to maintain the project now. Here's a link to the issue that's been created for this: https://github.com/restsharp/RestSharp/issues/583

RequestStreamCallback 方法也需要修改 Http.Async.cs。我实际上正在努力将此修复程序放入 repo 并发布到 Nuget,因为我现在正在帮助维护该项目。这是为此创建的问题的链接:https: //github.com/restsharp/RestSharp/issues/583

回答by andygjp

I had the same problem, but I didn't fancy forking the code and I didn't like the alternative suggested by Michael as the documentation says "RequestBody: Used by AddBody() (not recommended to use directly)".

我有同样的问题,但我不喜欢分叉代码,我不喜欢迈克尔建议的替代方案,因为文档说“RequestBody:由 AddBody() 使用(不建议直接使用)”。

Instead I replaced the RestClient.HttpFactory with my own:

相反,我用我自己的替换了 RestClient.HttpFactory :

RestClient client = GetClient();

var bytes = await GetBytes();
client.HttpFactory = new FactoryWithContent { GetBytes = () => new Bytes(bytes, "application/zip") };

var request = new RestRequest();
return await client.ExecutePostTaskAsync(request);

Where Bytes and FactoryWithContent look like:

Bytes 和 FactoryWithContent 如下所示:

public class Bytes
{
    public Bytes(byte[] value, string type)
    {
        Value = value;
        Type = type;
    }

    public byte[] Value { get; private set; }
    public string Type { get; private set; }
}

public class FactoryWithContent : IHttpFactory
{
    public IHttp Create()
    {
        var http = new Http();

        var getBytes = GetBytes;
        if (getBytes != null)
        {
            var bs = getBytes();
            http.RequestBodyBytes = bs.Value;
            http.RequestContentType = bs.Type;
        }

        return http;
    }

    public Func<Bytes> GetBytes { get; set; }
}

回答by Stephan Ryer

I had the same issue. Turned out that RestSharp behaves in a little odd way.

我遇到过同样的问题。事实证明,RestSharp 的行为方式有点奇怪。

NOT WORKING:

不工作:

request.Parameters.Add(new Parameter() {
  ContentType = "application/x-www-form-urlencoded",
  Type = ParameterType.RequestBody,
  Value = bytes
});

WORKING (Add content-type as name):

工作(添加内容类型作为名称):

request.Parameters.Add(new Parameter() {
  Name = "application/x-www-form-urlencoded", // This is the 'funny' part
  ContentType = "application/x-www-form-urlencoded",
  Type = ParameterType.RequestBody,
  Value = bytes
});

I tried this solution based on a comment here: https://github.com/restsharp/RestSharp/issues/901

我根据这里的评论尝试了这个解决方案:https: //github.com/restsharp/RestSharp/issues/901

which states "...name value will be used as Content-Type Header and contentType value will be ignored."

其中指出“...name 值将用作 Content-Type 标头,而 contentType 值将被忽略。”

You dont have to add the value as the Content-Type parameter as well, but I fear that a future bug-fix might change the behaviour and then requiring the Content-Type to be used instead of name.

您也不必将该值添加为 Content-Type 参数,但我担心将来的错误修复可能会改变行为,然后要求使用 Content-Type 而不是名称。