Alex
Alex

Reputation: 1692

Implementing a custom context in C# for server application

I'm implementing a plugin based server architecture, and would like the plugins to be aware of the server state, and to have a common method of reporting status and results back to the server.

My intention is to define a context which is passed to each of the plugins when they are called, and the plugins will report status information back into the context. The context will then be used to track the status of each task carried out by each plugin.

Is there a standard for creating custom contexts in C#, or is there a generic Context object which can be used?

All the context will need to do is store properties, but I'm uncertain which Context class would be the best to extend or use as-is.

In this case, the context will consist of

1) a set of shared properties read by each plugin which will govern their execution (db addresses, folder names for finding items to process etc)

2) A dictionary which will contain results produced by the plugins' Execute method

3) Status information as to the success/failure of a process

4) A record of the current state of the process (values from an enum)

I'm intending to use a basic object for this, but as there are a number of Context classes in various libraries for C#, I'm debating whether extending an existing Context object would be a better choice than just writing one from scratch.

Looking at the literature on MSDN, there doesn't seem to be much precedent for either approach, and I would appreciate any feedback from people who have done this already.

Upvotes: 0

Views: 1784

Answers (1)

jgauffin
jgauffin

Reputation: 101166

Do not use global/static contexts. It makes it harder to maintain and test your application.

Instead you can define the context and pass it as an instance to the plugin during plugin initialization. Something like:

public interface IPlugin
{
    void Init(ApplicationContext context)

    // [.. other methods that plugins must implement ..]
}

and just like that you have the same functionality but without having to take [ThreadStatic] and async context into account.

I'm intending to use a basic object for this, but as there are a number of Context classes in various libraries for C#, I'm debating whether extending an existing Context object would be a better choice than just writing one from scratch.

I think it's better to write it from scratch. Do not that context classes tend to grow and move towards GOD objects. By crafting one yourself you can keep it small.

An alternative to context objects is to expose small services to the plugin that they can use instead. A nice way of doing so is to use an inversion of control container to build the classes that implement the IPlugin interface.

In that way they can simply use dependency injection to get the application services (their contracts i.e. interfaces) directly.

Something like:

//register the plugins in the container
var plugins = Directory.GetFiles(yourAppDirectory, "plugin_*.dll");
foreach (var pluginDll in plugins)
{
    var assembly = Assembly.Load(pluginDll);
    var pluginType = assembly.GetTypes().FirstOrDefault(x=> typeof(IPlugin).IsAssignableFrom(x));
    yourContainer.RegisterType(pluginType, typeof(IPlugin));
}

And finally to load them:

var plugins = container.ResolveAll<IPlugin>();
foreach(var plugin in plugins)
    plugin.Init();

A plugin can then be defined like:

public class HelpPlugin : IPlugin, IMenuHandler
{
    public HelpPlugin(IMenuService service)
    {
        service.AddTopMenu("Help", this);
    }

    void IMenuHandler.Handle(MenuClick click)
    {
        MessageBox.Show("Menu button was clicked");
    }
}

Yay! No need for a context object.

Upvotes: 2

Related Questions