cancel
Showing results for 
Search instead for 
Did you mean: 

Tip: How to Load Assembly DLLs Dynamically

StefanSchnell1
Level 7
Hello Community,
in my opinion dynamic loading of dotNET assembly DLLs at the runtime a necessity. Therefore here a first approach how this possibility can be realized.

At first I developed a tiny library, which I packed in a NuGet.
//-Begin----------------------------------------------------------------

using System;

namespace test {

  public class nuget {

    public string mtest(string Input = "") {
      if(String.IsNullOrEmpty(Input)) {
        return "Hello World";
      } else {
        return "Hello " + Input;
      }
    }

  }

}

//-End------------------------------------------------------------------​


In the next step I installed this NuGet package at the target system in the UserProfile directory.

nuget.exe Install TestNuget -Source "%cd%" -OutputDirectory "%USERPROFILE%\.nuget"
13429.png


And with a Code Stage I call the method of this library dynamically, independently from the customizing in the Code Options.

//-Begin----------------------------------------------------------------

Result = string.Empty;
ErrRet = string.Empty;

string UserDir = Environment.GetEnvironmentVariable("UserProfile");
string DLLPath = UserDir + "\\.nuget\\TestNuget.1.0.0\\lib\\net40";

try {

  //-Loads assembly-----------------------------------------------------
  Assembly TestNugetDLL = Assembly.LoadFile(DLLPath + "\\TestNuget.dll");

  //-Gets the class type------------------------------------------------
  Type TestNugetClass = TestNugetDLL.GetType("test.nuget");
  if(TestNugetClass == null) {
    return;
  }

  //-Gets the method----------------------------------------------------
  MethodInfo mtest = TestNugetClass.GetMethod("mtest");

  //-Creates instance of the class--------------------------------------
  object TestNugetObj = Activator.CreateInstance(TestNugetClass);

  //-Call method without parameter--------------------------------------
  var oResult = mtest.Invoke(TestNugetObj, new object[] { null });
  Result = oResult.ToString();
  Result += Environment.NewLine;

  //-Call method with parameter-----------------------------------------
  oResult = mtest.Invoke(TestNugetObj, new object[] { "Stefan" });
  Result += oResult.ToString();

} catch(Exception ex) {
  ErrRet = ex.Message;
}

//-End------------------------------------------------------------------


Only the namespace System.Reflection must be included.
13430.png
13431.png


Yes, including the library and calling the methods is "a bit cumbersome". But this approach offers a great possibility, to call methods of an assembly which are not in the program directory of BP. This separation simplifies especially the deployment of libraries.

Enjoy it.

Best regards
Stefan



------------------------------
Stefan Schnell
Senior Systems Engineer at BWI GmbH
------------------------------
7 REPLIES 7

jhogelp
Level 8
Hi Stefan,

Thanks for you contribution.

Regards

------------------------------
Jhogel Ponne
Senior RPA
Ernst & Young
America/Panama
------------------------------

StefanSchnell1
Level 7
Hello Community,
to verify my approach I tried to use the integration of AutoIt scripting language, I have described the basic approach here in the context of different RPA platforms.
I was particularly interested in using the existing NuGet package.

I installed the existing NuGet package in the user directory.
13384.png

In the next step I build an object to use the AutoIt library. 
13385.png

13386.png

Here the Code Stage:

//-Begin----------------------------------------------------------------

//-Initialization of output variables-----------------------------------
Result = string.Empty;
ErrorMessage = string.Empty;

//-Check if file exists-------------------------------------------------
if(!File.Exists(AutoItFileName)) {
  ErrorMessage = "File not found";
  Console.WriteLine(ErrorMessage);
  return;
}

string UserDir = Environment.GetEnvironmentVariable("UserProfile");
string DLLPath = UserDir + "\\.nuget\\AutoIt4dotNET.1.0.0\\lib\\net40";

