320 likes | 512 Views
Rozszerzalna architektura. Rozszerzalna architektura -. Zagadnienia: Interfejsy Odkrywanie Komunikacja. Rozszerzalna architektura. MAF ( System.AddIn -s ) .NET v.3.5. Izolacja ( odddzielna AppDomain ), stosunkowo ciężki MEF .Net 4.0
E N D
Rozszerzalna architektura - Zagadnienia: • Interfejsy • Odkrywanie • Komunikacja
Rozszerzalna architektura • MAF (System.AddIn-s) • .NET v.3.5. • Izolacja (odddzielnaAppDomain), stosunkowociężki • MEF • .Net 4.0 • Discovery, obsługametadanych, opóźnionakreacja • IOC/DI Containers • Decoupling, testowanie, scentralizowanarejestracja,
MAF – System-addin • Odkrywanie (odkrywanie pluginow w czasie dzialania) • Aktywacja • Wersjonowanie • Izolacja (oddzielny AppDomain/proces) • Zarządzanie czasem życia • Piaskownica – (możliwośc okreslenia zestawu uprawnień) • wyładowywanie – (w rune-time)
MAF – System-addin • System.AddIn • System.AddIn.Contract • Klasy z System.AddIn.Hosting:AddInController, AddInEnvironment, AddInProcess,, AddInStore, AddInToken, InvalidPipelineStoreException, AddInSegmentDirectoryNotFoundException • Źródła: • MSDN • http://clraddins.codeplex.com/
MAF – kalkulator WPF Plugin: Visual Studio Pipeline Builder http://clraddins.codeplex.com/releases/view/9454
MAF – WPF calculator [System.AddIn.Pipeline.AddInContract] public interface ICalculatorContract : IContract { IListContract<IOperationContract> GetOperations(); double Operate(IOperationContract op, double[] operands); string GetName(); }
MAF – System-addin AddInStore.Rebuild(path); IList<AddInToken> tokens = AddInStore.FindAddIns(typeof(Calculator), path); foreach (AddInToken token in tokens) { addins.Add(token.Activate<IAddIn>(AddInSecurityLevel.Internet)); } addins[i].Operate(...);
MAF – pipeline builder - nazwy [assembly:PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.HostView, "MyApplica PipelineHints.PipelineSegment.HostView, PipelineHints.PipelineSegment.AddInView, PipelineHints.PipelineSegment.HostSideAdapter, PipelineHints.PipelineSegment.AddInSideAdapter
MEF • DI • Atrybuty • Discovery • Brak izolacji
MEF – Podstawowe pojęcia • Export • Export dlatypu/funkcji/pól • Wymuszonytyp: Export(typeof(Ixxx)) • Nazwanykontrakt: Export("name",typeof(Ixxx)) • Export nie jest dziedziczony – możnaużyćInheritedExport • Import • Dlatypuokreślonego w kodzie • Import określonegotypu/kontraktu
MEF – Zalecane praktyki • Imort/Eksport Interfejsów zamiast konkretnych typow • Stałe jako nazwy kontraktow • stale/i kontrakty w oddzielnych assembly
MEF – rozwiązywanie zależności • Polaimporowanesąinicjowanepokonstruktorzestądniemoznaichuzyc w konstruktorze • Rozwiazanie: • ImportingConstructornakonstruktorze (ciaglepotrzbne import naparametrach) • Przykonstruktorze - eksportowaneklasy/interfejsymuszabycpubliczne
MEF – export/import [Export] public class SomeComposablePart { ... } public class MessageSender { [Export(typeof(Action<string>))] public void Send(string message) {Console.WriteLine(message); } } public class Configuration { [Export("Timeout")] public int Timeout { get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); } } }
MEF – export/import class Program { [Import] public IMessageSender MessageSender { get; set; } } class Program { [ImportingConstructor] public Program(IMessageSender messageSender) { ... } } class Program { [Import] private IMessageSender _messageSender; }
MEF – tworzenie obiektu var catalog = new AssemblyCatalog(System.Reflection.Assembly .GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this);
MEF – liczebność (cardinality) 1 – domyślne podejście 0..1 [Import(AllowDefault=True)], 0..* [ImportMany] -> zwraca IEnumerable<interface>
MEF – nieobligatoryjny import [Export] public class OrderController { private ILogger _logger; [ImportingConstructor] public OrderController([Import(AllowDefault=true)] ILogger logger) { if(logger == null) logger = new DefaultLogger(); _logger = logger; } }
MEF – import kolekcji public class Notifier { [ImportMany(AllowRecomposition=true)] public IEnumerable<IMessageSender> Senders {get; set;} public void Notify(string message) { foreach(IMessageSender sender in Senders) { sender.Send(message); } } }
MEF – opóźniony import Pozwalanietworzycnieużywanych (jeszcze?) obiektów GetGetExport<>(), GetExports(), GetExports<>() Zwracają: • Lazy<T> • Lazy<T,Metadata> • Value • IsValueCreated • Meadata
MEF – opóźniony import [Export] public class HttpServerHealthMonitor { [Import] public Lazy<IMessageSender> Sender { get; set; }
MEF – metadane • Mogązostaćodczytane I przetworzoneprzedutworzeniemobiektu • Metadane -> ExportMetada • Dictionary<String,obiect> • Silnietypowane, oparte o interfejsy Metadanemożnawykorzystaćnp do • wyświeleniainformacji o nieutworzonychobiektach • Podjęciadecyzjiczytworzyćdaneobiekty
MEF – filtrowanie var catalog = new AssemblyCatalog(typeof(Program).Assembly); var parent = new CompositionContainer(catalog); var filteredCat = new FilteredCatalog(catalog, def => def.Metadata.ContainsKey("scope") && def.Metadata["scope"].ToString() == "webrequest"); var perRequest = new CompositionContainer(filteredCat, parent); var controller = perRequest.GetExportedObject<HomeController>(); perRequest.Dispose();
MEF – rekompozycja Możliwa jest zmiana skomponowanych obiektów w rune-time. Nie dziala to przy wstrzykiwaniu przez konstruktor Wymaga zezwolenia Import(RecompositionAllowed=true) Można miejscowo zablokowac przez SatisfyImportOnce...
MEF – czas życia Shared = singleton Release – uwalnianie elementu var batchProcessorExport = container.GetExport<IBatchProcessor>(); var batchProcessor = batchProcessorExport.Value; batchProcessor.Process(); container.ReleaseExport(batchProcessorExport);
MEF – diagnostyka Command window: The mefx Command-Line Analysis Tool
MEF – Typowe problemy Liczebność skojarzeń (cardinality) Katalogi, maska, ignorowanie części Niedopasowanie kontraktów – zbyt ogólne/szegółowe Brak eksportów Warto wlaczyc tracing w konf. (std. .NET)