如果从 C# 控制台应用程序调用,则调用的 Arcpy 脚本不会完成

Posted

技术标签:

【中文标题】如果从 C# 控制台应用程序调用,则调用的 Arcpy 脚本不会完成【英文标题】:Called Arcpy Script doesn't finish if called from C# Console App 【发布时间】:2021-12-01 16:36:59 【问题描述】:

早安 ***ers,

如果没有您的帮助,我无法解决另一个问题。我正在开发一个 C# 控制台应用程序 (.NET 5),它调用不同的 Python 脚本来执行 ArcGis 内容 (=> "arcpy"-Lib :)。打电话给他们的方案总是一样的,从来没有问题。在渗透测试过程中,我发现其中一个脚本存在问题:

以下脚本“搜索”要素类中的每一行,放大到它并将其导出为 .png 文件。

通过 cmd(非管理员和管理员)或通过 Python Gui(可通过 ArcGis 设置获得)执行此操作,它可以完美运行(=> 创建 138 个图像),但是如果我通过 C# 应用程序执行它,它只会创建 36 个图像,之后,该过程继续运行但不创建图像。创建第 36 张图像后,CPU 使用率从 12% 下降到 0%。

第二个代码 sn-p 显示了被调用的方法,但也描述了调用我的 python 脚本的方案。我非常清楚这写得不好,我会在解决这个问题后做一些代码润色:)

希望有人给点小费。

提前非常感谢您。 亲切的问候, 一月

import arcpy,os, logging

logging.basicConfig(filename='appPython.log', format='%(asctime)s - %(message)s', level=logging.INFO)

#Static Variables
mxdfileName = "D:\DigitalesFahrtenbuch_Datenpunkte\Templates\TemplateTelematik.mxd"

# Set the workspace for ListFeatureClasses
arcpy.env.workspace = str(sys.argv[1])
#arcpy.env.workspace = r"D:\DigitalesFahrtenbuch_Datenpunkte\DigFahrtenbuch_Datenpunkte.gdb"

featureclasses = arcpy.ListFeatureClasses()

try:
    
    # Copy shapefiles to a file geodatabase
    for fc in featureclasses:
        featureName = os.path.splitext(fc)[0]
        if "Dienstverrichtung_" in featureName and "_Projection" in featureName:
            print(featureName)

            #Global Variables
            mxd = arcpy.mapping.MapDocument(mxdfileName)
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            #Create FeatureLayer
            SelectionLayer = arcpy.management.MakeFeatureLayer(fc, "SelectionLayer").getOutput(0)

            #Add Layer to mxd
            arcpy.mapping.AddLayer(df, SelectionLayer, "TOP")

            #Refresh TOC and DataFrames
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            #Refresh TOC and DataFrames
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            feature = arcpy.mapping.ListLayers(mxd, SelectionLayer, df)[0]

            fields = ['OID@', 'SHAPE@', 'Name']
            pngPath = r"D:\DigitalesFahrtenbuch_Datenpunkte\Images"

            with arcpy.da.SearchCursor(feature, fields) as cursor:
                for FID, Geometry, Name in cursor:
                    mxd.title = Name
                    print(" in Bearbeitung.".format(mxd.title))
                    query = "ObjectID = ".format(str(FID))
                    arcpy.management.SelectLayerByAttribute(feature, "NEW_SELECTION", query)
          
                    df.zoomToSelectedFeatures()
                    df.scale=2500
                    df.referenceScale = 3500
                    arcpy.RefreshActiveView()
       
                    png = "\\.png".format(pngPath, Name)
        
                    arcpy.mapping.ExportToPNG(mxd, png, df, df_export_width=2200, df_export_height=1300)
                    print(" erfolgreich exportiert.".format(mxd.title))

    print("Script beendet")

except Exception as e:
    logging.error("Exception occurred", exc_info = True)

