0

Totally new with this.

What im trying to achieve, is to have an interface, and people from the outside implement it and in my program load the "implementation" and bind it to my interface, so i have a few questions about this and what restrictions do i need to satisfy.

1- To the user implementing my interface, do i give him a dll which contains my interface, or just the source code and he uses it and adds his implementing code?

1.1- If 1 is true, on my program, which interface do i use? Can i use the interface loaded directly from my code or im forced to use the interface from the same DLL i gave to the user?

2- Do namespaces need to be the same? For example, the interface on my side is in namespace Server.Interface, however the one in the dll i send is just namespace Interface.

Im trying two methods to verify if an assembly implements my interface:

both inside a loop:

foreach (Type t in plugin.GetTypes())
 {

Method1

if (typeof(INovedades).IsAssignableFrom(t))
                {
                    i = (INovedades)Activator.CreateInstance(t);
                    break;
                }

Method2

Type typeInterface = t.GetInterface("CapaDatos.ServiciosExternos.INovedades", true);

                if (typeInterface != null)
                {
                    i = (INovedades)Activator.CreateInstance(t);
                    break;
                }

Method 1, is always false, meaning it never validates.

Method 2, finds a match, however when calling CreateInstance, it gives an exception about not being able to create an instance.

anything i should know?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Cristiano Coelho
  • 1,675
  • 4
  • 27
  • 50
  • An interface is a Type. In a given AppDomain, there can be only one version of a type, so, 1:true, 1.1: same DLL, 2:yes – Simon Mourier May 24 '13 at 08:11

3 Answers3

4

The typical approach for that is to create a project where all your contracts are (contracts are interfaces) are placed. There should be no business logic. This is then used by your own application (implementing logic) and this is the assembly you can provide to others to implement it. Namespaces should be the same as it should be the same dll used.

What you probably wish to do, is to create a plugin system of some sort Writing C# Plugin System

You can use both methods you described, I personally prefer method1.

Need more code to explain this. First think when dynamically creation objects: You need to have a simple constructor without any arguments, otherwise the activator won't be able to create an instance.

I assume method 1 is failing because there is no shared contract between plugin and consumer

Community
  • 1
  • 1
Samuel
  • 6,126
  • 35
  • 70
  • Ok so i used the same interface dll in the main code and in the "plugin dll" code and it seemed to work. But i find it a little too much restrictive to be honest, managing an extra project just for ONE interface (which also has just one method!) is absurd... – Cristiano Coelho May 24 '13 at 08:12
  • What seems absurd to you? Interface objects should be accessible to all. So your solution is either distribute the contracts.dll or distribute your application, which then must be referenced by the implemented to obtain the correct type. Furthermore the separate project is more robust in terms of extensibility, single responsibility and separation of concerns. – Samuel May 24 '13 at 09:08
0

Regarding your first question (1 - whether to distribute the interface as a DLL or via source code), you have to distribute the DLL. Otherwise the .NET Runtime will not regard the interface to be identical, because the user of the interface and the one who implements it will have two versions of the DLL. Typically you will create a separate DLL for the interface that does not include your program.

Regarding question 1.1, you will have to reference that separate interface DLL from your DLL, and the users/implementors of the interface will have to reference it as well. Since you both use the same DLL, the namespaces will be the same.

In order to create an instance (regarding Method 1 and Method 2), you have to create an instance of the class, not of the interface. So you need to know the Type of the class from somewhere. One way is described in Getting all types that implement an interface. But you could also create it from a string, as described in Create class instance from string.

Community
  • 1
  • 1
EFrank
  • 1,880
  • 1
  • 25
  • 33
0

From my experience of implementing interfaces in DLL-s (aka plugins) i've used:

namespace TransportInterface
{
    public interface Transport
    {
        string Name { get; }
        // etc
    }
}

compiled it into a DLL file TransportInterface.dll

after, this DLL was added as a reference into 1) a project of the application itself 2) a project of any plugin created using this interface

A plugin implementing this interface:

namespace IRCTransport
{
    public class IRCTransport : Transport
    {
        // here's the implementation
    }
}

and here's the loading of a plugin from a project of an application (Method #2 from your post)

using TransportInterface;

// ...

private void LoadTransportPlugins()
{
    string folder = System.AppDomain.CurrentDomain.BaseDirectory + "\\Transports";

    string[] files = Directory.GetFiles(folder, "*.dll");

    foreach (string file in files)
        try
        {
            Assembly assembly = Assembly.LoadFile(file);

            foreach (Type type in assembly.GetTypes())
            {
                Type iface = type.GetInterface("TransportInterface.Transport");

                if (iface != null)
                {
                    try
                    {
                        Transport plugin = (Transport)Activator.CreateInstance(type);

                        // executing this code means transport creation succeded
                    }
                    catch (Exception ex)
                    {
                        _System(ex.InnerException.Message + '\n', Color.Red);
                    }
                    AnyPlugins = true;
                }
            }
        }
        catch { };
}

That was written a few years ago on a .NET 3.5, but I guess nothing should've changed since.

All three namespaces of: 1) 'Transport' interface 2) Plugin implementing the interface 3) Application using plugins

are different, I doubt they actually need to be the same.

If you simply get an exception of not being able to create an instance, I guess you need to verify that plugin construction doesn't fire any exceptions. You need to go deeper to debug this case with an "InnerException" (maybe even more that once), this should show you what is your actual error, Activator's exception is almost of no use here.