İngilizce dilinde oku

Aracılığıyla paylaş


Managed Extensibility Framework (MEF)

Bu konu başlığında, Managed Extensibility Framework 4. bölümde tanıtıldı olan .NET Framework yer velanmıştır.

MEF nedir?

Managed Extensibility Framework veya MEF, basit ve genişletilebilir uygulamalar oluşturmaya yönelik bir kitaplıktır. Uygulama geliştiricilerinin yapılandırmaya gerek yoktur uzantılarını bulmalarını ve kullanmalarını sağlar. Ayrıca uzantı geliştiricilerinin kodu kolayca kapsüllemesine ve hassas sabit bağımlılıklardan kaçınmaya da olanak sağlar. MEF, uzantıların yalnızca uygulamalar içinde değil uygulamalar arasında da yeniden kullanılmasına izin verir.

Genişletilebilirlik sorunu

Imagine genişletilebilirlik için destek sağlamaları gereken büyük bir uygulamanın mimarı olduğunu kabul ediyorum. Uygulamanın çok sayıda daha küçük bileşen içermesi gerekir ve bunları oluşturmak ve çalıştırma sorumluluğundadır.

Soruna en basit yaklaşım, bileşenleri uygulamanıza kaynak kod olarak eklemek ve doğrudan kodunuzdan çağırarak yapmaktır. Bunun bir dizi belirgin dezavantajı vardır. En önemlisi, bir Web uygulamasında kabul edilebilir ancak istemci uygulamasında çalışılamaz olan bir kısıtlama olan kaynak kodu değiştirmeden yeni bileşenler ekilemez. Aynı derecede sorunludur; üçüncü taraflarca geliştirilene ve aynı nedenle sizin bileşenlerinize erişmelerine izin veremeyen bileşenler için kaynak koduna erişiminiz olamaz.

Biraz daha karmaşık bir yaklaşım, uygulama ve bileşenleri arasında bir farka izin sağlamak için bir uzantı noktası veya arabirim sağlamaktır. Bu model altında, bir bileşenin uygulay olabileceği bir arabirim ve uygulamanıza etkileşim kurmasını sağlamak için bir API sebilirsiniz. Bu, kaynak kodu erişimi gerektirme sorununu çözer, ancak yine de kendi güçlükleri vardır.

Uygulama, bileşenleri kendi başına bulmak için herhangi bir kapasiteye sahip olmadığı için, hangi bileşenlerin kullanılabilir olduğu ve yükleniyor olması gerektiği açıkça açık bir şekilde açık bir şekilde anlatılamalı. Bu genellikle kullanılabilir bileşenleri bir yapılandırma dosyasına açıkça kaydederek yapılandırmasını gerçekleştirebilirsiniz. Bu, bileşenlerin doğru olduğunu kabul etmek, özellikle de güncelleştirmeyi yapmaları beklenen geliştirici değil son kullanıcıysa bakım sorununa neden olur.

Ayrıca, uygulamanın katı olarak tanımlanmış kanalları dışında bileşenler birbirleriyle iletişim kuramaz. Uygulama mimarı belirli bir iletişim ihtiyacıyla ilgili bir tahminde yoksa, bu genellikle imkansızdır.

Son olarak, bileşen geliştiricilerin hangi derlemenin uygulayacakları arabirimi içerdiğine sıkı bir bağımlılığı kabul etmeleri gerekir. Bu, bir bileşenin birden fazla uygulamada kullanılmalarını zorlaştırarak bileşenler için bir test çerçevesi oluşturmanızı da zorlaştırabilirsiniz.

MEF neler sağlar?

MEF, kullanılabilir bileşenlerin bu açık kaydı yerine, bunları bileşim aracılığıyla örtülü olarak bulmanın bir yolunu sağlar. Parça olarak adlandırılan MEF bileşeni, hem bağımlılıklarını (içeri aktarmalar olarak bilinir) hem de hangi özellikleri (dışarı aktarmalar olarak bilinir) kullanılabilir olduğunu bildirimli olarak belirtir. Bir parça oluşturulduğunda, MEF bileşim altyapısı diğer parçalardan kullanılabilenlerle içeri aktarmalarını karşılar.

