2

在本页面的评论:Response.TransmitFile()与UNC共享(ASP.NET)

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的方法:

  • 可扩展性(不读取整个文件到内存或者占用ASP.NET线程)
  • 作品与UNC共享

映射网络驱动器作为虚拟目录不是我们的选择。我想避免将文件复制到本地Web服务器。

感谢

回答

1

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

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

另一种方法可能是安装UNC机器上的Web服务器,然后Web服务器上安装一个反向代理服务器,如新IIS7 Application Request Routing模块。

如果您愿意绑定服务器线程,您可以使用KB812406中推荐的方法,该方法可处理RAM消耗,超时,客户端断开等问题。确保关闭Response Buffering!

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

+0

IIS7应用程序请求路由模块听起来像它可能适用于我...会给它一个镜头。 – frankadelic 2011-08-19 16:07:52

0

的东西,你可以尝试使用FileStream正在打开网络文件,并使用循环读取文件的块,传输(使用Response.Write(Char[], Int32, Int32))块,处理该块,并重复,直到该文件已被完全读取。

+0

与此相关的一个问题是它在整个文件传输过程中占用了ASP.NET工作进程线程。所以它可能不如TransmitFile()那样可伸缩。 – frankadelic 2009-10-31 01:35:39

+0

是的。但它可能是你必须解决的快乐媒介,因为它似乎没有任何内置的功能来满足你的需求。 – 2009-10-31 04:50:19

+0

这种方法也存在脚本超时的风险,不是吗? – frankadelic 2009-11-04 17:55:02

0

您可以将文件写入本地目录,并使用监控目录的robocopy作业进行复制。

既然你想避免书写到本地服务器,不过,你可能需要调查把目标服务器上的服务器(HTTP或FTP,例如),并写入文件到该服务。

+0

这也是我的解决方案,但对于任何可能负载均衡的任何情况都不理想。我们有一个实际使用此方法的客户端,并且每30秒在站点中的所有文件夹中运行robo,并且当一个机器人踩到另一个时,它会失败几次。 – 2009-11-17 17:25:16

+0

我在负载平衡的环境中运行。正如你所提到的,我想避免写入本地Web服务器。 – frankadelic 2009-11-17 18:58:44

0

你能不能成立另一个IIS网站,指向UNC,然后将其重定向到文件,其他网站上?

的Response.Redirect( “http://files.somewhere.com/some/file.blah”);

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

+0

与此相关的问题是,如果有人知道该URL,则该文件可用于开放访问。从同一个进程提供文件意味着我可以使用表单身份验证来限制对文件的访问。 – frankadelic 2009-11-17 19:00:20

+0

好吧,我不认为你会找到一个想法的解决方案,你想服务的文件没有任何asp.net的参与,使用asp.net autentication ...你需要找到一个解决方案之间。 – 2009-11-17 21:47:27

0

您收到的实际错误是文件共享的登录失败(考虑到用户IIS可能正在运行,以及您试图访问管理共享,这并不令人惊讶) 。你是否尝试设置一个没有访问限制的共享,只是为了检查这个问题,而不是传输文件中的任何特定限制。

如果修复了这个问题,那么您需要以单向方式登录该共享或另一个作为当前用户,或者模拟一个有权限的用户

还值得指出的是,在用反射器环视四周后,TransmitFile可能会结束无论如何将文件添加到内存中,并且WriteFile具有另一个版本,它需要一个布尔值来决定是否将文件读入内存(事实上,默认的WriteFile将为此参数传递false)。可能值得你在代码中徘徊。

+0

我已经删除了对共享的访问限制 - 没有帮助。 – frankadelic 2009-11-25 01:40:45

0

我会推荐第二个站点方法并实现基于令牌的认证机制。在通过重定向传递给客户端的URL中对认证Cookie进行编码。例如,这可能是幕后分享的一个不透明的值,或者可能像秘密密码的散列和当前日期一样简单。

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

+0

ASP.NET是第二个站点吗?它如何处理cookie? – frankadelic 2009-11-25 01:42:32

+0

第一个网站是PHP,第二个是使用HttpListener的自定义C#服务。但是,这种技术适用于任何地方。 – 2009-11-30 19:42:55

-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(); 
    } 
} 

感谢,

菲尔。