2

在此页面的评论中:

http://msdn.microsoft.com/en-us/library/12s31dhy%28v=VS.90%29.aspx

..它说 TransmitFile() 不能与 UNC 共享一起使用。据我所知,情况就是这样;当我尝试它时,我在事件日志中收到此错误:

TransmitFile failed. File Name: \\myshare1\e$\file.zip, Impersonation Enabled: 0, Token Valid: 1, HRESULT: 0x8007052e

建议的替代方法是使用 WriteFile(),但是,这是有问题的,因为它将文件加载到内存中。在我的应用程序中,文件大于 200MB,因此不会扩展。

ASP.NET 中是否有一种方法可以将文件流式传输给用户:

  • 可扩展(不将整个文件读入 RAM 或占用 ASP.NET 线程)
  • 与 UNC 股票合作

将网络驱动器映射为虚拟目录对我们来说不是一个选项。我也想避免将文件复制到本地 Web 服务器。

谢谢

4

7 回答 7

1

您是否尝试过使用远程 UNC 路径作为其主目录来设置 IIS vroot?如果可行,这可能是最简单的解决方案。您仍然可以对文件实施身份验证障碍(例如,通过 HttpModule,或者甚至可能通过开箱即用的表单身份验证模块),但是一旦您的身份验证过滤器获得批准,您就可以依靠 IIS 来有效地流式传输内容。

一个警告:我上次在 UNC 场景中配置 IIS 是很久以前(1998 年!!!),我遇到了文件被锁定在远程机器上的间歇性问题,导致更新文件有时会出现问题。处理 UNC 服务器重新启动后的恢复也很有趣。我想从那以后的 11 年里,这些问题已经解决了,但你永远无法确定!

另一种方法可能是在 UNC 机器上安装 Web 服务器,然后在您的 Web 服务器上安装反向代理服务器,例如新的IIS7 应用程序请求路由模块。

如果你愿意占用一个服务器线程,你可以使用KB812406中推荐的方法来处理 RAM 消耗、超时、客户端断开等问题。确保关闭响应缓冲!

理想的最大控制解决方案是“流式 HttpHandler”,您可以将流返回给 ASP.NET,让 ASP.NET 处理有关分块结果的详细信息,而不是一次发送所有输出。 ,处理断开连接等。但我无法找到一个好的方法来做到这一点。:-(

于 2009-11-17T20:04:38.407 回答
0

您可以尝试使用 a 打开网络文件FileStream,并使用循环读取文件的一个块,传输该块(使用Response.Write(Char[], Int32, Int32)),处理该块,然后重复直到文件被完全读取。

于 2009-10-30T23:42:38.927 回答
0

您可以将文件写入本地目录,并让 robocopy 作业监视目录以进行复制。

但是,由于您想避免写入本地服务器,您可能需要调查将服务器(例如 HTTP 或 FTP)放在目标服务器上,并将文件写入该服务。

于 2009-11-17T17:20:34.227 回答
0

您可以设置另一个指向 UNC 的 IIS 网站,然后将它们重定向到该其他网站上的文件吗?

Response.Redirect(" http://files.somewhere.com/some/file.blah ");

这样,它将在单独的工作进程中运行并且对您当前的站点没有影响,并且文件将直接由 IIS 提供,这显然是最好的。

于 2009-11-17T17:33:36.213 回答
0

您得到的实际错误是文件共享的登录失败(考虑到用户 IIS 可能正在运行,以及您尝试访问管理共享,这并不奇怪)。您是否尝试过设置一个完全没有访问限制的共享,只是为了检查这是否是问题,而不是 TransmitFile 中的任何特定限制。

如果可以解决它,那么您需要以一种或另一种方式以当前用户身份登录到该共享,或者冒充具有权限的用户。

还值得指出的是,在使用反射器 TransmitFile 环顾四周之后,无论如何都可能最终将文件读入内存,并且 WriteFile 有另一个版本,它采用一个布尔值来决定是否将文件读入内存(在事实上,默认的 WriteFile 为这个参数传递了 false)。可能值得您在代码中四处寻找。

于 2009-11-21T09:03:07.420 回答
0

我会推荐第二种站点方法并实施基于令牌的身份验证机制。在通过重定向传递给客户端的 URL 中编码身份验证 cookie。例如,这可能是在幕后共享的不透明值,也可能是密码和当前日期的哈希值一样简单。

我做过的一个项目使用了散列。一台服务器生成了一个共享密码和一个分机号码的哈希值。第二台服务器(在不同的网络上)采用相同的密码和分机,并对它们进行哈希处理,以确认用户被允许从该分机拨打所需的电话号码。

于 2009-11-24T01:25:07.270 回答
-1

TransmitFile 的代码很简单,为什么不修改它来做你需要的呢?

public void TransmitFile(string filename, long offset, long length)
{
    if (filename == null)
    {
        throw new ArgumentNullException("filename");
    }
    if (offset < 0L)
    {
        throw new ArgumentException(SR.GetString("Invalid_range"), "offset");
    }
    if (length < -1L)
    {
        throw new ArgumentException(SR.GetString("Invalid_range"), "length");
    }
    filename = this.GetNormalizedFilename(filename);
    using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        long num = stream.Length;
        if (length == -1L)
        {
            length = num - offset;
        }
        if (num < offset)
        {
            throw new ArgumentException(SR.GetString("Invalid_range"), "offset");
        }
        if ((num - offset) < length)
        {
            throw new ArgumentException(SR.GetString("Invalid_range"), "length");
        }
        if (!this.UsingHttpWriter)
        {
            this.WriteStreamAsText(stream, offset, length);
            return;
        }
    }
    if (length > 0L)
    {
        bool supportsLongTransmitFile = (this._wr != null) && this._wr.SupportsLongTransmitFile;
        this._httpWriter.TransmitFile(filename, offset, length, this._context.IsClientImpersonationConfigured || HttpRuntime.IsOnUNCShareInternal, supportsLongTransmitFile);
    }
}



private void WriteStreamAsText(Stream f, long offset, long size)
{
    if (size < 0L)
    {
        size = f.Length - offset;
    }
    if (size > 0L)
    {
        if (offset > 0L)
        {
            f.Seek(offset, SeekOrigin.Begin);
        }
        byte[] buffer = new byte[(int) size];
        int count = f.Read(buffer, 0, (int) size);
        this._writer.Write(Encoding.Default.GetChars(buffer, 0, count));
    }
}


internal void TransmitFile(string filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile)
{
    if (this._charBufferLength != this._charBufferFree)
    {
        this.FlushCharBuffer(true);
    }
    this._lastBuffer = null;
    this._buffers.Add(new HttpFileResponseElement(filename, offset, size, isImpersonating, supportsLongTransmitFile));
    if (!this._responseBufferingOn)
    {
        this._response.Flush();
    }
}

谢谢,

菲尔。

于 2009-11-24T16:14:59.023 回答