从ColdFusion传递IEnumerable变量到.NET [英] Passing IEnumerable Variables into .NET from ColdFusion

查看:315
本文介绍了从ColdFusion传递IEnumerable变量到.NET的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一些ColdFusion 10与自定义.NET DLL集成,我没有能力调整。在这个过程中,我已经能够做所有我需要做的事情,除了创建一个 IEnumerable 数据类型传递给对象的一个​​方法。这里是我需要整合的:

I'm working on doing some ColdFusion 10 integration with a custom .NET DLL that I don't have the ability to tweak. During this process, I've been able to do everything that I need to do other than create an IEnumerable data type to pass to one of the methods of the object. Here's what I need to integration with:

这是我遇到麻烦的 Set_Events 方法。我可以创建应该是该枚举变量的一部分的单个事件,但我无法创建它显然是期望作为正确的变量类型。我试过这样做:

It's the Set_Events method that I'm having the trouble with. I can create the individual Events that are supposed to be part of that enum variable, but I'm unable to create what it apparently is expecting as the proper variable type. I've tried doing this:

<cfset enum = createObject(".net", "System.Collections.Generic.IEnumerable__1") />

这给我一个有效的.NET对象,用 GetEnumerator 方法:

And this gives me a valid .NET object, with a GetEnumerator() method:

当我尝试调用该方法时:

When I attempt to call that method:

<cfdump var="#enum.GetEnumerator()#">

这只是给我以下错误:

The GetEnumerator method was not found.



我尝试过的其他事情:



创建通用列表和添加内容:



Other things I've tried:

Creating a Generic List and Adding things:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset eventList.Add(javacast("bigdecimal", "30.1234" )) />

这给我以下错误:

An exception occurred while instantiating a Java object. The class must not be an interface or an abstract class. If the class has a constructor that accepts an argument, you must call the constructor explicitly using the init(args) method. Error : System.Collections.Generic.List__1

这又给我一个错误:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset eventList.Add("foo") />



尝试初始化列表



来自Leigh的代码:

Trying to Init the List

This code from Leigh works:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset elemClass = createObject(".net", "System.String", "dotNetCoreProxy.jar") />
<cfset elemType = elemClass.getDotNetClass() />
<cfset eventList.init( elemType ) />
<cfset eventList.Add("foo") />
<cfdump var="#eventList#">

但这不是:

<cfobject type="dotnet" name="VideoWallEvent" class="Utilities.VideoWall.VideoWallEvent" assembly="#ExpandPath("Utilities.dll")#">
<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset elemType = VideoWallEvent.getDotNetClass() />
<cfset eventList.init( elemType ) />
<cfdump var="#eventList#">

我得到以下错误:

Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).



JNBProxyGUI.exe



完全无用。我可以浏览到我的Utilities.dll文件,并从GAC添加System.Collections程序集,但项目菜单中的生成选项始终禁用,一旦添加这些程序集,任何窗格中都不显示。

JNBProxyGUI.exe

This has been completely useless. I can browse to my Utilities.dll file, and add the System.Collections assembly from GAC, but the Build option in the Project menu is always disabled, and nothing shows in any of the panes once those assemblies have been added.

我已在一页上运行以下所有代码:

I've run all of the following code on one page:

<cfset UtilitiesProxy = ExpandPath("UtilitiesProxy.jar") />
<cfset DotNetCoreProxy = "dotNetCoreProxy.jar" />
<cfset CoStarUtilities = ExpandPath("CoStar.Utilities.dll") />

<h2>Try using base DLLs and DotNetCore</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try using the Utilities Proxy for Everything</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#UtilitiesProxy#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", UtilitiesProxy) /> (error line)
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#">
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try using Utilities Proxy for VideoWall, and DotNetCore for List</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#UtilitiesProxy#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try Initing Wall Event</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset VideoWallEvent.Init() />
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try Initing Wall Event</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset VideoWallEvent.Init() />
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent)#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

我得到以下错误输出(提示,每一个都失败)。

And I get the following error output (hint, every single one of these fails).

09:22:45.045 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 9
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - coldfusion.runtime.dotnet.ProxyGenerationException - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 19
09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 31
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 43
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 55
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( CoStar.Utilities.VideoWall.VideoWallEvent ).

我已经生成了一个代理(我认为)我需要的所有项目。

I've generated a proxy with (what I think is) all of the items that I need.

现在我被困住了。我可以实例化和填充所有必要的对象,使这个东西工作,我只是不能把所有的对象在一起,使他们的工作。

So now I'm stuck. I can instantiate and fill all of the necessary objects to make this thing work, I just can't push all of the objects together to make them work. What am I missing when trying to create the ENum object necessary to fill the Set_Events method?

推荐答案

如上所述,您需要使用一个方法来创建需要填充Set_Events方法的ENum对象一个具体的类(不是接口)。然而,看看方法签名,它必须是实现 System.Collections。通用 .IEnumerable ,而不是 System.Collections.IEnumerable 。后者仅用于非通用集合。您可以使用的通用集合的一个示例是 List< T> ,其中< T> 是列表所持有的对象的类型。 (您需要检查您的API以确定对象类型)。

As mentioned, you need to use a concrete class (not the interface). However, looking at the method signature, it must be one that implements System.Collections.Generic.IEnumerable, and not System.Collections.IEnumerable. The latter is only for non-generic collections. One example of a generic collection you could use is List<T>, where <T> is the type of object the list holds. (You will need to review your API to determine the object type).

