Dieser Artikel wurde maschinell übersetzt.

Multi-Plattformentwicklung

Portable Klassenbibliotheken: Eine Einführung

Bill Kratochvil

Downloaden des Codebeispiels

Ein Projekt tragbaren Class Library (PCL) generiert eine verwaltete Assembly, die von Windows Phone 7, Silverlight, die Microsoft verwiesen werden kann.NET Framework und Xbox 360-Plattformen. Wiederverwendung von Code zu maximieren Sie können und reduzieren die Anzahl der erforderlichen Projekte, insbesondere in Multi-bezogene Anwendungen, die die gleiche Codebasis zu teilen, wie im Fall der Demo-Anwendung, die diesen Artikel begleitet. Ich investierte Zeit in eine Windows Phone 7-Anwendung für diesen Artikel geschrieben, und die WPF/Silverlight-Anwendungen kostenlos kam. Die einzige Einschränkung ist, dass der PCL-Plattform-spezifische Projekte verweisen kann. Es kann nur andere PCL-Projekte verweisen. Auf der Oberfläche scheint dies begrenzen, insbesondere für Anwendungen, die Prisma und Abhängigkeitsinjektion (DI) nutzen. Aber bei sorgfältiger Planung können Sie diese Einschränkung zu umgehen und erstellen Sie effiziente PCL-Projekte, die gute Entwicklung Practices durchzusetzen.

Vor dem PCL-Projekte konnte Lösung Projekte nur auf der gleichen Plattform Assemblys verweisen. Silverlight-Projekte auf anderen Silverlight-Assemblys verwiesen.NET-Projekten andere.NET-Assemblys und so weiter. Um effektiv code, sammeln wir konnte eine unüberschaubare Anzahl von Projekten; Beim Erstellen von freigegebenen codebases (Code, der auf allen Plattformen verwendet werden kann), hätten wir ein Projekt für jede Plattform erstellen.

Eine Lösung für Multi-bezogene Kennwort-Manager

Der Kennwort-Manager-Lösung (passwordmgr.codeplex.com) ist eine Multi-bezogene Anwendung mit einer einzigen Codebase (gehostet von Windows Phone 7 Projekte mit Verknüpfungen zu den Telefon-Projektdateien Silverlight und WPF-Projekte). Wie Sie sehen können, hat diese kleine Anwendung eine große Anzahl von Projekten.

Warum Projekte so viele? Das ist eine beliebte Frage, die ich oft von Entwicklern hören, wie ich Frameworks für Client-Lösungen Architekt. Eine typische Refrain ist, "sie machen die Lösung verwirrend und schwer zu verstehen," das ist ein gutes Argument.

Meine Antwort ist immer: "haben eine klare Trennung von Bereichen und Wiederverwendung zu maximieren.” Jedes Projekt sollte haben einen bestimmten Zweck (und auch in einer lose gekoppelten Weise zu tun). Beachten Sie als ein Beispiel dafür die scheinbare Trennung in die PasswordMgr-Lösung und die Möglichkeit, eine unterschiedliche Datenzugriffsebene (DAL) DI mit problemlos ersetzen zur Verfügung. Trotzdem würden Sie gezwungen werden, in den SQLite Assemblys und zugehörige Projekte zum Wiederverwendung dieses Codes zu ziehen, auch wenn Sie nicht über die Verwendung von SQLite (vielleicht würden Sie SQL Server für Ihre DAL verwenden).

Sobald Sie ein anderes Projekt verweisen, kann das Projekt eng gekoppelt werden zwingt Sie, nicht nur, sondern auch alle Abhängigkeiten, die es hat, die zu anderen Projekten zu ziehen. Wenn Sie nur wenige Projekte haben, macht es zunehmend schwieriger, die Wiederverwendung von Code in anderen Lösungen.

Ein PCL kann reduziert die Anzahl der Projekte müssen Sie verwalten, insbesondere, wenn Sie haben eine klare Trennung von Bereichen erlaubt Ihnen, Ihre Projekte in anderen Modulen oder Lösungen problemlos wiederverwenden möchten. Der Schlüssel ist, Ihre Projekte lose durch Programmieren mit Schnittstellen zu halten. So ermöglichen Sie verwenden, DI-Frameworks, wie z. B. die verwaltete Erweiterbarkeit Framework (MEF) und die Einheit, die Sie einfach die Implementierung für die Schnittstellen konfigurieren können. Das heißt, konnte die DAL-Implementierung für Schnittstellen SQL Server, die Cloud oder SQLite Klassen sein.

