none
Interfacing between assemblies without referencing RRS feed

  • Question

  • Hi,

     

    I am working on a GUI framework. The framework is a WPF executable that can load ‘modules’ (.NET assemblies) that belong to components. The framework can show views that are defined in a module. Each main project in the organization creates their own component. Each component is a VS solution with multiple projects containing views and a reference to the framework executable which is the startup project.

     

    Some modules of a component need to interface with a module of another component. There is a requirement to store in the interface between them in a human readable format. Preferably XML, but C# is okay too. However, It is not allowed for Project A to have references to Project B.

     

    Anyone got a good idea for a clean implementation?

     

    Currently, it’s done by having a single C# file with the interface in a central place. Project A and B both have a symbolic link to it and compile it. Both projects need to implement the interface. If A needs B, the framework offers some functionality (implemented via reflection) so the implementation at A side can invoke the method at B side. This works okay but gets complicated when you want to pass around types that are defined in the interface file: each side will have its own compiled version, and although they are the same you cannot cast them to each other. So A needs to create an instance in B (again via reflections) and move all properties from the object used a B side to the object at A side. This gets messy if the type is a class that has subclasses.

     

    Any ideas for an alternative are welcome!

    Wednesday, January 25, 2012 4:55 PM

Answers

  • Why do they want this? What reasons do they have for that? They should think twice about their requirements (my perosnal opinion).

    You could go and use reflection. This will take away a lot performance. But there are some ways how you could speed it up a little. See http://msdn.microsoft.com/en-us/magazine/cc163759.aspx for some hints.

    I even saw some code from louis.fr inside the forums, where he was building a new object of a new type around the unknwon object which you could cast to the interface. But it was more or less reflection but the call to the methods he got by reflection was cached that way in the new type which implemnts the interface.
    (The op of the thread had the problem that he had a class which implemented all methods of an interface but didn't say: I implement the interface. But I was unable to find that thread again, sorry).

    With kind regards,

    Konrad

    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Wednesday, January 25, 2012 6:06 PM
  • The difference is that the interface only gets compiled once (lives in one assembly), so you don't have to deal with the fact the objects which feel like they implemented the same interface (same C# file) technically implemented different interfaces because each interface was compiled into the individual assemblies.
    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Wednesday, January 25, 2012 8:54 PM
  • Sorry if this has been said; I didn't read all responses fully.

    I glanced at the question and apparently the OP wants a circular reference between at least two projects.  This can be done.  It is tricky.

    1. Start a solution with one of the projects.  Let's call this one Project A.
    2. Shape up the classes in this project of yours as much as you can without making any reference to classes that will belong to the other project.
    3. Add the second project.  This will be Project B.
    4. In project B, add a reference to project A.
    5. Shape up the classes of project B as much as possible.  You may refer to class names (and other objects like enums, structs and interfaces) of project A as they exist now.
    6. Compile project B.
    7. Switch to project A.  Make a reference to the DLL product of compiling project B.  Note that I said reference the DLL; do NOT try to reference the project B.
    8. Complete project A now that the classes in project B are available.
    9. Compile project A.
    10. If you must, switch to project B and complete it now that project A is probably completed.
    11. Compile project B again.
    12. Done.  You have your two .Net assemblies that reference each other.

    I show this with a disclaimer:  I don't know if this is a supported scenario by Microsoft.  I just know it can be done.  Should you do it?  Up to you.

    Personally I don't think it is a big deal.  After all, what the compiler needs is the meta data of the classes, not the actual code in the other dll.  So as long as you can write enough code in order to produce good meta data, the compiler will be happy.  This hack needs to be because there are no header files that you can give the compiler; this is the equivalent of producing C++ header files in my eyes.


    Jose R. MCP
    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Thursday, January 26, 2012 12:32 AM
  • If they are used to web services then they can of course build up such a solution, too. Instead of projects, they build web services. Each project can then read the wsdl and use the services offered.

    But if they want to do everything on assembly level, then they should think about the technology there, too. And I am also thinking about the argument, that they want a "readable file".

    An assembly is also readable. It is always the same: To read a file you need a tool. A simple textfile could be read with notepad but you still need such a program! And you can read the assembly, too: Just look at the object browser after inserting a reference to the DLL. (So you see the interface with all members of the interface.) If you want to see real code, then you have to use a tool like refactor. (Resharper also has that functionality now!) But the main documentation iwll be in XML form .. you can even use tools so you get a full documentation inside the MS Help System!

    So I do not see this readable argument. I even see one disadvantage: You have one file ... e.g. Interface.cs. All projects are sharing it. Project A has a good idea and extends it. Project B extends it also ... And Project C had some changes, too. Have fun merging all changes together. One copy of the source for an assembly and you can maintain the problems much easier. The simple reason for this is, that people cannot directly change the assembly. But a simple cs script is quickly changed. And each project will have its own copy in their own source control!

    But if something like that is really required: It is ok. You can use reflection to access all objects of the others. You can define some common interfaces ... so if you have an Interface ITest with just one method void Test();, you will have one such Interface ITest in a.dll, b.dll, c.dll, ... (All will be different) but you can simply check, if an object implements all methods of the interface you have and in case it does, you create a new object on the fly which implements your ITest and internally stores the reference to your object. The methods are calling Invokes which you stored while creating this object. I think louis.fr posted such code some time ago but I was unable to find that thread. But fact is: You use reflection so you loose some performance. But of course: You only look up the methods once so you can directly Invoke.

    That are just my thoughts. Sorry if my reply seems ignorant or so, but from my perspective I would double check if the requirements are really correct. Maybe people will change their mind when they think about what the requirement means. (I like to give the example, that someone wants a car which can also be used as a ship (in case he needs to cross a river or sea) ad which can fly (so he can quickly fly from europe to america) ... you could spend a lot of money on it and it might be possible so build such a vehicle. But I doubt that you will be allowed to drive that car on the public streets in germany... and it will cost a lot of money. So maybe people might agree, that it could be better to not build such a car. Instead they agree to just book a normal flight when required, to use bridges or get a fairy ticket ... I will never say, that the idea is wrong or bad. Maybe you have a big idea and in a few years we all have star wars vehicles which can fly and dive .... But it might be good to think about the consequences. In this case you loose performance through reflection use - which might be ok for you!)

    With kind regards,

    Konrad
     

     

    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Thursday, January 26, 2012 10:53 AM

All replies

  • Typically, this would be handled by having a separate project that defines the interface, so that Project A and B could both reference (directly) the types in "project C".

     

    This has many advantages over your current approach, as it allows for full type safety and proper compiler support.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Wednesday, January 25, 2012 5:03 PM
    Moderator
  • Yes, I know. But that's not what they want. They want a readable file (and just that) and no extra projects or compile steps.
    Wednesday, January 25, 2012 5:26 PM
  • Why do they want this? What reasons do they have for that? They should think twice about their requirements (my perosnal opinion).

    You could go and use reflection. This will take away a lot performance. But there are some ways how you could speed it up a little. See http://msdn.microsoft.com/en-us/magazine/cc163759.aspx for some hints.

    I even saw some code from louis.fr inside the forums, where he was building a new object of a new type around the unknwon object which you could cast to the interface. But it was more or less reflection but the call to the methods he got by reflection was cached that way in the new type which implemnts the interface.
    (The op of the thread had the problem that he had a class which implemented all methods of an interface but didn't say: I implement the interface. But I was unable to find that thread again, sorry).

    With kind regards,

    Konrad

    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Wednesday, January 25, 2012 6:06 PM
  • The clean implementation is to architect the system to not have circular references.

    I think that a C# file which declares just an interface is a readable file.

    A possible option is to place everything in the same solution. It's not scalable, but it is an option.

    It sounds like you're trying really hard to not have type safety in a type safe language.

    Lets say that you do write code which creates types, at runtime, based off of some scheme (say an xml file). It can be done, it's a lot of work, but it is doable. But you would still run into the problem of passing the objects between the assemblies, because the types would still be different, because each assembly would have generated their own version of the type.

    Reed told you the easy solution to the problem. It sounds like the existing system went out of its way to make things difficult.

    Wednesday, January 25, 2012 6:19 PM
  • They probably want this because they are used to something similar. The user interfaces of the coponents and the component to component communication is through web services, the interfaces are specified in wsdl and xsd files.

    I agree that the current solution seems a strange detour to let 2 assemblies in the same executable communicate. Unless I get a better idea, I will try to convince them to go the normal way (interface in separate project, both reference the interface project).

    Wednesday, January 25, 2012 7:39 PM
  • I don't know how the gut of the system works, but if it's plugin like there's chance.

    Assembly A defines an interface, and needs to use objects from Assembly B. Assembly A also defines an attribute. A class in Assembly B implements the interface and has the attribute. During runtime Assembly A looks at a configuration file for a list of assemblies, loads the assemblies, reflects for all classes with the attribute that have implemented the interface and instantiates an instance of the class (default constructors are important). Viola, Assembly B knows about and references Assembly A, Assembly A has no dependencies on or pre run time knowledge of Assembly B, and can use types from Assembly B (but only those which follow a strict contract).

    Wednesday, January 25, 2012 8:35 PM
  • Thanks, but I think this is similar to how the interface mechanism now works.

    Wednesday, January 25, 2012 8:42 PM
  • The difference is that the interface only gets compiled once (lives in one assembly), so you don't have to deal with the fact the objects which feel like they implemented the same interface (same C# file) technically implemented different interfaces because each interface was compiled into the individual assemblies.
    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Wednesday, January 25, 2012 8:54 PM
  • Ah, thanks, I see the difference now. I will look into this!

     

    Wednesday, January 25, 2012 9:37 PM
  • Sorry if this has been said; I didn't read all responses fully.

    I glanced at the question and apparently the OP wants a circular reference between at least two projects.  This can be done.  It is tricky.

    1. Start a solution with one of the projects.  Let's call this one Project A.
    2. Shape up the classes in this project of yours as much as you can without making any reference to classes that will belong to the other project.
    3. Add the second project.  This will be Project B.
    4. In project B, add a reference to project A.
    5. Shape up the classes of project B as much as possible.  You may refer to class names (and other objects like enums, structs and interfaces) of project A as they exist now.
    6. Compile project B.
    7. Switch to project A.  Make a reference to the DLL product of compiling project B.  Note that I said reference the DLL; do NOT try to reference the project B.
    8. Complete project A now that the classes in project B are available.
    9. Compile project A.
    10. If you must, switch to project B and complete it now that project A is probably completed.
    11. Compile project B again.
    12. Done.  You have your two .Net assemblies that reference each other.

    I show this with a disclaimer:  I don't know if this is a supported scenario by Microsoft.  I just know it can be done.  Should you do it?  Up to you.

    Personally I don't think it is a big deal.  After all, what the compiler needs is the meta data of the classes, not the actual code in the other dll.  So as long as you can write enough code in order to produce good meta data, the compiler will be happy.  This hack needs to be because there are no header files that you can give the compiler; this is the equivalent of producing C++ header files in my eyes.


    Jose R. MCP
    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Thursday, January 26, 2012 12:32 AM
  • If they are used to web services then they can of course build up such a solution, too. Instead of projects, they build web services. Each project can then read the wsdl and use the services offered.

    But if they want to do everything on assembly level, then they should think about the technology there, too. And I am also thinking about the argument, that they want a "readable file".

    An assembly is also readable. It is always the same: To read a file you need a tool. A simple textfile could be read with notepad but you still need such a program! And you can read the assembly, too: Just look at the object browser after inserting a reference to the DLL. (So you see the interface with all members of the interface.) If you want to see real code, then you have to use a tool like refactor. (Resharper also has that functionality now!) But the main documentation iwll be in XML form .. you can even use tools so you get a full documentation inside the MS Help System!

    So I do not see this readable argument. I even see one disadvantage: You have one file ... e.g. Interface.cs. All projects are sharing it. Project A has a good idea and extends it. Project B extends it also ... And Project C had some changes, too. Have fun merging all changes together. One copy of the source for an assembly and you can maintain the problems much easier. The simple reason for this is, that people cannot directly change the assembly. But a simple cs script is quickly changed. And each project will have its own copy in their own source control!

    But if something like that is really required: It is ok. You can use reflection to access all objects of the others. You can define some common interfaces ... so if you have an Interface ITest with just one method void Test();, you will have one such Interface ITest in a.dll, b.dll, c.dll, ... (All will be different) but you can simply check, if an object implements all methods of the interface you have and in case it does, you create a new object on the fly which implements your ITest and internally stores the reference to your object. The methods are calling Invokes which you stored while creating this object. I think louis.fr posted such code some time ago but I was unable to find that thread. But fact is: You use reflection so you loose some performance. But of course: You only look up the methods once so you can directly Invoke.

    That are just my thoughts. Sorry if my reply seems ignorant or so, but from my perspective I would double check if the requirements are really correct. Maybe people will change their mind when they think about what the requirement means. (I like to give the example, that someone wants a car which can also be used as a ship (in case he needs to cross a river or sea) ad which can fly (so he can quickly fly from europe to america) ... you could spend a lot of money on it and it might be possible so build such a vehicle. But I doubt that you will be allowed to drive that car on the public streets in germany... and it will cost a lot of money. So maybe people might agree, that it could be better to not build such a car. Instead they agree to just book a normal flight when required, to use bridges or get a fairy ticket ... I will never say, that the idea is wrong or bad. Maybe you have a big idea and in a few years we all have star wars vehicles which can fly and dive .... But it might be good to think about the consequences. In this case you loose performance through reflection use - which might be ok for you!)

    With kind regards,

    Konrad
     

     

    • Marked as answer by Paul Zhou Thursday, February 9, 2012 8:51 AM
    Thursday, January 26, 2012 10:53 AM