Esta respuesta será específica para mi contenedor.
Nuestra aplicación actual necesita comenzar a soportar carga dinámica y "enganche" de diferentes "complementos"/"extensiones" que son desconocidos para la aplicación en tiempo de compilación.
Para poder hacer eso, debe definir algunas interfaces de extensión que coloca en una biblioteca de clases que se compartirá entre su aplicación y todos sus complementos.
Por ejemplo, si desea que sus aplicaciones para ser capaz de añadir material al menú de la aplicación se puede crear la siguiente interfaz:
class ApplicationMenu
{
// The "File" menu
IMenuItem File { get; }
}
interface IMenuRegistrar
{
void Register(ApplicationMenu menu);
}
Lo que significa que su plugin puede crear la siguiente clase:
[Component]
public class CoolPluginMenuRegistrar : IMenuRegistrar
{
public void Register(ApplicationMenu menu)
{
menu.File.Add("mnuMyPluginMenuName", "Load jokes");
}
}
Mi contenedor utiliza el atributo [Component]
para que pueda descubrir y registrar automáticamente las clases por usted.
Todo lo que necesita hacer para registrar a todos los puntos de extensión como la de arriba es la siguiente:
public class Program
{
public static void Main(string[] args)
{
var registrar = new ContainerRegistrar();
registrar.RegisterComponents(Lifetime.Transient, Environment.CurrentDirectory, "MyApp.Plugin.*.dll");
var container = registrar.Build();
// all extension points have been loaded. To load all menu extensions simply do something like:
var menu = GetMainMenu();
foreach (var registrar in container.ResolveAll<IMenuRegistrar>())
{
registrar.Register(menu);
}
}
}
Estas extensiones serían "enganchado" en diferentes áreas de la aplicación, tales como ADED como controladores de eventos de ciertas clases. Por lo que sé, los contenedores IoC permiten descubrir dinámicamente objetos en tiempo de ejecución y registrarlos en un contenedor.
Yep. Usted obtiene todo eso.
¿Es un contenedor IoC capaz de hacer este enganche en varios eventos para mí? ¿O es más fácil hacer esta tarea sin ese marco?
Sí. Obtuve un mecanismo de evento incorporado. Coloque las clases de eventos (clases .NET regulares en bibliotecas de clases compartidas). El simplemente suscribirse en ellos mediante la implementación de una interfaz:
[Component]
public class ReplyEmailNotification : ISubscriberOf<ReplyPosted>
{
ISmtpClient _client;
IUserQueries _userQueries;
public ReplyEmailNotification(ISmtpClient client, IUserQueries userQueries)
{
_client = client;
_userQueries = userQueries;
}
public void Invoke(ReplyPosted e)
{
var user = _userQueries.Get(e.PosterId);
_client.Send(new MailMessage(user.Email, "bla bla"));
}
}
y publicar eventos:
DomainEvent.Publish(new ReplyPosted(user.Id, "This is a subject"));
Los eventos pueden ser manejados por ningún plugin, siempre y cuando:
- puede acceder la clase de evento
- Se han registrado en el contenedor (
[Component]
o registro manual)
- Implementa
ISubscriberOf<T>
¿Es común que el propio plugin ofrece un método Registro para hacer el registro?
Yep. A través de diferentes interfaces que se definen como puntos de extensión en un conjunto compartido.
¿Debería hacer la inscripción el IoC? (¿cómo se hace eso generalmente?)
Sí. Si el contenedor lo proporciona.
¿Cómo se pueden definir fácilmente los puntos de extensión cuando se utiliza un contenedor IoC?
Usted puede leer sobre ello con más detalle aquí: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container
Con MEF, cada "parte" es una aplicación de alguna de las interfaces. Esto significa que para cada punto de extensibilidad, ¿debería crearse una nueva interfaz? Por ejemplo, tengo 3 eventos: OnA, OnB, OnC. ¿Cómo habilito los complementos para que se enganchen a estos eventos con MEF? (sin definir 3 interfaces diferentes). –
Realmente no entiendo la pregunta: si OnA, OnB y OnC están lógicamente asociados de tal manera que puedan formar parte de una interfaz única, conviértanla en una única interfaz. Si no están asociados, hágalos parte de interfaces separadas. ¿O he entendido mal tu pregunta? –
Quiero decir, si tengo muchos eventos diferentes en los que quiero registrarme dinámicamente, cada uno de ellos debe definir explícitamente que están importando una determinada interfaz. Esto significa que tengo que definir 3 interfaces diferentes (una para cada tipo de evento). Digamos que tengo 1 interfaz y 3 eventos importan esta implementación de interfaz. Los 3 eventos importarán todas las implementaciones, que no es lo que busco. –