Bee*_*bok 5 c# python asp.net iis arcgis
这表面上看起来像是Python ArcGIS ArcPy RuntimeError: NotInitialized的重复,但这是不同的,因为
\n\n指的是持续发生的错误,而我仅从 IIS 收到\n错误
\n\n我有一个调用 Python 脚本的 ASP.NET 应用程序。该代码使用 System.Diagnostics.Process 对象调用 Python.exe 并向其传递参数,例如 Python 脚本的位置和其他参数。\n该 Process 对象在 C# 中如下所示
\n\n Process proc = new Process();\nproc.StartInfo.Verb = "runas"; \nproc.StartInfo.FileName = pathToPythonExe;\nproc.StartInfo.Arguments = procArgs;\nproc.StartInfo.RedirectStandardError = true;\nproc.StartInfo.RedirectStandardOutput = true;\nproc.StartInfo.CreateNoWindow = true;\nproc.StartInfo.UseShellExecute = false;\nproc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;\nproc.Start();\nproc.WaitForExit(); \nerrorToConsole = proc.StandardError.ReadToEnd();\nproc.WaitForExit();\nmessageToConsole = proc.StandardOutput.ReadToEnd();\nproc.WaitForExit();\nRun Code Online (Sandbox Code Playgroud)\n\nPath 和 PYTHONPATH 环境变量准确指向 Python 可执行文件所在的位置。
\n\n当我在 Visual Studio 2015 的 IIS Express 中从 ASP.NET C# 应用程序运行 Python 脚本时,一切运行正常。当我通过命令控制台运行 Python 脚本时,一切运行正常。当我从 IDLE 运行 Python 脚本时,一切运行正常。但是,当我将应用程序发布到 IIS 8.5 并运行它时,Python 脚本中出现错误。此外,当我从 Visual Studio 运行应用程序并使用本地 IIS 而不是 IIS Express 时,Python 脚本再次失败。
因此,这里回顾一下它起作用的条件:
\n\n以下是它不起作用的条件的回顾:
\n\n错误的要点是脚本行“import acrpy”上的“RuntimeError: NotInitialized”。这列在下面的“错误 #1”下。我发现在 VS(本地 IIS 或 IIS Express)与常规 IIS 中运行它的唯一区别是权限。
\n\n当我在 Visual Studio 中运行它时,Visual Studio 应用程序具有管理员权限。\n在 IIS 中,身份验证是在启用 Windows 身份验证的情况下设置的。其他所有内容均被禁用。\n以下是应用在 IIS 8.5 中运行以及在具有本地 IIS 的 Visual Studio 中运行时出现的完整错误消息。
\n\n错误#1:
\n\nTraceback (most recent call last):\n File "E:\\Application Development\\PublishServiceDefinition\\MapPublisher\\MapSdDraftCreator.py", line 1, in <module>\n \xc3\xaf\xc2\xbb\xc2\xbfimport arcpy\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\__init__.py", line 21, in <module>\n from arcpy.geoprocessing import gp\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\geoprocessing\\__init__.py", line 14, in <module>\n from _base import *\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\geoprocessing\\_base.py", line 598, in <module>\n env = GPEnvironments(gp)\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\geoprocessing\\_base.py", line 595, in GPEnvironments\n return GPEnvironment(geoprocessor)\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\geoprocessing\\_base.py", line 551, in __init__\n self._refresh()\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcpy\\geoprocessing\\_base.py", line 553, in _refresh\n envset = (set(env for env in self._gp.listEnvironments()))\nRuntimeError: NotInitialized\nRun Code Online (Sandbox Code Playgroud)\n\n这是迄今为止我已完成的故障排除操作。
\n\n第一次尝试进行故障排除: \n 我完全卸载并重新安装了 Desktop 10.3(其中包括 Python 文件和 arcpy 文件)。那没有帮助。我遇到了同样的错误。
\n\n第二次尝试进行故障排除: \n我在另一台 Windows 2012 服务器上安装了 Desktop 10.3(和 Python.exe),并在该计算机上设置了 IIS(第二台计算机上没有 Visual Studio)。发生了同样的错误。在第二台计算机上安装之前,我确保已删除所有 ESRI 产品(包括从注册表中删除)。
\n\n第三次尝试进行故障排除: \n我添加了“import arcinfo”作为第一行,以便 Python 脚本的前两行如下所示:
\n\nimport arcinfo\nimport arcpy\nRun Code Online (Sandbox Code Playgroud)\n\n这导致了以下错误:
\n\n错误#2:
\n\nTraceback (most recent call last):\n File "<string>", line 1, in <module>\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\__init__.py", line 21, in <module>\n from arcpy.geoprocessing import gp\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\geoprocessing\\__init__.py", line 14, in <module>\n from _base import *\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\geoprocessing\\_base.py", line 598, in <module>\n env = GPEnvironments(gp)\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\geoprocessing\\_base.py", line 595, in GPEnvironments\n return GPEnvironment(geoprocessor)\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\geoprocessing\\_base.py", line 551, in __init__\n self._refresh()\n File "e:\\program files (x86)\\arcgis\\desktop10.3\\arcpy\\arcpy\\geoprocessing\\_base.py", line 553, in _refresh\n envset = (set(env for env in self._gp.listEnvironments()))\nRuntimeError: NotInitialized\n\nTraceback (most recent call last):\n File "E:\\Application Development\\PublishServiceDefinition\\MapPublisher\\MapSdDraftCreator.py", line 1, in <module>\n \xc3\xaf\xc2\xbb\xc2\xbfimport arcinfo\n File "E:\\Program Files (x86)\\ArcGIS\\Desktop10.3\\ArcPy\\arcinfo.py", line 18, in <module>\n gp.setProduct("ArcInfo")\nRuntimeError: ERROR 999999: Error executing function.\nRun Code Online (Sandbox Code Playgroud)\n\n第四次尝试进行故障排除: \n由于 Windows 身份验证使用本地 IIS_IUSRS 帐户,因此我将该帐户完全控制给 \n\xe2\x80\xa2 包含 Python.exe 文件的文件夹,\n\xe2\x80\xa2 ArcGIS\\Desktop10.3 文件夹\n\xe2\x80\xa2 包含 Python 脚本的文件夹\n\xe2\x80\xa2 由 Python 脚本访问的任何文件夹
\n\n我从 Python 脚本中删除了 \xe2\x80\x9cimport arcinfo\xe2\x80\x9d 。结果与我第一次从 IIS 尝试时的结果相同。
\n\n第五次故障排除尝试: \n 由于错误似乎引用了环境变量,我认为本地 IIS_IUSRS 组可能出于安全原因不允许\xe2\x80\x99t 允许其进程中的任何线程访问环境变量。那只是一个猜测。在我看来,这就像微软可能会做的事情。\n 因此,我在 IIS 中获取了应用程序来模拟具有本地管理员权限的帐户。当我再次运行 ASP.NET 应用程序时,它似乎甚至没有尝试读取 Python 脚本。包装 Python 脚本的 C# 进程捕获 StandardError 和 StandardOutput。使用模拟时不会捕获任何内容。此外,调试器停留在 Start() 和 WaitForExit() 方法上的时间可以忽略不计,就好像 Process 对象中的执行线程甚至没有尝试读取 Python 脚本。\n 如果这是文件夹安全权限的问题,那么当 IIS_IUSRS 没有\xe2\x80\x99t 具有足够的权限时,我就会收到模拟帐户的错误。但是,我没有\xe2\x80\x99 收到任何错误。看起来使用模拟帐户运行的进程甚至没有尝试执行任何操作。
\n\n第六次尝试故障排除: \n 由于已安装的 Python.exe 是 Python 的 32 位版本,因此我转到 ASP.NET 应用程序使用的应用程序池,并确保 32 位应用程序设置为在高级设置中启用。\xe2\x80\x99 并没有改变 IIS 模拟打开或关闭的结果。
\n\n我看到的唯一奇怪的事情是 Visual Studio 中的 ASP.NET 项目属性显示它是针对 .NET Framework 4.5 的,而应用程序池是为版本设置的 IIS 管理器显示应用程序池是为 .NET CLR 设置的4.0版本。当我尝试在IIS管理器中更改.NET Framework版本时,它只提供v4.03和v2.05两种选择。我不知道这有多重要。
\n\n编辑(5/18/2016 4:06 pm): \n我已经做了一些更多的测试。我查看了三种不同条件下的一些环境变量。我使用以下三个设置在 Visual Studio 中运行 ASP.NET 应用程序:
\n\n以下是这些测试的一些结果。
\n\n本地 IIS ,禁用模拟:
\n\nEnvironment.UserDomainName = "IIS APPPOOL"\nEnvironment.UserName = .NET v4.5\nRun Code Online (Sandbox Code Playgroud)\n\n本地 IIS,启用模拟,身份 = x12345:
\n\nEnvironment.UserDomainName = x12345\nEnvironment.UserName = ABC\nRun Code Online (Sandbox Code Playgroud)\n\nIIS 快递:
\n\nEnvironment.UserDomainName = x12345\nEnvironment.UserName = ABC\nRun Code Online (Sandbox Code Playgroud)\n\n从上面请注意,启用模拟运行如何以与 IIS Express 运行相同的身份运行,从而产生相同的环境变量。\n这告诉我,也许我应该在启用 ASP.NET 模拟开始时专注于使其正常工作,因为,我之前提到过,使用 IIS Express 运行始终是成功的。尝试尽可能接近地模拟那些已知的成功条件似乎对我有利。\n 对我来说,将我的精力集中在尝试找出为什么使用与 IIS 相同的环境用户进行 ASP.NET 模拟似乎是合理的Express 无法运行脚本。如有意见和建议,我们将不胜感激。
\n\n编辑(2016年5月19日下午1:40):
\n\n我尝试在“IIS 管理服务”属性和 W3SVC 属性中启用“允许服务与桌面交互”选项。这没有帮助。
\n\n我的下一次尝试将是创建一个调用 Python 可执行文件并返回结果的 Web 服务。我将让当前的 ASP.NET 应用程序调用 Web 服务,然后返回结果。\n除非有人对为什么这不起作用有意见,或者有关于如何使当前 ASP.NET 应用程序按预期运行的意见,否则我将继续采用 Web 服务策略。
\n\n编辑(2016年5月25日)
\n\n经过近三周的努力,我终于成功了。
\n\n虽然我到底做了什么才能使其正常工作还没有定论,但以下是我所做的两件主要事情。
\n\n我使用 IIS 中托管的 basicHttpBinding 创建了一个 WCF 服务。wsHttpBinding 对我不起作用,因为当我尝试将其配置为 Windows 身份验证并设置 mode="transport" 时,我收到一条错误,指出需要 ssl。
\n\n更重要的事情似乎是我将WCF服务的应用程序池的进程标识从ApplicationPoolIdentity更改为具有提升权限的帐户。
\n\n现在,当我在任务管理器中查看 w3wp.exe 用户名时,我发现它正在使用该帐户的名称运行。
\n\n我的下一步是开始按顺序撤消之前的所有配置并测试以查看哪些配置是不必要的。例如,我已将应用程序池帐户添加到包含所使用的 Python 脚本和可执行文件的文件夹的安全访问权限中。\n现在我认为这可能是不必要的,因为 w3wp 可以通过其新帐户访问 Python 脚本。我将开始删除之前添加的其他帐户。
\n\n事后看来,我认为创建 Web 服务在技术上可能是不必要的,因为我可能刚刚能够更改运行 ASP.NET 应用程序的应用程序池的进程标识。但是,这可能存在安全问题,因为 ASP.NET 应用程序可由用户直接访问,而 Web 服务只能间接访问,即使该应用程序是 Intranet 应用程序并且没有面向外部的接口。
\n\n任何关于我让它发挥作用的见解(建议和/或建设性批评)将不胜感激。
\n我对此进行了更多研究,现在我明白了为什么我的解决方案有效。这些信息回答了我原来的问题。以下是我的研究发现的关于该主题的有用且相关的信息。
当 ArcGIS Desktop 10.3 安装在计算机上时,它会创建一个用于存储重要信息的目录。该目录的默认位置取决于启动 ArcGIS Desktop 应用程序安装的用户的登录帐户名。例如,如果登录帐户是 MS\AHejlsberg,则默认安装的 UNC 路径将为
C:\Users\AHejlsberg.MS\AppData\Roaming\ESRI\Desktop10.3\
该目录将包含基本文件,例如 .sde数据库连接默认位于此处,
C:\Users\AHejlsberg.MS\AppData\Roaming\ESRI\Desktop10.3\ArcCatalog\
当调用 .NET System.Diagnostics.Process 对象的 Start() 方法时,Process 对象将使用与运行 ASP.NET 应用程序的应用程序池中标识的 w3wp.exe 工作进程相同的帐户来运行。因此,如果 ASP.NET 应用程序在 DefaultAppPool 下运行,并且该应用程序池具有标识 ApplicationPoolIdentity,则 Windows 本地安全机构将使用 DefaultAppPool 的用户 SID 和应用程序池的组 SID 创建一个新的虚拟帐户。其访问令牌中的 IIS_IUSRS 安全主体。
新的 .NET Process 对象将在该新虚拟帐户的安全上下文中运行。因此,如果新的 Process 对象包装 Python.exe 文件,则该可执行文件将像由应用程序池标识中标识的同一帐户调用一样运行。
再例如,如果 ASP.NET 应用程序在某个应用程序池下运行,该应用程序池的身份设置为某个特定用户(例如域帐户),则从 ASP.NET 应用程序生成的 .NET Process 对象将在安全上下文下运行该用户的。在这种情况下,Python.exe 将像由设置为应用程序池标识的特定用户调用一样运行。
即使 ASP.NET 应用程序启用了模拟,使得经过身份验证的 HTTP 上下文标识和返回的 WindowsIdentity.GetUser() 标识恰好相同,新的 .NET Process 对象仍然不会在该 ASP.NET 应用程序标识下运行如果应用程序池的标识不同。
注意:程序员可能会过分地假设,如果启用 ASP.NET 模拟以某个帐户运行,并且应用程序池的标识设置为同一帐户,则 ASP.NET 应用程序和新生成的 .NET Process 对象将使用彼此完全相同的安全上下文运行,实际上,ASP.NET 应用程序进程中尝试访问安全对象的线程将具有模拟令牌,而代表新生成的 .NET 访问安全对象的线程将具有模拟令牌进程对象将只有一个主访问令牌。
如果 Python 运行时需要使用随 ArcGIS Desktop 安装的 ESRI ArcPy,则运行时需要能够访问我在上面的信息 #1 部分中提到的 AppData\Roaming\ESRI 子文件夹。当我的 Python 脚本调用“import ArcPy”命令时,情况就是如此。
Windows 中的帐户有一个与其关联的环境变量列表。从该帐户创建的任何进程都将引用该环境变量列表。
这些变量之一将称为“AppData”。
Python 运行时将在与触发 Python 可执行文件的帐户身份关联的环境变量列表中查找 AppData 变量。
该 AppData 变量需要对 ArcGIS Destkop 安装其 ESRI 子文件夹的位置进行赋值。将 AppData 变量赋值为所需 UNC 路径的一种方法是运行进程,该进程使用用于安装 ArcGIS Desktop 的同一帐户的身份触发 Python 可执行文件。
因此,例如,如果使用名为 MS\AHejlsberg 的帐户安装 ArcGIS Desktop,则从 ASP.NET 生成的 .NET 进程(随后将调用 Python 可执行文件)也需要在 MS\AHejlsberg 帐户的身份下运行。将托管 ASP.NET 应用程序池的应用程序池的标识设置为该帐户将实现让 ASP.NET 应用程序使用所需帐户创建 .NET Process 对象的目标。
人们可以检索运行 ASP.NET 应用程序的身份的环境变量列表,如下所示:
var envVars = Environment.GetEnvironmentVariables();
Run Code Online (Sandbox Code Playgroud)
如果为 MS\AHejlsberg 启用了 ASP.NET 模拟,则 AppData 变量将如下所示:
// ["APPDATA"] = "C:\\Users\\AHejlsberg.MS\\AppData\\Roaming"
Run Code Online (Sandbox Code Playgroud)
人们可以检索环境变量列表来识别从 ASP.NET 应用程序生成的进程的身份,如下所示:
ProcessStartInfo procInfo = proc.StartInfo;
Run Code Online (Sandbox Code Playgroud)
如果托管该 ASP.NET 应用程序的应用程序池的标识设置为 ApplicationPoolIdentity 并且应用程序池的名称恰好是“.NET v4.5”,则 AppData 将如下所示:
// Environment = {System.Collections.Specialized.StringDictionary.GenericAdapter}
// Count = 43
// [19] = {[APPDATA, C:\Windows\system32\config\systemprofile\AppData\Roaming]}
Run Code Online (Sandbox Code Playgroud)
另一方面,如果托管 ASP.NET 应用程序的应用程序池的标识设置为 MS\AHejlsberg,则 AppData 将如下所示:
// Environment = {System.Collections.Specialized.StringDictionary.GenericAdapter}
// Count = 49
// [21] = {[APPDATA, C:\Users\AHejlsberg.MS\AppData\Roaming]}
Run Code Online (Sandbox Code Playgroud)
现在,Python 运行时将能够找到 ArcGIS Desktop 安装的子文件夹。
如果程序员无法将应用程序池的身份设置为特定用户帐户(例如上面所示的域帐户),则另一种选择是将所有 ESRI 子文件夹复制到对身份可见的位置应用程序池,例如
C:\Windows\system32\config\systemprofile\AppData\Roaming,
如上所示,其中应用程序池的名称为“.NET 4.5”,标识为 ApplicationPoolIdentity。
我想这应该可行;但我还没有测试过。可能还需要更改其他变量设置。
请注意倒数第二行,用于跟踪我的错误:
envset = (set(env for env in self._gp.listEnvironments()))
我们可以看到Python运行时显然正在尝试访问环境变量。
当我将应用程序池标识设置为 ApplicationPoolIdentity 时,从 ASP.NET 生成的 .NET Process 对象在 Windows 创建的虚拟帐户的标识下运行,因此 Python 运行时在错误的 UNC 路径中查找 AppData。这导致了我们在回溯的最后一行中看到的运行时未初始化错误。
当我将应用程序池的标识设置为安装 ArcGIS Destkop 的同一帐户的同一标识时,从 ASP.NET 应用程序生成的 .NET Process 对象能够引用 AppData 变量,该变量评估 Python 的路径运行时可以成功用于“导入 ArcPy”语句。
这解决了 Python 运行时在 IIS Express 上成功但在本地 IIS 上失败的谜团。