通过 WCF 服务接收大文件

Receive large files via WCF service

我有一个应该接收大文件的应用程序,这就是我使用 stream 参数的原因。

服务合同:

[ServiceContract]
public interface IFile
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "/Upload?fileName={fileName}&requestType={requestType}", ResponseFormat = WebMessageFormat.Json)]
    FileMetadata Upload(string fileName, RequestType requestType, Stream stream);
}

实施:

public FileMetadata Upload(string fileName, RequestType requestType, Stream stream)
{
    var contract = GetContract(fileName, requestType, stream);
    ...
}

private static FileUploadRequest GetContract(string fileName, RequestType requestType, Stream content)
{
    var ms = new MemoryStream();
    content.CopyTo(ms);
    return new FileUploadRequest
    {
        Filename = fileName,
        RequestType = requestType,
        Content = ms.ToArray()
    };
}

但是对于流,我收到垃圾信息(边界等),传输的示例 XML 是:

--a288ea6c-376a-4c7e-9680-39199e34082c
Content-Disposition: form-data

<Doc> ... rest of XML

如何传输流本身?我应该在客户端删除边界还是在服务器一上截断?因为这个服务也应该从JS使用,我不知道它是否包含这样的额外信息。

客户端发送这样的请求:

public async Task<FileMetadata> Upload(string fileName, RequestType requestType, Stream stream)
{
    var requestUri = $"Upload?fileName={fileName}&requestType={requestType}";
    using (var requestContent = new MultipartFormDataContent())
    {
        requestContent.Add(new StreamContent(stream));
        var response = await _client.PostAsync(requestUri, requestContent).ConfigureAwait(false);
        if (response.IsSuccessStatusCode)
        {
            var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            return JsonConvert.DeserializeObject<FileMetadata>(responseContent);
        }
    }
    throw new Exception();
}

HttpWebRequest 配合使用效果很好,但我想使用更现代的方法。我确定我做错了什么,请指教:

public FileMetadata Upload(string fileName, RequestType requestType, Stream stream)
{
    var requestUri = $"Upload?fileName={fileName}&requestType={requestType}";
    var request = WebRequest.CreateHttp(new Uri(_client.BaseAddress, requestUri));
    request.Method = "POST";
    request.AllowWriteStreamBuffering = false;
    request.ContentLength = stream.Length;
    using (var requestStream = request.GetRequestStream())
    {
        stream.CopyTo(requestStream);
    }
    using (var response = (HttpWebResponse) request.GetResponse())
    {
        if (response.StatusCode != HttpStatusCode.OK)
        {
            throw new Exception();
        }
        using (var sr = new StreamReader(response.GetResponseStream()))
        {
            return JsonConvert.DeserializeObject<FileMetadata>(sr.ReadToEnd());
        }
    }
}

已解决:只需单独使用 StreamContent,不包含在 MultipardFormDataContent 中。代码示例:

public async Task<FileMetadata> Upload(string fileName, RequestType requestType, Stream stream)
{
    var requestUri = $"Upload?fileName={fileName}&requestType={requestType}";
    var response = await _client.PostAsync(requestUri, new StreamContent(stream)).ConfigureAwait(false);
    if (response.IsSuccessStatusCode)
    {
        var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        return JsonConvert.DeserializeObject<FileMetadata>(responseContent);
    }
    throw new Exception();
}