c# MongoDB RunCommand - c#

Can someone give me an example of the use of the RunCommand method that takes a string argument only (called CommandName) available in the MongoDB .NET driver? I know there is an overloaded RunCommand method that takes an object reference (I think a CommandDocument object) as an argument, but I'd rather not use that one.
I'm having trouble getting the syntax right for CommandName. Thanks in advance!

If you are using some recent version of the official C# driver, the "real" string based version you are referring to (CommandResult RunCommand(string commandName)) is only part of the legacy driver component (check the namespace). I would hence not recommend using it.
The "official" interface currently looks like this:
TResult RunCommand<TResult>(Command<TResult> command, /* and some additional optional parameters */)
And since the C# driver heavily relies on implicit type conversions, there also is one from a string (and a BsonDocument) to the corresponding sub types of Command<TResult> (JsonCommand<TResult> and BsonDocumentCommand<TResult>). So you can effectively pass a string to the above new RunCommand() method, too.
You can therefore write either one of the following lines both of which do the exact same thing:
RunCommand<BsonDocument>("{count: \"collection_name\"}")
RunCommand<BsonDocument>(new BsonDocument("count", "collection_name"))

Related

PowerShell conversion of String into FileInfo automatically - What is this called?

Some sample code to illustrate what I'm talking about. I've got a utility class with a single method. That method takes one argument: a System.IO.FileInfo object. From the PowerShell side I can pass in a System.String object and everything "just works". I'm curious as a develop getting more into PowerShell this year I'm curious:
What feature of PowerShell allows this to happen?
Is this open to extension / use by any developer in PowerShell 7.x? (non-internal)
C#:
using System.IO;
using System.Linq;
namespace TestProject
{
public class Utility
{
public string GetFirstLine(FileInfo fileInfo)
{
string firstLine = File.ReadLines(fileInfo.FullName).First();
return firstLine;
}
}
}
PowerShell:
Add-Type -Path "C:\assemblies\TestProject.dll"
$util = [TestProject.Utility]::New()
$util.GetFirstLine("C:\temp\random-log.txt")
Note: I realize this is trivial example. Code is meant for quickly illustrating the capability in PowerShell I am interested in.
Although PowerShell is more or less a "real .NET language", it does extend the common type system with an array of behaviors that sometimes conflict with what you know about .NET's type system behavior from languages like C# or VB.NET.
This additional type system layer bolted on top of the CLR is aptly named the Extended Type System (ETS), and it's directly responsible for making argument conversion "just work" the way you've observed.
When the PowerShell runtime reaches a method invocation statement like $util.GetFirstLine("C:\temp\random-log.txt"), it has to pick an appropriate overload, just like the C# compiler does.
The first step is to identity overloads for which the number of arguments passed can cover all mandatory parameters of the given overload signature. In your case, only 1 such signature can be resolved at this step, so PowerShell now has two pieces of the puzzle:
A method stub with the signature string GetFirstLine(FileInfo fileInfo)
An argument value of type [string]
At this point, the C# compiler would give up and report CS1503: Argument 1: cannot convert from 'string' to 'System.IO.FileInfo'.
PowerShell, on the other hand, is designed to be helpful in the hands of system administrators and operators - people who might not put too much thought into data structure design, but who are chiefly concerned with string representations of data (after all, this is what bash, cmd, etc. taught them to use).
To meaningfully convert from a string (or any other non-compliant argument type) at just the right time, ETS comes with a number of facilities and hooks for implicit type conversion that the runtime then attempts, one by one, until it either finds a valid conversion mechanism, or fails (at which point the method invocation fails too):
Built-in converters
These take priority to handle the most common edge cases, like null-conversions, "truthy/falsy"-to-real-[bool] conversions, stringification of scalars, etc. - without these, PowerShell would be a pain in the ass to work with interactively.
Example:
These flow control statements behave exactly like you'd expect thanks to built-in conversions: if($null){ <# unreachable #> }, do{ Stop-Process chrome }while(Get-Process chome)
Custom type converters
These are concrete type converter implementations registered to one or more target types - this can be useful for modifying the binding behavior of complex types you've brought with you into the runtime.
Example:
The RSAT ActiveDirectory module uses type adapters to interchange between the different data types modeling specific directory object classes - allowing you to seamlessly pipe output from Get-ADComputer (very specific output type) to Get-ADObject (generalized output type) and vice versa.
Parse converters
If no appropriate built-in or custom type converter can be found, PowerShell will attempt to resolve a Parse() method with the appropriate return type on the target type.
Example:
The cast operation [timespan]'1.02:15:25' can succeed this way.
Constructor-based conversions
If none of the above works, PowerShell will attempt to resolve a constructor that can be invoked with a single parameter argument of the source type given.
This is what happens in your case - PowerShell effectively excutes $util.GetFirstLine([System.IO.FileInfo]::new("C:\temp\random-log.txt")) for you
CTS conversions
Finally, if all of ETS' conversation attempts fail, it falls back to resolving implicit (and eventually explicit) conversions defined by the types themselves.
Example:
This conversion succeeds because the [DateTimeOffset] type has an implicit conversion operator for [DateTime]: (Get-Date) -as [DateTimeOffset]
The concrete type converters mentioned above will automatically be respected by ETS if they've either been included in a type data file (see about_Types.ps1xml), or if the target type is public and the source definition was decorated with a [TypeConverter()] attribute.
Additionally, you can register new type conversion primitives at runtime with the Update-TypeData cmdlet.
Of course the madness doesn't stop there, there are also additional facilities specifically for converting/transform command arguments, but that's beyond the scope of this question :)

