从ASP.NET调用的Python脚本在IIS Express中运行良好但在本地IIS

时间:2016-05-18 16:03:21

标签: c# python asp.net iis arcgis

这可能表面上看起来像是Python ArcGIS ArcPy RuntimeError: NotInitialized的副本,但这是不同的,因为

  • 使用ArcGIS 10.0,后来存在巨大差异 版本,例如我使用的
  • 10.3
  • 指的是安装了多个版本的Python而我只是 有一个
  • 指的是我已经完成的卸载和重新安装
  • 指的是不同的操作系统(我在Win 2012上运行)
  • 指的是一直出现的错误,而我得到的错误 仅来自IIS的错误

    我有一个调用Python脚本的ASP.NET应用程序。该代码使用System.Diagnostics.Process对象来调用Python.exe并传递它的参数,例如Python脚本的位置和其他参数。 Process对象在C#

    中看起来像这样
        Process proc = new Process();
    proc.StartInfo.Verb = "runas";     
    proc.StartInfo.FileName = pathToPythonExe;
    proc.StartInfo.Arguments = procArgs;
    proc.StartInfo.RedirectStandardError = true;
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    proc.Start();
    proc.WaitForExit();            
    errorToConsole = proc.StandardError.ReadToEnd();
    proc.WaitForExit();
    messageToConsole = proc.StandardOutput.ReadToEnd();
    proc.WaitForExit();
    

    Path和PYTHONPATH环境变量指向Python可执行文件所在的位置。

    当我在Visual Studio 2015中的IIS Express中从ASP.NET C#应用程序运行Python脚本时,一切运行正常。当我通过命令控制台运行Python脚本时,一切运行正常。当我从IDLE运行Python脚本时,一切运行正常。但是,当我将应用程序发布到IIS 8.5并运行它时,Python脚本中会出现错误。此外,当我从Visual Studio运行应用程序并使用本地IIS而不是IIS Express时,Python脚本再次失败。

