How to resolve/load external dependencies for MEF Export assemblies - mef

I can import MEF assemblies into my host application. However, when the Imported assembly has other dependencies, e.g. other external assemblies, I get a ReflectionTypeLoadException.
I don't think I should have to reference external dependencies in my host project but cannot see how to get these external dependencies to resolve/load.
The Imports are retrieved using a DirectoryCatalog where I have the Import-annotated assemblies. I have tried adding the external dependency assemblies into the folder as well but that doesn't seem to get me anywhere. Here is the code:
var catalog = new DirectoryCatalog(assemblyLocation);
var container = new CompositionContainer(catalog);
var pluginRepo = new PluginRepository()
{
TestAdaptors = container.GetExportedValues<ITestAdaptor>()
};
foreach (var testAdaptor in pluginRepo.TestAdaptors)
{
testAdaptor.Execute();
}
Is there a different approach I should use? How can I get these external dependencies to load?

It turned out that yes, I can place all of the external assemblies in the folder with the Import-annotated assemblies and they are correctly loaded and therefore I don't have to reference these external dependencies in my host project.
The problem was that the test project I was given had some spurious, unused assemblies which were failing due to missing dependencies. (Yet another reminder of why a build server is your best friend!).
However, we are at the early stage of development of this so issues like this can be expected.

Related

Trying to install package into a project that targets '.NETFramework,Version=v4.7.2', but the package does not contain any assembly references

I used NuGet Package Explorer (for the first time) to create a .nupkg to share with others. I have one DLL that targets NetStandardLibrary 2.0,
But when I try to add the package I receive the following error:
Could not install package 'iCANMVCSDK 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.7.2', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
I thought that by using NETStandard 2.0 it could be installed in any .NET app. I also tried adding additional assemblies:
I rebuild, repackage, and I still get the same error. What am I missing?
I tried editing the project file like this:
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
When I try to build after adding net472, I receive the following error:
The type or namespace name 'Http' does not exist in the namespace 'System.Net'
What really makes no sense to me is that I can add the DLL directly into the project (the one that targes NET 4.72) and it works as expected. The problem is when attempting to install it as a NuGet package.

How do I reference a UWP+NET46 portable library from a .NET 4.6 console application?

I have a portable class library project that targets .NET 4.6 and Universal Windows Platform. This class library contains just one class with the following line of code in its constructor:
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
Now I create a new .NET 4.6 console application project in the same solution and add a project reference to the portable class library. Calling the method that houses the above line of code results in the following exception at runtime:
Could not load file or assembly 'System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
What am I doing wrong here? There are no compile-time errors or warnings.
Things I have tried: add missing(?) NuGet package manually
It seems that System.IO.FileSystem is a library delivered via NuGet, as part of the Microsoft.NETCore mega-package. Okay, perhaps I need to explicitly add this package to any project that uses my portable class library. I attempt to do so.
Could not install package 'Microsoft.NETCore.Platforms 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
No luck with this approach.
Things I have tried: create a project.json file
While there is no clear info on the web, I read a few tidbits about a new project.json based NuGet harness or build system. Just to experiment, I created the following project.json file in my console application project:
{
"dependencies": {
},
"frameworks": {
"net46": { }
},
"runtimes": {
"win-anycpu": { }
}
}
It works! The runtime error goes away! However, I soon found that this was either not the right solution or not a complete solution. I started writing some code to read configuration section values, which involved making use of the IConfigurationSectionHandler interface, and got the following compile-time error:
error CS0246: The type or namespace name 'IConfigurationSectionHandler' could not be found (are you missing a using directive or an assembly reference?)
This interface is part of the System assembly. I see a reference to this assembly, but it has a yellow exclamation mark icon, and a warning appears in the warnings window:
The referenced component 'System' could not be found.
This is where I ran out of ideas. Am I missing something totally obvious?
I have found the solution. My initial attempt was to install the Microsoft.NETCore package into the console application, resulting in the error shown in my original post.
However, if I install only the narrowly-scoped packages, e.g. System.IO.FileSystem, then I achieve success and the application works correctly. Apparently there is something special about the Microsoft.NETCore "master package" that prevents it from correctly installing into dependent projects.

OSGI: How to update a 'consumer' bundle

