# netcorehost
[![CI](https://github.com/OpenByteDev/netcorehost/actions/workflows/ci.yml/badge.svg)](https://github.com/OpenByteDev/netcorehost/actions/workflows/ci.yml) [![crates.io](https://img.shields.io/crates/v/netcorehost.svg)](https://crates.io/crates/netcorehost) [![Documentation](https://docs.rs/netcorehost/badge.svg)](https://docs.rs/netcorehost) [![dependency status](https://deps.rs/repo/github/openbytedev/netcorehost/status.svg)](https://deps.rs/repo/github/openbytedev/netcorehost) [![MIT](https://img.shields.io/crates/l/netcorehost.svg)](https://github.com/OpenByteDev/netcorehost/blob/master/LICENSE)
A Rust library for hosting the .NET Core runtime.
It utilizes the .NET Core hosting API to load and execute managed code from withing the current process.
## Usage
### Running an application
The example below will setup the runtime, load `Test.dll` and run its `Main` method:
```rust
let hostfxr = nethost::load_hostfxr().unwrap();
let context = hostfxr.initialize_for_dotnet_command_line(pdcstr!("Test.dll")).unwrap();
let result = context.run_app().value();
```
The full example can be found in [examples/run-app](https://github.com/OpenByteDev/netcorehost/tree/master/examples/run-app).
### Calling a managed function
A function pointer to a managed method can be aquired using an [`AssemblyDelegateLoader`](https://docs.rs/netcorehost/*/netcorehost/hostfxr/struct.AssemblyDelegateLoader.html).
This is only supported for [`HostfxrContext`'s](https://docs.rs/netcorehost/*/netcorehost/hostfxr/struct.HostfxrContext.html) that are initialized using [`Hostfxr::initialize_for_runtime_config`](https://docs.rs/netcorehost/*/netcorehost/hostfxr/struct.Hostfxr.html#method.initialize_for_runtime_config). The [`runtimeconfig.json`](https://docs.microsoft.com/en-us/dotnet/core/run-time-config/) is automatically generated for executables, for libraries it is neccessary to add `True` to the projects `.csproj` file.
#### Using the default signature
The default method signature is defined as follows:
```csharp
public delegate int ComponentEntryPoint(IntPtr args, int sizeBytes);
```
A method with the default signature (see code below) can be loaded using [`AssemblyDelegateLoader::get_function_with_default_signature`](https://docs.rs/netcorehost/*/netcorehost/hostfxr/struct.AssemblyDelegateLoader.html#method.get_function_with_default_signature).
**C#**
```cs
using System;
namespace Test {
public static class Program {
public static int Hello(IntPtr args, int sizeBytes) {
Console.WriteLine("Hello from C#!");
return 42;
}
}
}
```
**Rust**
```rust
let hostfxr = nethost::load_hostfxr().unwrap();
let context =
hostfxr.initialize_for_runtime_config(pdcstr!("Test.runtimeconfig.json")).unwrap();
let fn_loader =
context.get_delegate_loader_for_assembly(pdcstr!("Test.dll")).unwrap();
let hello = fn_loader.get_function_with_default_signature(
pdcstr!("Test.Program, Test"),
pdcstr!("Hello"),
).unwrap();
let result = unsafe { hello(std::ptr::null(), 0) };
assert_eq!(result, 42);
```
#### Using UnmanagedCallersOnly
A function pointer to a method annotated with [`UnmanagedCallersOnly`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute) can be loaded without specifying its signature (as these methods cannot be overloaded).
**C#**
```cs
using System;
using System.Runtime.InteropServices;
namespace Test {
public static class Program {
[UnmanagedCallersOnly]
public static void UnmanagedHello() {
Console.WriteLine("Hello from C#!");
}
}
}
```
**Rust**
```rust
let hostfxr = nethost::load_hostfxr().unwrap();
let context =
hostfxr.initialize_for_runtime_config(pdcstr!("Test.runtimeconfig.json")).unwrap();
let fn_loader =
context.get_delegate_loader_for_assembly(pdcstr!("Test.dll")).unwrap();
let hello = fn_loader.get_function_with_unmanaged_callers_only::(
pdcstr!("Test.Program, Test"),
pdcstr!("UnmanagedHello"),
).unwrap();
hello(); // prints "Hello from C#!"
```
#### Specifying the delegate type
Another option is to define a custom delegate type and passing its assembly qualified name to [`AssemblyDelegateLoader::get_function`](https://docs.rs/netcorehost/*/netcorehost/hostfxr/struct.AssemblyDelegateLoader.html#method.get_function).
**C#**
```cs
using System;
namespace Test {
public static class Program {
public delegate void CustomHelloFunc();
public static void CustomHello() {
Console.WriteLine("Hello from C#!");
}
}
}
```
**Rust**
```rust
let hostfxr = nethost::load_hostfxr().unwrap();
let context =
hostfxr.initialize_for_runtime_config(pdcstr!("Test.runtimeconfig.json")).unwrap();
let fn_loader =
context.get_delegate_loader_for_assembly(pdcstr!("Test.dll")).unwrap();
let hello = fn_loader.get_function::(
pdcstr!("Test.Program, Test"),
pdcstr!("CustomHello"),
pdcstr!("Test.Program+CustomHelloFunc, Test")
).unwrap();
hello(); // prints "Hello from C#!"
```
The full examples can be found in [examples/call-managed-function](https://github.com/OpenByteDev/netcorehost/tree/master/examples/call-managed-function).
### Passing complex parameters
Examples for passing non-primitive parameters can be found in [examples/passing-parameters](https://github.com/OpenByteDev/netcorehost/tree/master/examples/passing-parameters).
## Features
- `nethost` - Links against nethost and allows for automatic detection of the hostfxr library.
- `download-nethost` - Automatically downloads the latest nethost binary from [NuGet](https://www.nuget.org/packages/Microsoft.NETCore.DotNetHost/).
## Related crates
- [nethost-sys](https://crates.io/crates/nethost-sys) - bindings for the nethost library.
- [hostfxr-sys](https://crates.io/crates/hostfxr-sys) - bindings for the hostfxr library.
- [coreclr-hosting-shared](https://crates.io/crates/coreclr-hosting-shared) - shared bindings between [hostfxr-sys](https://crates.io/crates/hostfxr-sys) and [nethost-sys](https://crates.io/crates/nethost-sys).
## Additional Information
- [Hosting layer APIs](https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/hosting-layer-apis.md)
- [Native hosting](https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/native-hosting.md#runtime-properties)
- [Write a custom .NET Core host to control the .NET runtime from your native code](https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting)
## License
Licensed under the MIT license ([LICENSE](https://github.com/OpenByteDev/netcorehost/blob/master/LICENSE) or http://opensource.org/licenses/MIT)