This might ostensibly seem like a duplicate of Python ArcGIS ArcPy RuntimeError: NotInitialized but this is different because
- that uses ArcGIS 10.0 and there were huge differences in later versions such as the 10.3 that I'm using
- that refers to multiple versions of Python installed whereas I only have one
- that refers to uninstalling and reinstalling which I've already done
- that refers to a different operating system (I'm running on Win 2012)
that refers to an error that occurs consistently whereas I get the error only from IIS
I have an ASP.NET application that calls a Python script. The code uses a System.Diagnostics.Process object to call the Python.exe and pass it arguments such as the location of the Python script and other arguments. That Process object looks like this in 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();
The Path and PYTHONPATH environmental variables point to exactly where the Python executable resides.
When I run the Python script from an ASP.NET C# app in IIS Express in Visual Studio 2015, everything runs fine. When I run the Python script through the command console, everything runs fine. When I run the Python script from IDLE, everything runs fine. When I publish the application to IIS 8.5 and run it, however, an error occurs in the Python script. Also, when I run the app from Visual Studio and use the local IIS instead of IIS Express, the Python script fails again.
So, here is a recap of the conditions where it does work:
- Run the Python script from an ASP.NET C# app in IIS Express in Visual Studio 2015.
- Run the Python script through the command console.
- Run the Python script from IDLE.
Here is a recap of the conditions where it does not work:
- Run the Python script from an ASP.NET C# app in a local IIS Express in Visual Studio 2015.
- Run the Python script from an ASP.NET C# app on IIS.
The gist of the error is "RuntimeError: NotInitialized" on the script line, "import acrpy." This is listed under "Error #1" below. The only difference I saw between running it in VS (either local IIS or IIS Express) versus regular IIS was the permissions.
When I run it in Visual Studio, the Visual Studio app has admin privileges. In IIS, the authentication is set with Windows Authentication enabled. Everything else is disabled. Here is the full error message that occurs when the app runs in IIS 8.5 and when run in Visual Studio with the local IIS.
Error #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
Here is what I've done to troubleshoot so far.
1st attempt at troubleshooting: I made a full uninstall and reinstall of Desktop 10.3 (which includes the Python files and the arcpy files). That didn't help. I got the same error.
2nd attempt at troubleshooting: I installed Desktop 10.3 (and Python.exe) on a different Windows 2012 server and I setup the IIS on that machine (no Visual Studio on that second machine). The same error occurred. Before the install on the second machine, I made sure that any ESRI products had been removed (including from the registry).
3rd attempt at troubleshooting: I added "import arcinfo" as the first line such that the first two lines of the Python script look like:
import arcinfo
import arcpy
That resulted in the following error:
Error #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.
4th attempt at troubleshooting: Since Windows Authentication uses the local IIS_IUSRS account, I gave full control to that account to • the folder that has the Python.exe file, • the ArcGIS\Desktop10.3 folder • the folder that has the Python script • any folders accessed by the Python script
I removed “import arcinfo” from the Python script. The results were the same as the first time I tried it from IIS.
5th attempt at troubleshooting: Since the error seems to reference environmental variables, I figured that maybe there is something about the local IIS_IUSRS group that doesn’t permit any thread in its process from accessing environmental variables for security reasons. That was just a guess. It seems to me like something Microsoft might do. So, I got the application in IIS to impersonate an account that has local admin rights. When I ran the ASP.NET application again, it seemed to not even try to read the Python script. The C# process that wraps the Python script captures the StandardError and the StandardOutput. Nothing is caught when impersonation is used. Also, the time the debugger stays on the Start() and WaitForExit() methods is negligible, as if the executing thread in the Process object is not even trying to read the Python script. If it were a matter of folder security permissions, then I would have gotten an error with the impersonated account the way I got when IIS_IUSRS didn’t have sufficient permissions. However, I didn’t get any errors. It just appeared that the process running with the impersonated account didn’t even try to do anything.
6th attempt at troubleshooting: Since the Python.exe that has been installed is a 32-bit version of Python, I went to the application pool that the ASP.NET application uses and I made sure that the 32-bit applications setting was enabled in the advanced settings. That didn’t change the results either for IIS impersonation on or off.
The only other odd thing that I saw was that the ASP.NET project properties in Visual Studio shows that it is targeted for .NET Framework 4.5 whereas the application pools are set for version IIS Manager shows that the app pool is set for .NET CLR Version 4.0. When I try to change the .NET Framework version in the IIS Manager, it only offers the two choices of v4.03 and v2.05. I don’t know how important that is.
edit (5/18/2016 4:06 pm): I've done some more testing. I looked at some environment variables under three different conditions. I ran the ASP.NET app in Visual Studio with these three settings:
- Local IIS , impersonation disabled
- Local IIS , impersonation enabled , identity = x12345
- IIS Express
Here are some of the results of those tests.
Local IIS , impersonation disabled:
Environment.UserDomainName = "IIS APPPOOL"
Environment.UserName = .NET v4.5
Local IIS , impersonation enabled , identity = x12345:
Environment.UserDomainName = x12345
Environment.UserName = ABC
IIS Express:
Environment.UserDomainName = x12345
Environment.UserName = ABC
Notice from above how running with impersonation enabled to the same identity that runs with IIS Express results in the identical Environment variables. That tells me that maybe I should be focusing on getting this to work while starting with ASP.NET impersonation enabled since, as I've mentioned before, running with IIS Express is consistently successful. It seems that it would benefit me to try to emulate those known successful conditions as closely as possible. It seems reasonable to me to focus my efforts moving forward on trying to find out why ASP.NET impersonation with the same environment user as IIS Express fails to run the script. Comments and suggestions will be appreciated.
edit (5/19/2016 1:40 pm):
I have tried enabling the, "Allow service to interact with desktop" option in both the "IIS Admin Service" properties, and also in the W3SVC properties. This did not help.
My next attempt will be to create a web service that calls the Python executable and returns the results. I will have the current ASP.NET application call the web service and then get back the results. Unless anyone has comments as to why this would not work, or has comments as how to get the current ASP.NET application to function as desired, then I will proceed with the web service strategy.
edit (5/25/2016)
It appears that I've got this working, finally, after nearly 3 weeks of working on it.
While it is not conclusive exactly what I did to get it working, here follow the two main things that I did.
I created a WCF Service with basicHttpBinding hosted in IIS. The wsHttpBinding did not work for me because when I tried to configure it for Windows authentication and set mode="transport" I received an error stating that ssl would be required.
The more important thing seems to be that I changed the WCF Service's application pool's process identity from ApplicationPoolIdentity to an account with elevated privileges.
Now when I look at the w3wp.exe user name in Task Manager, I see that it is running with that account's name.
My next step is to start sequentially undoing all the previous configurations and testing to see which ones were nonessential. For example, I had added the app pool account in the security access of the folders that contained the Python scripts and executable that were used. Now I think that might have been unnecessary since the w3wp has access to the Python scripts through its new account. I will start to remove the other accounts that I had previously added.
On hindsight, I think that creating the web service might have been technically unnecessary since I might have just been able to change the process identity of the application pool that runs the ASP.NET application. However, there might have been security issues with that since the ASP.NET app is directly accessible by users and the web service is only indirectly accessible even though this application is an intranet app and has no outside facing interface.
Any insights (suggestions and/or constructive criticisms) on what I got to get it to work will be appreciated.