【问题标题】:REST post request with optional file upload带有可选文件上传的 REST 发布请求
【发布时间】:2013-05-09 15:51:08
【问题描述】:

在创建 WCF REST 服务时,我以 json 格式接收数据并能够保存在数据库中。现在我需要提供使用相同服务上传文件(可选、图像或视频)的选项。我尝试发送字节数组,但它给出了错误的请求错误,可能是因为序列化了这么长的数组。我读到上传需要使用流的大文件。在发送其他参数时我将如何做到这一点?我正在创建此服务以从移动设备接收数据。这是我的服务接口

[WebInvoke(UriTemplate = "SaveFBPost", 
    Method = "POST", 
    BodyStyle = WebMessageBodyStyle.Wrapped,
    RequestFormat = WebMessageFormat.Json, 
    ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
void SaveFacebookPost(FBPostData fbPostData);

公共类 FBPostData:

[DataMember]
public string scheduleDate { get; set; }

[DataMember]
public string userId { get; set; }

[DataMember]
public string groupId { get; set; } 

[DataMember]
public string postText { get; set; }

[DataMember]
public byte[] file { get; set; }

[DataMember]
public string fileType { get; set; }

[DataMember]
public string accessToken { get; set; }

【问题讨论】:

  • 如果有人怀疑我没有付出努力,那么你可以看到它已经一整天了,我仍然遇到同样的问题。在发帖之前我又搜索了 1 天。可能是正确方向的一点指导。有人吗?
  • 您需要发布一些更实质性的代码示例 - 您是否调整了 maxBufferSize 和 maxArrayLength?
  • 是的,我增加了 maxBufferSize 和 maxReceivedMessageSize。网上有很多令人困惑和相互矛盾的信息(至少对于像我这样的初学者来说)。就像您提到的博客中所说的“如果使用流,WCF 不会让您拥有任何其他参数”。很好。您还可以将参数传递给 Webinvoke,当然也可以使用 REST 发送流。我现在正在使用多部分文件上传。似乎可以正常工作,但尚未经过全面测试。会在这里更新
  • 并对迟到的回复表示歉意。我也在安卓方面工作,中间有一个周末:)
  • 我已经给出了这个问题的解决方案。非常感谢您的帮助和跟进

标签: c# wcf


【解决方案1】:

我会首先为 web.config 中的特定绑定增加 maxBufferSize 和 maxArrayLength,看看是否能解决问题。

您还应该能够提取有关该错误的更多细节,这样您就可以准确了解为什么会出现 400 错误。

This blog article 过去对我也很有用 - 底部也有一些很好的链接。

还可以查看Stream 类。不确定“发送其他参数”是什么意思 - 如果您能澄清这一点,我们可以为您提供更多指导。

【讨论】:

  • 我正在查看您提到的博客,并会回复您。至于其他参数,就像我说的那样,我正在使用这个 api 调用发送其他数据,正如您在 FBPostData 类中看到的那样。这仅在我删除文件字节数组以进行文件上传时才有效。
  • 这篇文章很有帮助,但仍然没有运气。我使用的是 webinvoke,但现在我使用的是 SOAP,因为 Steam 不能用 REST 完成?现在我的服务根本没有受到影响。可能是我搞砸了我的配置。你能帮帮我吗?
【解决方案2】:

我不得不使用来自 android 的分段上传和分段解析器的流来解决这个问题。我使用 Apache mime 库来上传文件并发送如下参数:

HttpPost postRequest = new HttpPost(
                context.getString(R.string.url_service_fbpost));
        MultipartEntity reqEntity = new MultipartEntity(
                HttpMultipartMode.BROWSER_COMPATIBLE);
        if(postData.data != null && !"".equals(postData.fileName)){
            ByteArrayBody bab = new ByteArrayBody(postData.data, postData.fileName);
            reqEntity.addPart("uploaded", bab);
        }
        reqEntity.addPart("scheduleDate", new StringBody(postData.scheduleDate));
        reqEntity.addPart("userId", new StringBody(postData.userId));
        reqEntity.addPart("groupIds",
                new StringBody(postData.groupIds.toString()));
        reqEntity.addPart("postText", new StringBody(postData.postText));
        reqEntity.addPart("postType", new StringBody(postData.postType));
        reqEntity.addPart("accessToken", new StringBody(postData.accessToken));
        if(postData.postId != null && postData.postId.length() > 0) {
            reqEntity.addPart("postId", new StringBody(postData.postId));
        }
        postRequest.setEntity(reqEntity);

之后我使用 c# 多部分解析器来获取文件和参数。这是服务代码:

[OperationContract]
[WebInvoke(Method = "POST",
        UriTemplate = "UploadFBPost",
        BodyStyle = WebMessageBodyStyle.WrappedRequest)]
void UploadFBPost(Stream stream);

 public void UploadFBPost(Stream stream)
{
    MultipartParser parser = new MultipartParser(stream);

    // Saves post data in database
    if (parser.Success)
    {
        string fileName = null, userId = null, postText = null, postType = null, accessToken = null;
        DateTime scheduleDate = DateTime.Now;
        string[] groupIds = null;
        int postId = 0;

        // Other contents
        foreach (MyContent content in parser.MyContents)
        {
            switch (content.PropertyName)
            {
                case "scheduleDate":
                    if (string.IsNullOrEmpty(content.StringData.Trim()))
                        scheduleDate = DateTime.Now;
                    else
                        scheduleDate = DateTime.ParseExact(content.StringData.Trim(), "M-d-yyyy H:m:s", CultureInfo.InvariantCulture);
                    break;

                case "fileName":
                    fileName = content.StringData.Trim();
                    break;

                case "userId":
                    userId = content.StringData.Trim();
                    break;

                case "postText":
                    postText = content.StringData.Trim();
                    break;

                case "accessToken":
                    accessToken = content.StringData.Trim();
                    break;

                case "groupIds":
                    groupIds = content.StringData.Trim().Split(new char[] { ',' });
                    break;

                case "postType":
                    postType = content.StringData.Trim();
                    break;

                case "postId":
                    postId = Convert.ToInt32(content.StringData.Trim());
                    break;
            }
        }

        string videoFile = null, imageFile = null;
        if (parser.FileContents != null)
        {
            string filePath = GetUniqueUploadFileName(parser.Filename);
            File.WriteAllBytes(filePath, parser.FileContents);
            if (postType == "photo")
                imageFile = Path.GetFileName(filePath); 
            else 
                videoFile = Path.GetFileName(filePath); 
        }
    }
}

您确实需要根据您发送的数据修改多部分解析器。希望这会节省一些时间。

感谢雷的帮助。

还有一件事。我不得不在 web config 中添加这些行:

<httpRuntime maxRequestLength="2000000"/>

<bindings>
  <webHttpBinding>
    <binding maxBufferSize="65536"
             maxReceivedMessageSize="2000000000"
             transferMode="Streamed">
    </binding>
  </webHttpBinding>
</bindings>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 2018-02-04
    相关资源
    最近更新 更多