views:

504

answers:

2

I've been working with asp.net MVC and am still not very good at it. However, I have started wondering how would I go about creating applications that can be "plugged" or installed into an existing ASP.net MVC site with minimal complexity.

For example, in ASP.net web forms I developed a sort of Blogging app. In order to install this app I just need to drop a dll into the Bin folder, add a few web.config lines and then add controls to the aspx pages as needed. No other change needs to be made.

Now I'm working with MVC and I've come across partial views which seem to replace webform usercontrols in some way. However, it seems you still need to pass the partial view's data from the controller and that is at a higher level than the page. I'd have to modify controller code to install an app.

I'm pretty sure I am thinking about this with the wrong mindset. Is there a way to create applications for asp.net mvc that can be easily plugged into an existing web site?

+3  A: 

I have done quite a lot of work like this and I got almost all of the information I neeed to start from here:

http://www.codeproject.com/KB/cs/pluginsincsharp.aspx

My largest project using plugins was an audio processing app.

The general Idea is:

You create an interface for each of the plugin types you need in a separate, distributable, signed DLL. Here is an example interface:

/// <summary>
/// Describes an audio reader.
/// </summary>
public interface IReader : IPlugin
{
    /// <summary>
    /// Fired by the reader to update the UI on long operations.
    /// </summary>
    event EventHandler<ProgressChangedEventArgs> ProgressChanged;

    /// <summary>
    /// Gets a list of of MIME types the reader supports.
    /// </summary>
    ReadOnlyCollection<string> TypesSupported { get; }

    /// <summary>
    /// Loads a SampleSet from the given input stream.
    /// </summary>
    /// <param name="inStream">The stream to read the</param>
    /// <returns>A SampleSet read from the stream.</returns>
    SampleSet Load(Stream inStream);
}

Then in your plugin dll, you implement a class with the interface:

public sealed class WavReader : IReader
{
    ...
}

Then you load the DLL using reflection:

    private void LoadPlugins(string applicationPath)
    {
        if (!Directory.Exists(applicationPath))
            throw new ArgumentException("The path passed to LoadPlugins was not found.", "applicationPath");

        List<IPluginFactory> factoriesList = new List<IPluginFactory>();
        List<IReader> readersList = new List<IReader>();

        foreach (string assemblyFilename in Directory.GetFiles(applicationPath, "*.plugin"))
        {
            Assembly moduleAssembly = Assembly.LoadFile(Path.GetFullPath(assemblyFilename));

            foreach (Type type in moduleAssembly.GetTypes())
            {
                IPluginFactory instance = null;
                if (type.GetInterface("IPluginFactory") != null)
                    instance = (IPluginFactory)Activator.CreateInstance(type);
                if (instance != null)
                {
                    factoriesList.Add(instance);
                    switch (instance.PluginType)
                    {
                        case PluginType.Reader:
                            readersList.Add((IReader)instance.Create());
                            break;
                    }
                }
            }
        }

        this.readers = readersList.AsReadOnly();
    }

And BAM you have your plugins!

John Gietzen