Sharing code between two c# assemblies - c#

1) I have a project called SocketServer in which there is a Class Room, this project is a complied exe and can also be complied as a DLL.
2) In Another project called, lets say, MyGame, there is a class called MyAwesomeGame, in which I need to do something like:
public class MyAwesomeGame
{
public Init(Room room)
{
//I can get data from Room
}
}
Now MyGame Project is compiled into a MyGame.DLL, and is placed somewhere relative to the SocketServer.exe, which at runtime loads MyGame.DLL and Instantiates MyAwesomeGame class and calls the Method Init and passes room as its parameter. Code is SocketServer project is something like:
public class Room
{
private InstantiateGameRoom()
{
//Load External MyGame.DLL Assembly
Task<MyAwesomeGame> task = Task<MyAwesomeGame>.Factory.StartNew(() => (MyAwesomeGame)Activator.CreateInstance(classType, new object[] { this }));
MyAwesomeGame instance = task.result;
instance.init(this);
}
}
So my question is how can I get reference of the Class room in MyGame Project? Should I add reference of my SocketServer Project? and if I do, wont it get complied into my MyGame.dll?
p.s: I also intend to distribute the socketserver.dll as an API to thrid-party users.

You should add the SocketServer's generated dll to the references of the MyGame project. Right click on MyGame, click Add, click References..., in the dialog select Projects and select the SocketServer project.
I believe it is also wise to make sure that SocketServer is a depedency for the MyGame project to make sure SocketServer is built before MyGame.
--edit: please read the comment below that I made after Sushant's clarification. Or go straight to Sid's answer. :-)

I think the proper way to share Models among two or more projects is to extract all the models and relative logics to a separate project.
Then you can reference that project from every project that needs to use that data.
The scenario I am talking about is the following:
ModelsProject (Contains models and business logic)
ProjectA (has a dependency on ModelsProject)
ProjectB (has a dependency on ModelsProject)
Scheme

Related

DLL dependency not getting copied issue

I'm using VS2015 and have two projects where the child project references DapperExtensions (X--> Y--> DapperExtensions).
Now DapperExtensions seems to have implicit dependency on Dapper.
When I try and use code from Y in X, I get an error regarding Dapper.dll missing.
It seems with dlls being copied to project X debug folder, only DapperExtensions.dll is getting copied but Dapper.dll isn't.
Presumably related to the direct dependency issue identified in stackoverflow already :
Dll not copying to bin folder
So I created some dummy code to reference an arbitrary reference from Dapper but this doesn't seem to lead to the DLL getting copied as per existing suggestions in stackoverflow:
public static void Dummy()
{
Action<Type> noop = _ => { };
var dummy = typeof(Dapper.DbString);
noop(dummy);
}
The only thing I guess left is to add dappper dll reference directly to ProjectX which I really want to avoid.
Any ideas why the dummy reference thing doesn't work?

Accessing class members defined in another *.cs file

