Load .Net assemblies with higher .Net version at runtime via reflection - c#

We are developing addons for an other application. The application was built with .Net 4.5 and also runs on .Net 4.5. Our code is called via reflection from this application.
Is it possible to build our assemblies with higher .Net version (e.g. 4.6.1 or 4.7) than the application was build? (assumed the higher .Net run time is installed on the machine)
This what I found on MSDN (https://learn.microsoft.com/de-de/dotnet/framework/migration-guide/version-compatibility)
An app can control the version of the .NET Framework on which it runs, but a component cannot. Components and class libraries are loaded in the context of a particular app, and therefore automatically run on the version of the .NET Framework that the app runs on.
That means for me: NO
On the other hand I found that article:
Loading an assembly targeted for .NET 4.5 on a .NET 4.0 app domain
If I interpret that article correctly (in context of .Net 4.0 and 4.5), the answer was there: Yes. It is no problem to load a .Net assembly with higher version (here 4.5) into an app build with and running on a lower .Net version (here 4.0)

I have had the same problem and have found following solution that works for me to make use of an .NET 4.61 Assembly within an .NET 4.5 Application:
public void FunctionOfDotNet45Application()
{
// Load .net4.61 Assembly in .net4.5 Application
AppDomainSetup domaininfo = new AppDomainSetup();
domaininfo.ApplicationBase = System.Environment.CurrentDirectory;
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);
Proxy prxy = (Proxy)domain.CreateInstanceAndUnwrap(typeof(Proxy).Assembly.FullName, typeof(Proxy).FullName);
string executionPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string net461AssemblyFilename = Path.Combine(executionPath, "DotNet461.dll");
var net461Assembly = prxy.GetAssembly(net461AssemblyFilename);
// Create and use object
Type net461Type = net461Assembly.GetType("DotNet461DllNamespace.Net461Type");
object net461Object = Activator.CreateInstance(net461Type, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
net461Type.GetProperty("Property1").SetValue(net461Object, 1);
net461Type.GetProperty("Property2").SetValue(net461Object, 2);
byte[] retval = (byte[])net461Type.GetMethod("Function1", new Type[] { typeof(int) }).Invoke(net461Object, new object[] { 7 });
}
public class Proxy : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
return Assembly.LoadFile(assemblyPath);
}
}
Sources:
(1) https://jonathancrozier.com/blog/how-to-dynamically-load-different-versions-of-an-assembly-in-the-same-dot-net-application
(2) How to Load an Assembly to AppDomain with all references recursively?

Related

DLL injection and ejection from .NET Framework 4.8 app

I'm injecting DLL into the WPF process using an Injector from snoop or Reloaded.Injector.
Injected DLL is .net 4.8 class library.
The injection works, but ejection - does not. My library is still locked by the target process after ejection. Is it possible to unload it at all?
I've tried FreeLibrary and FreeLibraryAndExitThread with no success. Reloaded.Injector Eject() function returns true, but DLL is still locked.
var process = Process.GetProcessesByName("ModsOptimizer").FirstOrDefault();
_injector = new Injector(process);
_injectionDllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Injection.dll");
var address = _injector.Inject(_injectionDllPath);
_injector.CallFunction(_injectionDllPath, "Spam", default);
_injector.Eject(_injectionDllPath);

.Net Core 3.0 invoking .Net Framework 4.8 program via Reflection

