Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List of methods to try for .NET interface #26

Closed
msevestre opened this issue Jun 6, 2019 · 14 comments
Closed

List of methods to try for .NET interface #26

msevestre opened this issue Jun 6, 2019 · 14 comments

Comments

@msevestre
Copy link
Member

msevestre commented Jun 6, 2019

  • Calling a method without parameters and void return value
  • Calling a method with simple parameters returning void value
    • string parameter
    • int parameter
    • object (structure)
  • Calling a method with parameters and return values
    • The return value is integer, string
    • the return value is an object
  • Can we call a method on an object created in .NET from R
  • Can we call an async method and await the result from R
@msevestre
Copy link
Member Author

FYI @Yuri05 @ktseow

@msevestre msevestre changed the title List of method to try for .NET interface List of methods to try for .NET interface Jun 6, 2019
@PavelBal
Copy link
Member

@msevestre I do not understand what you mean by the point

  • Can we call a method on an object created in .NET from R

?

@msevestre
Copy link
Member Author

@PavelBal Let say I have an object in .NET called Parameter with a property Value {get;set;}.
This object has a public method MultiplyValyeBy(double value)

Is it possible in R to do something like this: (pseudo code)

param = new Parameter()
param.Value = 10
param.MultiplyValueBy(2)
assert.IsEqual(param.Value, 20)

@PavelBal
Copy link
Member

Can we call an async method and await the result from R

As I did not work with async in .NET so far, could you provide a simple example (.NET) code for an async-method?

@PavelBal
Copy link
Member

@msevestre @Yuri05
Which version of .NET Core do we test?
Also - .NET Core or .NET Standard?

@msevestre
Copy link
Member Author

msevestre commented Jun 24, 2019

@PavelBal I'll provide some sample code for async method today

We will aim for now at supporting .NET Standard 2.0 for all our components except the one that are purely windows based or don't need to be converted (such as TexReporting)

Then you need a runtime. .NEt Standard is a common interface between .NET Core and .NET Framework

  • Under windows (until we manage to migrate everything to .NET Core, which might be never depending on compatibility with for example devexpress), we will use .NET Framework (4.8)

  • Under linux, we will use .Net Core (2.2)

In the future, we might move everything to .NET Core. This really depends on what our component providers are doing. Not high prio however

see this table here
https://docs.microsoft.com/en-us/dotnet/standard/frameworks

Target Framework Latest
Stable Version
Target Framework Moniker (TFM) Implemented
.NET Standard Version
.NET Standard 2.0 netstandard2.0 N/A
.NET Core 2.2 netcoreapp2.2 2.0
.NET Framework 4.8 net48 2.0

That means that for your test, as long as you are using standard component, you should be good to go

In fact, I have just migrated OSPSuite.Utility to .NET Standard and you could try to instantiate some classes already :) (Version 4.0.0.1)

@msevestre
Copy link
Member Author

@PavelBal Attached a .NET Core console project with a .NET Standard library
R would typically call the lib directly
The lib as one service with one Async method. It returns a Task<T>.

This how it's being called from the .NET core console


      static async Task Main(string[] args)
      {
         Console.WriteLine("Hello World!");

         var service = new MyService();

         var res = await service.PerformSimulationAsync("MySim");
         Console.WriteLine($"Simulation Result: {res.Success}");

      }

RTestAsync.zip

@PavelBal
Copy link
Member

PavelBal commented Jun 28, 2019

Results of the evaluation of the rClr-package for communicating with .NET:

  • The package is in development
  • NOT on CRAN
  • Tested version 0.8.3
  • Compiled version for Windows exists - straightforward installation
  • On Linux - tested on a virtual machine with Ubuntu 19.04
    • The package has to be compiled -> compilation from GitHub fails (issue opened Failing to install rClr in Ubuntu 19.04 rdotnet/rClr#45)
    • Installation on Ubuntu possible with workaround (copying of compiled components from Windows release, editing installation script to not clean up the installation folder).

I have tested calling a set of simple methods from a library (.dll) of a .NET Framework 4.6.1, a .NET Core 2.2, and .NET Standard 2.0 projects.

.NET Framework 4.6.1 Windows .NET Framework 4.6.1 Ubuntu .NET Core Windows .NET Standard 2.0 Windows .NET Standard 2.0 Ubuntu
Get public static int [X] [X] Fail** [X] [X]
Get public static string [X] [X] Fail** [X] [X]
Call static method without argument with void output [X] [X] Fail** [X] [X]
Call static method with int argument with void output [X] [X] Fail** [X] [X]
Call static method with string argument with void output [X] [X] Fail** [X] [X]
Create an object [X] [X] Fail** [X] [X]
Call static method with object argument with void output [X] [X] Fail** [X] [X]
Call static method with int argument with int output [X] [X] Fail** [X] [X]
Call static method with int argument with string output [X] [X] Fail** [X] [X]
Call static method with int argument with object output [X] [X] Fail** [X] [X]
Call method without argument with void output [X] [X] Fail** [X] [X]
Get boolean value of an object [X] [X] Fail** [X] [X]
Call method with int argument with void output [X] [X] Fail** [X] [X]
Call method with str argument with void output [X] [X] Fail** [X] [X]
Call method with object argument with void output [X] [X] Fail** [X] [X]
Call method with int argument with int output [X] [X] Fail** [X] [X]
Call method with int argument with string output [X] [X] Fail** [X] [X]
Call method with int argument with object output [X] [X] Fail** [X] [X]
Multiplicate internal int by a given int) [X] [X] Fail** [X] [X]
Call an async method and await the result from R [X] [X] [X] [X]
getPKSimCreateIndividual() [X] Fail* [NA] [NA] [NA]

Both, .NET Framework and .NET Standard work in Windows and Linux. .NET Core cannot be acccessed from R at all.