Create new PayPal.Payments.DataObjects.TransactionResponse

Is it possible to create a new PayPal.Payments.DataObjects.TransactionResponse?
I'm currently working on upgrading (our old ERP system) to TLS 1.2, and I need to override a function that returns a PayPal.Payments.DataObjects.TransactionResponse, but PayPal.Payments.Communication.PayflowNETAPI.SubmitTransaction returns a string. Trying to simply create a new PayPal.Payments.DataObjects.TransactionResponse hasn't worked - I'm told in the VB code that:
'PayPal.Payments.DataObjects.TransactionResponse.Private Sub New()' is not accessible in this context because it is 'private'.
Trying in the C# code yields a less descriptive error:
'TransactionResponse' does not contain a constructor that takes 0 arguments
(replacing the 0 with any number of arguments that you put in -- I tried up to 8 or 9)
I am open to solutions in either VisualBasic or C#. Although the function in question is in VB, we opted to send our transactions to an internal processing server, which will return the string (written in C#), so I can do this from either side.
Basically, I just need to take the response (currently in string format), probably parse it (although a straight string conversion would be fine too), and put the info into a PayPal.Payments.DataObjects.TransactionResponse.
You have source code here.
You can check which parameter send to the constructor.
From a quick read of the Paypal SDK code mentioned by Ygalbel, it looks like there is no new() function. Rather, you would declare your var of type PayPal.Payments.DataObjects.TransactionResponse and then use the set and get accessors to set/get data in the class.

Passing a COM object from C# to Perl using PerlNET

I’m trying to pass a COM object from C# code to Perl.
At the moment I’m wrapping my Perl code with PerlNET (PDK 9.4; ActiveState) and I have defined a simple subroutine (+ required pod declaration) in Perl to pass objects from C# to the wrapped Perl module.
It seems that the objects I pass are not recognized correctly as COM objects.
An example:
In C# (.NET 4.0), the ScriptControl is used to load a simple class from a file written in VBScript.
var host = new ScriptControl();
host.Language = "VBScript";
var text = File.ReadAllText("TestScript.vbs");
host.AddCode(text);
dynamic obj = host.Run("GetTestClass");
What I get (obj) is of type System.__ComObject. When I pass it to my Perl/PerlNET assembly and try to call method Xyz() in Perl I get the following (runtime) exception:
Can't locate public method Xyz() for System.__ComObject
If, however, I do more or less the same thing in Perl, it works. (In the following case, passing only the contents of my .vbs file as parameter.)
I can even use the script control :
sub UseScriptControl {
my ($self, $text) = #_;
my $script = Win32::OLE->new('ScriptControl');
$script->{Language} = 'VBScript';
$script->AddCode($text);
my $obj = $script->Run('GetTestClass');
$obj->Xyz();
}
Now, calling Xyz() on obj works fine (using Win32::OLE).
In both cases I use:
use strict;
use Win32;
use Win32::OLE::Variant;
Another approach:
I can invoke methods by using InvokeMember of class System.Type if I specify exactly which overload I want to use and which types I’m passing:
use PerlNET qw(typeof);
typeof($obj)->InvokeMember("Xyz",
PerlNET::enum("System.Reflection.BindingFlags.InvokeMethod"),
PerlNET::null("System.Reflection.Binder"),
$obj,
"System.Object[]"->new());
Using this approach would mean rewriting the whole wrapped Perl module. And using this syntax..
Now I am wondering if I am losing both the advantages of the dynamic keyword in .NET 4.0 and the dynamic characteristics of Perl (with Win32::OLE) by using PerlNET with COM objects.
It seems like my preferred solution boils down to some way of mimicking the behaviour of the dynamic keyword in C#/.NET 4.0.
Or, better, finding some way of converting the passed COM object to something that will be recognized as compatible with Win32::OLE. Maybe extract some information of the __ComObject for it to be identified correctly as COM object.
I have to add that I posted to the PDK discussion site too (but didn’t get any response yet): http://community.activestate.com/node/18247
I also posted it to PerlMonks - as I'm not quite sure if this is more a Perl or C#/.NET question:
http://www.perlmonks.org/?node_id=1146244
I would greatly appreciate any help - or advise on where to look further.

