Loading Assembly and Type in .NET Core - .net-core-3.0

I'm trying to dynamically load assemblies at runtime in .NET Core by essentially looking in an external folder and loading assemblies from there. Loading seems to work fine, however, i can't seem to instantiate the now loaded types in a .NET Core application.
I'm using the the following loading code (very basic for feasibility testing at this point):
private void LoadPrivateBinAssemblies()
{
var binPath = Path.Combine(WebRoot, "PrivateBin");
if (Directory.Exists(binPath))
{
var files = Directory.GetFiles(binPath);
foreach (var file in files)
{
if (!file.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase) &&
!file.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
continue;
try
{
var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
//var asm = Assembly.LoadFrom(file);
Console.WriteLine("Additional Assembly: " + file);
}
catch (Exception ex)
{
Console.WriteLine("Failed to load private assembly: " + file);
Console.WriteLine(" " + ex.Message);
}
}
}
}
Note - I am using AssemblyLoadContext.Default to load into the .NET Core default context, from which I would presumably be creating a new type.
Then - for testing I now explicitly try to instantiate a type like this at the bottom of the Configure() startup sequence:
LoadPrivateBinAssemblies();
// this has my loaded assemblies in it
var list = AssemblyLoadContext.Default.Assemblies;
try
{
// this works
var t = Type.GetType(typeof(Startup).FullName);
// fails - Markdig is loaded and has no dependencies
var t2 = Type.GetType("Markdig.Markdown", true); // fails
// fails
var md = Type.GetType("Westwind.AspNetCore.Markdown.Markdown", true);
// never get here
md.InvokeMember("Parse", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { "**asdasd**", false, false, false });
}
catch (Exception ex)
{
Console.Log($"{ex.message}");
}
I've verified that the types exist in the assemblies and that the names are correct, but it fails on several custom loaded assemblies.
The figure shows the list of loaded assemblies (here from AppDomain.GetAssemblies(), but I get the same list from AssemblyLoadContext.Default.Assemblies). The assemblies are loaded, but I can't get a type reference to the types contained within it.
Any ideas what I'm missing here?

You need to use the assembly qualified name so, Type.GetType("Namespace.TypeName, AssemblyName").

Related

the type or namespace name 'httpcontext 'does not exist in the namespace system.web(are you missing an assembly reference )

I got an error like this when trying to add google drive service to my project. Although there is "System.Web" in the "Library" section, it cannot be used actively. Could you help?
public static string DownloadGoogleFile(string fileId)
{
DriveService service = GetService();
string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/");
FilesResource.GetRequest request = service.Files.Get(fileId);
string FileName = request.Execute().Name;
string FilePath = System.IO.Path.Combine(FolderPath, FileName);
MemoryStream stream1 = new MemoryStream();
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the
// download is completed or failed.
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream1, FilePath);
break;
}
case DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream1);
return FilePath;
}
Trying to pass the current HttpContext to a static method gets tricky depending on the project framework. It's also not clear the type of project or framework you are using.
Here's a similar question that might help you clarify the difference between HttpContext when it pertains to .net and .net-core.
HttpContext in .net standard library

unable to validate data in Framework 4.6.1