不幸的是...有一个 Generic类的问题。基本上, createObject 使用的工具不能生成泛型的代理。 (博客条目说它是在CF9中解决,但在我的测试中,我遇到了与9.0.1 - YMMV相同的问题。)所以你需要自己使用 JNBProxyGUI.exe 。坦率地说,这不是最直观的工具..但经过一个小争吵,我设法让它工作在CF9。幸运的是它只是一次性事件。

Unfortunately ... there is an issue with Generic classes. Essentially the tool used by createObject cannot generate proxies for Generics. (The blog entry says it was resolved in CF9, but in my tests I encountered the same problem with 9.0.1 - YMMV.) So you need to do it yourself using the JNBProxyGUI.exe. Frankly it is not the most intuitive tool .. but after a little wrangling I managed to get it working under CF9. Fortunately it is only a one time event.

将生成的代理导出到jar文件后,使用博客条目中的示例创建一个通用的列表 。只需将代理jar添加到程序集列表中。说集合商店简单字符串

After exporting the generated proxies to a jar file, use the example in the blog entry to create a generic List. Just add the proxy jar to the assembly list. Say the Collection stores simple Strings:

    // create a generic list of strings ie new List<String>()
    path = "c:/path/yourGenericsProxy.jar,c:/path/yourApplication.dll"; 
    list = createObject(".net", "System.Collections.Generic.List__1", path);
    elemClass = createObject(".net", "System.String", path);
    elemType = elemClass.getDotNetClass();
    list.init( elemType );

初始化 List 后,添加几个元素:

Once the List is initialized, you can add a few elements to it:

    list.add( "foo" );
    list.add( "bar" );

Then最后调用GetEnumerator()并将它传递给您的方法 列表到您的方法中:

    // wrong: yourObject.Set_Events( list );
    yourObject.Set_Events( list );

(如果您对生成代理有任何疑问,请问。)

(If you have any questions about generating the proxies, just ask.)

UPDATE:

Dan指出,方法使用 IEnumerable 不是 IEnumerator。因此, List 本身应该传递到 set_Event ,而不是 Get_Enumerator $ c>(如上例所示)。此外,当您调用 createObject 时, assemblyList必须包含代理jar和dll文件。否则方法调用可能会失败。

As Dan pointed out, his method is using IEnumerable not IEnumerator. So the List itself should be passed into set_Event, not Get_Enumerator() (as in the previous example). Also, when you invoke createObject, the assemblyList MUST include both the proxy jar AND the dll file. Otherwise the method call(s) may fail. Turns out that was the cause of the later problems.

以下是与CF10配合使用的修正版本。

Below is a corrected version that works with CF10.

重新生成代理仓库


  1. 打开JNBProxyGUI.exe并选择 > .NET项目

  2. 输入本地java设置(我的设置)

    • 远程主机/ 6089

    • Java路径:C:\ColdFusion10\cfusion\jetty\jre\bin\java.exe

    • jnbcore。 jar:C:\ColdFusion10\cfusion\lib\jnbcore.jar

    • bcel.jar:C:\ColdFusion10\cfusion\lib\becel- jnbridge.jar

  1. Open JNBProxyGUI.exe and select Create new Java -> .NET Project
  2. Enter local java settings (My settings)
    • Remote host/port: local host 6089
    • Java path: C:\ColdFusion10\cfusion\jetty\jre\bin\java.exe
    • jnbcore.jar: C:\ColdFusion10\cfusion\lib\jnbcore.jar
    • bcel.jar: C:\ColdFusion10\cfusion\lib\becel-5.1-jnbridge.jar

清理: strong>

Cleanup:

为了安全起见,我停止了CF并删除了所有生成的代理jar从 WEB-INF \cfclasses \dotNetProxy except dotNetCoreProxy.jar。然后重新启动CF并运行代码。它工作完美。串。 (请参阅下面的完整代码)。

Just to be safe, I stopped CF and removed all generated proxy jars from WEB-INF\cfclasses\dotNetProxy except dotNetCoreProxy.jar. Then restarted CF and ran the code. It worked perfectly. String. (See complete code below).

MyClass.cs b

using System;
using System.Text;
using System.Collections.Generic;

namespace MyLibrary
{
    public class MyClass {
        private IEnumerable<CustomClass> events;

        public void set_Events(IEnumerable<CustomClass> evts) 
        {
            this.events = evts;
        }

        public IEnumerable<CustomClass> get_Events()
        {
            return this.events;
        }
    }
}

CustomClass.cs

using System;
using System.Text;
using System.Collections.Generic;

namespace MyLibrary
{
    public class CustomClass
    {
        private string title;
        public CustomClass(string title)
        {
            this.title = title;
        }

        public string getTitle()
        {
            return this.title;
        }

        public override string ToString()
        {
            return getTitle();
        }
    }
}

<cfscript>
    // MUST include both proxy jar and DLL file
    path = arrayToList([ExpandPath("./MyLibrary.dll"), ExpandPath("genericListAndEnumerator.jar")]);
    //initialize custom class
    customObj = createObject(".net", "MyLibrary.CustomClass", path).init("Blah, blah");
    elemType = customObj.getDotNetClass();

    // create generic list of custom class
    list = CreateObject(".net","System.Collections.Generic.List__1", path);
    list.init( elemType );
    list.add( customObj );

    // test setter
    mainObj = createObject(".net", "MyLibrary.MyClass", path);
    mainObj.set_Events( list );

    // test getter
    enum = mainObj.get_Events().getEnumerator();
    writeDump(enum);
    while (enum.MoveNext()) {
        WriteDump("Current="& enum.Get_Current().toString());
    }
</cfscript>

这篇关于从ColdFusion传递IEnumerable变量到.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