Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat is a good way to compose parts that aren't imported by the class performing composition?
    primarykey
    data
    text
    <p>I have an ASP.NET MVC application which uses MEF to implement a plugin framework. Plugins are separate DLLs that exist in the application's bin directory. Plugins usually export one or more controllers like this...</p> <pre><code>&lt;Export(GetType(IController))&gt; &lt;MYAPP_Interfaces.Attributes.MVCPluginMetadata( "SomePlugin", "A Description for the plugin", "A Readable Name", {"ScriptsForThePlugin.js"}, {"StylesForThePlugin.css"}, Enumerations.MVCPluginType.DataView, "DefaultActionName")&gt; &lt;PartCreationPolicy(CreationPolicy.NonShared)&gt; Public Class MyPluginController Inherits System.Web.Mvc.Controller &lt;Import()&gt; Private m_objHost As IWebHost </code></pre> <p>... and so on.</p> <p>This all works fine, the host app includes all controllers in an <code>ImportMany</code> property, and composes itself upon creation in the usual way. So <code>m_objHost</code> is populated automagically and the controller has access to all the things the host application provides, like logging and information about the user and what they're currently working on and all that.</p> <p>My question has to do with my models, and any DAL or utility classes that I have in a plugin. These classes usually have need of information from the <code>IWebHost</code> object. However, the host doesn't need to know about these classes, so they are not included in composition. Since they are not composed, if they want an <code>IWebHost</code> reference they each have to compose themselves upon instantiation, like this:</p> <pre><code>Public Class MyModel &lt;Import()&gt; Private m_objHost As IWebHost &lt;Import()&gt; Private m_objLog As ILog Public Sub New() Compose() End Sub ... Private Sub Compose() Try Dim objCatalog As New AggregateCatalog objCatalog.Catalogs.Add(New DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory &amp; "bin")) Dim container As New CompositionContainer(objCatalog) container.ComposeParts(Me) Catch ex As Exception If m_objLog IsNot Nothing Then m_objLog.writeError(ex) End If End Try End Sub End Class </code></pre> <p>So my main question can be broken into two parts:</p> <ol> <li><p>Is there any noticeable performance problem with having, say, 20 or so classes that perform composition whenever they are instantiated? I currently only have a few, and if there is a hit it's not noticeable. <strong>In other words, do I actually need to change this strategy?</strong> It violates DRY because I have a <code>Compose</code> method in every class, but I can learn to live with it.</p></li> <li><p><strong>Is there a better way?</strong> How can I handle a single composition in the main application that takes care of populating all of the classes in the plugins, including those not imported in the class performing the main composition?</p></li> </ol> <p>I've considered the following:</p> <ul> <li><p>Having all models and utility classes and whatever implement a marker interface, export them all using that interface as a contract, and importing them in the host class, even though the host class doesn't need them. I think this is an even cruddier design than what I have, and I don't want to do it. I'm willing to listen to arguments in favor of this, though.</p></li> <li><p>Having a class in each plugin that needs it that implements <code>IWebHost</code> that acts as a wrapper for the class exported by the main app. I'd still have to do composition in each plugin, but at least it would only be once per plugin. This one seems okay to me.</p></li> </ul> <p>Thanks in advance for any help you can give, and for reading this whole novel of a question.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload