Questions on MEF strategy and structure

那年仲夏 提交于 2020-01-03 17:31:06

问题


I am tasked with modularizing a C# app that is a rewrite of a very large Delphi app (the DB has 249 tables!). Business constraints proscribe a complete redesign for .NET and better overall architecture, so we are basically just incrementally rewriting module for module of the Delphi app in C#. Until finished, the suite will comprise a mixture of pending rewrites, and C# app modules I want to integrate using MEF.

The app concerns itself with Time-and-Attendance and Access-Control, and has diverse business areas like 'Employee Leave' and 'Visitors'. I think these should be separate projects, where we can swap out a rewritten C# project, and it will be imported into the MEF container. Each project will export an IBusinessArea, as a highest level definition, then these will export standard, shared interfaces like IService, that introduce the services available in a business area, like CreateEmployee. Each service will be a class, in order to standardise the interface of the service with the container, and contain service metadata, such as a Command for the service, data on who may use the service, etc.

Am I heading in the right direction, and if so, how do I store and expose IBusinessArea and IService metadata as classes, versus legions of untyped metadata attributes?


回答1:


So far, everything you say sounds reasonable to me. You modularize certain areas, define interfaces on different levels of abstraction and export each of your modules with different interfaces, i.e. each module will be registered as several interfaces it implements. You'll be able to resolve your modules according to the level of abstraction you require, get all services, all business areas, etc. So, in my opinion you are heading in the right direction.

How to deal with metadata? MEF provides exporting of metadata, which would appear to be a reasonable thing to use. Maybe I didn't get it entirely, but I have made really bad experiences with MEF metadata export. As far as I can recall, MEF stores metadata as key-value pairs, where the key is a string.

Even if you use the typed metadata export and usage functions, the metadata is not really typesafe. Say you have an interface 'IMetadata' with a property called 'PropertyA' and you register a type (lets call it Foo for the sake of creativity) which is decorated with an according attribute in a, what MEF calls typesafe, manner (metadata implementing IMetadata). Now suppose you have a second metadata interface 'IMetadataB' which also has a property called PropertyA. If you now request resolving Foo with metadata IMetadataB you'll get the instance you registered in the first place because MEF is satisfied with PropertyA being existent in the metadata key-value pairs and builds an according proxy metadata type which implements IMetadataB.

Long story short, maybe I'm being unfair to MEF, but I stopped using the MEF built in metadata support and would recommend you to do the same.

As I'm dealing with very complex and lengthy metadata, including kind of documentations of classes which I want to be tightly coupled to the classes I export, I developed a system which works really well for me, although it is a little bit unconventional:

Basically, I define an interface and a baseclass for my metadata, say MetadataBase with a string property called Description.

public class MetadataBase : IMetadata
{
    public string Description { get; set; }
}

Afterwards, for every class I want to have metadata for, I derive a class (FooMetadata) from this base class and define it partially in XAML. Then, in XAML, I define the class specific value of the property, for example:

<md:MetadataBase.Description>
    The description of my class goes here
</md:MetadataBase.Description>

With a custom attribute, I relate the metadata type to my actual class:

[Export(typeof(IFoo))]
[AssociatedMetadata(typeof(FooMetadata))]
public class Foo : IFoo
{
    // Whatever
}

An extension method for objects lets you read the metadata via reflection:

public static IMetadata GetMetadata(this object objectWithMetadata)
{
     // Read attribute type
     // Create instance of the metadata type, i.e. FooMetadata
     // A caching mechanism can be implemented, if needed, but, honestly,
     // my really big metadata objects including images and stuff like this
     // are created within 3-5 ms
     // Return this instance
}

Now, you're basically there, you can read the metadata of any object which has metadata like this:

var myObjectsMetadata = myObject.GetMetadata();

You can utilize this metadata in MEF when you make your AssociatedMetadataAttribute implement an interface and register your types with metadata of this interface. Nothing will get mixed up, because you have one type of metadata for everything which holds one property and nothing else (the type).

This solution is not the right way to go for everything, but I love it and your question is a good occasion to present it. Hope it helps!



来源:https://stackoverflow.com/questions/19131916/questions-on-mef-strategy-and-structure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!