ironpython2 icon indicating copy to clipboard operation
ironpython2 copied to clipboard

MongoDb GetCollection error: get MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

Open bnuzhouwei opened this issue 2 years ago • 4 comments

.NET6 and IronPython 2.7.11

call the function:

def cnt():
    import System, clr
    clr.AddReference("MongoDB.Bson")
    clr.AddReference("MongoDB.Driver")
    from MongoDB.Bson import *
    from MongoDB.Driver import *
    connStr = "....."
    client = MongoClient(connStr)
    database = client.GetDatabase("db")    
    dataset = database.GetCollection[BsonDocument]("collection")
    return dataset.CountDocument(BsonDocument()) 
cnt()

database.GetCollection raise error:

System.InvalidOperationException: MongoDB.Driver.IMongoCollection`1[TDocument] GetCollection[TDocument](System.String, MongoDB.Driver.MongoCollectionSettings) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

bnuzhouwei avatar May 24 '22 13:05 bnuzhouwei

The issue appears to be something like this:

public abstract class MyBaseClass {
    public abstract T GetCollection<T>();

    // this is just a helper to get an instance of the internal class
    public static MyBaseClass test() {
        return new MyInternalClass();
    }
}

internal sealed class MyInternalClass : MyBaseClass {
    public override T GetCollection<T>() {
        throw new NotImplementedException();
    }
}
MyBaseClass.test().GetCollection[object]

which results in:

SystemError: T GetCollection[T]() is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

A possible workaround is to enable private bindings with the PrivateBinding option.

slozier avatar May 24 '22 19:05 slozier

Thanks, you are right, the code in mongodb driver is:

namespace MongoDB.Driver
{
	// Token: 0x020000C0 RID: 192
	internal sealed class MongoDatabaseImpl : MongoDatabaseBase
}

Internal without public....,

But how to to enable private bindings with the PrivateBinding option? Can add any paramters to the CreateEngine method?

IronPython.Hosting.Python.CreateEngine()

bnuzhouwei avatar May 25 '22 03:05 bnuzhouwei

I modified the source code, changed the class MongoDatabaseImpl from internal to public, and recompile it.

namespace MongoDB.Driver
{
	public sealed class MongoDatabaseImpl : MongoDatabaseBase
}

The GetCollection in above code run correctly, but in mongodb, there are many methods with default value as default(CancellationToken), i.e.

long CountDocuments(FilterDefinition<TDocument> filter, CountOptions options = null, CancellationToken cancellationToken = default(CancellationToken));

but in IronPython, when we call the method:

GetCollection[BsonDocument]("collection")

got

IronPython.Runtime.Exceptions.TypeErrorException: expected CancellationToken, got NoneType

I seems that IronPython does't support default value for structs, such as default(CancellationToken)

bnuzhouwei avatar May 25 '22 09:05 bnuzhouwei

But how to to enable private bindings with the PrivateBinding option? Can add any paramters to the CreateEngine method?

You can enable private binding like this:

Python.CreateEngine(new Dictionary<string, object> { {"PrivateBinding", true} });

slozier avatar May 25 '22 13:05 slozier