try {

  //-Loads AutoIt assembly----------------------------------------------
  Assembly AutoItDLL = Assembly.LoadFile(DLLPath + "\\AutoIt4dotNET.dll");

  //-Gets the class type------------------------------------------------
  Type AutoItClass = AutoItDLL.GetType("AutoIt4dotNET");
  if(AutoItClass == null) {
    return;
  }

  //-Gets the method----------------------------------------------------
  MethodInfo Run = AutoItClass.GetMethod("Run");

  //-Creates instance of the class--------------------------------------
  object AutoIt = Activator.CreateInstance(AutoItClass);

  //-Call method--------------------------------------------------------
  var oResult = Run.Invoke(AutoIt, new object[] {
    AutoItFileName,
    Arguments,
    Convert.ToInt32(TimeOut),
    x64,
    "", //-Path to AutoIt if local available, not necessary here
    OutputDebug
  });
  Result = oResult.ToString();

} catch(Exception ex) {
  ErrorMessage = ex.Message;
}

//-End------------------------------------------------------------------​

It works as expected.
13387.png

This approach shows us how to use libraries of NuGet packages with BP, with the advantage that the libraries no longer have to be stored in the BP program directory. In addition, we also see how AutoIt can be seamlessly integrated with BP via its CLI.

Enjoy it.

Best regards
Stefan






------------------------------
Stefan Schnell
Senior Systems Engineer at BWI GmbH
------------------------------

Hello, Stefan,

excellent piece of work! I like your posts very much! Thanks for your contributions here!

However, I have one question - when you use this approach (I haven't had time to play with it that's why I am asking) - you are not getting syntax errors from Code Stage? BP is able to understand references thanks to System.Reflection or....?

Regards,


------------------------------
Zdeněk Kabátek
Head of Professional Services
NEOOPS
http://www.neoops.com/
Europe/Prague
------------------------------

Hello Zdeněk,

thank you very much for your reply.

I got no syntax errors, all works well and as expected.
As attachment a tiny video.

Best regards
Stefan





------------------------------
Stefan Schnell
Senior Systems Engineer at BWI GmbH
------------------------------

StefanSchnell1
Level 7
Hello Community,

with the knowledge of how to use dynamic data type is it possible to simplify the code and make it better understandable.
The call method section now consists of only one line.

Enjoy it.

Best regards
Stefan

//-Begin----------------------------------------------------------------

//-Initialization of output variables-----------------------------------
Result = string.Empty;
ErrorMessage = string.Empty;

//-Check if file exists-------------------------------------------------
if(!File.Exists(AutoItFileName)) {
  ErrorMessage = "File not found";
  Console.WriteLine(ErrorMessage);
  return;
}

string UserDir = Environment.GetEnvironmentVariable("UserProfile");
string DLLPath = UserDir + "\\.nuget\\AutoIt4dotNET.1.0.0\\lib\\net40";

try {

  //-Loads AutoIt assembly----------------------------------------------
  Assembly AutoItDLL = Assembly.LoadFile(DLLPath + "\\AutoIt4dotNET.dll");

  //-Gets the class type------------------------------------------------
  Type AutoItClass = AutoItDLL.GetType("AutoIt4dotNET");
  if(AutoItClass == null) {
    return;
  }

  //-Gets the method----------------------------------------------------
  MethodInfo Run = AutoItClass.GetMethod("Run");

  //-Creates instance of the class--------------------------------------
  dynamic AutoIt = Activator.CreateInstance(AutoItClass);

  //-Call method--------------------------------------------------------
  Result = AutoIt.Run(
    AutoItFileName,
    Arguments,
    Convert.ToInt32(TimeOut),
    x64,
    "", //-Path to AutoIt if local available, not necessary here
    OutputDebug
  );

} catch(Exception ex) {
  ErrorMessage = ex.Message;
}

//-End------------------------------------------------------------------​


------------------------------
Stefan Schnell
Senior Systems Engineer at BWI GmbH
------------------------------

@StefanSchnell1, you can even bundle your DLL inside VBO as base64 string - Abbyy does that in their VBO (zip+base64 actually).
It works if you just have a few methods in dll, but problem is that you dont have namespace anymore and missing all the enums etc.

------------------------------
Andrey Kudinov
Project Manager
MobileTelesystems PJSC
Europe/Moscow
------------------------------

@AndreyKudinov

Hello Andrey,
thank you very much for this interesting hint.
Best regards
Stefan​

------------------------------
Stefan Schnell
Senior Systems Engineer at BWI GmbH
------------------------------