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

时间:2012-04-15 02:04:53

标签: c# restsharp

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

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

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

我并不反对解决这个问题的反思,但我希望避免修改源只是为了在HTTP请求中发送任意数据。

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

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

<arbitrary bytes>

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

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

<other arbitrary bytes>

6 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:5)

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

我修改了RestSharp,因此它只在文件数量时使用多部分编码&gt; 1或文件数= 1,还有正文或其他帖子数据集。

您必须从

修改第288行的Http.cs
if(HasFiles)

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

对于Http.Sync.cs,从

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

    PreparePostBody(webRequest);
}

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

如果使用异步版本,则必须在Http.Async.cs中修改与上述类似的代码。

现在你可以像这样使用RestSharp

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

Client.Execute(request);

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

答案 2 :(得分:5)

在编写本文时的最新版本的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);
    }

答案 3 :(得分:4)

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

相反,我将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);

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

答案 4 :(得分:1)

我有同样的问题。原来,RestSharp表现得有些奇怪。

不工作:

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

WORKING(将内容类型添加为名称):

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

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

表示“...名称值将用作Content-Type标头,而contentType值将被忽略。”

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

答案 5 :(得分:0)

对于RequestStreamCallback方法,还需要对Http.Async.cs进行修改。我正在努力将这个修复程序放到repo中并发布到Nuget,因为我现在正在帮助维护项目。以下是为此创建的问题的链接:https://github.com/restsharp/RestSharp/issues/583