2010-04-29 19 views
22

¿Cuáles son algunas de las mejores prácticas para usar MEF en su código? ¿Hay algún inconveniente que tener en cuenta al iniciar su aplicación extensible? ¿Te encontraste con algo que deberías haber sabido antes?¿Qué son las mejores prácticas de MEF?

Respuesta

7

estoy en medio de la construcción de una aplicación extensible de pleno derecho en el MEF (y usando WPF con el patrón MVVM) . Tomé el marco de aplicación básico que construí y lo abrí como SoapBox Core. También publiqué una demostración basada en SoapBox Core en Code Project: Building an Extensible Application with MEF, WPF, and MVVM.

No estoy seguro de si el uso de MVVM se aplica a usted, pero si lo hace, entonces puede aprender mucho al observar la implementación de MVVM con MEF. Particularmente la forma en que importa Vistas.

En cuanto a las mejores prácticas ... Creé una jerarquía de extensiones anidadas (por lo que el módulo básico se llama Host, y todo lo que hace es componer la aplicación e importar algunas extensiones básicas). Luego, esas extensiones exponen otros puntos de extensión y el tipo de aplicación se construye cuando lo ejecuta (un cruce entre la composición y las extensiones).

Para mantener todo correcto, puse la jerarquía de extensiones en un conjunto de clases estáticas. Por ejemplo, aquí están todos los puntos de extensión que el marco básico proporciona:

namespace SoapBox.Core.ExtensionPoints 
{ 
    public static class Host 
    { 
     public const string Styles = "ExtensionPoints.Host.Styles"; 
     public const string Views = "ExtensionPoints.Host.Views"; 
     public const string StartupCommands = "ExtensionPoints.Host.StartupCommands"; 
     public const string ShutdownCommands = "ExtensionPoints.Host.ShutdownCommands"; 
    } 
    public static class Workbench 
    { 
     public const string ToolBars = "ExtensionPoints.Workbench.ToolBars"; 
     public const string StatusBar = "ExtensionPoints.Workbench.StatusBar"; 
     public const string Pads = "ExtensionPoints.Workbench.Pads"; 
     public const string Documents = "ExtensionPoints.Workbench.Documents"; 

     public static class MainMenu 
     { 
      public const string Self = "ExtensionPoints.Workbench.MainMenu"; 
      public const string FileMenu = "ExtensionPoints.Workbench.MainMenu.FileMenu"; 
      public const string EditMenu = "ExtensionPoints.Workbench.MainMenu.EditMenu"; 
      public const string ViewMenu = "ExtensionPoints.Workbench.MainMenu.ViewMenu"; 
      public const string ToolsMenu = "ExtensionPoints.Workbench.MainMenu.ToolsMenu"; 
      public const string WindowMenu = "ExtensionPoints.Workbench.MainMenu.WindowMenu"; 
      public const string HelpMenu = "ExtensionPoints.Workbench.MainMenu.HelpMenu"; 
     } 
    } 

    public static class Options 
    { 
     public static class OptionsDialog 
     { 
      public const string OptionsItems = "ExtensionPoints.Options.OptionsDialog.OptionsItems"; 
     } 
    } 
} 

Así que si quería su extensión para añadir algo al menú archivo, que le exportar algo que IMenuItem implementa con el nombre de contrato SoapBox.Core. ExtensionPoints.Workbench.MainMenu.FileMenu

Cada extensión tiene una "ID" que es solo un identificador de cadena. Estos identificadores existentes se definen en otra jerarquía:

namespace SoapBox.Core.Extensions 
{ 
    public static class Workbench 
    { 
     public static class MainMenu 
     { 
      public const string File = "File"; 
      public const string Edit = "Edit"; 
      public const string View = "View"; 
      public const string Tools = "Tools"; 
      public const string Window = "Window"; 
      public const string Help = "Help"; 

      public static class FileMenu 
      { 
       public const string Exit = "Exit"; 
      } 

      public static class ViewMenu 
      { 
       public const string ToolBars = "ToolBars"; 
      } 

      public static class ToolsMenu 
      { 
       public const string Options = "Options"; 
      } 
     } 
    } 
} 

Como se puede ver FileMenu ya contiene una extensión de salida (que viene programada para cerrar la aplicación). Si desea agregar una extensión al menú Archivo, probablemente desee que aparezca antes del elemento del menú Salir. IMenuItem hereda de IExtension, que tiene dos propiedades:

  • InsertRelativeToID
  • BeforeOrAfter