Bu yaklaşım, önceki bölümde ele alınacak sorunları çözer. MEF parçaları, yeteneklerini bildirimli olarak belirterek çalışma zamanında keşfedilebilir. Bu da uygulamanın sabit kodlu başvurular veya hassas yapılandırma dosyaları olmadan parçaları kullanabileceği anlamına gelir. MEF, uygulamaların meta verilerine göre parçaları bulmalarına ve incelemelerine, hatta derlemelerini yüklemelerine gerek kalmadan bunları bulmalarına ve incelemelerine olanak sağlar. Sonuç olarak uzantıların ne zaman ve nasıl yük olacağını dikkatli bir şekilde belirtmenize gerek yoktur.

Bir parça, sağlanan dışarı aktarmalara ek olarak, diğer parçalar tarafından doldurulacak olan içeri aktarmalarını da belirterek. Bu, parçalar arasındaki iletişimi yalnızca mümkün değil, kolay bir şekilde sağlar ve kodun iyi çarpanlara iner. Örneğin, birçok bileşende ortak olan hizmetler ayrı bir bölüme alınarak kolayca değiştirilebilir veya değiştirilebilir.

MEF modeli, belirli bir uygulama derlemesi üzerinde sabit bağımlılık gerekmeyy olduğundan, uzantıların uygulamada yeniden kullanılmasına olanak sağlar. Bu, uzantı bileşenlerini test etmek için, uygulamadan bağımsız bir test donanımı geliştirmeyi de kolaylaştırır.

MEF kullanılarak yazılan genişletilebilir bir uygulama, uzantı bileşenleri tarafından doldurulan bir içeri aktarma bildirebilir ve uygulama hizmetlerini uzantılara göstermek için dışarı aktarmalar da bildirebilir. Her uzantı bileşeni bir dışarı aktarma bildirer ve içeri aktarmaları da bildirebilirsiniz. Bu şekilde uzantı bileşenleri otomatik olarak genişletilebilir.

MEF'nin kullanılabilir olduğu yer

MEF, .NET Framework 4'.NET Framework parçasıdır ve her .NET Framework kullanılabilir. MEF'i ister Windows Forms, WPF, ister başka bir teknoloji ya da kaynak kullanan sunucu uygulamalarında kullanın, istemci uygulamalarınız için ASP.NET.

MEF ve MAF

Önceki sürümler .NET Framework uygulamaların uzantıları yalıtıp yönetmesine olanak sağlayacak şekilde tasarlanmış Yönetilen Eklenti Çerçevesi'ne (MAF) ekti. MAF'nin odak noktası MEF'den biraz daha yüksek düzeydedir ve uzantı yalıtımına ve derleme yükleme ve kaldırmaya odaklanırken MEF'nin odak noktası keşfedebilirlik, genişletilebilirlik ve taşınabilirliktir. İki çerçeve sorunsuz bir şekilde birlikte çalışır ve tek bir uygulama her iki durumdan da faydalanabilirsiniz.

SimpleCalculator: Örnek bir uygulama

MEF'nin neler yapalarını görmenin en basit yolu basit bir MEF uygulaması oluşturmaktır. Bu örnekte SimpleCalculator adlı çok basit bir hesap makinesi kurabilirsiniz. SimpleCalculator'ın amacı, "5+3" veya "6-2" şeklinde temel aritmetik komutları kabul eden ve doğru yanıtları döndüren bir konsol uygulaması oluşturmaktır. MEF kullanarak, uygulama kodunu değiştirmeden yeni işleçler ekabileceksiniz.

Bu örneğin tam kodunu indirmek için bkz. SimpleCalculator örneği (Visual Basic).

Not

