I have 3 class libraries, LibA, LibB & LibC. These libraries have defined classes A, B & C respectively.
class C
{
public IEnumerable<X> FuncInC()
{
return something;
}
}
LibC is added as a reference in LibB. And class B uses class C. Using MEF, I have exported class B from LibB.
[Export(typeof(InterfaceForB))]
class B : InterfaceForB
{
public IEnumerable<X> FuncInB()
{
return new C().FuncInC();
}
}
In class A, i am using the exported class from B, as follows.
public class A : InterfaceForA
{
[Import(typeof(InterfaceForB))]
private InterfaceForB _b;
private CompositionContainer _container;
public A()
{
var _catalog = new DirectoryCatalog(System.IO.Directory.GetCurrentDirectory());
_container = new CompositionContainer(_catalog);
_b = _container.GetExportedValue<InterfaceForB>();
}
public IEnumerable<X> FuncInA()
{
return _b.FuncInB();
}
}
When i run FuncInA(), it raises FileNotFoundException with the following details:
"Could not load file or assembly
'LibC, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'
or one of its dependencies. The system
cannot find the file specified."
Note:
LibC reference exists in LibB, and it is build without errors.
And all the assemblies (output dlls in this case) exist in the the same folder.
If I comment the code "return new C().FuncInC();" in FuncInB() definition, & return a dummy object, it works without errors. The problem is because of the reffered LibC use.
In the LibB References shown in the solution explorer, right click on LibC, "properties", set "Specific Version" to "False".
Or better yet, delete the binary reference and replace it by a project reference (assuming that LibC is in the same solution as LibB).
Related
I have type A implementing interface IA from assembly aA.dll. It creates K instances of type B from aB.dll. I want to get A from aA.dll to use type B from bB.dll which is same in its name and version to aB.dll yet with minor code differences. So I try:
public class CollectibleAssemblyLoadContext
: AssemblyLoadContext
{
public CollectibleAssemblyLoadContext() : base(isCollectible: true)
{ }
protected override Assembly Load(AssemblyName assemblyName)
{
string path = "";
if (AssemblyNameToPath.TryGetValue(assemblyName.FullName, out path))
{
return Assembly.LoadFile(path);
}
return null;
}
}
Yet when I try to create a A as IA using:
public static object GetRaw<T>() where T : class
{
AssemblyLoadContext context = new CollectibleAssemblyLoadContext();
var type = typeof(T);
Assembly assembly = context.LoadFromAssemblyName(type.Assembly.GetName());
Type programType = assembly.GetType(type.FullName);
object result = Activator.CreateInstance(programType);
return result;
}
Generally X is what I get while V is what I want from this picture:
Type B is used from preloaded in general context aB.dll. How to make it load if from bB.dll? How to make sure AssemblyLoadContext would use Load to get all the assemblies from scratch, not only one?
A small demo project we tried to test it with, yet it fails to load more than one assembly deep no matter what...
To my knowledge different versions of DLLs / dependencies are not allowed in the same AppDomain. So a type can only resolve to one DLL in the same ApPDomain. Spinning up a new AppDomain might be what you can try.
I have a .dll library, which I cannot modify, with classes which uses many static variables and singleton instances.
Now I need a second instance of all these classes and I need some solution which would isolate static variables between instances of some class without altering any other properties of the assembly.
Loading the same assembly second time doesn't actually load it again, but I found that reading it to byte array and then loading it, actually solves half of the problem:
lib.dll:
namespace lib
{
public class Class1 : ILib
{
private static int i;
public int DoSth()
{
return i++;
}
public string GetPath()
{
return typeof(Class1).Assembly.Location;
}
}
}
app.exe:
namespace test
{
public interface ILib
{
int DoSth();
string GetPath();
}
class Program
{
static void Main()
{
var assembly1 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance1 = (ILib)assembly1.CreateInstance("lib.Class1");
Console.WriteLine(instance1.GetPath());
Console.WriteLine(instance1.DoSth());
Console.WriteLine(instance1.DoSth());
var assembly2 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance2 = (ILib)assembly2.CreateInstance("lib.Class1");
Console.WriteLine(instance2.GetPath());
Console.WriteLine(instance2.DoSth());
Console.WriteLine(instance2.DoSth());
var assembly3 = AppDomain.CurrentDomain.Load(File.ReadAllBytes("lib.dll"));
var instance3 = (ILib)assembly3.CreateInstance("lib.Class1");
Console.WriteLine(instance3.GetPath());
Console.WriteLine(instance3.DoSth());
Console.WriteLine(instance3.DoSth());
Console.Read();
}
}
}
this returns:
C:\bin\lib.dll
0
1
C:\bin\lib.dll
2
3
0
1
Static variables got restarted but unfortunately the next problem is that assembly location which is used within the library is empty.
I would like to avoid loading the library to different AppDomain because it creates too many problems with cross domain code; some classes are not serializable.
I would like to avoid physically copying the library on disk.
I would like to avoid IL weaving and using Mono.Cecil or similar because it's an overkill.
Loading assembly into separate AppDomain or separate process are only sensible options you have. Either deal with cross-domain/cross-process communication or get version of library that does not have problems you trying to work around.
If you want to fix your load from bytes you'd need to read all articles around https://blogs.msdn.microsoft.com/suzcook/2003/09/19/loadfile-vs-loadfrom/.
Note that this might be a duplicate of this question, I'm not entirely sure.
My problem is that I have a class library project which has a reference to a third-party type library (COM). I want to put contracts into the methods in the class library, like so:
public class foo
{
public static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
And then have a client project make use of this method, e.g.
var n = foo.divide(null, 4, 2);
But I'd also like the client project also use contracts in some of its methods. So, I set the Code Contracts properties on both projects to 'Perform Runtime Contract Checking' (without which you get the runtime assert telling you that it needs this setting).
Now, when I then try to compile the client, I get the following error:
Could not resolve member reference: my_class_lib.foo::divide.
ccrewrite : error : Rewrite aborted due to metadata errors.
Which seems unavoidable - any time a method is called which has a type from the third party type library this happens. Remove the type from the method's signature and it's fine.
Can anyone explain why this happens? Is this a clue that the structure of my code is fundamentally flawed (if so, why?), or is it a quirk of code contracts? Is there a recommended fix for this problem?
To be honest I don't know why ccrewrite has a problem with interop types but I can give you 3 workarounds:
Solution 1
This one is the simplest:
Go to list of references for a project.
Find third-party type library.
Right click.
From the context menu select Properties.
Change Embed Interop Types from True to False.
You have to do that for both projects. The drawback of this solution is that after a build you will get an additional interop assembly in the bin folder.
Solution 2
Another solution might be to remove types from a third-party type library from a public interface i.e.:
public class foo
{
public static int divide(int a, int b)
{
return divide(null, a, b);
}
private static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
Of course you can do that only if you do not need to use TypeFromTypeLib in your client.
Solution 3
If you need to use TypeFromTypeLib in your client you may write a wrapper for this class i.e.:
public class MyTypeFromTypeLib
{
//...
}
public class foo
{
public static int divide(MyTypeFromTypeLib mytftl, int a, int b)
{
var tftl = new TypeFromTypeLib();
//Map MyTypeFromTypeLib to TypeFromTypeLib
//...
return divide(tftl , a, b);
}
private static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
However, this solution is cumbersome because additional classes are needed.
IDE: VS 2010, C# .net,
I have two win projects in 1 solution,
ProjA, and ProjB
now ProjA contains classA.cs
namespace ProjA
{
class ClassA
{
public static int aValue = 5;
}
}
same way ProjB contains ClassB.cs
namespace ProjB
{
public class ClassB
{
public static int bValue = 10;
}
}
and here is FormA.cs
using System;
using System.Windows.Forms;
using ProjB;
namespace ProjA
{
public partial class FormA : Form
{
public FormA()
{
InitializeComponent();
}
private void FormA_Load(object sender, EventArgs e)
{
int va = ProjB.ClassB.bValue;; //Here getting error.???
}
}
}
Error : Cannot resolve symbol ProjB
Hint: This Problem Is related to namespace, I am trying to access ClassB which is in ProjB from FormA which is in ProjA, Here ProjA and ProjB are the 2 winforms project in Same solution
---xxxx----------- THis problem has been solved.
but now I want to access ClassA.cs in FormB.cs (just reverse of above problem),
when I tried same way ProjB(RighClick) -> Add reference -> ProjName(Tab) ProjA(Click)
The new problem I am facing is its saying unable to add it will create circular dependency, Please suggest How to solve this issue.
I want to access ClassA.cs in ProjB->FormB.cs here FormB is in ProjB
You need to create new instance of class or make it static.
So this:
namespace ProjB
{
public static class ClassB
{
public static int bValue = 10;
}
and then
int va = ClassB.bValue;
OR
int va = new ClassB().bValue;
ProjB is the namespace, so it doesn't know which class to use. If they're in the same solution(package of projects), just use the classname ClassB.(Or ProjB.ClassB.bValue)
If your projects aren't in the same Solution, go to Project A, File->Add->Existing Project, and add ProjB.
Provided you have referenced correctly ProjB you just need to instatinate classB in ProjA:
using System;
using System.Windows.Forms;
using ProjB;
namespace ProjA
{
ProjB.ClassB classb=new ProjB.ClassB();
public FormA()
{
InitializeComponent();
....
classb.bValue=....//set desired valued
}
private void FormA_Load(object sender, EventArgs e)
{
int va =classb.bValue;
}
The problem was with reference,
I added reference
Right click ProjA -> References -> Add Reference, then I added ProjB.
And Problem resolved. :-)
In your visual studio
1-) Right click to your solution
2-) Then open Properties of the solution..
In the properties page, on the left you'll see menus..
3-) Click to Project Dependencies
In Details of project Dependencies (right side of the page )
4-) Select your Project A from the DropDownList which has a label with "Project"
5-) Under the DropDownList Check (Mark as checked) the ProjectB
6-) Click to save / ok
This operation what you did, warns the compiler as so :
"When you start to build ProjectA, Before build/compile ProjectA First build/Compile ProjectB and then continue to build ProjectA"
or in another saying
" Dear Compiler !
When you work with my ProjectA, You will need My ProjectB to do your work properly.
So please also check my ProjectB.
Best Regards, Your Lovely Developer "
NOTE : Never circular reference (ProjectA depends to ProjectB and ProjectB depends to ProjectA) to eachother..this gets infinitive recursion error of the compiling your code..!
Visual Representation of The VS2010-ProjectDependencies Box
Example:
Console application:
class Program
{
static void Main(string[] args)
{
var calculator = ObjectFactory.GetInstance<ICalculator>();
for (var i = 0; i < 10; i++)
{
Console.WriteLine(calculator.Calculate(10, 5));
Console.ReadLine();
}
Console.ReadLine();
}
}
Assembly "Interface":
public interface ICalculator
{
int Calculate(int a, int b);
}
Assembly "Implemenation":
internal class Calculator : ICalculator
{
public int Calculate(int a, int b)
{
return a + b;
}
}
Assembly "Implemenation", this assembly shall replace the assembly above at runtime:
internal class Calculator : ICalculator
{
public int Calculate(int a, int b)
{
return a * b;
}
}
Assembly "Resolver"
For<ICalculator>().Use<Calculator>();
I want to replace the concrete implementation at runtime. This could be done by an UpdateService which just replace the old assembly "Implementation".
The problem I have is that the assembly "Implementation" is locked. I can't replace it.
What do I have to do to achieve this?
Is the IoC container responsible for my requirement or do I have to build my own infrastructure?
EDIT:
In a web environment you can easily replace an assembly. I did this already with success.
I'm afraid you can only load an additional assembly.
From MSDN:
There is no way to unload an individual assembly without unloading all
of the application domains that contain it. Even if the assembly goes
out of scope, the actual assembly file will remain loaded until all
application domains that contain it are unloaded.
I think this has what you're looking for:
http://structuremap.net/structuremap/ChangingConfigurationAtRuntime.htm