Passing a COM method default parameter

I have a ComVisible COM class written in C#. I want to call it from another C# bit of code using COM and pass the default value for the parameter. I can call plenty of other methods without default arguments.
This is the best I can come up with. The first two lines work for all my other methods.
Type mytype = Type.GetTypeFromProgID("MyType");
dynamic myinstance = Activator.CreateInstance(mytype);
object missingValue = System.Reflection.Missing.Value;
myinstance.generatecsvdocument("mystring", ref missingValue);
My method looks like this:
public void generatecsvdocument(string mystring, string rowseperator = "\n")
When I run it I get the error:
The best overloaded method match for 'generatecsvdocument(string,
string)' has some invalid arguments
object missingValue = System.Reflection.Missing.Value;
That cannot work here. It is only valid for a COM method that takes a VARIANT as an argument. Looks like object or dynamic in C#. A very different kind of default argument mechanism than C# supports, it is the callee that determines the default value. In C# it is the caller that determines it, the C# compiler uses metadata to know that default.
Missing.Value turns in a variant of type vtError with the value DISP_E_PARAMNOTFOUND at runtime. Signalling the COM method to use the default value. Not actually that commonly used, usually only implemented in COM servers that support scripting languages. Office Automation is the most common example, probably what inspired you to try this.
But no, your argument is string, not a variant. There is no way to discover the default either when you use late binding, implicit is that you don't know anything about the default value stored in metadata. Otherwise the reason that the vtError mechanism exists, scripting languages have the same problem. The only real way to get ahead is to rewrite the method and test for a null argument, substituting "\n" if that's the case.

C# 3.5 DLR Expression.Dynamic Question

I have inherited a small scripting language and I am attempting to port it to the DLR so that it is a little easier to manage. So far it has been fairly straight forward. I have run into a problem though attempting to dynamically call members of a variable. The current language runs on .NET and uses a parsing loop and reflection to do this, but I was hoping to get away from that. Here is an example of the script language:
string $system1RemoteUri;
string $dbconnection = $config.GetDBConnection ("somedb");
float $minBad = 0.998;
float $minGood = 0.2;
$systen1RemoteURI, $minBad, and $minGood are variables that will be set in the script, along with $dbconnection. However $dbconnection will get its value from a variable passed in called $config. The 4 variables need to be available to the caller, so they are passed into the lambda, initially as null. Here is the generated Lambda IL (debug view):
.Lambda #Lambda1<Delegate6$1>(
System.String& $$system1RemoteUri,
System.String& $$dbconnection,
System.Double& $$minBad,
System.Double& $$minGood
System.Object $$config) {
.Block() {
$$minBad = 0.998D;
$$minGood = 0.2D
}
//Some assignment similar to...
//.Dynamic Call GetDBConnection($config, "somedb");
}
What I am trying to figure out is how to use Expression.Dynamic to emit the $config.GetDBConnection("somedb"). From looking at examples in the Sympl libraries I believe the emitted IL should look like:
.Dynamic Call GetdbConnection($config, "somedb") but I cant figure out how to actually emit that from Expression.Dynamic.
It seems to want a CallSiteBinder which I cannot create correctly, and I do not understand what the order of parameters is to Expression.Dynamic, as it seems to only want the "member" being invoked, and not the base.
I do not know the runtime type of $config it is just some object which implements a function called GetDBConnection(string). This is not provided by an interface or base class.
Any help would be appreciated.
You can either turn this into an InvokeMemberBinder or turn "$config.GetDBConnection" into a GetMember and then do an Invoke on the result of that passing $someDb as the argument.
To implement your GetMemberBinder and InvokeMemberBinder you can use the DLR outer-layer DefaultBinder class. In the latest IronPython/IronRuby source code you can just create a new DefaultBinder instance out of thin air. Then in your FallbackGetMember / FallbackInvoke you can call defaultBinder.GetMember(...) and defaultBinder.Call (which should be renamed Invoke). That'll deal with most .NET types for you. Also all objects which implement IDynamicMetaObjectProvider will work with it as well. For other dynamic operations you can use the other methods on the default binder. And if you want to start customizing your overload resolution and binding rules it has lots of knobs you can turn.
Unfortunately the default binder doesn't have an InvokeMemberBinder implementation right now so you're probably better off w/ GetMember/Invoke.

Categories