所以,这里回顾一下它运作的条件:

  1. 从IIS Express中的ASP.NET C#应用程序运行Python脚本 Visual Studio 2015。
  2. 通过命令控制台运行Python脚本。
  3. 从IDLE运行Python脚本。
  4. 以下是不起作用的条件概述:

    1. 从本地IIS Express中的ASP.NET C#应用程序运行Python脚本 在Visual Studio 2015中。
    2. 从IIS上的ASP.NET C#应用程序运行Python脚本。
    3. 错误的要点是" RuntimeError:NotInitialized"在脚本行上," import acrpy。"这列在"错误#1"下面。我在VS(本地IIS或IIS Express)中运行它与常规IIS之间的唯一区别是权限。

      当我在Visual Studio中运行它时,Visual Studio应用程序具有管理员权限。 在IIS中,身份验证在启用Windows身份验证时设置。其他一切都被禁用了。 以下是应用程序在IIS 8.5中运行时以及在使用本地IIS的Visual Studio中运行时发生的完整错误消息。

      错误#1:

      Traceback (most recent call last):
        File "E:\Application Development\PublishServiceDefinition\MapPublisher\MapSdDraftCreator.py", line 1, in <module>
          import arcpy
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\__init__.py", line 21, in <module>
          from arcpy.geoprocessing import gp
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\geoprocessing\__init__.py", line 14, in <module>
          from _base import *
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\geoprocessing\_base.py", line 598, in <module>
          env = GPEnvironments(gp)
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\geoprocessing\_base.py", line 595, in GPEnvironments
          return GPEnvironment(geoprocessor)
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\geoprocessing\_base.py", line 551, in __init__
          self._refresh()
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\geoprocessing\_base.py", line 553, in _refresh
          envset = (set(env for env in self._gp.listEnvironments()))
      RuntimeError: NotInitialized
      

      以下是我目前为排查问题所做的工作。

      首次尝试进行问题排查:   我完全卸载并重新安装了Desktop 10.3(包括Python文件和arcpy文件)。这没有任何帮助。我得到了同样的错误。

      第二次尝试排查: 我在另一台Windows 2012服务器上安装了Desktop 10.3(和Python.exe),并在该机器上设置了IIS(第二台机器上没有Visual Studio)。发生了同样的错误。在第二台机器上安装之前,我确保已删除任何ESRI产品(包括从注册表中删除)。

      第三次尝试排查: 我添加了#34;导入arcinfo&#34;作为第一行,Python脚本的前两行如下所示:

      import arcinfo
      import arcpy
      

      导致以下错误:

      错误#2:

      Traceback (most recent call last):
        File "<string>", line 1, in <module>
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\__init__.py", line 21, in <module>
          from arcpy.geoprocessing import gp
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\geoprocessing\__init__.py", line 14, in <module>
          from _base import *
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\geoprocessing\_base.py", line 598, in <module>
          env = GPEnvironments(gp)
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\geoprocessing\_base.py", line 595, in GPEnvironments
          return GPEnvironment(geoprocessor)
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\geoprocessing\_base.py", line 551, in __init__
          self._refresh()
        File "e:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\geoprocessing\_base.py", line 553, in _refresh
          envset = (set(env for env in self._gp.listEnvironments()))
      RuntimeError: NotInitialized
      
      Traceback (most recent call last):
        File "E:\Application Development\PublishServiceDefinition\MapPublisher\MapSdDraftCreator.py", line 1, in <module>
          import arcinfo
        File "E:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcinfo.py", line 18, in <module>
          gp.setProduct("ArcInfo")
      RuntimeError: ERROR 999999: Error executing function.
      

      第4次排除故障: 由于Windows身份验证使用本地IIS_IUSRS帐户,因此我完全控制该帐户 •具有Python.exe文件的文件夹, •ArcGIS \ Desktop10.3文件夹 •具有Python脚本的文件夹 •Python脚本访问的任何文件夹

      我从Python脚本中删除了“import arcinfo”。结果与我第一次从IIS中尝试的结果相同。

      第五次尝试排查:   由于错误似乎引用了环境变量,我认为可能存在一些本地IIS_IUSRS组,由于安全原因,它不允许其进程中的任何线程访问环境变量。这只是猜测。在我看来,这似乎是微软可能做的事情。   因此,我在IIS中获取了应用程序以模拟具有本地管理员权限的帐户。当我再次运行ASP.NET应用程序时,它似乎甚至没有尝试阅读Python脚本。包装Python脚本的C#进程捕获StandardError和StandardOutput。使用模拟时没有任何东西被捕获。此外,调试器停留在Start()和WaitForExit()方法上的时间可以忽略不计,就好像Process对象中的执行线程甚至没有尝试读取Python脚本一样。   如果它是文件夹安全权限的问题,那么当IIS_IUSRS没有足够的权限时,我会得到模拟帐户的错误。但是,我没有得到任何错误。看来,使用模拟帐户运行的流程甚至没有尝试做任何事情。

      第6次尝试进行问题排查:   由于已安装的Python.exe是32位版本的Python,因此我访问了ASP.NET应用程序使用的应用程序池,并确保在高级设置中启用了32位应用程序设置。这并没有改变IIS模拟开启或关闭的结果。

      我看到的唯一其他奇怪的事情是,Visual Studio中的ASP.NET项目属性显示它是针对.NET Framework 4.5而应用程序池是针对版本设置的IIS管理器显示应用程序池已设置为.NET CLR版本4.0。当我尝试在IIS管理器中更改.NET Framework版本时,它只提供v4.03和v2.05这两个选项。我不知道那有多重要。

      编辑(2016年5月18日下午4:06): 我做了一些测试。我在三种不同的条件下查看了一些环境变量。我使用以下三个设置在Visual Studio中运行ASP.NET应用程序:

      1. 本地IIS,禁用模拟
      2. 本地IIS,已启用模拟,identity = x12345
      3. IIS Express
      4. 以下是这些测试的部分结果。

        本地IIS,禁用模拟:

        Environment.UserDomainName = "IIS APPPOOL"
        Environment.UserName = .NET v4.5
        

        本地IIS,已启用模拟,identity = x12345:

        Environment.UserDomainName = x12345
        Environment.UserName = ABC
        

        IIS Express:

        Environment.UserDomainName = x12345
        Environment.UserName = ABC
        

        请注意上面如何启用与IIS Express一起运行的同一身份的模拟运行会导致相同的环境变量。 这告诉我,也许我应该专注于在启用ASP.NET模拟的同时使其工作,因为正如我之前提到的,使用IIS Express运行始终是成功的。试图尽可能地模仿那些已知的成功条件似乎对我有利。    我似乎有理由集中精力继续努力找出为什么ASP.NET模拟与IIS Express相同的环境用户无法运行脚本。意见和建议将不胜感激。

        编辑(2016年5月19日下午1:40):

        我已尝试启用,&#34;允许服务与桌面互动&#34; &#34; IIS Admin Service&#34;中的选项属性,以及W3SVC属性。这没有用。

        我的下一个尝试是创建一个调用Python可执行文件并返回结果的Web服务。我将使当前的ASP.NET应用程序调用Web服务,然后返回结果。 除非有人评论为什么这不起作用,或者有关如何使当前ASP.NET应用程序按需运行的评论,否则我将继续使用Web服务策略。

        编辑(2016年5月25日)

        看来,经过将近3周的努力,我终于有了这个工作。

        虽然我并没有确切地知道我的工作是什么,但这里遵循我做的两件主要事情。

        我使用IIS中托管的basicHttpBinding创建了一个WCF服务。 wsHttpBinding对我不起作用,因为当我尝试为Windows身份验证配置它并设置mode =&#34; transport&#34;我收到一条错误,说明需要ssl。

        更重要的是,我将WCF服务的应用程序池的进程标识从ApplicationPoolIdentity更改为具有提升权限的帐户。

        现在,当我在任务管理器中查看w3wp.exe用户名时,我发现它正在运行该帐户的名称。

        我的下一步是开始按顺序撤消所有先前的配置并进行测试以查看哪些配置不重要。例如,我在包含所使用的Python脚本和可执行文件的文件夹的安全访问中添加了应用程序池帐户。 现在我认为这可能是不必要的,因为w3wp可以通过其新帐户访问Python脚本。我将开始删除我之前添加的其他帐户。

        事后看来,我认为创建Web服务可能在技术上是不必要的,因为我可能刚刚能够更改运行ASP.NET应用程序的应用程序池的进程标识。但是,可能存在安全问题,因为ASP.NET应用程序可由用户直接访问,并且Web服务只能间接访问,即使此应用程序是Intranet应用程序且没有面向外部的界面。

        对于我将其付诸实践的任何见解(建议和/或建设性批评)将不胜感激。