Nach der Installation der erforderlichen Komponenten (wie beschrieben in der MSDN-Dokumentation unter bit.ly/fxatk0), müssen Sie ein neues Feature unter "Neues Projekt hinzufügen", erstellen Sie einen PCL.

Mithilfe der DI-Frameworks

Eine Frage, die schnell entstehen, wie Sie versuchen, diese leistungsstarke DI-Frameworks ist, verwenden "wie verwende ich die PCL mit dieser Frameworks Wenn ich DI Framework-Komponenten verweisen kann – d. h., die [Beziehung] oder [Exportieren] Attribute?" SecurityViewModel im folgenden Codebeispiel hat beispielsweise eine Einheit [Beziehung]-Attribut, das die Implementierung der ISecurityViewModel aufgelöst werden:

namespace MsdnDemo.MvpVmViewModels
{
  public class SecurityViewModel : PresentationViewModelBase
  {
    [Dependency]
    public ISecurityViewModel UserInfo { get; set; }

    public bool IsAuthenticated
    {
      get { return UserInfo.IsAuthenticated; }
      set
      {
        UserInfo.IsAuthenticated = value;
        OnPropertyChanged("IsAuthenticated");

        if(value)
        {
          IsAdmin = UserInfo.IsInRole("Admin");
          IsGuest = UserInfo.IsInRole("Guest");
        }
      }
    }
  }
}

Da Sie nur andere PCL-Projekte verweisen können, mag es scheinen nicht praktikabel ist, verwenden einen PCL mit DI oder andere freigegebenen Ressourcen, die Sie in wiederverwendbaren Bibliotheken haben. In der Realität, diese Einschränkung kann wirklich helfen eine klare Trennung von Bedenken, machen Ihre Projekte noch wiederverwendbare erzwingen – Sie müssen möglicherweise in Zukunft Projekte, die DI wird nicht nutzen, aber das PCL-Projekt profitieren könnte.

Die Prinzipien bei DI mithilfe einer Demoanwendung mit dem PCL vorgestellt werden. Es ist eine einfache Anwendung, die zwei Module (Gast und main) verfügt, die nach Bedarf geladen mithilfe der rollenbasierten Sicherheit sind. Verfügbaren Features für diese Module und Ansichten werden bestimmt durch die Rollen-Modul und angemeldeten Benutzer zugeordnet. There are three users: Admin, Guest and Jane Doe (user). Eine Geschäftsregel ist, dass das Gastkonto nie das Hauptmodul zugreifen kann.

Die Magie dieser Anwendung liegt in seiner Einfachheit; kein Codebehind finden Sie in den Ansichten oder Domänenobjekte verschmutzt von UI-Anforderungen. Die ViewModels UI-spezifischen Status beibehalten, und der Vortragende verwalten Ansichten/ViewModels, ihre Bedenken über die Verwendung von Geschäftslogik und DALs zugeordnet. Sanitärinstallation erfolgt über die Infrastruktur, z. B. auf eine Schaltfläche, entlastet die Entwickler von Geschäftslogik konzentrieren. Entwickler, die zu einer Anwendung lernen, wo Sie beginnen, suchen Code schnell – beginnen immer mit dem Vortragenden.

Eng gekoppelten Komponenten

Nur enge Kopplung wird angezeigt, Abbildung 1. Diese Kopplung ist mit dem Model-View-Presenter-ViewModel (MVPVM)-Muster mit Prisma und DI zu erwarten. Mit diesem Muster ist das Modul verantwortlich für die Instanziierung der Presenter, die wiederum die erforderlichen Ansicht und wählen, die sie als erforderliche Verdrahtung instanziiert. Die Module und deren Komponenten haben keine Kenntnis von den anderen.

Tightly Coupled Components

Abbildung 1 eng gekoppelter Komponenten

