Export and metadata
Declare the exit to explain the basic component output service and value. In some cases, export related information is required for various reasons. Generally, it is used to explain the performance of a public contract. This can effectively meet the requirements of allowing or restricting the egress, or importing all available implementations at that time and checking their running capabilities before using the egress.
Append metadata to exit
Think about our previous imessagesender service. Suppose we have some implementations, which are different from those of consumers. In our example, whether the message is running and whether the message is secure is important to the consumer (importer.
Use exportmetadataattribute
To add this information, you only need to use[System. componentmodel. Composition. exportmetadataattribute]:
public interface IMessageSender{ void Send(string message);}[Export(typeof(IMessageSender))][ExportMetadata("transport", "smtp")]public class EmailSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}[Export(typeof(IMessageSender))][ExportMetadata("transport", "smtp")][ExportMetadata("secure", null)]public class SecureEmailSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}[Export(typeof(IMessageSender))][ExportMetadata("transport", "phone_network")]public class SMSSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}
Use custom export attributes
To make it more restrictive than exportmetadataattribute, you need to create your own attributes and use[System. componentmodel. Composition. metadataattribute]Modification. In this example, we also derive from exportattribute, so creating a custom export attribute is also the specified metadata.
[MetadataAttribute][AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]public class MessageSenderAttribute : ExportAttribute{ public MessageSenderAttribute() : base(typeof(IMessageSender)) { } public MessageTransport Transport { get; set; } public bool IsSecure { get; set; }}public enum MessageTransport{ Undefined, Smtp, PhoneNetwork, Other}
In the preceding example, metadataattribute is applied to custom export attributes. The next step is to apply the attributes to imessagesender.
[MessageSender(Transport=MessageTransport.Smtp)]public class EmailSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}[MessageSender(Transport=MessageTransport.Smtp, IsSecure=true)]public class SecureEmailSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}[MessageSender(Transport=MessageTransport.PhoneNetwork)]public class SMSSender : IMessageSender{ public void Send(string message) { Console.WriteLine(message); }}
This is required by the egress. In the engine, MEF is still used as a dictionary, but this fact is invisible to you.
Note: You can also create metadata attributes that are not exported by yourself. You only need to create attributes modified by using metadataattributeattribute.
In these examples, metadata is added to the same Member of the exported custom metadata attribute.
Import metadata
The importer can access the metadata appended to the egress.
Use strong metadata
To access metadata in a strongly typed manner, use the defined interface to match read-only attributes (names and types) to create a metadata view. In our example, an interface is similar to the following:
public interface IMessageSenderCapabilities{ MessageTransport Transport { get; } bool IsSecure { get; }}
So you can start usingSystem. Lazy <t, tmetadata>Import. (T is the contract type, and tmetadata is the interface you created)
[Export]public class HttpServerHealthMonitor{ [ImportMany] public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; } public void SendNotification() { foreach(var sender in Senders) { if (sender.Metadata.Transport == MessageTransport.Smtp && sender.Metadata.IsSecure) { var messageSender = sender.Value; messageSender.Send("Server is fine"); break; } } }}
Use Weak metadata
To access metadata in a weak type, you useSystem. Lazy <t, tmetadata>Type import transmits idictionary <string, Object> metadata. Then you can access the metadata by using the metadata attribute of the dictionary.
Note: We recommend using a strongly typed method to access metadata. However, some systems need to dynamically access metadata, which is also allowed.
[Export]public class HttpServerHealthMonitor{ [ImportMany] public Lazy<IMessageSender, IDictionary<string,object>>[] Senders { get; set; } public void SendNotification() { foreach(var sender in Senders) { if (sender.Metadata.ContainsKey("Transport") && sender.Metadata["Transport"] == MessageTransport.Smtp && sender.Metadata.ContainsKey("Issecure") && Metadata["IsSecure"] == true) { var messageSender = sender.Value; messageSender.Send("Server is fine"); break; } } }}
Metadata filtering and default attribute values
When you select a metadata view, a hidden filter will trigger matching the egress of the metadata attributes defined in the view. You can use system. componentmodel. defaultvalueattribute in the metadata view to specify attributes that are not required. As you can see below, we have specified a default value of false for issecure. This means that a part exports imessagesender, but does not provide issecure metadata, but it still matches.
public interface IMessageSenderCapabilities{ MessageTransport Transport { get; } [DefaultValue(false)]; bool IsSecure { get; }}