1 个答案:

答案 0 :(得分:2)

我已经对此进行了更多的研究,现在我理解为什么我的解决方案有效了。此信息回答了我原来的问题。以下是我的研究发现的有关该主题的有用和相关信息。

  • info#1

当ArcGIS Desktop 10.3安装在计算机上时,它会创建一个存储重要信息的目录。该目录的默认位置取决于启动ArcGIS Desktop应用程序安装的用户的登录帐户名。例如,如果登录帐户是MS \ AHejlsberg,那么默认安装的UNC路径将是,C:\ Users \ AHejlsberg.MS \ AppData \ Roaming \ ESRI \ Desktop10.3 \
 该目录将包含基本文件,例如.sde数据库连接,默认情况下位于此处,
 C:\ Users \用户AHejlsberg.MS \应用程序数据\漫游\ ESRI \ Desktop10.3 \ ArcCatalog中\

  • info#2

当调用.NET System.Diagnostics.Process对象的Start()方法时,Process对象将使用与ASP中应用程序池中标识的w3wp.exe工作进程相同的帐户运行。 NET应用程序运行。  因此,如果ASP.NET应用程序在DefaultAppPool下运行,并且该应用程序池具有标识ApplicationPoolIdentity,那么Windows&#39;本地安全机构将使用其访问令牌中的DefaultAppPool的用户SID和IIS_IUSRS安全主体的组SID创建新的虚拟帐户。
 新的.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 Process对象只有一个主访问令牌。

  • info#3