Recently I upgraded a project from Framework 4.6 to 4.6.1. We started facing the following issue:
We combine all the css files to generate a common css file. During this process AjaxControlToolkit Calendar creates a WebResource.axd file. When we try to process this file then the decryption fails and Error is thrown stating : "unable to validate data".
Following code is used:
var queryString = WebResourcePath.Split(new[] { '?' })[1];
var stringBuilder = new StringBuilder();
var textWriter = new StringWriter(stringBuilder);
var context = new HttpContext(new SimpleWorkerRequest("/WebResource.axd", queryString, textWriter));
var urlEncodedData = context.Request.QueryString["d"];
var encryptedData = HttpServerUtility.UrlTokenDecode(urlEncodedData);
var machineKeySection = typeof(MachineKeySection);
var paramTypes = new Type[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) };
var encryptOrDecryptData = machineKeySection.GetMethod("EncryptOrDecryptData", BindingFlags.Static | BindingFlags.NonPublic, null, paramTypes, null);
try
{
var decryptedData = (byte[])encryptOrDecryptData.Invoke(null, new object[] { false, encryptedData, null, 0, encryptedData.Length });
var decryptedContent = Encoding.UTF8.GetString(decryptedData).Substring(1);
var resourceParts = decryptedContent.Split('|');
Assembly = AssemblyCache.Load(resourceParts[0]);
ResourceName = resourceParts[1];
}
catch (Exception ex)
{
throw ex;
}
Error is thrown on the line : var decryptedData = (byte[])encryptOrDecry........
Some solution I went through suggested use of static machine key but we are already doing it.
NOTE : This is occuring only when we set httpRuntime targetFramework to 4.6.1 otherwise it works as expected.
From forums.asp.net:
So our problem was that some Webresource.axd requests are cached by
browsers (we didn't knew that...) but our machinekeys changes.
Fix the machineKeys in Web.config and wait for all our users to clean
their browser cache.
Comment:
https://forums.asp.net/post/5620791.aspx
Full thread:
https://forums.asp.net/t/1963234.aspx?Unable+to+validate+data+EncryptOrDecryptData+problem
Hope that helps

JxBrowser not connecting

I am having troubles to make the jxbrowser work outside of the development environment. When I run it in eclipse it works fine, but when I compile it and run the screen doesn't seems to load. Here is the code that I'm using:
browser = new Browser();
com.teamdev.jxbrowser.chromium.swing.BrowserView view = new com.teamdev.jxbrowser.chromium.swing.BrowserView(browser);
javax.swing.JFrame frame = new javax.swing.JFrame();
frame.add(view, java.awt.BorderLayout.CENTER);
frame.setSize(800, 450);
frame.setVisible(true);
browser.loadURL(Main.class.getResource("/assets/engine.html").toExternalForm());
> When I run from eclipse <
> When I compile and run <
Am I missing something?
If your HTML resource "/assets/engine.html" is located inside the RPGItems.jar after build, the path to it will not be resolved properly by the Chromium engine by default. To be able to load resources located inside JAR archive you must register custom ProtocolHandler with the following implementation:
BrowserContext browserContext = browser.getContext();
ProtocolService protocolService = browserContext.getProtocolService();
protocolService.setProtocolHandler("jar", new ProtocolHandler() {
#Override
public URLResponse onRequest(URLRequest request) {
try {
URLResponse response = new URLResponse();
URL path = new URL(request.getURL());
InputStream inputStream = path.openStream();
DataInputStream stream = new DataInputStream(inputStream);
byte[] data = new byte[stream.available()];
stream.readFully(data);
response.setData(data);
String mimeType = getMimeType(path.toString());
response.getHeaders().setHeader("Content-Type", mimeType);
return response;
} catch (Exception ignored) {}
return null;
}
});
The getMimeTypemethod here returns appropriate mime type for the given resource extension:
private static String getMimeType(String path) {
if (path.endsWith(".html")) {
return "text/html";
}
if (path.endsWith(".css")) {
return "text/css";
}
if (path.endsWith(".js")) {
return "text/javascript";
}
return "text/html";
}
Once you register ProtocolHandler and define what mime types are supported, you can load resources from JAR archive using standard Java and JxBrowser API:
browser.loadURL(Main.class.getResource("/assets/engine.html").toString());

Resolving a FileNotFound issue when running a custom test type for Visual Studio

I have implemented a custom test type for Visual Studio. The custom test type reads its test elements from dlls. My ITip implementation is working like a charm. The test elements are loaded and are displayed on the Test View tool window.
When I select the test elements and run them they end up in a Not Executed status. While debugging this issue I found out that a FileNotFoundException is thrown from QTAgent32.exe. It tells me that it cannot find the dll that defines the test cases. Also, it fails before my TestAdapter.Initialize method is called. I copied my test dll to the PrivateAssemblies directory of Visual studio. When I do that my test elements pass. I can also debug the code in my custom test adapter. So, the meaning of all of this is that QTAgent32.exe cannot find my test dll in its original directory.
My question is what should I do to make QTAgent32 find my test dll in the original directory? For completenes I add my Tip Load method code:
public override ICollection Load(string location, ProjectData projectData, IWarningHandler warningHandler)
{
Trace.WriteLine("Started RegexTestTip Load.");
if (string.IsNullOrEmpty(location))
{
throw new ArgumentException("File location was not specified!", "location");
}
var fileInfo = new FileInfo(location);
if (!fileInfo.Exists)
{
throw new ErrorReadingStorageException(
string.Format("Could not find a file on the specified location: {0}", location));
}
var result = new List<ITestElement>();
var extension = fileInfo.Extension.ToLower();
if (extension != ".dll")
{
return result;
}
Assembly testAssembly = Assembly.LoadFrom(location);
var testClasses = testAssembly.GetTypes().
Where(t => Attribute.IsDefined(t, typeof(RegexTestClassAttribute)));
foreach (Type testClass in testClasses)
{
PropertyInfo property = testClass.GetProperties().
SingleOrDefault(p => Attribute.IsDefined(p, typeof(TestedRegexAttribute)));
if (property == null || !TestedRegexAttribute.Validate(property))
{
throw new InvalidDataInStorageException("A Regex test must define a Tested Regex property with type Regex");
}
var testCases = testClass.GetProperties().
Where(p => Attribute.IsDefined(p, typeof(RegexTestCaseAttribute)));
foreach (PropertyInfo testCase in testCases)
{
if (!RegexTestCaseAttribute.Validate(testCase))
{
throw new InvalidDataInStorageException("A test case property must return a String value.");
}
var testElement = new RegexTestElement(property, testCase);
testElement.Storage = location;
testElement.Name = testCase.Name;
testElement.Description = "A simple description";
testElement.ProjectData = projectData;
result.Add(testElement);
}
}
Trace.WriteLine("Finished RegexTestTip Load.");
return result;
}
Have you tried just putting the dll in the same directory as the executable? Forgive the obviousness of that, but sometimes its the really simple things that bite us. But it's in the GAC right?

Unable to get Core Service client working

I am trying to publish the component using core service, to do this, I just created a console application, and executed from the server. I am getting the below error message.
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Tridion.ContentManager.CoreService.Client, Version=6.1.0.996, Culture=neutral, PublicKeyToken=ddfc895746e5ee6b' or one of its dependencies. The system cannot find the file specified.
The below is my code, can anyone faced this issue?
static void Main(string[] args)
{
try
{
string compid = "tcm:56-935";
var client = new SessionAwareCoreServiceClient();
var readoption = new ReadOptions();
var component = (ComponentData)client.Read(compid, readoption);
var ItemToPublish = new List<string>();
ItemToPublish.Add(component.Id);
var instruction = new PublishInstructionData();
var pubtarget = (PublicationTargetData)client.Read(
"tcm:0-21-65537", readoption);
List<string> target = new List<string>();
target.Add(pubtarget.Id);
client.Publish(ItemToPublish.ToArray(), instruction, target.ToArray(),
PublishPriority.Normal, readoption);
Console.WriteLine("component published");
Console.WriteLine(component.Title);
Console.WriteLine(pubtarget.Title);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
The error is clear, it says that you don't have dependency in place. You must place Tridion.ContentManager.CoreService.Client.dll into the same directory where your executable is (alternatively, you can place in GAC). Usually there is an option in Visual Studio on referenced assembly on your project "Copy Local", you can try to to set it to true and try to execute your code again.
Looks like (based on your comment to Igor's answer) you're missing some config. Check out Frank's wiki post on the Tridion Practice site - https://code.google.com/p/tridion-practice/wiki/GetCoreServiceClientWithoutConfigFile

Resources