I'm writing an update checker for my program and I'm using xml from a remote server. The request is working fine and it does what I want. The problem is that I can't call the function from another file. (See code below)
The files
home.cs - The place i want to call the RequestVersion()
version.cs - Where the RequestVersion() is located
The code
version.cs
namespace MyName
{
class version
{
public string[] RequestVersion()
{
XmlDocument doc = new XmlDocument();
try
{
string[] version_data = new string[3];
doc.Load("link_here");
foreach (XmlNode node in doc.DocumentElement)
{
string version = node.Attributes[0].Value;
string date = node["date"].InnerText;
string changelog = node["changelog"].InnerText;
version_data[0] = version;
version_data[1] = date;
version_data[2] = changelog;
return version_data;
}
}
catch (Exception xml_ex)
{
}
return null;
}
}
}
(returns an array)
home.cs
private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
{
//This is the place from where i want to access the array!
}
And my XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<SerialMate>
<release version="1.0.0">
<date>12-10-2014</date>
<changelog>Test</changelog>
</release>
</SerialMate>
(I'm not adding any new <release> tags on the xml so it always has 1)
The question
So, my question is: How do it access the array elements from the RequestVersion() within home.cs?
I don't really understand your problem, but:
version v = new version();
string[] s = v.RequestVersion();
Referencing code within other files and projects
Within the same project it makes absolutely no difference whether the code is in the same or in different files. The only things which matter are the access modifiers (public, protected, internal, and private).
If the two code pieces are in different projects, then the compiled code will be compiled into two different assemblies (*.exe or *.dll). Therefore one project will have to reference the other one. Typically the start up project (*.exe) will reference a class library project (*.dll).
If the two projects are within the same solution, you can add a so called project reference. Right click on the class library project in the solution explorer and click “Copy As Project Reference”. In the startup project, right click on “References” and click “Paste Reference”.
If the two projects are within different solutions you will have to add a reference to the class library DLL (usually the one in bin/Release) from within the startup project. Right click “References” and click “Add Reference…”. In the references dialog choose “Browse” and select the DLL.
Also make sure not to create circular dependencies (project A references project B and project B references project A). If you have such a dependency, you can usually resolve it by placing the code that has to be accessed by the two projects into a third project C. Then change the references to: A references C and B references C.
Calling the method of another class
Types (a class in your case) and their members (properties, methods, events …) must be declared as public in order to be accessible from other projects. Within the same project they can also be declared as internal. (They can also be declared as protected if you want to derive new classes.)
If a member is declared as static or if it is a constant, you can access it by specifying the type name dot the member name:
var result = MyClass.MyMethod();
If the member is an instance member you must call it from an instance of the type (an object):
MyClass obj = new MyClass();
var result = Obj.MyMethod();

Ninject + Auto Discovery

Here's the deal: I want to create a C# console app. When run, this app will look in a particular folder for dll's with classes that implement a particular interface, and then run a method on those dll's.
I haven't done this before but from my reading that should be "easy enough" from an IoC/Ninject perspective. I think you can do something with kernel.Bind() to load assemblies of a certain interface in a certain directory. I think/hope I can figure that part out (if you know otherwise, please do tell!).
But here is my quandary.
Here is a visual to help first:
MainProgramFolder
-- MainProgram.exe
-- MainProgram.exe.config
-- LibraryFolder
----- Library1Folder
--------Library1.dll
--------Library1.dll.config
----- Library2Folder
--------Library2.dll
--------Library2.dll.config
The dll's that implement this interface are technically stand alone apps -- they are just libraries instead of exe's (or, rather, I'd like them to be for IoC purposes). I'd like for them to be run in their own context, with their own app.configs. So for example, MainProgram.exe would bind the ILibrary interface to classes inside Library1.dll and Library2.dll because they implement ILibrary. But inside Library1, it calls ConfigurationManager to get its settings. When I call Class.Method() for each of the bindings from MainProgram, how can I ensure they are referencing their own .config's and not MainProgram.exe.config? (Also, fwiw, these additional libraries will likely not be a part of the assembly or even namespace of the main programs -- we're basically providing a drop folder for an application to kind of "subscribe" to the main program's execution.)
IOW, I know you can attach an app.config to a class library but I wouldn't know how, after the bindings have been resolved from the IOC, to make those dll's "see" its own config rather than the main program's config.
All thoughts appreciated!
Thanks
Tom
First, to load and bind all of your classes you'll need ninject.extensions.conventions, and something like this:
var kernel = new StandardKernel();
/*add relevant loop/function here to make it recurse folders if need be*/
kernel.Bind(s => s.FromAssembliesMatching("Library*.dll")
.Select(type => type.IsClass && type.GetInterfaces().Contains(typeof(ILibrary)))
.BindSingleInterface()
.Configure(x=>x.InSingletonScope()));
To make each instance load its configuration as if it was the entry point you will need to run it in a new app domain. Your ILibrary implementation needs to inherit MarshalByRefObject and be Serializable so that it will run correctly in the alternate appdomain
[Serializable]
public class LibraryA :MarshalByRefObject, ILibrary
You can then add this activation strategy to your kernel that will cause it to swap out instances of ILibrary with an instance loaded in an alternate appdomain with your config file convention before they are returned.
public class AlternateAppDomainStrategy<T> : ActivationStrategy
{
public override void Activate(IContext context, InstanceReference reference)
{
if (reference.Instance.GetType().GetInterfaces().Contains(typeof(T)))
{
var type = reference.Instance.GetType();
var configFilePath = type.Assembly.GetName().Name + ".dll.config";
var file = new FileInfo(configFilePath);
if (file.Exists)
{
var setup = new AppDomainSetup() { ConfigurationFile = file.FullName, ApplicationBase = AppDomain.CurrentDomain.BaseDirectory };
var domain = AppDomain.CreateDomain(type.FullName, null, setup);
var instance = domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
reference.Instance = instance;
}
else
{
throw new FileNotFoundException("Missing config file", file.FullName);
}
}
}
}
And Add it to your kernel
kernel.Components.Add<IActivationStrategy, AlternateAppDomainStrategy<ILibrary>>();
From there you can simply instantiate your ILibrary instances and call methods on them. They will load in their own app domains with their own configs. It gets a lot more complicated if you need to pass things in/out of the instance either via methods or constructor, but from the sound if it you don't so this should be OK.
var libs = kernel.GetAll<ILibrary>();
foreach (var lib in libs)
{
lib.Method();
}

Alternatives to reading config files from class libraries at design time?

I have a WinForm project that contains several UserControls. This WinForm project has a reference to an assembly (lets call it lib.dll) that is created from another project (Class Library) that exists in a different solution.
Now, several of the UserControls make calls into lib.dll that return values from the app.config file. At runtime lib.dll works fine and returns the necessary data but at design time, I am getting an exception from lib.dll because the app.config sections are NULL (the exceptions are by design).
Now I could go through each control and wrap any code that calls into lib with
if(!DesignMode) { //code }
But that is a lot of controls to go and apply that to. Is there something I can do globally that would be more elegant then testing the DesignMode property?
Edit
In response to the two comments left below: the solutions provided don't appear to work. The assembly that is causing me a problem lives in the same directory as the app.config. The general directory structure looks like this
References Folder
Configurations (Folder)
appsettings.config
app.config
lib.dll
app.config pulls in several other config files (appsettings, cnx strings, etc) which reside in the Configurations directory. In the case of my exception the value I am trying to get resides in one of these ancillary config files that is referenced by app.config.
This is an interesting question. A solution could be to create in lib.dll a static class like this one :
public static class Config
{
private static readonly _param1;
static Config()
{
_param1 = ConfigurationManager.AppSettings["Param1"] ?? "Your default value";
}
public static string Param1
{
get { return _param1; }
}
}
Then, in your code, insted of writing ConfigurationManager.AppSettings["Param1"], you will use Config.Param1. So you won't need to test the property DesignMode.
There are so many ways to do this, IMHO.
One thought that immedidately comes to mind would be to use an inheritance-based approach for the user controls in question? That way, in the base class, you can put that if (DesignMode) check in, and do the correct branching from there.
// if i were to visualizeyour lib.dll data initializer call like this:
class BaseUserControl
{
// i'm guessing that you initialize the data somehow...
void InitializeData()
{
if (!DesignMode)
{
InitializeDataLocal();
}
}
protected virtual InitializeDataLocal()
{
// whatever base behavior you want should go here.
}
}
// in the derived classes, just put the code you currently have for
// fetching the data from lib.dll here...
class UserControl : BaseUserControl
{
protected override InitializeDataLocal()
{
// fetch from lib.dll...
// optionally invoke some base behavior as well,
// if you need to...
base.InitializeDataLocal();
}
}

MEF not loading a references again

I have a interface as follows:
[InheritedExport(typeof(ITransform))]
public interface ITransform
{...}
Now, I have two classes:
namespace ProjectA
{
public class Transform:ITransform {....}
}
And
namespace ProjectB
{
public class Transform:ITransform {....}
}
I am using DirectoryCatalog for loading each parts. Each project is compiled and their binaries(build output) location is given as an input to DirectoryCatalog for further composition.
The code for fetching ITransform parts is as follows:
public static class ExtensionFactory
{
public static ITransform GetExtension(string extensionPath)
{
IEnumerable<ITransform> extensions = null;
try
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(extensionPath));
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(catalog);
extensions = container.GetExportedValues<ITransform>();
return extensions.FirstOrDefault();
}
catch (Exception ex) {........}
return extensions.FirstOrDefault();
}
}
I have another project ProjectXYZ(auto generated by third party tool(Altova Mapforce 2012 SP1)).
For ProjectA:
namespace ProjectXYZ
{
public classA{...}
}
For ProjectB:
namespace ProjectXYZ
{
public classA{...}
public classB{...}
}
ProjectA.Transform uses ProjectXYZ.ClassA, whereas ProjectB.Transform uses ProjectXYZ.ClassB from another implementation of ProjectXYZ. The implementation and classes of ProjectXYZ varies across for different implementation of ITransform. The classes in ProjectXYZ are automatically generated through some third-party tools, which I need to use directly. So, I cannot make any changes to ProjectXYZ.
So, when first time MEF loads ProjectA.Transform, it also loads ProjectXYZ to be used as a reference for ProjectA. When ProjectB.Transform is getting loaded/exported, then as ProjectXYZ being already in MEF memory, it uses the ProjectXYZ reference available from ProjectA. Thus, when ProjectB.Transform is executing, it searches for ProjectXYZ.ClassB, which it does not gets as MEF has load ProjectXYZ reference available in ProjectA.
How to resolve this problem. The MEF loads the parts correctly, but it does not load the supporting dll's references in a desired manner. I have also tried PartCreationPolicy attribute, but the results are same.
It not a MEF problem. The problem is in the loading model of .NET. (or better the way you're objects are loaded by .net)
When MEF loads it returns the correct objects. But when looking for class ProjectXYZ when projectB is loaded there is already a ProjectXYZ dll loaded with the correct assembly name projectB is referring to. And the loader the dll actually referenced by projectB is not loaded.

Categories