05-15-2017 01:06 PM
Hello everyone,
I'm currently working on utilizing the MongoDB C# / dotNET driver with LabVIEW (https://docs.mongodb.com/ecosystem/drivers/csharp/). My current version of the driver is 2.4.3.23.
After overcoming some basics (missing DDLs for dorNET Core, etc.) things are starting to take shape.
Unfortunately, due to the Async nature of the library (it seems to me that way), there are a few hoops to jump through when processing results from dotNET Invoke Node / Property Nodes...
I'm calling the "ListCollections" method (https://mongodb.github.io/mongo-csharp-driver/2.3/apidocs/html/M_MongoDB_Driver_IMongoDatabase_ListC...) with an IMongoDatabase refnum.
This works without any errors, but I have troubles handling the result.
According to the documentation it is an "IAsyncCursor<BsonDocument>", which is aimed at being able to be handled asynchronuously (if there is a tutorial out there how to implement that in LabVIEW, I'm very interested).
By looking at this tutorial (https://www.codementor.io/pmbanugo/working-with-mongodb-in-net-2-retrieving-mrlbeanm5) I figured out a way in LabVIEW, but it is one example of complicated code due to programming languages interfaces...
(Thanks to Richard Carpenter from RBX Systems Ltd for the inspiration via his library)
This does not seem like a suitable idea for the long term, and I came across the extension methods for IAsyncCursors (https://mongodb.github.io/mongo-csharp-driver/2.3/apidocs/html/T_MongoDB_Driver_IAsyncCursorExtensio...), which offer methods such as "ToList". Casting the dotNET ref from IAsyncCursor to IAsyncCursorExtensions unfortunately didn't offer me any of those methods... (see following picture).
Is there something I'm missing when using the extension methods?
I found a post from the TestStand forums from 2012 (http://forums.ni.com/t5/forums/v3_1/forumtopicpage/board-id/330/thread-id/36029/page/1) that suggest that extension methods are not available.
Is this also the case for LabVIEW?
And regarding the iteration through the IEnumerable pointed to by the cursor: Is there another, more compact or elegant way??
Thank you!
Niels Göran
Solved! Go to Solution.
05-15-2017 02:53 PM - edited 05-15-2017 02:57 PM
First up regarding the enumeration - no, there is no better way in LabVIEW (besides using SubVIs to hide the mess of course). C# has nice syntactic sugar for performing the enumeration but, in the background, the C# compiler actually converts it back into the same thing as what you are doing.
Extension methods in C# are actually just static method calls on static classes with a particular syntax when defining the method - the first input to the static method call is the class instance you want to operate on and defined with "this". The C# language allows a developer to perceive that you have somehow magically added a new method to a class when you use them but this is not the case; they are simply bog standard static method calls in the end and can even be called like any other static method call in LabVIEW (even C# if you wanted to for some reason).
So Extension methods are available to call in LabVIEW but you have to understand the secret sauce behind the magic and call it just like any other static method call. Here's a quick example I whipped up that reverses a given string. You can see that I call the static method directly (the class is static so no need for a constructor) and the extension method is marked as [S] for static:
In case you are curious, here is the basic code for this assembly, see how it follows the requirements for extension methods I described above:
Now, back to your case. Looking at the documentation for IAsyncCursorExtensions, I see that it is a static class (as we would require for a class housing extension methods):
So far, so good. In order to use the methods on this class we need a static object instance. In LabVIEW, we basically don't need to do anything - we just drop down a property or invoke node for the static class to call its properties / methods. Now lets look at the ToList method:
See that this is a static method call. The first parameter is a type designated with a "this" - this is the special definition that makes this an extension method so that the C# syntactic sugar can work however it is just a class instance of the type that this static method operates on.
However there is a wrinkle - note that this is a generic method (rather than a method call on a generic class); you can tell from the "<>" brackets format in front of the method name. LabVIEW is not great with generics in general (you will have noticed that strange '1 style syntax in your nodes) and, in particular, LabVIEW cannot call generic methods on a non-generic class. This is because the type is not defined until run-time and LabVIEW cannot create new open or closed generic types (although you can instantiate generic objects from completely closed types, refer http://digital.ni.com/public.nsf/allkb/DC41DCDA972642CF8625787E00732DDD). This is why you don't see any in the list (every method in that static IAsyncCursorExtensions class is generic, so you only see the methods inherited from the type 'object').
The solution I would suggest for you would be a wrapper class in C#. This would expose the basic functionality you need and also conveniently hide the generic and enumerating portions from your LabVIEW codebase. You would be able to leverage those same C# syntactic sugar constructs in your wrapper assembly but then expose basic calls (using primitive types).
05-15-2017 03:05 PM
Dear tyk007,
thank you very much for the extensive answer !!
I was afraid something like that was causing my troubles.
I can follow your answer up to the second to last paragraph...
However there is a wrinkle - note that this is a generic method (rather than a method call on a generic class). LabVIEW is not great with generics in general (you will have noticed that strange '1 style syntax in your nodes). LabVIEW cannot call generic methods on a non-generic class since the type is not defined until run-time and LabVIEW cannot create new open or closed generic types (although you can instantiate generic objects from completely closed types, refer http://digital.ni.com/public.nsf/allkb/DC41DCDA972642CF8625787E00732DDD). This is why you don't see any in the list (every method in that static IAsyncCursorExtensions class is generic, so you only see the methods inherited from the type 'object').
The solution I would suggest for you would be a wrapper class in C#. This would expose the basic functionality you need and also conveniently hide the generic and enumerating portions from your LabVIEW codebase. You would be able to leverage those same C# syntactic sugar constructs in your wrapper assembly but then expose basic calls (using primitive types).
I noticed the "1"s in the nodes, but didn't really looked at it closely..
When you say that "LabVIEW cannot call generic methods on a non-generic class", does this mean, that I would be able to call generic methods on generic classes (instead of non-generic classes) ??
I was assuming that IAsyncCursor is a generic class (interface)...
Regarding the solution with the wrapper class: Could you maybe point me in the direction of a tutorial / starting point on how to handle this?
Thank you!!!
Niels Göran
05-15-2017 03:20 PM
I noticed the "1"s in the nodes, but didn't really looked at it closely..
When you say that "LabVIEW cannot call generic methods on a non-generic class", does this mean, that I would be able to call generic methods on generic classes (instead of non-generic classes) ??
I was assuming that IAsyncCursor is a generic class (interface)...
Sorry, my wording is confusing. I should just say LabVIEW cannot call generic methods at all (generic class or no). The angle brackets ("<>") along with a type name in the middle are the giveaway for whether something is generic or not. If a method is generic then the method signature has those brackets attached to the name. if a class or interface is generic, then the class or interface name has those same angle brackets (eg. "List<T>"). IAsyncCursor is indeed a generic interface by its definition:
Regarding the solution with the wrapper class: Could you maybe point me in the direction of a tutorial / starting point on how to handle this?
This could be tricky depending on your experience with C#. The best advice I can give you is the general process that I would follow:
05-15-2017 03:30 PM
Dear tyk007,
thanks for the answer!
Given that my experience with C# started this morning, I'm expecting to invest several hours to days to make that work..
But I will give it a go and see what becoms of it..
One last question:
I figured out that there seems to be a specific class "MongoDatabase" (http://mongodb.github.io/mongo-csharp-driver/2.4/apidocs/html/T_MongoDB_Driver_MongoDatabase.htm), which unfortunately resides in the "legacy" driver part...
So I'm assuming that using that driver (which apperas to be simply implementing most methods with BSON type as <TDocument>), is a possible but not future-proof approach.
Is that correct?
And if so, why is casting to more specific of an IMongoDatabase to MongoDatabase not possible?
Thank you!
Niels Göran
05-15-2017 03:38 PM
I don't have the specifics (you would need to dig further) but this is the signature of the MongoDatabase class
Notice that it does not implement the IMongoDatabase interface (or any other class except object implicitly). So the To More Specific class will not work and LabVIEW rightly points that out.
I'd be guessing but I'd say that the C# MongoDB API has undergone refactoring in the past and, unfortunately, some of the names between the legacy namespaces and the current namespaces are similar which leads to confusion. The course of action I'd recommend is to stick with the current namespaces - the advantage of using a C# wrapper is that LabVIEW will be blissfully unaware of all this and will not change if you make any adjustments to the inner workings of your wrapper.
05-15-2017 03:42 PM
Dear tyk007,
thank you for the quick response!
I will give creating a C# wrapper a go tomorrow and see how it goes..
Thanks!
Niels Göran
05-15-2017 04:13 PM
Dear tyk007,
one more question:
Any recommendations as what IDE to use for the development of the C# wrapper?
Thanks!
Niels Göran
05-15-2017 04:18 PM
There are several IDEs around that are free:
My suggestion would be to consider what you would like to experiment with in the future. VS is a large beast but it will also allow you to experiment with newer frameworks etc. and their is a lot more support for IDE usage (Channel 9 for example).
05-23-2017 04:13 AM
Hello tyk007,
I'm working through getting started with C# and LabVIEW DLLs.
The following question keeps bugging me though:
What is the recommend (best accepted) "version" of .NET to use for LabVIEW?
Visual Studio offers me "Class Library (.NET Framework)", "Class Library (.NET Core)" and "Class Library (.NET Standard)".
So far I got the MongoDriver to work with .NET Core in version 1.0 instead of 1.1, but they should work with netstandard1.5 and net45 (at least the download contains folder named that way..).
What is your recommendation as to what version of .NET to work with to ensure best interoperability with LabVIEW?
Thanks!
Niels Göran