如果Python运行时需要使用随ArcGIS Desktop安装的ESRI ArcPy,那么运行时需要能够访问我在上面的信息#1部分中提到的AppData \ Roaming \ ESRI子文件夹。在我的情况下,当我的Python脚本调用&#34;导入ArcPy&#34;命令。
 Windows中的帐户有一个与之关联的环境变量列表。从该帐户创建的任何流程都将引用该环境变量列表。
 其中一个变量将被称为&#34; AppData。&#34;
 Python运行时将在与触发Python可执行文件的帐户的标识相关联的环境变量列表中查找AppData变量。
 该AppData变量需要估算ArcGIS Destkop安装其ESRI子文件夹的位置。将AppData变量值化为所需UNC路径的一种方法是运行触发Python可执行文件的Process,其中包含用于安装ArcGIS Desktop的同一帐户的标识。
 因此,例如,如果使用名为MS \ AHejlsberg的帐户安装ArcGIS Desktop,那么从ASP.NET生成的.NET进程将调用Python可执行文件,也需要以MS \ AHejlsberg帐户的身份运行。将承载ASP.NET应用程序池的应用程序池的标识设置为该帐户将实现使ASP.NET应用程序使用所需帐户创建.NET Process对象的目标。

一个人可以检索运行ASP.NET应用程序的标识的环境变量列表,如下所示:

var envVars = Environment.GetEnvironmentVariables();

如果为MS \ AHejlsberg启用了ASP.NET模拟,则AppData变量将如下所示:

// ["APPDATA"] = "C:\\Users\\AHejlsberg.MS\\AppData\\Roaming"

一个人可以检索从ASP.NET应用程序生成的进程的标识的环境变量列表,如下所示:

ProcessStartInfo procInfo = proc.StartInfo;

如果托管该ASP.NET应用程序的应用程序池的标识设置为ApplicationPoolIdentity,并且应用程序池的名称恰好是,那么#34; .NET v4.5&#34;然后AppData将如下所示:

// Environment = {System.Collections.Specialized.StringDictionary.GenericAdapter}
    // Count = 43        
        // [19] = {[APPDATA, C:\Windows\system32\config\systemprofile\AppData\Roaming]}

另一方面,如果托管该ASP.NET应用程序的应用程序池的标识设置为MS \ AHejlsberg,则AppData将如下所示:

// Environment = {System.Collections.Specialized.StringDictionary.GenericAdapter}
    // Count = 49     
        // [21] = {[APPDATA, C:\Users\AHejlsberg.MS\AppData\Roaming]}

现在,Python运行时将能够找到ArcGIS Desktop安装的子文件夹。

如果程序员无法将应用程序池的标识设置为特定的用户帐户(如上面所示的域帐户),则另一个选项是将所有ESRI子文件夹复制到一个可见的位置应用程序池的标识,例如,
C:\ Windows \ system32 \ config \ systemprofile \ AppData \ Roaming
如上所示,应用程序池的名称是,&#34; .NET 4.5&#34;并且身份是ApplicationPoolIdentity。
我想这应该有用;但我没有测试过。可能还需要更改其他变量设置。

注意我的错误追溯的倒数第二行:
    envset =(set(env in self._gp.listEnvironments()))

我们可以看到Python运行时显然正在尝试访问环境变量。

当我将应用程序池标识设置为ApplicationPoolIdentity时,从ASP.NET生成的.NET Process对象在Windows创建的虚拟帐户的标识下运行,因此Python运行时正在查找错误的AppData UNC路径。这导致我们在回溯的最后一行中看到的RunTime未初始化错误。

当我将应用程序池的标识设置为安装ArcGIS Destkop的同一帐户的相同标识时,从ASP.NET应用程序生成的.NET Process对象能够引用评估路径的AppData变量Python运行时可以成功用于&#34;导入ArcPy&#34;言。

这解决了使用IIS Express成功但使用本地IIS失败的Python运行时的神秘感。