【问题标题】:Uploading file using MemoryStream via WCF MessageContract to SQL FileStream is empty when it reaches service使用 MemoryStream 通过 WCF MessageContract 将文件上传到 SQL FileStream 在到达服务时为空
【发布时间】:2021-03-07 17:10:36
【问题描述】:

我已经用谷歌搜索了我的 ***,但找不到发生这种情况的原因。 我有一个 WCF 服务(文件),我在其中上传了仅在内存流中的 PDF。内存流显示我在将数据发送到服务之前有数据。当它到达服务时,流是空的。我有一个用于上传的 MessageContract,它有一个 Stream 的 MessageBodyMember。我在服务中调用上传并传递参数(与 MessageContract 中的参数相同。当我查看上传请求对象时,我可以看到除 Stream 之外的所有值。

这是我的 UploadRequest 类:

[MessageContract]
public class UploadRequest
{
    [MessageHeader(MustUnderstand = true)]
    public long EntityID { get; set; }

    [MessageHeader(MustUnderstand = true)]
    public string FileName { get; set; }

    [MessageHeader(MustUnderstand = false)]
    public bool IsPrivileged { get; set; }

    [MessageHeader(MustUnderstand = false)]
    public string Folder { get; set; }

    [MessageHeader(MustUnderstand = false)]
    public Guid stream_id { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream Stream { get; set; }
}

这是我对服务中上传方法的调用:

private void SaveAs()
    {
        var UserID = Convert.ToInt64(Application.Current.Properties["VetID"]);
        var ms = new MemoryStream();
        Control.SaveDocument(ms);
        ms.Position = 0;

        if (!svc.Upload(UserID, null, null, true, gVar.stream_id, ms, out string errormsg))
            _ = errormsg;
    }

注意:我确实将 MemoryStream 位置设置为 0,并且对象 ms 有数据。

这里是FileService上传方法:

public UploadResponse Upload(UploadRequest request)
    {
        DB.dbFileMgr fm = new DB.dbFileMgr();
        return fm.UploadFile(request);
    }

这里是 UploadFile 方法:

if (request.stream_id != null && request.stream_id != new Guid())
            {
                var stream = SharedCommon.ConvertStreamToMemoryStream(request.Stream);
                dbConn.UpdateDocument(request.EntityID, request.IsPrivileged, request.stream_id, stream);
                return new UploadResponse { UploadSucceeded = true };
            }
            else
            {
                dbConn.CreateDocumentFolder(request.Folder, request.EntityID);
                var stream = SharedCommon.ConvertStreamToMemoryStream(request.Stream);
                dbConn.InsertDocument(request.EntityID, stream, request.FileName, request.Folder, request.IsPrivileged);
                return new UploadResponse { UploadSucceeded = true };
            }

当我在 Upload 处设置断点时,Stream 是这样的: Debug info of the Stream

我有一种将 Stream 转换为 MemoryStream 的方法,我认为这会有所帮助,但是当它到达 ReadFully 方法中的 while 循环时,它会跳过它。这告诉我 Stream 是空的。

下面是 Convert 和 ReadFully 方法的代码:

public static MemoryStream ConvertStreamToMemoryStream(Stream stream)
    {
        MemoryStream memoryStream = new MemoryStream();

        if (stream != null)
        {
            byte[] buffer = ReadFully(stream);

            if (buffer != null)
            {
                var binaryWriter = new BinaryWriter(memoryStream);
                binaryWriter.Write(buffer);
            }
        }
        return memoryStream;
    }

    public static byte[] ReadFully(this Stream input)
    {
        byte[] buffer = new byte[48 * 1024];
        using (MemoryStream ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            return ms.ToArray();
        }
    }

我已阅读所有 Microsoft、C-SharpCorner 和 StackOverflow 文章,但我不知道哪里出了问题。我将不胜感激有关发生了什么以及如何解决此问题的任何想法。

编辑 也许我没有说清楚,对不起。我可以使用 FileUpload.InputStream 从文件系统上传文件,但是当我尝试将仅在 MemoryStream 中的动态创建的 PDF 发送到与文件上传相同的服务时,它失败了。在有人说该文件可能有问题之前,我可以将 MemoryStream 保存到我的桌面,并且该文件在 Adob​​e 中可以正常打开。问题似乎是通过 MessageContract 发送 MemoryStream。 InputStream (FileUpload) 似乎没有问题,但 MemoryStream 没有问题。

【问题讨论】:

  • 不,还没有。我试图找出为什么它适用于文件上传(InputStream)但在我发送 MemoryStream 时失败。他们都使用相同的代码。

标签: c# wcf stream memorystream


【解决方案1】:

Stream.Length 仅适用于可搜索的 Stream 实现。您通常可以检查 Stream.CanSeek 是否为真。许多流,因为它们正在被流式传输,所以具有无法提前知道长度的性质。

如果您必须知道长度,您可能需要实际缓冲整个流,提前将其加载到内存中。

您可以考虑将上传的文件复制到 MemoryStream:

 public void Upload(UploadRequest request)
    {

        MemoryStream outstream = new MemoryStream();
        const int bufferLen = 4096;
        byte[] buffer = new byte[bufferLen];
        int count = 0;
        while ((count = request.Stream.Read(buffer, 0, bufferLen)) > 0)
        {
            outstream.Write(buffer, 0, count);
        }

        byte[] b = outstream.ToArray();
        string s = System.Text.Encoding.UTF8.GetString(b, 0, b.Length);
        Console.WriteLine(s);

    }

更新:

你需要修改你的 ConvertStreamToMemoryStream 方法:

  public static MemoryStream ConvertStreamToMemoryStream(Stream stream)
        {
            MemoryStream outstream = new MemoryStream();
            const int bufferLen = 48 * 1024;
            byte[] buffer = new byte[bufferLen];
            int count = 0;
            while ((count = stream.Read(buffer, 0, bufferLen)) > 0)
            {
                outstream.Write(buffer, 0, count);
            }
            return outstream;
        }

【讨论】:

  • 谢谢,但我不是在寻找流的长度。我只是在评论您无法获得长度,因为它不可用。此外,我已经将输入流转换为内存流(var stream = SharedCommon.ConvertStreamToMemoryStream(request.Stream);)。问题是此时的输入流现在是空的。我有一个应用程序的文件上传部分,它使用完全相同的代码,没有任何问题。但是当我尝试发送内存流时它失败了。那是我的问题。
  • 谢谢邓鹏,可惜没用。当它到达“while”循环时,它不会进入它,因此它永远不会写入内存流。问题似乎是传入的流。 MemoryStream 可以很好地离开 WPF 应用程序。然后它转到 Service,它将发送给它的参数带入一个 MessageContract,该 MessageContract 具有一个用于 Stream 的 MessageBodyMember。我在服务的 Upload 方法中调用了 ConvertStreamToMemoryStream,它也没有进入“while”循环。似乎是转换为 MessageContract 可能是问题。
猜你喜欢
  • 2023-04-06
  • 2014-08-26
  • 2011-10-04
  • 1970-01-01
  • 2019-09-24
  • 2020-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多