Swi prolog的C#接口中的System.AccessViolationException

Swi prolog的C#接口中的System.AccessViolationException,c#,.net,wcf,swi-prolog,C#,.net,Wcf,Swi Prolog,我是新来的,我希望我能找到解决问题的办法。问题的背景如下: 我正在尝试构建一个专家系统,该系统构成一个与Swi prolog交互的C#前端 我已经下载了SwiPlCs.dll(一个连接.NET语言和Swi Prolog的CSharp类库) 并在Visual Studio项目(Win form app)中添加了对它的引用,我创建该项目是为了测试是否可以从c#查询prolog(我遵循了找到的文档中使用的示例) 它工作得很好 然后,在一个更复杂的场景中,我构建了一个WCF服务,它将充当Swi Pro

我是新来的,我希望我能找到解决问题的办法。问题的背景如下:

  • 我正在尝试构建一个专家系统,该系统构成一个与Swi prolog交互的C#前端
  • 我已经下载了
    SwiPlCs.dll
    (一个连接.NET语言和Swi Prolog的CSharp类库)
  • 并在Visual Studio项目(Win form app)中添加了对它的引用,我创建该项目是为了测试是否可以从c#查询prolog(我遵循了找到的文档中使用的示例)
  • 它工作得很好
  • 然后,在一个更复杂的场景中,我构建了一个WCF服务,它将充当Swi Prolog和C#client应用程序之间的中介层(它使用该服务)
  • 该服务托管在IIS 7.0中
  • 为了简单起见,假设我的服务包含三种方法。
    • 第一个方法初始化prolog引擎,查阅prolog源文件,然后查询该文件
    • 第二个方法执行另一个查询
    • 第三个方法调用PlCleanup()
方法#1:

客户端很好地调用了第一个方法,并且成功地返回了第一个查询的结果。当客户端尝试调用第二个方法时,将抛出一个异常,并显示一条消息(试图读取或写入受保护内存),这将导致应用程序冻结。我检查了事件查看器,得到的结果如下:

    Application: w3wp.exe
    Framework Version: v4.0.30319
    Description: The process was terminated due to an unhandled exception.
    Exception Info: System.AccessViolationException
堆栈:

    at SbsSW.SwiPlCs.SafeNativeMethods.PL_new_term_ref()
    at SbsSW.SwiPlCs.PlQuery..ctor(System.String, System.String)
    at SbsSW.SwiPlCs.PlQuery..ctor(System.String)
    at PrologQueryService.PrologQueryService.DetermineAgeGroup(Int32)

尝试在第一个方法结束时关闭引擎,并在第二个方法中再次初始化它


除非您反对,否则您可以将此作为问题的答案进行检查。

尝试在第一个方法结束时关闭引擎,并在第二个方法中再次初始化它


除非您反对,否则您可以将此复选框作为问题的答案。

我还尝试将此接口用于.NET项目

查看CSharp界面与SWI Prolog的连接,我注意到该项目非常古老,官方网站下载页面上的二进制文件中似乎没有最新的更新

然后我做了以下步骤:

  • 专用于.NET的contrib存储库表明兼容的SWI Prolog版本(在编写本文时)为“8.0.3-1”(请参阅)。 ->然后我从我的计算机上卸载了最新的stable,并安装了指定的一个。我是从这个网站上下载的旧版本的完整列表中得到的

  • 我克隆了SWI-Prolog/contrib-swiplcs存储库,从解决方案中卸载了不兼容的项目,因为我不使用visualstudio。 ->我将目标框架设置为NETFramework4.8,并重新编译了它(您也可以使用标准的Net进行此操作)。注意旧项目文件中定义的一些pragma指令(例如,我通过代码重新定义了_PL_X64变量)

  • 我将主要的单元测试方法引入到xUnit的一个新项目中,并进行了适当的更改

  • 我将目标设置为x64,重新编译并重建了测试和“hello world”示例

成功了! 我能够在Net4.8和其他NetCore应用程序中使用SWI Prolog(如果您进行了必要的更改以达到Net标准),在这两种情况下都不会有任何问题

这是我的一个初步例子

最后,我可以在我的C#应用程序中加载一个带有程序的*.pl Prolog文件,并使用它来评估一些业务逻辑规则(例如布尔答案[allowed/notallowed]):