Additionally, I have tried PKSimCreateIndividual() version (.NET Framework), and it works in windows but not in Linux (though I suppose it is an issue of the dll and not of R).

@msevestre
Copy link
Member Author

@PavelBal . Wow great work!

A few questions so that I understand:

  • What does .NET framework on Linux means? Do you mean mono?
  • .NET Standard is just a definition of functionality without implementation. You need a runtime to execute it. Which runtime was installed on windows and ubuntu (the last two columns)
  • I don't see the entry: "Creating an object and calling method on that object"
  • Could you share the R script so that I can see how it looks like?

Looking good ??

@PavelBal
Copy link
Member

Sorry, got messed up with all the .NET definitions.

  • On Linux, I use Mono 5.18 as runtime.
  • By ".NET Framework 4.6.1", ".NET Core ", and ".NET Standard 2.0 " I meant the type of projects created in VisualStudio. The runtime on Windows is CLR 4 (.NET Framework), on Linux Mono.
  • I don't see the entry: "Creating an object and calling method on that object"

The entry is called "Multiplicate internal int by a given int)" :)

@PavelBal
Copy link
Member

Example of R code. Functions from the rClr-package start with "clr".

require(rClr)

#Default int value
defIntVal = 42;
#Default str value
defStrVal = "myString";

asyncFun = function(object){
  print("Starting async call");
  res = clrCall(obj = object, methodName = "PerformSimulationAsync", "MySim");
  clrCall(res, methodName = "Wait")
  print(paste("Simulation result:", clrGet(clrGet(res, "Result"), "Success")));
}

#Path to the folder containing the library
dllDir = "rDotNet_test_Framework/rDotNet_test_Framework/bin/Debug";
#Path to the library
dllPath = file.path(getwd(), dllDir, "rDotNet_test_Framework.dll", fsep = .Platform$file.sep);
#Load the library
clrLoadAssembly(dllPath);

#Getting a public static int
defInt = clrGet(objOrType = "rDotNet_test_Framework.RClrTest", name = "IntArgDef")
print(paste("Getting a public static int value:", (defInt == defIntVal)));
#Getting a public static string
defStr = clrGet(objOrType = "rDotNet_test_Framework.RClrTest", name = "StrArgDef")
print(paste("Getting a public static string value:", (identical(defStr, defStrVal))));

#Static methods
#Calling static void method withour arguments
tmp = clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticVoidMethod");
#Calling static void method with int argument
tmp = clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticVoidMethodIntArg", defInt);
#Calling static void method with string argument
tmp = clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticVoidMethodStrArg", defStr);
#Calling static void method with object argument
#Create a new object of type InternalClass
internalClassObj = clrNew(typename = "rDotNet_test_Framework.InternalClass");
tmp = clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticVoidMethodObjArg", internalClassObj);
#Calling static int method with int argument
tmp = clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticIntMethodIntArg", defInt);
print(paste("Calling static int method with int argument:", (tmp == (defIntVal + 1))));
#Calling static string method with int argument
clrCallStatic(typename =  "rDotNet_test_Framework.RClrTest", methodName = "StaticStrMethodIntArg", defInt);
#Calling static method returning an InternalClass object with int argument
internalClassObj = clrCallStatic(typename = "rDotNet_test_Framework.RClrTest", methodName = "StaticObjMethodIntArg", defInt);
internalClassObj;

#Non-static methods
#Create an object of RClrTest
classObj = clrNew("rDotNet_test_Framework.RClrTest");
#Calling void method without arguments
tmp = clrCall(obj = classObj, methodName = "VoidMethod");
clrGet(objOrType = classObj, name = "isVoidMethodNoArgTrue");
#Calling void method with int argument
tmp = clrCall(obj = classObj, methodName = "VoidMethodIntArg", defInt);
clrGet(objOrType = classObj, name = "isVoidMethodIntArgTrue");
#Calling void method with string argument
tmp = clrCall(obj = classObj, methodName = "VoidMethodStrArg", defStr);
clrGet(objOrType = classObj, name = "isVoidMethodStringArgTrue");
#Calling void method with object argument
tmp = clrCall(obj = classObj, methodName = "VoidMethodObjArg", internalClassObj);
clrGet(objOrType = classObj, name = "isVoidMethodObjArgTrue");
#Calling int method with int argument
clrCall(obj = classObj, methodName = "IntMethodIntArg", defInt);
clrGet(objOrType = classObj, name = "isIntMethodIntArgTrue");
#Calling string method with int argument
clrCall(obj = classObj, methodName = "StrMethodIntArg", defInt);
clrGet(objOrType = classObj, name = "isStringMethodIntArgTrue");
#Calling method returning an InternalClass object with int argument
internalClassObj = clrCall(obj = classObj, methodName = "ObjMethodIntArg", defInt);
clrGet(objOrType = classObj, name = "isObjMethodIntArgTrue");

#Multiplication of default int value of the class.
tmp = clrCall(obj = classObj, methodName = "MultiplyDefIntBy", as.integer(5));
print(paste("Multiplication of default int value of the class by a given integer:", (tmp == 15*5)))

asyncFun(classObj);

@msevestre
Copy link
Member Author

@PavelBal Ok cool
DO you think you could share the code so that I can try to run in on windows (create a repo somewhere)?

@msevestre
Copy link
Member Author

msevestre commented Jun 28, 2019

@PavelBal Another think that we need to try: Parallel execution of code

Can we instantiate two instances of the same object, run the code in //, and get some values (provided that said object is implemented in a thread-safe way...otherwise we have bigger problems )

@PavelBal
Copy link
Member

@msevestre I have sent you an invitation to a repo, please contact me if something does not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants