I want to write a F# Library that is used in a C# Application.
The purpose is F# library get an input Deedle Frame and use an R script to calculate and return an output Deedle Frame. So in my Visual Studio 2013 solution, there are two projects: one F# library (called RRunner) and one C# console application (which uses the RRunner library). Both of projects use Nuget package: Deedle.RPlugin
type RRunner() =
static member CreateFrameList(input: Frame<int,string>) : Frame<int,string> =
R.assign("input", input) |> ignore
let script = R.source(rScriptPath)
let result: Frame<int, string> = script.GetValue()
result
Inside C# code
var result = RRunner.RRunner.CreateFrameList(inputFrame);
The above F# code works well. However, when I change the return type of CreateFrameList method to:
static member CreateFrameList(input: Frame<int,string>) : List<Frame<int,string>> =
R.assign("input", input) |> ignore
let script = R.source(rScriptPath)
let result: List<Frame<int, string>> = script.GetValue()
result
I can build the F# project successfully, but I can not build the C# project.
The error message:
Assembly 'RRunner, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' uses 'FSharp.Core, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' which has a higher version than referenced assembly 'FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
What is the problem with my code? And How to solve this problem? or Is there any other way to resolve my purpose to run R script (that receives a Deedle Frame and returns a List of Deedle Frames) in C# code.
Related
Should it be possible to use ef-core-5.0 in a native c++ application using an c++/cli interop assembly with .net core 5 as the target framework? To experiment with this I've modified the netcore branch of the CppCliMigrationSample (https://github.com/mjrousos/CppCliMigrationSample), changing the from "netcoreapp3.1" to "net5.0" for CppCliInterop and the from "net47;netcoreapp3.1" to "net5.0-windows" for the ManagedLibrary. The sample builds and works as expected with these changes. However, adding the efcore 5 assemblies to ManagedLibrary and trying to a simple query on a scaffolded model fails with the following error:- System.IO.FileNotFoundException: 'Could not load file or assembly 'Microsoft.EntityFrameworkCore, Version=5.0.5.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.'. I figure I need an entry in the app's .config but I'm not sure what it should be. Can anyone help with resolving this?
Following is what I have in my modified ManagedLibrary.csproj:-
ManagedLibrary.csproj
Sample query:
using ManagedLibrary.Context;
using ManagedLibrary.Model;
using System.Linq;
namespace ManagedLibrary
{
public static class Mi2cdbData
{
public static Prjdata GetFirstProject()
{
using (var context = new BaseContext())
{
return context.Prjdata.FirstOrDefault();
}
}
}
}
The following shows how it's being called in CppClinterop.cpp:-
CppClinterop.cpp
In my c# application (asp.net mvc), I want to use Autofac to handle my dependency injection, but I got an error when atttempting to use the RegisterAssemblyTypes function (error message below).
I did some experiments with a new solution and found that the error seems to be related to a dot in the project name. The test solution looks like this:
AssemblyTest.sln
- Main.csproj
--> Program.cs
- TestLoadAssembly.csproj
--> Test.cs
- TestWith.Dots.csproj
--> Test.cs
The test classes both have one method that prints "Hello" to the screen. Program.cs looks like this:
using System.Reflection;
namespace Main
{
class Program
{
static void Main(string[] args)
{
var x = Assembly.Load(nameof(TestLoadAssembly)); //This works
var y = Assembly.LoadFrom("TestWith.Dots.dll"); // This seems to work
var z = Assembly.Load(nameof(TestWith.Dots)); // Error here
}
}
}
Main is the active project, and there are project references from Main to the other two. All projects are .net 5 projects.
The error I get from line 3:
System.IO.FileNotFoundException: 'Could not load file or assembly 'Dots, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.'
My question is, how do I make the third line (z) work? Since the first line works, but the third line does not, it seems the error is related to the dot in the name, or is there something that I'm missing here? However, as line two shows, it seems to work when loading the dll by referencing it directly by name.
I have been staring myself blind at this, so I would appreciate your help!
I am using dnLib to generate MSIL assemblies dynamically from a custom language I'm writing, named CSASM:
string absolute = Path.Combine(Directory.GetCurrentDirectory(), forceOutput ?? $"{asmName}.exe");
ModuleDefUser mod = new ModuleDefUser(asmName, Guid.NewGuid(), new AssemblyRefUser(new AssemblyNameInfo(typeof(int).Assembly.GetName().FullName))){
Kind = ModuleKind.Console,
RuntimeVersion = "v4.0.30319" //Same runtime version as "CSASM.Core.dll"
};
var asm = new AssemblyDefUser($"CSASM_program_{asmName}", new Version(version));
asm.Modules.Add(mod);
// Adding attribute code omitted for brevity
//Adds types to the module and constructs methods and method bodies for those types based on the CSASM source file in question
Construct(mod, source);
mod.Write(absolute);
The generation of the executable is working as intended.
However, when trying to run this executable, the TypeLoadException below is thrown:
System.TypeLoadException: Could not load type 'CSASM.Core.IntPrimitive' from assembly
'CSASM_program_Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' due to
value type mismatch.
at Example.Program.csasm_main()
CSASM_program_Example being the name of assembly for the generated executable, Example.exe.
The type IntPrimitive is actually found in the CSASM.Core.dll assembly, which is also in the same folder as the generated executable.
Due to the extreme lack of documentation surrounding dnLib, I'm essentially stumbling around in the dark here.
In short, is there a reason why the type is trying to be loaded from the wrong assembly?
If so, is there a way that I can remedy this?
Viewing the assembly in dnSpy shows the TypeRefs and MemberRefs referencing correct assemblies, which makes this predicament even more frustrating.
After a very thorough examination of a dnLib DLL, the problem was due to me using Importer.ImportDeclaringType(Type).ToTypeDefOrRef(), which caused value-type TypeSigs to be registered as class-type TypeSigs instead.
Even though the docs say to use Importer.ImportDeclaringType(Type) over Importer.ImportAsTypeSig(Type) for method and field declarations, you really shouldn't be using it.
I ran the HelloWorld console app example from a SO anwser compiled with .NET Core 2 and Mono.Cecil 0.10.0-beta7:
var myHelloWorldApp = AssemblyDefinition.CreateAssembly(
new AssemblyNameDefinition("HelloWorld", new Version(1, 0, 0, 0)), "HelloWorld", ModuleKind.Console);
var module = myHelloWorldApp.MainModule;
// create the program type and add it to the module
var programType = new TypeDefinition("HelloWorld", "Program",
Mono.Cecil.TypeAttributes.Class | Mono.Cecil.TypeAttributes.Public, module.TypeSystem.Object);
module.Types.Add(programType);
// add an empty constructor
var ctor = new MethodDefinition(".ctor", Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig
| Mono.Cecil.MethodAttributes.SpecialName | Mono.Cecil.MethodAttributes.RTSpecialName, module.TypeSystem.Void);
// create the constructor's method body
var il = ctor.Body.GetILProcessor();
il.Append(il.Create(OpCodes.Ldarg_0));
// call the base constructor
il.Append(il.Create(OpCodes.Call, module.Import(typeof(object).GetConstructor(Array.Empty<Type>()))));
il.Append(il.Create(OpCodes.Nop));
il.Append(il.Create(OpCodes.Ret));
programType.Methods.Add(ctor);
// define the 'Main' method and add it to 'Program'
var mainMethod = new MethodDefinition("Main",
Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static, module.TypeSystem.Void);
programType.Methods.Add(mainMethod);
// add the 'args' parameter
var argsParameter = new ParameterDefinition("args",
Mono.Cecil.ParameterAttributes.None, module.Import(typeof(string[])));
mainMethod.Parameters.Add(argsParameter);
// create the method body
il = mainMethod.Body.GetILProcessor();
il.Append(il.Create(OpCodes.Nop));
il.Append(il.Create(OpCodes.Ldstr, "Hello World"));
var writeLineMethod = il.Create(OpCodes.Call,
module.Import(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })));
// call the method
il.Append(writeLineMethod);
il.Append(il.Create(OpCodes.Nop));
il.Append(il.Create(OpCodes.Ret));
// set the entry point and save the module
myHelloWorldApp.EntryPoint = mainMethod;
myHelloWorldApp.Write("HelloWorld.exe");
The above code executes fine when compiling with .NET Framework, but when compiling with .NET Core resulted in the error:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Console, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
at HelloWorld.Program.Main(String[] args)
I'd like to ask, why can't the HelloWorld app locate the assembly file mscorlib.dll? What should I do to fix it?
I solved this by creating a HelloWorld.runtimeconfig.json at the same folder of HelloWorld.exe and then ran dotnet ./HelloWorld.exe. It would print Hello World to the console.
The Json file:
{
"runtimeOptions": {
"tfm": "netcoreapp2.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.0.0"
}
}
}
you must be performing the assembly manipulation from within .net classic, ie .net 4.x. so this means when u do typeof(Console) is imports the Console from the full runtime, no from the NET Core runtime
If you use typeof(...), you are importing types from the current runtime (.NET Core 2). If you want to make a .NET Framework application from .NET Core, you need to import mscorlib from .NET Framework on Windows, or mono, and use the types from it. See my other answer: https://stackoverflow.com/a/73434552/4205390
Apologies for the dodgy question - happy to rephrase if someone has a better suggestion.
I'm trying to create an object by dynamically invoking an assembly belonging to another application.
The following PowerShell code is working nicely for me:
[Reflection.Assembly]::LoadFrom("C:\Program Files\Vendor\Product\ProductAPI.dll")
$bobject = new-object ProductAPI.BasicObject
$bobject.AddName("Some Name")
I'm struggling to do the same thing in C#. Based on other posts on StackOverflow I currently have this:
System.Reflection.Assembly myDllAssembly =
System.Reflection.Assembly.LoadFile("C:\\Program Files\\Vendor\\Product\\ProductAPI.dll");
System.Type BasicObjectType = myDllAssembly.GetType("ProductAPI.BasicObject");
var basicObjectInstance = Activator.CreateInstance(BasicObjectType);
The final line results in a TargetInvocationException.
{"Could not load file or assembly 'AnotherObject, Version=1.2.345.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
It appears that the BasicObject constructor is trying to invoke AnotherObject (from AnotherObject.dll in the same folder) but can't find it.
Any tips on how to get around this?
If it can't find a dependent assembly in the usual places, you'll need to manually specify how to find them.
The two easiest ways I'm aware of for doing this:
manually load the dependent assemblies in advance with
Assembly.Load.
handle the AssemblyResolve event for the domain which is loading the
assembly with additional assembly dependencies.
Both essentially require you to know the dependencies for the assembly you're trying to load in advance but I don't think that's such a big ask.
If you go with the first option, it would also be worthwhile looking into the difference between a full Load and a reflection-only Load.
If you would rather go with 2 (which I'd recommend), you can try something like this which has the added benefit of working with nested dependency chains (eg MyLib.dll references LocalStorage.dll references Raven.Client.dll references NewtonSoft.Json.dll) and will additionally give you information about what dependencies it can't find:
AppDomain.CurrentDomain.AssemblyResolve += (sender,args) => {
// Change this to wherever the additional dependencies are located
var dllPath = #"C:\Program Files\Vendor\Product\lib";
var assemblyPath = Path.Combine(dllPath,args.Name.Split(',').First() + ".dll");
if(!File.Exists(assemblyPath))
throw new ReflectionTypeLoadException(new[] {args.GetType()},
new[] {new FileNotFoundException(assemblyPath) });
return Assembly.LoadFrom(assemblyPath);
};