【问题标题】:Opening a Memory Mapped File causes FileNotFoundException when deployed in IIS在 IIS 中部署时打开内存映射文件会导致 FileNotFoundException
【发布时间】:2013-12-03 23:28:39
【问题描述】:

按照this 网站的代码示例,我创建了一个 Windows 控制台应用程序,该应用程序创建了一个映射内存文件:

        using (var file = MemoryMappedFile.CreateNew("myFile", 24))
        {
            var bytes = new byte[24];
            for (var i = 0; i < bytes.Length; i++)
                bytes[i] = (byte)(65 + i);

            using (var writer = file.CreateViewAccessor(0, bytes.Length))
            {
                writer.WriteArray<byte>(0, bytes, 0, bytes.Length);
            }
            Console.WriteLine("Run memory mapped file reader before exit");
            Console.WriteLine("Press any key to exit ...");
            Console.ReadLine();
        }

在一个新的 asp.net web 应用程序中,我使用代码读取了 MMF:

 protected void Page_Load(object sender, EventArgs e)
    {
        string sOutput = "";

        using (var file = MemoryMappedFile.OpenExisting("myFile"))
        {
            using (var reader = file.CreateViewAccessor(0, 24))
            {
                var bytes = new byte[24];
                reader.ReadArray<byte>(0, bytes, 0, bytes.Length);

                for (var i = 0; i < bytes.Length; i++)
                    sOutput += (char)bytes[i] + " ";

            }
        }

        Response.Write(sOutput);
    }

在开发 IIS Express 中,文件按预期读取,页面显示映射内存文件中的数据。

但是,当部署到 IIS 时,我在 locationMemoryMappedFile.OpenExisting("myFile") 得到异常 System.IO.FileNotFoundException

我尝试将应用程序池标识更改为与运行 MMF 控制台应用程序的相同,但这并没有奏效。

【问题讨论】:

  • myFile 在哪里?
  • 生产 IIS 上是否安装了 ISAPI 模块?
  • Page_Load 你打电话给MemoryMappedFile.OpenExisting。但是您在 Web 应用程序中有 MemoryMappedFile.CreateNew 方法调用吗?
  • CreateNew 在创建 MMF 的控制台应用程序中被调用。在控制台应用程序运行时,您可以从另一个进程访问 MMF。使用 IIS Express 时就是这种情况,但不是标准 IIS
  • ISAPI 模块安装。

标签: asp.net .net iis ipc memory-mapped-files


【解决方案1】:

在地图名称中添加“Global\\”前缀。这是它对我有用的唯一方法。 当我们尝试访问在第一个进程中创建的共享内存时,它在不同的安全上下文中运行,并且共享内存对象是不可见的,除非它们是在全局命名空间中创建的。

这是对我有用的代码。我在 WinForm 应用程序中使用了 CreateOrOpen,在 IIS 进程中使用了 OpenExisting:

mSec = new MemoryMappedFileSecurity();
mSec.AddAccessRule(new AccessRule<MemoryMappedFileRights>(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MemoryMappedFileRights.FullControl, AccessControlType.Allow));

mmf = MemoryMappedFile.CreateOrOpen("Global\\\MmfName", 100, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, mSec, HandleInheritability.Inheritable);

mmf = MemoryMappedFile.OpenExisting("Global\\\MmfName");

【讨论】:

  • 我将代码稍微更改为MemoryMappedFile.OpenExisting("Global\\myFile",MemoryMappedFileRights.FullControl,System.IO.HandleInheritability.None),这似乎成功了。非常感谢。
【解决方案2】:

如果您想要实现进程间通信 (IPC),则可以将 WCF 与命名管道绑定一起使用。以牺牲一些性能为代价获得了很多简单性。

【讨论】:

  • 自从我原来的帖子以来,这实际上是我走的路,而且效果很好。
  • 这是一种解决方法,而不是解决方案。接受这个作为答案是错误的,因为它对将来可能需要解决这个问题的其他人没有帮助。
【解决方案3】:

对于非物理文件,有两种情况,

  1. 您的进程退出后文件将被删除。
  2. IIS 不会在与您的控制台进程相同的用户中运行,IIS 以很少受限的模式运行,因此除非您创建具有附加安全性的文件以允许进程访问您的服务。

你必须使用http://msdn.microsoft.com/en-us/library/dd267529(v=vs.110).aspx这个具有以下安全性的构造函数。

        MemoryMappedFileSecurity mSec = new MemoryMappedFileSecurity ();
        mSec.AddAccessRule(new AccessRule<MemoryMappedFileRights>(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
            MemoryMappedFileRights .FullControl, AccessControlType.Allow));

然后尝试从具有相同安全性的 IIS 访问它。

【讨论】:

  • 默认文件夹位于 \windows\system32 或 \windows\system32\inetsrv 中。您需要指定完整路径,如此答案所示,或调用 Server.MapPath("~/myFile.txt") 根据您的 Web 应用程序根目录计算它。
  • myFile 只是内存映射文件的名称,它在磁盘 afaik 上没有可访问的物理位置,此外,myFile 引用是由另一个 Windows 进程创建的(在我的示例中它只是一个小控制台应用程序)。当网站在 IIS Express 中运行时,它可以正常访问映射的内存位置,当我将 Visual Studio 设置为使用本地 IIS 时,它会失败。
  • 内存映射文件必须是磁盘上的物理位置,您在哪里读到它不一定是? “文件”表示它是磁盘上的物理位置,否则无论如何你都有内存。
  • 我正在使用here 中描述的非持久内存映射文件@“CreateNew 和 CreateOrOpen 方法创建了一个未映射到磁盘上现有文件的内存映射文件。”
  • 仍然没有喜悦。我创建了 MMF 以在 NetworkService 的上下文中运行并将 IIS 工作进程的标识设置为相同,但我仍然得到 Unable to find the specified file. 异常。
猜你喜欢
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
相关资源
最近更新 更多