Im Idealfall würde ich separate Projekte für jedes Modul (ApplicationController, Main und Gast) erstellen, damit ich diese Module (mit diesem Rahmen) in anderen Projektmappen wiederverwenden kann. (Hinweis: Because both the GuestPresenter and MainPresenter share the MainViewModel, I’d also have to move this ViewModel into a shared project that could be accessed by both of them. Sie können sehen wie schnell ich Projekte im Namen der Trennung Bedenken und Wiederverwendbarkeit, sammeln, insbesondere, wenn ich wurden die Codierung für mehrere Plattformen.) Sie werden auch sehen, dass, da ich mein Demo einfach gehalten, die einzige Wiederverwendbarkeit bietet es kopieren und einfügen. Der Schlüssel ist das Gleichgewicht finden, und der PCL hilft, bieten.

Abbildung 2 wird veranschaulicht, wie alle Ebenen (Presentation, Business und Daten) Freigabe-PCL-Ressourcen. Da Sicherheit mit nahezu jeder Anwendung ein Anliegen ist, ich kann problemlos integrieren – mit seinen Elementen – in UC0100, die meine PCL, mit der Vorstellung, dass es nur wieder verwendbare Komponente sein kann, die diese Demoanwendung hat (und eine nützliche noch dazu) sein.

All Layers and Shared PCL Resources

Abbildung 2 Alle Ebenen und freigegebene PCL-Ressourcen

Es ist nicht zum Gegenstand dieses Artikels, um alle Aspekte der PCL abdecken, die ich mit meiner Infrastruktur verwalten; Allerdings werde ich die Anwendungsfälle in Blau hervorgehoben Abbildung 3.

PCL Use Cases

Abbildung 3 PCL-Anwendungsbeispiele

UC0100-020 Base Anwendungsfall

Um die Erweiterbarkeit in Enterprise-Anwendungen zu verbessern, ist es hilfreich, einen konsistenten Standard für die Verkabelung der Plattform haben. Dies hilft, neue Entwickler als auch für erfahrene Entwickler, die kein Modul für eine Weile besucht haben können. Sie werden können schnell Rampe bis zu erforderliche Aufgaben durchgeführt; minimaler Zeit wird Jagd nach Code ausgegeben werden. Vor diesem Hintergrund, die ich erstellt eine ModuleBase, die Arbeit mit dem Prisma IModule-Schnittstelle entwickelt wurde – genauer gesagt, mit der Initialize-Methode. Hier das Problem war, dass IModule nicht verfügbar war, da es in einer Assembly Prisma (einen nicht-PCL) befindet. Ich wollte die Base Protokollierungsfunktionen, haben so die ILogger-Schnittstelle eine Instanz bereitgestellt werden muss, bevor die Initialize-Methode aufgerufen wird. Dieses ModuleBase kann dienen nun als Vertrag für alle Module in allen Projektmappen und Projekte, da die IModule Initialize-Methode implementiert in dargestellten Abbildung 4.

Abbildung 4 die Initialize-Methode in der ModuleBase-Klasse

public class ModuleBase
{
  public ILogger Logger { get; set; }

  /// <summary>
  /// Called by Prism catalog manager.
Provides hook 
  /// to register types/views and initialize the view model.
/// </summary>
  public virtual void Initialize()
  {
    try
    {
      // Provide hooks for registrations
      RegisterTypes();
      RegisterViews();

      InitializeModule();
    }
    catch (Exception ex)
    {
      Logger.Log("ERROR in [{0}] {1}{2}", 
        GetType().Name, ex.Message, ex.StackTrace);
    }
  }

Im Gegensatz zu den PCL hat mein MsdnDemo.Phone-Projekt einen plattformspezifischen Verweis auf Mein Assembly Prisma so DI-Code in einer PresentationModuleBase-Klasse in diesem Projekt befinden kann; Es wird die Basisklasse für alle Module sein. In einer realen Anwendung würden diese Klasse, wie andere DI Basisklassen in separaten wiederverwendbare Projekte befinden.

Wenn das Modul (instanziiert), vom Container DI aufgelöst wird, wird der Logger festgelegt werden wie durch meine GwnBootstrapper konfiguriert. Wenn der Wert der Logger-Eigenschaft festgelegt ist, wird die Instanz auf Basis-Logger, effektiv bereitstellen ModuleBase-ILogger-Referenz für die Initialize (und andere) virtuelle Methoden übergeben (siehe Abbildung 5).

Abbildung 5 Festlegen der Logger-Eigenschaft

public class PresentationModuleBase : ModuleBase, IModule
{
  [Dependency]
  public override ILogger Logger {get;set;}