Por lo que su extensión volvería SoapBox.Core.Extensions.Workbench.MainMenu.FileMenu.Exit para InsertRelativeToID, y me return Before para la propiedad BeforeOrAfter (una enumeración). Cuando el banco de trabajo importa todas las extensiones del menú Archivo, ordena todo según estos ID. De esta forma, las extensiones posteriores se insertan en relación con las extensiones existentes.

6

la mejor práctica es utilizar el modelo Compartido (singleton). Esto nos lleva a consideraciones de diseño que sugieren que debe diseñar sus partes exportables como apátridas y seguras para la ejecución de subprocesos, para que no se vean afectadas por múltiples llamadas (tal vez en diferentes subprocesos) en la misma instancia.

En los casos en que el modelo singleton no sea adecuado para usted, se recomienda utilizar un patrón de generador (para separar la parte exportada de la instanciación real). Debe recordar que el uso del modelo no compartido es bastante costoso porque usa la reflexión para la instanciación real (al usar el patrón del generador puede obtener el mismo resultado con menos dolor).

También busque aquí http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-toc.aspx Y de cource usted sabe que usted puede encontrar información aquí: http://mef.codeplex.com

2

Todavía soy nuevo en el MEF, pero quería agregar más a esta discusión porque continuamente paso por un infierno al tratar de descubrir por qué las cosas no funcionan de la manera que esperaba.

En primer lugar, cuando trabaje con MEF, le recomiendo que agregue System.ComponentModel.Composition a su solución, en lugar de solo agregar referencias a los ensamblajes. Si bien los problemas de depuración en MEF se sienten como una pesadilla recursiva, es absolutamente inevitable y vital cuando no se puede descubrir qué está pasando mal.

Esto me lleva a mi siguiente punto, que es nunca, nunca olvidar que MEF no sabe lo que usted no lo dice, o si no lo dice correctamente. Por ejemplo, mi aplicación alfa funcionaba muy bien con MEF. Hice que compusiera partes en la GUI principal, y todos los ensamblajes que fueron cargados por el contenedor (que eran dependencias de la aplicación principal) exportaron las interfaces necesarias. Las cosas funcionaron bien y pude lograr que MEF resolviera las instancias en el momento y en el lugar que yo deseaba.

Sin embargo, recién comencé a trabajar en la próxima versión; algunos complementos cargados (aquellos que exportaron una interfaz, pero no tenían requisitos de importación), mientras que otros no (los que sí necesitaban importar). Esta vez compuse partes en mi clase ApplianceManager, que está a cargo de cargar complementos, pero los complementos necesarios para resolver las importaciones desde otras clases en la aplicación (en mi caso, el Modelo). Pensé que esto debería suceder automáticamente, especialmente porque puedo ver en la construcción del catálogo que esos ensamblajes fueron detectados ... pero todavía no puedo hacer que funcione ... lo que me lleva de regreso a mi primer punto: agregar la fuente código, y no solo las asambleas. La depuración de esto casi me está volviendo loco, pero eventualmente lo resolveré después de una gran cantidad de pasos diligentes a través del código MEF. :)

Me gustaría ver a alguien publicar una respuesta a esta pregunta que habla de arquitecturas que facilitan la integración MEF fácil. La respuesta con respecto a los menús de la barra de herramientas es muy buena, pero me gustaría ver algo que se refiera a cosas que residen completamente en el lado del Modelo de MVVM. Por ejemplo, cómo se deben organizar los administradores de complementos, las bases de datos, los complementos y las bibliotecas compartidas. Todavía estoy tratando de descubrir por qué estaba bastante bien hacer que mi primera aplicación MEF funcione, pero después de obtener más "experiencia" con ella, no puedo hacer que mi nueva aplicación funcione al 100%.

ACTUALIZACIÓN 2010-06-09

me gustaría añadir otra posible la práctica para ayudar a navegar a través de los arbustos MEF. Hoy, necesitaba hacer un control de la cordura en ese proyecto que "no podía entender", así que preparé un diagrama de clase UML no convencional, donde usé dependencias para marcar Importaciones y Exportaciones. Esto es lo que encontré, que dejó el tema muy claro.

aplicación de trabajo: alt text

aplicación No trabajo: alt text

no es tan estúpido? El Modelo no estaba cargado, y estaba en una isla por sí mismo. I crea esta es la razón por la que mis dependencias basadas en MEF no se resuelven (si alguien puede corregirme si me equivoco aquí, ¡lo agradecería!)

+2

Sus imágenes están rotas. –

+0

Uf ... Debo haber borrado algunas imágenes de mi cuenta. Tendré que buscar los originales. Gracias por hacérmelo saber. – Dave

Cuestiones relacionadas