I have a .net Core 3.0 application attempting to invoke .Net Framework 4.8 via reflection. Our goal is to read encrypted AppSettings.config (xml) with ConfigurationManager, which is not possible in .Net Core. Unencrypted yes, but encrypted (CipherData), no.
My reflection code that accesses a static class & method goes like this:
Assembly assembly = Assembly.LoadFrom(exeFullName);
MethodInfo method = assembly.GetType(nameSpacenClass).GetMethod(methodName);
if (method != null)
{
object rtnVal = method.Invoke(null, new object[] { jsonParms });
return rtnVal;
}
else
return null;
The method.Invoke errorred out with this exception message:
FileNotFoundException: Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
So I wrote a proxy program in .Net Framework 4.8, and use the same code to access the code that reads encrypted config via reflection, and it works fine.
Then, I coded .net Core 3.0 to access that proxy via reflection, and it fails. The proxy .Net Framework 4.8 has no references whatsoever. It is barebone. Yet core still requires ConfigurationManager even though the proxy does not. The Config program has only one reference - to System.Configuration.
Core 3.0 => Encrypted App.config => Failed
Core 3.0 => ConfigProgram 4.8 => App.Config => Failed
ConfigProgram 4.8 => App.config => Works
Proxy 4.8 => ConfigProgram 4.8 => App.Config => Works
Core 3.0 => Proxy 4.8 => ConfigProgram 4.8 => App.Config => Failed
I guess the referenced System.Configuration is not required for Reflection invoke by 4.8 but is required even though trough a barebone stepping stone, by .Net Core 3.0. Could someone help me please?
When you load an assembly built for .NET Framework via reflection on .NET Core, it does not load any parts of .NET Framework - just your assembly ("user cod"). And some parts may or may not work. In your case it fails because the requested classes / assemblies of the code compiled for .NET Framework is not part of .NET Core.
This is the reason why only the cases where you start a .NET Framework application to begin with - thus booting up the .NET Framework Runtime - work for you.

Unable to configure 'IApplicationBuilder UseOwin'