我还尝试将该接口用于.NET项目

查看CSharp界面与SWI Prolog的连接,我注意到该项目非常古老,官方网站下载页面上的二进制文件中似乎没有最新的更新

然后我做了以下步骤:

  • 专用于.NET的contrib存储库表明兼容的SWI Prolog版本(在编写本文时)为“8.0.3-1”(请参阅)。 ->然后我从我的计算机上卸载了最新的stable,并安装了指定的一个。我是从这个网站上下载的旧版本的完整列表中得到的

  • 我克隆了SWI-Prolog/contrib-swiplcs存储库,从解决方案中卸载了不兼容的项目,因为我不使用visualstudio。 ->我将目标框架设置为NETFramework4.8,并重新编译了它(您也可以使用标准的Net进行此操作)。注意旧项目文件中定义的一些pragma指令(例如,我通过代码重新定义了_PL_X64变量)

  • 我将主要的单元测试方法引入到xUnit的一个新项目中,并进行了适当的更改

  • 我将目标设置为x64,重新编译并重建了测试和“hello world”示例

成功了! 我能够在Net4.8和其他NetCore应用程序中使用SWI Prolog(如果您进行了必要的更改以达到Net标准),在这两种情况下都不会有任何问题

这是我的一个初步例子

最后,我可以在我的C#应用程序中加载一个带有程序的*.pl Prolog文件,并使用它来评估一些业务逻辑规则(例如布尔答案[allowed/notallowed]):


在调用DetermineAgeGroup(int age)方法时,将在哪一行抛出异常。在这一行中:使用(var query=new PlQuery(“age_group(+age+”,G)”)在哪个实例化模式下您的WCF服务工作(PerCall,Single,Per Session)?它设置为Per Session,并发模式为singleHmmm。PerSession和单并发模式是正确的。尝试编译所有针对x86平台的程序集。有时,这种互操作性问题可能是由x64平台的编译引起的。在哪一行引发异常?在调用DetermineAgeGroup(int age)方法时。在这一行中:使用(var query=new PlQuery(“age_group(“+age+”,G)”)在其中inst
    public void QuitProlog()
    {
        if (PlEngine.IsInitialized)
        {
            PlEngine.PlCleanup();
        }
    }
    Application: w3wp.exe
    Framework Version: v4.0.30319
    Description: The process was terminated due to an unhandled exception.
    Exception Info: System.AccessViolationException
    at SbsSW.SwiPlCs.SafeNativeMethods.PL_new_term_ref()
    at SbsSW.SwiPlCs.PlQuery..ctor(System.String, System.String)
    at SbsSW.SwiPlCs.PlQuery..ctor(System.String)
    at PrologQueryService.PrologQueryService.DetermineAgeGroup(Int32)
[Fact]
public void ShouldLoadAProgramAndUseIt()
{
    var pathValues = Environment.GetEnvironmentVariable("PATH");
    pathValues += @";C:\Program Files\swipl\bin";
    Environment.SetEnvironmentVariable("PATH", pathValues);

    // Positioning to project folder
    var currentDirectory = Directory.GetCurrentDirectory().Split('\\').ToList();
    currentDirectory.RemoveAll(r => currentDirectory.ToArray().Reverse().Take(3).Contains(r));
    var basePath = currentDirectory.Aggregate((c1, c2) => $"{c1}\\{c2}");
    
    var filePath = $"{basePath}\\prolog_examples\\exec_checker.pl";
    
    String[] param = { "-q", "-f", filePath };
    PlEngine.Initialize(param);
    try
    {
        var query = "exutable('2020-08-15',[('monthly', ['2019-12-30', '2020-03-10'])])";
        _testOutputHelper.WriteLine($"Query: {query}");
        
        using (var q = new PlQuery(query))
        {
            var booleanAnswer = q.NextSolution();
            _testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
            Assert.True(booleanAnswer);
        }

        query = "exutable('2020-08-15',[('daily', ['2019-12-30', '2020-08-15'])])";
        _testOutputHelper.WriteLine($"Query: {query}");
        
        using (var q = new PlQuery(query))
        {
            var booleanAnswer = q.NextSolution();
            _testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
            Assert.False(booleanAnswer);
        }
    }
    finally
    {
        PlEngine.PlCleanup();
    }
}