  [Dependency]
  public IUnityContainer Container { get; set; }

  [Dependency]
  public IRegionManager RegionManager { get; set; }

  [Dependency]
  public IEventAggregator EventAggregator { get; set; }

  [Dependency]
  public IRegionViewRegistry RegionViewRegistry { get; set; }

(Hinweis: Da Konstruktor Injektion vor Setter-Injektion tritt – im Rahmen Einheit – der Konstruktor des ModuleBase sind keine Logging-Anweisungen, da es null sein wird.)

Abgeleitet von PresentationModuleBase, ist der folgende Code für die MainModule die gleichen/Codedatei für alle drei Plattformen (Windows Phone 7, Silverlight und WPF):

public class MainModule : PresentationModuleBase
{
  protected override void RegisterViews()
  {
    base.RegisterViews(); 

    // Instantiate the presenter, which in turn will instantiate
    // (resolve) the View and ViewModel
    var presenter = Container.Resolve<MainPresenter>();

    // Load this presenters view into the MainRegion
    RegionViewRegistry
      .RegisterViewWithRegion(MvpVm.MainRegion, () => presenter.View);

    // Activate the presenters view after module is loaded
    RaiseViewEvent(MvpVm.MainModule, presenter.View.GetType().Name,      
      ProcessType.ActivateView);
  }
}

UC0200-050 Entitäten Anwendungsfall

Mithilfe von Plain Old CLR-Objekte (POCOs) bietet die beste Wiederverwendbarkeit. Obwohl die PCL INotifyPropertyChanged unterstützt, kann ich nicht immer diese Entitäten mit XAML verwenden. Ich möchte auch mit ASP verwenden.NET MVC-3-Projekt oder Entity Framework. Damit meine UserEntity und SecurityEntity-Objekte auf Unternehmensebene POCO Klassen, die in jeder Anwendung auf jeder Plattform problemlos wiederverwendet werden können wie in dargestellt werden können Abbildung 6.

Abbildung 6 die UserEntity und SecurityEntity-Objekte

public class UserEntity 
{
  public int Id { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string PrimaryEmail { get; set; }
  public string Password { get; set; }
  public override string ToString()
  {
    return string.Format("{0} {1} ({2})", FirstName, LastName, Password);
  }
}

public class SecurityEntity : ISecurityViewModel
{
  private string _login;
  public int Id { get; set; }
  public bool IsAuthenticated { get; set; }
  public IEnumerable<string> Roles { get; set; }

  public string Login
  {
    get { return _login; }
    set 
    { 
      _login = value;
      Id = 0;
      IsAuthenticated = false;
      Roles = new List<string>();
    }
  }

  public bool IsInRole(string roleName)
  {
    if (Roles == null)
      return false;
     
    return Roles.FirstOrDefault(r => r == roleName) != null;
  }