SimpleCalculator'ın amacı, kullanımı için gerçekçi bir senaryo sağlamak yerine MEF kavramlarını ve söz dizimlerini göstermektir. MEF'nin gücünden en çok yararlanabilecek uygulamaların çoğu SimpleCalculator'dan daha karmaşıktır. Daha kapsamlı örnekler için bkz. Managed Extensibility Framework GitHub.

  • Başlamak için, Visual Studio konsol uygulaması projesi oluşturun ve olarak ad girinSimpleCalculator.

  • MEF'nin bulunduğu System.ComponentModel.Composition derlemeye bir başvuru ekleyin.

  • Module1.vb veyaProgram.cs'yi açın ve ve Imports için veya using deyimleri System.ComponentModel.Composition ekleyinSystem.ComponentModel.Composition.Hosting. Bu iki ad alanı, genişletilebilir bir uygulama geliştirmek için ihtiyacınız olacak MEF türlerini içerir.

  • Anahtar sözcüğünü Visual Basic modülünü Public bildiren satıra Module1 ekleyin.

Kapsayıcı ve katalog oluşturma

MEF oluşturma modelinin çekirdeği, kullanılabilir tüm parçaları içeren ve bileşimi gerçekleştiren bileşim kapsayıcısıdır. Bileşim, dışarı aktarmalara yapılan içeri aktarmaların eşleşmesidir. En yaygın bileşim kapsayıcısı türü olan CompositionContainerbu kapsayıcıyı SimpleCalculator için kullanabilirsiniz.

Visual Basic kullanıyorsanız Module1.vb içinde adlıProgram bir genel sınıf ekleyin.

Module1.vb veya ProgramProgram.cs'de sınıfına aşağıdaki satırı ekleyin:

private CompositionContainer _container;

Bileşim kapsayıcıları, kullanılabilir olan parçaları bulmak için katalog kullanır. Katalog, bir kaynaktan bulunan parçaları kullanılabilir yapan bir nesnedir. MEF, sağlanan tür, derleme veya dizinden parçaları bulmak için kataloglar sağlar. Uygulama geliştiricileri, Web hizmeti gibi diğer kaynaklardan parçaları bulmak için kolayca yeni kataloglar oluşturabilir.

Sınıfına aşağıdaki oluşturucu ekleyin Program :

private Program()
{
    try
    {
        // An aggregate catalog that combines multiple catalogs.
        var catalog = new AggregateCatalog();
        // Adds all the parts found in the same assembly as the Program class.
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

        // Create the CompositionContainer with the parts in the catalog.
        _container = new CompositionContainer(catalog);
        _container.ComposeParts(this);
    }
    catch (CompositionException compositionException)
    {
        Console.WriteLine(compositionException.ToString());
    }
}

çağrısı, ComposeParts bileşim kapsayıcısını belirli bir parça kümesi (bu örnekte geçerli örneği) oluşturmasını söyler Program. Ancak bu noktada hiçbir şey olmaz çünkü doldurulacak Program içeri aktarma yoktur.

Öznitelikleri olan İçeri ve Dışarı Aktarmalar

İlk olarak, bir hesaplayıcıyı Program içeri aktarın. Bu, içine gidecek konsol girişi ve çıkışı Programgibi kullanıcı arabirimi endişelerinin hesaplayıcı mantığından ayrılmasına olanak sağlar.

Sınıfına aşağıdaki kodu Program ekleyin:

[Import(typeof(ICalculator))]
public ICalculator calculator;

Nesnenin bildiriminin olağan dışı calculator olmadığını, ancak özniteliğiyle birlikte dekore edilmiş olduğunu fark ImportAttribute edersiniz. Bu öznitelik bir şeyi içeri aktarma olarak bildiriyor; diğer bir ifadeyle, nesne ed-ed-yken bileşim altyapısı tarafından doldurulur.

