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

后端 未结 6 2215
闹比i
闹比i 2020-12-14 12:48

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

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


        
相关标签:
6条回答
  • 2020-12-14 13:03

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

    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

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

    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.

    0 讨论(0)
  • 2020-12-14 13:11

    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:

        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);
        }
    
    0 讨论(0)
  • 2020-12-14 13:15

    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

    0 讨论(0)
  • 2020-12-14 13:16

    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

    0 讨论(0)
  • 2020-12-14 13:20

    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:

    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.

    You have to modify Http.cs on Line 288 from

    if(HasFiles)
    

    to

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

    For Http.Sync.cs modify PreparePostData from

    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.

    Now u can use RestSharp like this

    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.

    0 讨论(0)
  • 2020-12-14 13:20

    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)".

    Instead I replaced the RestClient.HttpFactory with my own:

    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:

    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; }
    }
    
    0 讨论(0)
提交回复
热议问题