  public bool IsInRole(string[] roles)
  {
    return roles.Any(role => IsInRole(role));
  }
}

Wenn POCO UserEntity auf ein ViewModel verwendet werden soll, müssen diese umbrochen werden. Das ViewModel werden die Benachrichtigungen auslösen und hinter den Kulissen werden die Daten auf POCO, übertragen werden, wie dargestellt in den Auszug aus der MainViewModel-Klasse in Abbildung 7.

Abbildung 7 Übertragen von Daten in die POCO

public UserEntity SelectedUser
{
  get { return _selectedUser; }
  set
  {
    _selectedUser = value;

    OnPropertyChanged("SelectedUser");
    OnPropertyChanged("FirstName");
    OnPropertyChanged("LastName");
    OnPropertyChanged("Password");
    OnPropertyChanged("PrimaryEmail");
  }
}

public string FirstName
{
  get { return _selectedUser.FirstName; }
  set
  {
    _selectedUser.FirstName = value;
    OnPropertyChanged("FirstName");
  }
}

Beachten Sie, dass ich nur die FirstName-Eigenschaft zeigen, aber alle UserEntity Eigenschaften eine vergleichbare Wrapper haben. Wenn SelectedUser aktualisiert werden, wird die Eigenschaft geändert-Benachrichtigung für alle UserEntity-Eigenschaften so, dass XAML soll, zum Aktualisieren der UI-Felder als zutreffend benachrichtigt werden ausgelöst.

Anwendungsbeispiel für UC0100-060-Ereignisse

Ereignisaggregation, eine Funktion der Prisma, bietet die Möglichkeit, lose Paar Anwendungen und bietet gleichzeitig eine hervorragende Möglichkeit zur Kommunikation zwischen entkoppelte Komponenten. Dies geschieht, indem jede Komponente einfach Ereignisse ohne Wissen der Teilnehmer zu veröffentlichen. Ebenso können Komponenten Ereignisse abonnieren und Antworten ohne Kenntnis des Verlegers zu behandeln.

Einige würde argumentieren, dass ereignisaggregation Code schwer wird zu folgen, aber mit der richtigen Protokollierung es tatsächlich das Gegenteil ist. Angenommen, ich verfügen über eine Dropdown-Liste in einem anderen Modul den Benutzer ermöglicht, die Währung für finanzielle Werte zu wechseln. Eine Komponente, die, der ich arbeite, ist diese Einstellung abhängig und wird zum Berechnen des Wertes für eine ViewModel-Eigenschaft verwendet, und es gibt zwischen meine und die Komponente mit der Drop-Down-Liste logische Ebenen vielleicht (auch in einem separaten Modul). Wenn dieser Wert ändert, und Meine Komponente nicht benachrichtigt, wäre es leichter zu Debuggen mithilfe von ereignisaggregation als zur Ablaufverfolgung durch alle der möglichen Wege der Logik der Pfad (oder mehrere Pfade) mit anderen Mitteln abgeschlossen. With event aggregation, there are only two points to debug: the subscriber and publisher. Wenn ich angemeldet beide (wie die Demoanwendung), es ein Problem auf einem single Point of Failure verengt.

Prisma-Ereignis hat aufgrund der Abhängigkeiten auf das Prisma-CompositePresentationEvent im MsdnDemo.Phone-Projekt befinden. Es kann nicht als solche in der PCL befinden:

public class MessageEvent : CompositePresentationEvent<MessageEventArgs>
{
}

EventArgs, auf dem die Ereignisse Abhängigkeiten haben, werden auch von der PCL bedient, weil ich einen gemeinsamen Satz von Ereignisargumenten können – das wird in zahlreichen Enterpriseanwendungen verwendet werden – darin. Abbildung 8 zeigt die MessageEventArgs, die von der vorherigen MessageEvent behandelt wird.

Abbildung 8 der MessageEventArgs behandelt, indem die MessageEvent

public class MessageEventArgs : EventArgs
{
  public object Sender { get; set; }
  public Enum Type { get; set; }
  public string Message { get; set; }
  public bool IsError { get; set; }
  public bool IsInvalid { get; set; }
  public int StatusCode { get; set; }
  public int ErrorCode { get; set; }
  private Exception _exception;
  public Exception Exception
  {
    get { return _exception; }
    set
    {
      _exception = value;
      IsError = true;
    }
  }
}

UC0100-100 MvpVmBase-Anwendungsfall

Der höchste Vorteil der Wiederverwendung von Code ist Zuverlässigkeit; Es ist sehr wahrscheinlich, wie im Falle der MsdnDemo.Phone-Anwendung, dass Komponententests ein Großteil der Funktionalität der Code überprüft werden. Dies, kombiniert mit der Zeit im Feld, stabile, wiederverwendbaren Code führt. Dies wird erhöhter Geschwindigkeit und Zuverlässigkeit für Ihre Teammitglieder bereitzustellen, besonders wenn sie es für eine neue Anforderungen wiederzuverwenden. Weitere Vorteile sind, dass der Code leichter wird zu arbeiten, neue Features die globalen Vorteile haben können und Verkabelung, bis eine neue Anwendung innerhalb weniger Stunden passieren kann. Sie erstellen einfach die Ansichten, ViewModels und Vortragende (Anwendung anwendbar Schnittstellen), und das neue Modul kann ausgeführt werden und.

In der Anwendung MsdnDemo.Phone muss die PresentationPresenterBase (Basisklasse Presenter) einfach gesendet werden, die Ansicht und wählen, die von den Vortragenden verwendet werden. Beachten Sie, wie beide Vortragende denselben ViewModel in Teilen in Abbildung 9.

MsdnDemo.Phone Presenters

Abbildung 9 MsdnDemo.Phone Vortragende

Die PresentationPresenterBase leitet sich von MvpVmPresenter, eine Klasse in Meine PCL, die als einen Vertrag für alle freigegebenen Moderatoren und ihre ViewModels über meine Unternehmensanwendungen dienen wird. Der Code wird dargestellt, Abbildung 10.

Abbildung 10 der PresentationPresenterBase

public class MvpVmPresenter<TView,TViewModel> 
  : IMvpVmPresenter
    where TView: IView
    where TViewModel : IMvpVmViewModel
{

  public IShell Shell { get; set; }
  public TView View { get; set; }
  public TViewModel ViewModel { get; set; }

  /// <summary>
  /// Called when the view is activated (by Application controller)
  /// </summary>
  public virtual void ViewActivated(ViewEventArgs e){}
}

Wie bei ILogger, die weiter oben in der PresentationModuleBase-Klasse verwiesen, werde ich haben Wrappen von ILogger in ähnlicher Weise (übergeben die Instanz auf der Basis) sowie die Shell, Ansicht und wählen, da diese via DI injiziert werden.

PresentationPresenterBase, wie die PresentationModuleBase haben die Verantwortung für alle DI-Dienstleistungen zu behandeln, da es sich um Verweise auf das Prisma und Einheit plattformspezifische Assemblys hat. Laufe des Prozesses kann mehr Verantwortung in ihren Basisklassen in der PCL verschoben werden.

Beachten Sie, dass in Abbildung 11, wenn der DI-Container das angegebene ViewModel (TViewModel), löst die Bindungen für die ButtonCommand wird auf ViewModel (Zeile 99) festgelegt. Dies ermöglicht den Vortragenden, behandeln alle Klicks auf Schaltflächen über die ExecuteButtonCommandHandler in Zeile 56 in Abbildung 9.

The Presenter Base Class

Abbildung 11 die Presenter-Basisklasse

Die Vortragenden auf eine Schaltfläche, im Vergleich zu den ViewModels zu behandeln ist einer der vielen Vorteile, die "alten Day" Architekten aus der Präsentation-Modell- und das Application-Modell-Muster, das Model-View-Presenter-Muster weiterentwickelt inspiriert.

ViewModels freigegeben werden können, wie mit der MainViewModel der Fall ist und jeden Presenter die MainViewModel auf unterschiedliche Weise anhand ihrer Anforderungen verwenden kann. Ich hatte verschoben, dass in der ViewModel auf die Schaltfläche klickt, würde musste ich bedingte Anweisungen verwenden, die in der Zeit würde Codeumfang verursachen und erfordern Regressionstests, wie der neuer Code Logik für Module beeinflussen könnten, die nicht im Entwicklungszyklus. Halten, Ansichten und ViewModels ermöglicht für ihre maximale Wiederverwendung von Geschäftslogik sauber.

Zusammenfassung

Der PCL kann reduziert die Anzahl der Projekte, die für Multi-bezogene Anwendungen benötigt werden, während Aufträge für Enterprise-Anwendungen bereitstellen. Die Einschränkung nicht in der Lage, nicht-PCL-Verweisassemblys eignet sich für eine bessere Programmierpraktiken, aktivieren Projekte haben eine klare Trennung von Bereichen. Kombinieren diese Vorteile der PCL mit DI maximiert die Möglichkeit, entkoppelte Projekten wiederverwenden, die getestet wurden mit Zeit (und Komponententests verfügbar), erhöhen die Skalierbarkeit, Erweiterbarkeit und die Geschwindigkeit Ihres Teams in neue Aufgaben.

Bill Kratochvil , unabhängiger Auftragnehmer, ist ein Lead Technologist und Architekt für ein Elite-Team von Entwicklern, die für eine vertrauliche Projekt für ein führendes Unternehmen im medizinischen Bereich arbeiten. Seine eigene Firma, globale Webnet LLC basiert in Amarillo, Texas.

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Christina Helton und David Kean