StructureMap - Ability to replace an assembly at runtime - c#

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

Related

Load same assembly second time with clean static variables

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/.

Code contract rewrite failing with 'Could not resolve member reference'

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.

Force application to run with optional DLL

I have made desktop application. I have make class library and then make its DLL from University assembly. Now i want to make library DLL optional. In short i want to run the application weather or not library DLL is refereed.
Right now if i remove reference of library DLL then it gives error on library methods that they are not defined. I want this application to run with oujt giving error of library method.
I have search on google but i am unable to find out any reliable answer.
Check if assembly exists on disk, and if it's true use dynamic assembly loading:
http://msdn.microsoft.com/en-us/library/25y1ya39.aspx
Called classes/methods in your library can be replaced by stubs(new level of abstraction), in which you can check if assembly is successfully loaded, and invoke from it if yes.
Ok.. Very simple example:
"Real Assembly" code(First project, compiled as class library "RealAssembly.dll"):
namespace RealAssembly
{
using System;
public class RealClass
{
Random rand = new Random();
public int SomeProperty { get { return rand.Next(); } }
public string SomeMethod()
{
return "We used real library! Meow!";
}
}
}
"Our project" code with Fake(stub) class(Second project, compiled as Console applicaiton - "ClientApp.exe"):
using System;
using System.IO;
using System.Reflection;
namespace ClientApp
{
class FakeClass
{
public int SomeProperty { get { return 0; } }
public string SomeMethod()
{
return "Library not exists, so we used stub! :)";
}
}
class Program
{
// dynamic instance of Real or Fake class
private static dynamic RealOfFakeObject;
static void Main(string[] args)
{
TryLoadAssembly();
Console.WriteLine(RealOfFakeObject.SomeMethod());
Console.WriteLine(RealOfFakeObject.SomeProperty);
Console.WriteLine("Press any key...");
Console.ReadKey();
}
private static void TryLoadAssembly()
{
string assemblyFullName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RealAssembly.dll");
if (File.Exists(assemblyFullName))
{
var RealAssembly = Assembly.LoadFrom(assemblyFullName);
var RealClassType = RealAssembly.GetType("RealAssembly.RealClass");
RealOfFakeObject = Activator.CreateInstance(RealClassType);
}
else
{
RealOfFakeObject = new FakeClass();
}
}
}
}
This two projects are not referenced directly. "System" is the only reference used in this two projects.
So now, if compiled "RealAssembly.dll" exists in same directory we will have "We used real library! Meow!" string and random integer at console output. Otherwise if "RealAssembly.dll" not exists in same directory - "Library not exists, so we used stub! :)" and 0 will be shown.

Loading DLL in external program?

I have a C# ClassLibrary that contains a function to sum two numbers:
namespace ClassLibrary1
{
public class Calculator
{
public int Calc(int i, int b) {
return i + b;
}
}
}
I want to load this dll from other C# application externally. How can I do this?
Do you mean you want to load it dynamically, by file name? Then yes, you can use the Assembly.LoadFile method as follows:
// Load the assembly
Assembly a = Assembly.LoadFile(#"C:\Path\To\Your\DLL.dll");
// Load the type and create an instance
Type t = a.GetType("ClassLibrary1.Calculator");
object instance = a.CreateInstance("ClassLibrary1.Calculator");
// Call the method
MethodInfo m = t.GetMethod("Calc");
m.Invoke(instance, new object[] {}); // Get the result here
(Translated example from here, but I wrote it so don't worry!)
Just building on the answer by minitech.. If you can use C# 4.0 you can omit some reflection calls.
public static void Main()
{
Assembly ass = Assembly.LoadFile(#"PathToLibrar\ClassLibraryTest.dll");
var type = ass.GetType("ClassLibrary1.Calculator");
dynamic instance = Activator.CreateInstance(type);
int add = instance.Calc(1, 3);
}
Here as instance of of type dynamic, you don't have to find the method Calc by reflection.
But the best way is to define a interface upstream
public interface ICalculator
{
int Calc(int i, int b);
}
and implement it in your class downstream
public class Calculator : ICalculator
{
public int Calc(int i, int b)
{
return i + b;
}
}
Then you can do reflection minimally to construct the object.
public static void Main()
{
Assembly ass = Assembly.LoadFile(#"PathToLibrar\ClassLibraryTest.dll");
var type = ass.GetType("ClassLibrary1.Calculator");
ICalculator instance = Activator.CreateInstance(type) as ICalculator;
int add = instance.Calc(1, 3);
}
This will give you the best performance.
Right click on the References in the project explorer in Visual Studio and simply select the assembly. Then you can use it:
using ClassLibrary1;
class Program
{
static void Main()
{
Calculator calc = new Calculator();
int result = calc.Cal(1, 2);
}
}
In case your'e using visual studio you can reference this dll in your project and than include the namespace in your new source code

Unable to call a library from other in MEF

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).

Categories

Resources