Her içeri aktarmada hangi dışarı aktarmalarla eşleneceklerini belirleyen bir anlaşma vardır. Sözleşme açıkça belirtilen bir dize olabilir veya mef tarafından belirli bir türden (bu durumda arabirimi) otomatik olarak oluşturulacaktır ICalculator. Eşleşen bir sözleşmeyle bildirilen tüm dışarı aktarmalar bu içeri aktarmayı karşılar. nesnesinin türü aslında calculator iken bu gerekli ICalculatordeğildir. Anlaşma, içeri aktarma nesnesinin türünden bağımsızdır. (Bu durumda, 'i dışarıda bırakın typeof(ICalculator). MEF, sözleşmenin açıkça belirtmedikçe otomatik olarak içeri aktarma türüne bağlı olduğunu varsayacaktır.)

Bu çok basit arabirimi modüle veya ad alanına SimpleCalculator ekleyin:

public interface ICalculator
{
    string Calculate(string input);
}

Tanımlandığına göre ICalculator, bunu uygulayan bir sınıfa ihtiyacınız vardır. Aşağıdaki sınıfı modüle veya ad alanına SimpleCalculator ekleyin:

[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{

}

içinde içeri aktarmayla eş olacak dışarı aktarma işlemi şu şekildedir Program. Dışarı aktarmanın içeri aktarmayla eşleşmesi için dışarı aktarmanın aynı sözleşmeye sahip olması gerekir. Sözleşmeye dayalı olarak dışarı aktarma typeof(MySimpleCalculator) işlemi bir eşleşmeye neden olur ve içeri aktarma doldurulmaz; sözleşmenin tam olarak eşleşmesi gerekir.

Bileşim kapsayıcısı bu derlemede bulunan tüm parçalarla doldurulduğundan parça MySimpleCalculator kullanılabilir olur. oluşturucusu nesne Program üzerinde oluşturma işlemi Program gerçekleştirecek olduğunda, içeri aktarması MySimpleCalculator bu amaç için oluşturulacak bir nesnesiyle doldurulur.

Kullanıcı arabirimi katmanının (Program) başka bir şey bilmek zorunda değildir. Bu nedenle, kullanıcı arabirimi mantığının geri kalanını yönteminde doldurabilirsiniz Main .

Main yöntemine aşağıdaki kodu ekleyin:

static void Main(string[] args)
{
    // Composition is performed in the constructor.
    var p = new Program();
    Console.WriteLine("Enter Command:");
    while (true)
    {
        string s = Console.ReadLine();
        Console.WriteLine(p.calculator.Calculate(s));
    }
}

Bu kod, bir giriş satırını okur ve sonuç üzerinde öğesine çağrı CalculateICalculator yaparak konsola geri yazar. Bu, ihtiyacınız olan tüm kodlarda Program bulunur. Çalışmanın tüm geri kalanı parçalar halinde olur.

Alınanlar ve ImportMany öznitelikleri

SimpleCalculator 'ın Genişletilebilir olması için, işlem listesini içeri aktarması gerekir. Sıradan ImportAttribute bir öznitelik bir ve yalnızca bir ExportAttribute ile doldurulur. Birden fazla kullanılabilir varsa, bileşim altyapısı bir hata üretir. Herhangi bir sayıda dışarı aktarma tarafından doldurulabilecek bir içeri aktarma oluşturmak için, özniteliğini kullanabilirsiniz ImportManyAttribute .

Sınıfına aşağıdaki Operations özelliğini MySimpleCalculator ekleyin:

[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;

Lazy<T,TMetadata> , dışarı aktarmalar için dolaylı başvuruları tutmak üzere MEF tarafından sağlanmış bir türdür. Burada dışa aktarılmış nesnenin kendisinin yanı sıra dışarı aktarma meta verileriniveya dışarı aktarılmış nesneyi açıklayan bilgileri de alırsınız. Her biri Lazy<T,TMetadata> , gerçek bir işlemi temsil eden bir nesne ve meta verilerini temsil eden bir IOperationData nesnesi içerir IOperation .

Aşağıdaki basit arabirimleri modüle veya SimpleCalculator ad alanına ekleyin:

public interface IOperation
{
     int Operate(int left, int right);
}

public interface IOperationData
{
    char Symbol { get; }
}

Bu durumda, her bir işlemin meta verileri +,-, * gibi bir işlemi temsil eden simgedir. Ek işlemi kullanılabilir hale getirmek için modüle veya SimpleCalculator ad alanına aşağıdaki sınıfı ekleyin:

[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add: IOperation
{
    public int Operate(int left, int right)
    {
        return left + right;
    }
}

ExportAttributeÖzniteliği daha önce olduğu gibi çalışır. ExportMetadataAttributeÖzniteliği, meta verileri bir ad-değer çifti biçiminde bu dışarı aktarmaya iliştirir. AddSınıf uyguladığı IOperation sırada, uygulayan IOperationData bir sınıf açıkça tanımlanmamıştır. Bunun yerine, bir sınıf, belirtilen meta verilerin adlarına göre özellikler ile MEF tarafından örtülü olarak oluşturulur. (Bu, MEF 'teki meta verilere erişmenin çeşitli yöntemlerinden biridir.)

MEF 'te birleşim özyinelemeli. ProgramAçık olan nesneyi, türü MySimpleCalculator olması için bir ICalculator tanesi içeri aktardınız. MySimpleCalculator, sırasıyla bir nesne koleksiyonu IOperation içeri aktarır ve içeri aktarma işlemi oluşturulduğunda, içeri aktarmaların Program aynı anda doldurulur MySimpleCalculator . AddSınıf daha fazla içeri aktarma bildirmişse, bunun da doldurulması gerekir. Doldurulmamış herhangi bir içeri aktarma işlemi bir bileşim hatası ile sonuçlanır. (Ancak, içeri aktarmaları isteğe bağlı olarak bildirmek veya varsayılan değerleri atamak mümkündür.)

Hesaplayıcı mantığı

Bu parçalar yerinde olduğunda, her şey Hesaplayıcı mantığının kendisidir. Yöntemini uygulamak Calculate için aşağıdaki kodu MySimpleCalculator sınıfına ekleyin:

public String Calculate(string input)
{
    int left;
    int right;
    char operation;
    // Finds the operator.
    int fn = FindFirstNonDigit(input);
    if (fn < 0) return "Could not parse command.";

    try
    {
        // Separate out the operands.
        left = int.Parse(input.Substring(0, fn));
        right = int.Parse(input.Substring(fn + 1));
    }
    catch
    {
        return "Could not parse command.";
    }

    operation = input[fn];

    foreach (Lazy<IOperation, IOperationData> i in operations)
    {
        if (i.Metadata.Symbol.Equals(operation))
        {
            return i.Value.Operate(left, right).ToString();
        }
    }
    return "Operation Not Found!";
}

İlk adımlar, giriş dizesini sol ve sağ işlenenler ve bir işleç karakteri olarak ayrıştırır. foreachDöngüde, koleksiyonun her üyesi operations incelenir. Bu nesneler türündedir Lazy<T,TMetadata> ve meta veri değerlerine ve aktarılmış nesnesine sırasıyla özelliği ve Value özelliği ile Metadata erişilebilir. Bu durumda Symbol , nesnesinin özelliği IOperationData bir eşleşme olarak bulunursa, hesaplayıcı nesnenin yöntemini IOperation çağırır Operate ve sonucu döndürür.

Hesaplayıcıyı tamamlayabilmeniz için bir dizedeki ilk basamak olmayan karakterin konumunu döndüren bir yardımcı yöntemi de gereklidir. Sınıfına aşağıdaki yardımcı yöntemi MySimpleCalculator ekleyin:

private int FindFirstNonDigit(string s)
{
    for (int i = 0; i < s.Length; i++)
    {
        if (!char.IsDigit(s[i])) return i;
    }
    return -1;
}

Artık projeyi derleyip çalıştırabilmelisiniz. Visual Basic, anahtar sözcüğünü öğesine Module1 eklediğinizden emin Public olun. Konsol penceresinde, "5 + 3" gibi bir ek işlem yazın ve Hesaplayıcı sonuçları döndürür. Başka herhangi bir operatör "Işlem bulunamadı!" iletisi ile sonuçlanır.

Yeni bir sınıf kullanarak SimpleCalculator 'ı genişletme

Hesap Makinası artık işe yarar, yeni bir işlem eklemek kolaydır. Aşağıdaki sınıfı modüle veya SimpleCalculator ad alanına ekleyin:

[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : IOperation
{
    public int Operate(int left, int right)
    {
        return left - right;
    }
}

Projeyi derleyin ve çalıştırın. "5-3" gibi bir çıkarma işlemi yazın. Hesaplayıcı artık çıkarma ve ekleme de desteklemektedir.

Yeni bir derleme kullanarak SimpleCalculator 'ı genişletme

Kaynak koda sınıflar eklemek yeterince basittir, ancak MEF, bir uygulamanın parçalar için kendi kaynağını göz atabilme olanağı sağlar. Bunu göstermek için, SimpleCalculator ' ı, bir dizini ve kendi derlemesini, parçaları için bir ekleyerek bir DirectoryCatalog Dizin arayacak şekilde değiştirmeniz gerekir.

SimpleCalculator projesine adlı Extensions Yeni bir dizin ekleyin. Çözüm düzeyinde değil, proje düzeyine eklediğinizden emin olun. Ardından adlı ExtendedOperations çözüme yeni bir sınıf kitaplığı projesi ekleyin. Yeni proje ayrı bir derlemede derlenir.

extendedoperations projesi için Project özellikler tasarımcısını açın ve derle veya derle sekmesine tıklayın. derleme çıkış yolunu veya çıkış yolunu , SimpleCalculator proje dizinindeki (..) uzantıları dizinine işaret etmek üzere değiştirin. \Simplehesaplator\extensions\).

Module1. vb veya program. cs' de, oluşturucuya aşağıdaki satırı Program ekleyin:

catalog.Catalogs.Add(
    new DirectoryCatalog(
        "C:\\SimpleCalculator\\SimpleCalculator\\Extensions"));

Örnek yolu, uzantılar dizininizin yolunu ile değiştirin. (Bu mutlak yol yalnızca hata ayıklama amaçlıdır. Bir üretim uygulamasında göreli bir yol kullanırsınız.) Artık, DirectoryCatalog Uzantılar dizinindeki tüm derlemelerde bulunan herhangi bir parçayı bileşim kapsayıcısına ekler.

ExtendedOperations projesinde, SimpleCalculator ve System. ComponentModel. Composition başvurularını ekleyin. ExtendedOperations sınıf dosyasında, System. ComponentModel. Composition için bir Imports veya bir using ifade ekleyin. Visual Basic ayrıca, SimpleCalculator için bir Imports ifade ekleyin. Ardından, aşağıdaki sınıfı ExtendedOperations sınıf dosyasına ekleyin:

[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '%')]
public class Mod : SimpleCalculator.IOperation
{
    public int Operate(int left, int right)
    {
        return left % right;
    }
}

Sözleşmenin eşleşmesi için özniteliğinin ile ExportAttribute aynı türde ImportAttribute olması gerektiğini unutmayın.

Projeyi derleyin ve çalıştırın. Yeni mod (%) işlecini test edin.

Sonuç

Bu konu, MEF 'in temel kavramlarını ele almaktadır.

  • Parçalar, kataloglar ve bileşim kapsayıcısı

    Parçalar ve bileşim kapsayıcısı, MEF uygulamasının temel yapı taşlarıdır. Bir bölüm, kendisini içeren veya dahil olmak üzere bir değeri içeri aktaran veya dışarı aktaran herhangi bir nesnedir. Bir katalog, belirli bir kaynaktan bir parçalar koleksiyonu sağlar. Bileşim kapsayıcısı, bir katalog tarafından, dışarı aktarmalar için içeri aktarmalar bağlamayı bağlayan bir katalog tarafından sunulan bölümleri kullanır.

  • İçeri aktarmalar ve dışarı aktarmalar

    İçeri ve dışarı aktarmalar, bileşenlerin iletişim kurduğu yoldur. İçeri aktarma ile, bileşen belirli bir değer veya nesne için ihtiyacı belirtir ve bir dışarı aktarma ile bir değerin kullanılabilirliğini belirtir. Her içeri aktarma, sözleşmesi yoluyla dışarı aktarmalar listesi ile eşleştirilir.

Sonraki adımlar

Bu örneğe ilişkin tüm kodu indirmek için bkz. SimpleCalculator örneği (Visual Basic).

daha fazla bilgi ve kod örneği için bkz. Managed Extensibility Framework. MEF türlerinin bir listesi için bkz System.ComponentModel.Composition . ad alanı.