public static async Task<Tuple<string, bool>> ZoomToSelectedFeatures(string pPathToPythonExe, string pPathGeoDatabase)
        
            Tuple<string, bool> resultTuple = null;
            StringBuilder scriptMessageBuilder = new StringBuilder();

            string scriptExceptions = string.Empty;
            string scriptPrints = string.Empty;
            string pythonPath = @"C:/Python27/ArcGIS10.8/python.exe";

            try
            
                await Task.Run(delegate
                
                    if (pPathToPythonExe != "")
                    
                        pythonPath = pPathToPythonExe;
                    

                    ProcessStartInfo start = new ProcessStartInfo();
                    //python interprater location
                    start.FileName = pythonPath;
                    //argument with file name and input parameters
                    start.Arguments =
                        $"Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Python_Scripts\\Batch_ZoomToSelectedFeaturesAndExportPNG_2.py")" +
                        $" pPathGeoDatabase";

                    start.UseShellExecute = false; // Do not use OS shell
                    start.CreateNoWindow = true; // We don't need new window
                    start.RedirectStandardOutput = true; // Any output, generated by application will be redirected back
                    start.RedirectStandardError = true; // Any error in standard output will be redirected back (for example exceptions)
                    start.LoadUserProfile = true;

                    using (Process process = Process.Start(start))
                    
                        process.WaitForExit();

                        using (StreamReader reader = process.StandardOutput)
                        
                            scriptExceptions = process.StandardError.ReadToEnd(); // Here are the exceptions from our Python script
                            scriptPrints = reader.ReadToEnd(); // Here is the result of StdOut(for example: print "test")
                            Debug.WriteLine("Batch_ZoomToSelectedFeaturesAndExportPNG_2.py meldet:");
                            Debug.WriteLine(scriptPrints);
                            Debug.WriteLine(scriptExceptions);
                            scriptMessageBuilder.AppendLine(scriptPrints);
                            scriptMessageBuilder.AppendLine(scriptExceptions);
                        
                    

                    resultTuple = new Tuple<string, bool>(scriptMessageBuilder.ToString(), true);
                );
            
            catch (Exception e)
            
                Debug.WriteLine(e);
                Debug.WriteLine(scriptExceptions);
                resultTuple = new Tuple<string, bool>(scriptMessageBuilder.ToString(), false);
            

            return resultTuple;
        

【问题讨论】:

【参考方案1】:

我通过将输出从“打印消息”更改为“日志条目”解决了这个问题。现在....老实说,我不知道为什么,该脚本正确地创建了所有图像。在编辑后的脚本下方。

无论如何,谢谢,祝你有愉快的一天!

import arcpy,os,logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed
fh = logging.FileHandler('D:\\appPython.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)

#Define Variables
#Static Variables
mxdfileName = "D:\DigitalesFahrtenbuch_Datenpunkte\Templates\TemplateTelematik.mxd"

# Set the workspace for ListFeatureClasses
arcpy.env.workspace = str(sys.argv[1])
#arcpy.env.workspace = r"D:\DigitalesFahrtenbuch_Datenpunkte\DigFahrtenbuch_Datenpunkte.gdb"

# Use the ListFeatureClasses function to return a list of
#  shapefiles.
featureclasses = arcpy.ListFeatureClasses()


try:
    # Copy shapefiles to a file geodatabase
    for fc in featureclasses:
        featureName = os.path.splitext(fc)[0]
        if "Dienstverrichtung_" in featureName and "_Projection" in featureName:
            logger.info(featureName)

            #Global Variables
            mxd = arcpy.mapping.MapDocument(mxdfileName)
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            #Create FeatureLayer
            SelectionLayer = arcpy.management.MakeFeatureLayer(fc, "SelectionLayer").getOutput(0)

            #Add Layer to mxd
            arcpy.mapping.AddLayer(df, SelectionLayer, "TOP")

            #Refresh TOC and DataFrames
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            #Refresh TOC and DataFrames
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]

            feature = arcpy.mapping.ListLayers(mxd, SelectionLayer, df)[0]

            fields = ['OID@', 'SHAPE@', 'Name']
            pngPath = r"D:\DigitalesFahrtenbuch_Datenpunkte\Images"

            with arcpy.da.SearchCursor(feature, fields) as cursor:
                for FID, Geometry, Name in cursor:
                    mxd.title = Name
                    
                    #print(" in Bearbeitung.".format(mxd.title))
                    logger.info(" in Bearbeitung.".format(mxd.title))

                    query = "ObjectID = ".format(str(FID))
                    arcpy.management.SelectLayerByAttribute(feature, "NEW_SELECTION", query)
          
                    df.zoomToSelectedFeatures()
                    df.scale=2500
                    df.referenceScale = 3500
                    arcpy.RefreshActiveView()
       
                    png = "\\.png".format(pngPath, Name)
        
                    arcpy.mapping.ExportToPNG(mxd, png, df, df_export_width=2200, df_export_height=1300)
                    
                    logger.info(" erfolgreich exportiert.".format(mxd.title))
                    #print(" erfolgreich exportiert.".format(mxd.title))
    logger.info("Script beendet")

except Exception as e:
    logger.error(e)

【讨论】:

以上是关于如果从 C# 控制台应用程序调用,则调用的 Arcpy 脚本不会完成的主要内容,如果未能解决你的问题,请参考以下文章

ARC:没有调用 Dealloc

从 JavaScript 向不同文件夹中的 C# 控制器进行 ajax 调用

是否可以从 C# 运行 prolog?

C# mutex - 从 ASP.NET 和控制台应用程序调用错误

从 C# 应用程序的脚本中调用 PowerShell 函数

UIPopoverController dealloc 被调用——ARC 环境