As stated in official document, I am trying to implement UseOwin in the Startup.cs.I am trying to use/port IAppBuilder (Microsoft.Owin.Builder.AppBuilder) inside IApplicationBuilder (Microsoft.AspNetCore.Builder.IApplicationBuilder). I had legacy code written using IAppBuilder running fine on .Net Framework 4.5.
I have seen couple of examples about using IAppBuilder in IAplicationBuilder e.g. example 1 example 2. These attempts were about .netcore 1.1 and not .net core 2.0. May be this is the reason i am unable to port.
Please share your thoughts whether i am trying to achieve something not possible at the moment in .net core 2.0 or there is some error in my code.
Note:
I am using dotnetcore 2.0 with Visual Studio 2017
Error
I am getting following error.
return owinAppBuilder.Build,
Task>>(); TypeLoadException: Could not load type
'System.Security.Cryptography.DpapiDataProtector' from assembly
'System.Security, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
My attempt
app.UseOwin(setup => setup(next =>
{
var owinAppBuilder = new AppBuilder();
var aspNetCoreLifetime =
(IApplicationLifetime)app.ApplicationServices.GetService(typeof(IApplicationLifetime));
new AppProperties(owinAppBuilder.Properties)
{
OnAppDisposing = aspNetCoreLifetime?.ApplicationStopping ?? CancellationToken.None,
DefaultApp = next,
AppName = "test"
};
// Only required if CORS is used, configure it as you wish
var corsPolicy = new System.Web.Cors.CorsPolicy
{
AllowAnyHeader = true,
AllowAnyMethod = true,
AllowAnyOrigin = true,
SupportsCredentials = true
};
//corsPolicy.GetType()
// .GetProperty(nameof(corsPolicy.ExposedHeaders))
// .SetValue(corsPolicy, tusdotnet.Helpers.CorsHelper.GetExposedHeaders());
owinAppBuilder.UseCors(new Microsoft.Owin.Cors.CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context => Task.FromResult(corsPolicy)
}
});
PublicClientId = "self";
OAuthAuthorizationServerOptions OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new Microsoft.Owin.PathString("/Login"),
Provider = new MyServiceProvider(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
AllowInsecureHttp = true,
RefreshTokenProvider = new MyRefreshTokenProvider(),
};
owinAppBuilder.UseOAuthBearerTokens(OAuthOptions);
//owinAppBuilder.UseTus(context => new DefaultTusConfiguration
//{
// // Excluded for brevity, use the same configuration as you would normally do
//});
return owinAppBuilder.Build<Func<IDictionary<string, object>, Task>>();
}));
Microsoft.Owin and related packages do not have targets for .NET Core, no for .NET Standard. All they have is dlls targeting full .NET. You can reference such libraries from your project targeting .NET Core, but they are not guaranteed to work, as you see yourself, because API (set of classes\methods\signatures) of full .NET and .NET Core are different. Visual Studio even will show a warning when you are doing that, for example:
Package 'Microsoft.Owin 3.1.0' was restored using
'.NETFramework,Version=v4.6.1' instead of the project target framework
'.NETCoreApp,Version=v2.0'. This package may not be fully compatible
with your project.
There is Microsoft.AspNetCore.Owin package and you can use OWIN middleware in .NET Core app as your first link describes, but almost all it provides is UseOwin extension method. There is no AppBuilder type there and so on, and there are no Microsoft.AspNetCore.Owin.Cors packages or similar. So you have to either implement all that yourself (no reason to, because you can use the same functionality provided by asp.net core framework) or wait for OWIN packages that target .NET Standard\Core and do that (didn't check, maybe they even exist already).
So, your code uses packages which are indeed not compatible with your target framework, as exception you have at runtime shows. So another answer (for some reason downvoted) is technically correct.
If you still want to use those packages reliably - you need to target full .NET Framework and not .NET Core. To do that, open your .csproj file and change
<TargetFramework>netcoreapp2.0</TargetFramework>
To some .NET framework version that supports .NET Standard 2.0, for example:
<TargetFramework>net47</TargetFramework>
Then go to nuget package manager and, if you have microsoft.aspnetcore.all package (or other packages targeting .NET Core) - uninstall it, you don't need it anyway. Then install Microsoft.AspNetCore package and all other asp.net core packages you need (if not installed already). Rebuild, run and it will work just fine.
That works because all (most?) AspNetCore packages target .NET Standard, not .NET Core, and you can use them in projects targeting full .NET Framework.
Note that by doing that you have asp.net Core project, but not on .NET Core, with all consequences that come from that (cannot run with dotnet run, on linux need to run with mono, and so on).
The Microsoft.Owin components will not work on dotnet core 2.0, they only work on .NET 4.5+

PHP DOTNET hell

I'm quite a newbie in PHP and today I discovered DOTNET class.
So I studied manual, surfed the web to find some example and finally wrote my test app:
Created a new DLL using Framework 4.0 Client Profile
Signed the assembly with a strong name key
Marked assembly as COM-Visible
This is the test code I wrote
using System;
namespace CSharpCOM
{
public class CSharpCOMClass
{
public string Base64(string s)
{
return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(s));
}
}
}
I compiled the assembly and then registered in GAC (gacutil /if fullpath\CSharpCOM.dll).
If I use gacutil /l CSharpCOM I see
La cache di assembly globale contiene gli assembly seguenti:
csharpcom, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=beb607ae770f5750, processorArchitecture=MSIL
Numero di elementi = 1
So everything seems ok.
Then wrote this basic php:
<?php
try{
$csclass = new DOTNET("CSharpCOM, Version=1.0.0.0, Culture=neutral, " .
"PublicKeyToken=beb607ae770f5750",
"CSharpCOM.CSharpCOMClass");
echo $csclass->Base64("Test string"),"\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
?>
Whatever I try, loading page hosted in Apache (http://localhost/test01/dotnet.php) I always get
Caught exception: Failed to instantiate .Net object [CreateInstance]
[0x80070002] Impossibile trovare il file specificato.
Translation could be: unable to find specified file
Just another thing: using some example (a very basic one here) I read that my assembly (when registered) should be found on %windir%\assembly, but I'm only able to find it in %windi%\Microsoft.NET\assembly\GAC_MSIL\CSharpCOM\v4.0_1.0.0.0__beb607ae770f5750: is this correct? Why don't I have it on first directory?
More: if I create another framework project and try to add a .NET reference I can't find my assembly: is this related to the fact I'm not able to load this assembly from PHP?
Last note: I tried it on Windows XP Professional SP3 32bit and on Windows Seven Enterprise 64bit
UPDATE:
This works:
$form = new DOTNET('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'System.Windows.Forms.Form');
but this one does not:
$form = new DOTNET('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'System.Windows.Forms.Form');`
Is it possible that PHP can load only framework 2.0 assemblies?
According to this bug report the DOTNET class is not loading .NET 4.0 DLLs. If you're not using any of the new libraries in .NET 4.0 you can target your to .NET 3.5 or lower by opening the project properties and on the "Application" tab change the "Target framework" to ".NET Framework 3.5 Client Profile"
Now when you install your DLL into the GAC it will get installed into the CLR 2.0 GAC and should be able to be loaded using the DOTNET class in PHP.
There is a library out there called NetPhp (https://github.com/david-garcia-garcia/netphp) that will let you:
Use any .Net binaries (even without COM Visibility) and ANY version of the .Net framework including CLR4
Dump a PHP class model
Iterate over .Net collections directly from PHP
PHP class model generation, to use PHP classes as if it where .Net
Automatic propagation of .Net errors into native PHP exceptions that can be properly handled
Acces native enums and static methods
Use class constructors with parameters
Debug .Net and PHP code at the same time as if it was a single application.
There is a project with code samples here:
https://github.com/david-garcia-garcia/netphp-sample
This is what a piece of code with NetPhp looks like:
$datetime = $runtime->TypeFromName("System.DateTime");
$datetime->Instantiate();
echo $datetime->ToShortDateString()->Val(); // Outputs 01/01/0001
// We can only use Int32 from native PHP, so parse
// an Int64 that is equivalent to (long) in the DateTime constructor.
$ticks = $runtime->TypeFromName("System.Int64")->Parse('98566569856565656');
$ticks = \ms\System\netInt64::_Parse('98566569856565656');
$datetime->Instantiate($ticks);
echo $datetime->ToShortDateString()->Val(); // Outputs 07/05/0313
$now = $runtime->TypeFromName("System.DateTime")->Now;
echo $now->ToShortDateString()->Val(); // Outputs "23/10/2015"
$now = $runtime->TypeFromName("System.DateTime")->Now();
echo $now->ToShortDateString()->Val(); // Outputs "23/10/2015"
$timer = $runtime->TypeFromName("System.Timers.Timer")->Instantiate();
$timer->AutoReset(TRUE);
$timer->AutoReset = TRUE;

RhinoMock 3.5 Runtime error when running on .net

I'm using Rhino Mock 3.5 for .Net Framework 2.0 and when I run this code I get a run time error.
This is the code
IFile fileInterface = MockRepository.GenerateStub<IFile>();<br>
IUrlMapper urlMapper = MockRepository.GenerateStub<IUrlMapper>();
// this is the line causing the run-time error<br>
HttpContextBase mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
HttpRequestBase mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
RhinoMocksExtensions.Stub<HttpContextBase,HttpRequestBase>(mockHttpContext, delegate(HttpContextBase ctx)
{
return ctx.Request;
}
).Return(mockRequest);
RhinoMocksExtensions.Stub(fileInterface, delegate(IFile f)
{
f.Exists(Arg<string>.Is.Anything);
}
).Return(true);
AspxReplacementResolver resolverToTest = new AspxReplacementResolver(mockHttpContext, fileInterface, urlMapper);
This is the Error:
TestCase 'TestMockingRhinoMock35.TestTestFixtures.Test1'
failed: System.TypeLoadException : Could not load type 'System.Web.RequestNotification' from assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'......
System.Web.RequestNotification is part of Framework 3.0 but I'm using Framework 2.0 and I referenced the specific Rhino Mocks 3.5 for Framework 2.0 dll.
Thank you
HttpContextBase doesn't exist in .Net framework 2.0. It was added in a .dll called System.Web.Abstractions, and is only available if you've installed the .Net Framework 3.5, as well as Service Pack 1 for .Net Framework 3.5.
You'll have to target .net 3.5 if you want to mock this out. If you're using a seperate assembly for testing, there's no reason you couldn't target your test assembly to 3.5 and leave your production application alone.

Categories

Resources