I have been trying to understand a strange OSGI behavior. Hoping someone can shed some light on it. Here is my setup
1) Using eclipse\plugins\org.eclipse.osgi_3.7.0.v20110613.jar
2) I have a Bundle that exports a service (HelloworldService)
It registers the service in the activator as such
public void start(BundleContext context) throws Exception {
IHelloService helloService = new HelloServiceImpl();
helloServiceRegistration =context.registerService(
IHelloService.class.getName(), helloService, null
);
}
3) I have a 'consumer' bundle that uses the service via a ServiceTracker
ServiceReference externalServiceReference = Activator.getContext().getServiceReference(IHelloService.class.getName());
IHelloService externalService = (IHelloService) Activator.getContext().getService(externalServiceReference);
Now when I deploy both these jars to OSGI (helloworld.jar and helloworldservice.jar); it works fine. I am able to get a 'IHelloService' impl object and make calls on it. I can start/stop the bundles and when they come back; it works just fine
The problem happens when I 'uninstall' and then 'install' the HelloWorldservice bundle.
In that case; the 'Helloworld' consumer externalServiceReference is NULL.
If I view the bundle info; I see this
osgi> bundle 1
mypackage.helloworld_1.0.0.qualifier [1]
Id=1, Status=RESOLVED Data Root=C:\Users\\dev\eclipse\plugins\configuration\org.eclipse.obundles\1\data
No registered services.
No services in use.
No exported packages
Imported packages
mypackage.helloworldservice; version="0.0.0" **stale**
org.osgi.framework; version="1.6.0"
org.osgi.util.tracker; version="1.5.0"
No fragment bundles
Named class space
mypackage.helloworld; bundle-version="1.0.0.qualifier"[provided]
No required bundles
Notice that its 'imported packages' has GONE STALE. Here is the line in question
Imported packages
mypackage.helloworldservice; version="0.0.0"<stale>
Now I can fix this by issuing an 'update' command from the console.
Here is my question
1) How do I programatically do this from within my 'consumer' bundle..
2) If I am on a production system and I deploy a new 'copy' of the helloworlservice.jar (replacing the existing version); Do I have to update all its users.. I thought the ServiceTracker would give me the service on the fly
Thanks
The consumer bundle imports the mypackage.helloworldservice package from the service jar. When you uninstall the service jar, the consumer jar is still wired to the now stale package from the uninstalled service jar. When you install a new service jar, it exports a new "copy" of the mypackage.helloworldservice package (I suspect the service jar does not also import the mypackage.helloworldservice package). So you need to refresh the consumer jar to get it to wire to the new mypackage.helloworldservice package.

Loading a NuGet assembly in T4 Template

I need to reference a Type in one of the assemblies referenced by the project containing my Visual Studio T4 template. However, the referenced assembly is installed from a NuGet package. As that Nuget reference evolves, so will the path that NuGet places it in within my solution's packages folder. For example, suppose my NuGet package is:
Facade.Contract.1.0.1-alpha
Then the relative path to it from my project is:
..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll
If the prerelease is updated to beta, that path will change. When the package is released, the path will change. And every time the path changes, the assembly line in my *.tt file is out of date:
<## assembly name="..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll" #>
I don't think there's a way to accomplish this directly with the assembly directive; however, I'm open to some crazy ideas. Could I load the assembly myself into the current, or a subordinate or reflection-only AppDomain?
I think I could, but I'm not sure how to go about dynamically discovering the path to the referenced assembly in the project's references using T4 logic.
Any ideas?
I've found a solution using VSLangProject as suggested by this article: http://t4-editor.tangible-engineering.com/blog/add-references-to-visual-studio-project-from-t4-template.html
Given a string serviceContractReferenceAssembly a to identify the name of the reference assembly in my containing project, and serviceContractReferenceType to identify the type within that assembly, the following worked:
var templateItem = dte.Solution.FindProjectItem(this.Host.TemplateFile);
var project = templateItem.ContainingProject;
var vsProject = project.Object as VSLangProj.VSProject;
foreach(var referenceObj in vsProject.References)
{
var reference = (VSLangProj.Reference)referenceObj;
if(reference.Name != serviceContractReferenceAssembly) continue;
var serviceContractAssembly = Assembly.LoadFile(reference.Path);
var serviceContractType = serviceContractAssembly.GetType(serviceContractReferenceType);
// Do something with it here
}
The Nuget team has made an extension available that allows you some control over the packages in a solution/project. So if you have control over the environment and can be sure everyone has this installed you might be able to search for the installed packages and then dynamically load them during your T4 execution. Since these Nuget assemblies are already complied and not part of your solution/project I would think using the standard Assembly.Load would work but you would need to test that.

Moles hosting unable to resolve dependent assembly

I'm developing a test method where both RhinoMocks as well as Moles are used. I have declared the host type as Moles for the test method as required. Now when it comes to the point where RhinoMocks has to emit a runtime assembly to create a mock for an interface, a FileNotFoundException is thrown, pointing to one of my private DLLs, which infact resides in the same folder as the test DLL and the DLL containing the class under test.
But when I remove the HostType attribute, the creation of mock instance works just fine, without any exceptions.
So, I built a workaround to get this to work with the Moles host type using these following steps:
1) I registered to the AppDomain.CurrentDomain.AssemblyResolve event in my [TestInitialize]
2) In the event handler, I packed in the following logic:
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string asmPath = Environment.CurrentDirectory + "\\" + args.Name.Split(',')[0] + ".dll";
if(System.IO.File.Exists(asmPath))
return System.Reflection.Assembly.Load(new System.Reflection.AssemblyName(args.Name));
return null;
}
Now, as expected, this assembly resolver does get invoked when the test is executed under the Moles HostType. The test now runs.
But the questions still are:
1) why do I still need a separate assembly resolver even if we explicitly set the AppDomain's APPBASE path to the folder containing all my production DLLs and the test DLL using
AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory);
where I've checked that the current directory is indeed my bin folder where every binary, including the test DLL, can be found.
2) Why do I not encounter this error when I'm testing some other production DLL of mine, where the same dependencies are involved.
3) This problem occurs also when using NMock2, which I tried just to see if this was a RhinoMocks-specific problem. But turns out that even NMocks2 has the same problem in the Reflection.Emit step, with the same dependent DLL as with RhinoMocks. Any way to explain this?
The part you are missing is that when you run the unit test the app which is running is the unit test hosts the application. The CurrentDirectory of that application is probably the directory in which its runner is installed. Your assemblies are passed in with parameters to the application.
The assumption that the CurrentDirectory is the directory of your application is faulty, this explains points 1, 2 and 3.