Dieser Artikel wurde maschinell übersetzt.

OData und AtomPub

Erstellen eines AtomPub-Servers mit WCF Data Services

Chris Sells

Downloaden des Codebeispiels

Wenn Sie nicht vertraut sind, ist das Open Data Protocol (OData) eine Sache von Vorteil. OData (beschrieben in Details odata.org-) Builds auf HTTP-basierte Anpassungsgüte des Atom für die Veröffentlichung von Daten; AtomPub zum Erstellen, aktualisieren und Löschen von Daten; und Microsoft Entity Data Model (EDM) zum Definieren der Typen von Daten.

Haben Sie einen JavaScript-Client können Sie die Daten abrufen Back direkt in JSON anstelle von Atom-Format, und wenn Sie etwas anderes haben – wie z. B. Excel, Microsoft .NET Framework, PHP, AJAX – Clientbibliotheken für OData Anforderungen bilden und Nutzung von OData Antworten sind. Wenn Sie .NET Framework auf dem Server verwenden, bietet Microsoft auch einen leicht zu bedienenden Bibliothek mit dem Namen WCF Data Services zum Verfügbarmachen von .NET Framework-Typen oder Datenbanken, die durch Microsoft Entity Framework als OData Datenquellen unterstützt. Dies erleichtert es, HTTP und standardbasierte Weise Ihre Daten über das Internet verfügbar zu machen.

Müssen andererseits alle, sind einige Dinge, die Sie mit OData tun können, die nicht sehr Teil der Out-of-Box-Erfahrung, wie vorhandene Atom und AtomPub-basierten Lesern und Schreibern OData integrieren. Das ist, was wir experimentieren.

Simple-Blog

Stellen Sie sich z. B. let’s vor, die habe ich eine einfache Blogging-System erstellen (und sogar basiert diese Arbeit auf mich das Content Management-System auf sellsbrothers.com neu schreiben zu müssen). Ich bin ein großer Fan der Modell-First-Unterstützung in Visual Studio 2010, damit ASP.NET MVC-2.0-Projekt erstellte hinzugefügt, ein ADO.NET EDM-Datei MyBlogDB.edmx aufgerufen und eine Entität Post angeordnet sind, wie in der Abbildung 1 .

A nach Entität erstellt in Visual Studio 2010

Abbildung 1 A nach Entität erstellt in Visual Studio 2010

Komplizierter Blogging-Software wird sich mehr Daten verfolgen möchten, aber die Felder im Abbildung 1 sind die Grundlagen. Wenn ich auf der Designeroberfläche, selbst Generieren von Datenbankmodell, die SQL-Datei, die für mich (in diesem Fall MyBlogDB.sql) erstellt wird, zeigt auswählen und die SQL-Anweisung, die zum Erstellen der Datenbank generiert wird. Klicken Sie auf "Fertig stellen" SQL-Datei erstellen und die Datenbank an die Entitäten in der EDM-Designer erstellten binden. Abbildung 2 die wichtige Bits die SQL-Anweisung angezeigt.

Abbildung 2 der SQL-Code aus “ Datenbank aus Modell generieren ”

...
USE [MyBlogDB];
GO
...
-- Dropping existing tables
IF OBJECT_ID(N'[dbo].[Posts]', 'U') IS NOT NULL
    DROP TABLE [dbo].[Posts];
GO
...
-- Creating table 'Posts'
CREATE TABLE [dbo].[Posts] (
    [Id] int IDENTITY(1,1) NOT NULL,
    [Title] nvarchar(max)  NOT NULL,
    [PublishDate] datetime  NULL,
    [Content] nvarchar(max)  NOT NULL
);
GO
...
-- Creating primary key on [Id] in table 'Posts'
ALTER TABLE [dbo].[Posts]
ADD CONSTRAINT [PK_Posts]
    PRIMARY KEY CLUSTERED ([Id] ASC);
GO

Wir sind im Grunde einfach erstellen eine einzelne Tabelle aus unserer Einheit, wie erwartet, und SQL-Typen der Felder zuordnen. Beachten Sie, dass die PublishDate auf NULL, festgelegt ist, die nicht Standard ist. Ich habe mich entschieden explizit die Einstellung in der EDM-Designer, da ich wollte es nicht mit OK ein Veröffentlichungsdatum (einige Tools nicht standardmäßig angegeben), um.

Diese SQL ausführen und die Datenbank erstellen ist nur eine Frage von mit der rechten Maustaste auf die SQL-Anweisung im Text-Editor von Visual Studio und SQL ausführen auswählen. Es werden für die Verbindungsinformationen und den Datenbanknamen gefragt. Da es sich um eine neue Datenbank handelt, sollten Sie geben Sie den neuen Namen, z. B. MyBlogDB, und klicken Sie auf OK, um Sie bei der Aufforderung zu erstellen. Wenn die Datenbank erstellt wurde, können Sie ihn im Server-Explorer unter der Verbindung durchsuchen, die Visual Studio einfach für Sie erstellt hat.

Damit testen zu vereinfachen, können Sie die Daten direkt in der Tabelle hinzufügen, indem Sie mit der rechten Maustaste auf Beiträge und Tabellendaten anzeigen, die ein wenig Raster, Ihnen als in Abbildung 3 .

das Datenblatt anzeigen Tabelle formatiert die einfachere testen

Abbildung 3 das Datenblatt anzeigen Tabelle formatiert die einfachere testen

Er nicht das beste Bearbeitung Erfahrung in der ganzen Welt, aber es ist besser als SQL-Anweisungen schreiben, bis wir eine Bearbeitung End-to-End-Lösung, Einrichten gefunden haben und ausführen (es stammt – lesen lassen!).

Jetzt, da wir einige Daten haben, können wir tun, ein bisschen von ASP.NET Codierung, um ihn anzeigen, indem Sie HomeController.cs (Weitere Informationen zu MVC asp.net/mvc/-lesen) aktualisieren:

...
namespace ODataBloggingSample.Controllers {
  [HandleError]
  public class HomeController : Controller {
    MyBlogDBContainer blogDB = new MyBlogDBContainer();

    public ActionResult Index() {
      return View(blogDB.Posts);
    }

    public ActionResult About() {
      return View();
    }
  }
}

Hier alle ich war erstellen eine Instanz der MyBlogDBContainer-Klasse, die obersten Ebene ObjectContext abgeleitete Klasse Zugriff aus, damit wir unsere MyBlogDB.edmx-Datei erstellt ist unsere neue Datenbank. (Wenn Sie nicht mit Entity Framework vertraut sind, sollten Sie sein: msdn.com/data/aa937723-Siehe.) Wenn die Index-Methode der HomeController-Klasse aufgerufen wird, fordert jemand die Homepage der unsere neue Webanwendung, welche möchten wir unsere neue Blogbeiträge anzeigen, sodass wir die Auflistung Beiträge aus der Datenbank in eine Instanz der Ansicht Home/Index.aspx weiterleiten, die wir geändert haben wie folgt:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewPage<IEnumerable<ODataBloggingSample.Post>>" %>

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <% foreach (var post in Model) { %>
      <h1><%= post.Title %></h1>
      <div><%= post.Content %></div>
      <p><i>Posted <%= post.PublishDate %></i></p>
    <% } %>
</asp:Content>

Hier wurde die Basisklasse für eine Auflistung vom Typ Post (zusammen mit der Klasse MyBlogDBContainer) zum Modellieren von unseren Beiträge Tabelle generiert werden geändert. Es ersetzt auch die Homepage, die Inhalt mit einer Foreach-Anweisung zum Anzeigen jedes nach Titel, Inhalt und Veröffentlichungsdatum.

Das ist alles, die was wir brauchen. Wenn wir nun das Projekt ausführen (Debuggen | Debuggen starten), startet des Browsers und der Blogbeiträge angezeigt werden (nur eine buchen, wenn Sie mehr als die in die Datenbank eingefügt haben), wie in der Abbildung 4 .

die vollständige Webseite

Abbildung 4 die vollständige Webseite

Nun, sagte ich Sie alles bis zu diesem Zeitpunkt so, dass ich Sie dies feststellen konnten: OData also fabelhaften ist liegt, dass Sie mit einer Bewegung der Maus und der Tastatur zwei Shakes ich eine umfassende Programmierschnittstelle für diese Daten bereitstellen können, die ich aus JavaScript, .NET Framework, PHP und mehr zugreifen können. Diese magische geschieht, mit der rechten Maustaste auf das Projekt im Projektmappen-Explorer angezeigt wird, wählen Sie hinzufügen | Neues Element wählen Sie WCF Data Service, wählen Sie einen Namen (odata.svc verwendet), und klicken Sie auf Hinzufügen. Sie erhalten ein Skelett Codeabschnitt in einer Datei (in diesem Fall odata.svc.cs) ist, ignorieren die Sicherheit nur in der Gegenwart, wir wie folgt aussehen stellen möchten:

using System.Data.Services;
using System.Data.Services.Common;
using ODataBloggingSample;

namespace ODataBloggingSample {
  public class odata : DataService<MyBlogDBContainer> {
    public static void InitializeService(DataServiceConfiguration config) {
      config.SetEntitySetAccessRule("*", EntitySetRights.All);
      config.DataServiceBehavior.MaxProtocolVersion =  
        DataServiceProtocolVersion.V2;
    }
  }
}

Benachrichtigung, die wir in MyBlogDBContainer ausgelöst haben – unsere auf oberster Ebene Datenbankklasse Zugriff – als Vorlagenparameter der DataService-Klasse, die den Kern der serverseitigen WCF Data Services (siehe msdn.com/data/bb931106-) ist. DataService-Klasse ermöglicht es uns, unsere Datenbank über HTTP-Verb-basierten leicht verfügbar zu machen erstellen, lesen, aktualisieren und löschen (CRUD)-Operationen, die im Protokoll OData definiert. Der Typ der DataService übergeben wird für öffentliche Eigenschaften untersucht, die Auflistungen verfügbar zu machen. In unserem Beispiel enthält die Kontext Objektklasse Entity Framework generiert die Beiträge-Auflistung, die die Bill gut geeignet:

...
namespace ODataBloggingSample {
  ...
  public partial class MyBlogDBContainer : ObjectContext {
    ...
    public ObjectSet<Post> Posts {...}
   ...
  }

  ...
  public partial class Post : EntityObject {
    ...
    public global::System.Int32 Id { get { ... } set { ... } }
    public global::System.String Title { get { ... } set { ... } }
    public Nullable<global::System.DateTime> PublishDate { 
      get { ... } set { ... } }
    public global::System.String Content { get { ... } set { ... } }
    ...
  }
}

Beachten Sie, dass generierten MyBlogDBContainer ein ObjectSet (Dies ist nur eine Art von Auflistung) aufgerufen, Beiträge verfügbar macht, die Instanzen des Typs bereitstellen. Darüber hinaus ist der Post-Typ definiert die Zuordnung zwischen der ID, den Titel, den PublishDate und Content-Eigenschaften, um die zugrunde liegenden Spalten für die Tabelle Beiträge bieten wir bereits erstellt haben.

Mit odata.svc vorhanden ist können wir surfen mit dem Dienst-Dokument, das unsere Objekt Kontexteigenschaften Auflistung mithilfe des Namens der Dienst Endpunkt Datendatei in der URL verfügbar macht z. B. localhost:54423/odata.svc:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost:54423/odata.svc/" xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
    <workspace>
     <atom:title>Default</atom:title>
      <collection>
        <atom:title>Posts</atom:title>
      </collection>
    </workspace>
</service>

Die gesamte Datei wird durch die Spezifikation AtomPub (ietf.org/rfc/rfc5023.txt ) definiert. Dauert es eine Ebene tiefer, sehen wir unsere Beiträge, die als eine Reihe von Atom-Einträgen unter localhost:54423/odata.svc/Posts, verfügbar gemacht, wie in der Abbildung 5 .

Abbildung 5 Beiträge als Set Einträge für das Atom verfügbar gemachte

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xml:base="http://localhost:54423/odata.svc/"
  xmlns:d="https://schemas.microsoft.com/ado/2007/08/dataservices"
  xmlns:m=
    "https://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
  xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Posts</title>
  <id>http://localhost:54423/odata.svc/Posts</id>
  <updated>2010-03-15T00:26:40Z</updated>
  <link rel="self" title="Posts" href="Posts" />
  <entry>
    <id>http://localhost:54423/odata.svc/Posts(1)</id>
    <title type="text" />
    <updated>2010-03-15T00:26:40Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Post" href="Posts(1)" />
    <category term="MyBlogDB.Post"
      scheme=
        "https://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:Id m:type="Edm.Int32">1</d:Id>
        <d:Title>My first blog post</d:Title>
        <d:PublishDate m:type=
          "Edm.DateTime">2010-03-14T00:00:00</d:PublishDate>
        <d:Content>Hi! How are you?</d:Content>
      </m:properties>
    </content>
  </entry>
</feed>

Diese Datei ist fast vollständig unformatierten Vanille Atom (ietf.org/rfc/rfc4287.txt ), außer für die Microsoft-basierten URIs der OData-Funktionalität in Atom-Layer verwendet. Insbesondere sollten Sie das “ Eigenschaften ” Element innerhalb des Elements “ Inhalt ” bemerken. Diese Eigenschaften werden als die gleichen, die oben in die Post-Entität und den entsprechenden Beiträge Tabelle definiert erkannt werden. Diese Daten im Umschlag von Atom definiert und zur Verfügung gestellt, über die CRUD-Kommentare enthalten ist der selbst durch AtomPub definiert sind und
ermöglichen Ihnen das Erstellen, lesen, Aktualisierungs- und per POST verwendet, die HTTP-Methoden GET, PUT und DELETE bzw.. Das Problem ist, dass dies recht unformatierten-Vanille-Atom genug nicht. Wenn wir zum odata.svc/Posts in ein Atom-Reader wie Internet Explorer 8, den Titel und die Inhalte im Internet surfen z. B. Don ’t stammen wie in Abbildung 6 ordnungsgemäß durch.

Titel und Inhalt fehlen im Atom-Leser Blogbeiträge anzeigen Zeigt die

Abbildung 6 , Titel und Inhalt fehlen im Atom-Leser Blogbeiträge anzeigen Zeigt die

Sie können sehen, dass die Daten (Beachten Sie das Datum ist richtig und die Kategorie angezeigt wird), aber den Titel und den Inhalt an keiner Stelle angezeigt werden. Ist, weil die stellen, auf dem Internet Explorer ist für Titel und Inhalt suchen – “ Titel ” und “ ” Inhaltselemente in jedem Eintrag logisch genug – enthalten nicht genau vorhanden sein. “ Titelelement ” leer ist und das “ Inhalt ”-Element in einem Format, das Internet Explorer erkennt. Das Format, das Internet Explorer wirklich gerne sehen würden, sieht folgendermaßen aus:

<feed ...>
  <title type="text">Posts</title>
  <id>http://localhost:54423/atompub.svc/Posts</id>
  <updated>2010-03-15T00:42:32Z</updated>
  <link rel="self" title="Posts" href="Posts" />
  <entry>
    <id>http://localhost:54423/atompub.svc/Posts(1)</id>
    <title type="text">My first blog post</title>
    <updated>2010-03-15T00:42:32Z</updated>
    ...
    <content type="html">Hi! How are you?</content>
    <published>2010-03-14T00:00:00-08:00</published>
  </entry>
</feed>

Beachten Sie, dass das “ Titelelement ” hat was verwendet, um in die Title-Eigenschaft aus dem OData “ Eigenschaften ” Element im Element “ Inhalt ” begraben werden “ Inhalt ”-Element hat mit der Content-Eigenschaft überschrieben worden und “ veröffentlichte ” Element wurde aus dem Wert der Eigenschaft PublishDate hinzugefügt. Wenn diese Daten in Internet Explorer angezeigt werden, erhalten wir etwas viel mehr gefällt, was wir möchten, als in Abbildung 7 .

korrekte Anzeige der Titel und Inhalt Ergebnisse optimieren das XML-Format

Abbildung 7 korrekte Anzeige der Titel und Inhalt Ergebnisse optimieren das XML-Format

Ich sollte erwähnt werden, dass es nur für die Unterstützung von Blogtools handelt, die wir auch wichtig sind. Internet Explorer wird nicht erwartet wird, um eine Kundenliste oder eine Rechnung anzuzeigen, finden Sie unter Titel und Veröffentlichen von Daten und HTML-Inhalt erwartet wird. Manchmal ist es sinnvoll, führen Sie diese Zuordnung für Debitor Listet und, Rechnungen in diesem Fall Microsoft ein Feature in WCF Data Services genannt “ angezeigter Feeds ” hat (siehe blogs.msdn.com/astoriateam/archive/ 2008/09/28/making-feeds-friendly.aspx-). Es macht Recht nicht alles, jedoch (insbesondere, es wird nicht das Atom “ Inhalt ” Element zuordnen), da WCF Data Services-Team möchte sicherstellen, dass sogar “ angezeigten ” Feeds weiterhin mit verschiedenen Clientbibliotheken arbeiten. Ziel ist es, stellen die Feeds OData angezeigten, nicht aufgeben OData zugunsten der Atom/AtomPub.

In diesem Fall jedoch gerade wir Abkehr OData und einfach mithilfe von WCF Data Services als unsere AtomPub-Endpunkt, die eine Zuordnung zwischen Atom und OData, erforderlich ist, wie in der Abbildung 8 .

Mapping zwischen Atom und OData

Abbildung 8 Mapping zwischen Atom und OData

Ist der Trick, wie wir diese Zuordnung zu erhalten? Wir haben natürlich der Daten, aber wir müssen Atom-Eigenschaften neu zuordnen, so dass Atom-Reader (und Writer) kennen, in denen die Daten sofort eingebunden ist. Der Grund hierfür ist damit WCF Data Services weiterhin die Zuordnung zu den .NET Framework-Typen oder über Entity Framework, unsere Datenbanken durchführen können. Wir müssen lediglich ist ein wenig an Tür-Zuordnung von Atom/AtomPub bzw. von OData.

Im Codebeispiel für die mit diesem Artikel enthält Code zum Einfügen in die WCF-Pipeline, die nur genau diese Art von Nachricht Datentransformation zulässt. Sie können mit Ihren Vorstellungen (Auschecken ODataBlogging.cs) lesen, aber ich werde zeigen, wie Sie es verwenden.

Erstellen Sie zunächst einen neuen Endpunkt für WCF-Datendienste wie haben vor, jedoch mit einem anderen Namen (atompub.svc verwendet). Einbinden der Kontext der obersten Ebene Objektklasse und verfügbar gemacht, die gewünschten Entität Sie, genau wie zuvor wird, aber auch die Dienstklasse mit der ODataBloggingServiceBehavior Tag wie folgt:

...
using ODataBlogging;

namespace ODataBloggingSample {
  [ODataBloggingServiceBehavior(typeof(MyBlogDBContainer))]
  [EntityAtomMapping("Posts", "PublishDate", "published")]
  public class atompub : DataService<MyBlogDBContainer> {
    public static void InitializeService(DataServiceConfiguration config) {
      config.SetEntitySetAccessRule("*", EntitySetRights.All);
      config.DataServiceBehavior.MaxProtocolVersion = 
        DataServiceProtocolVersion.V2;
    }
  }
}

Dies ist die Zuordnung von Atom/AtomPub in – z. B. “ Titel, ” “ Inhalte ” und “ veröffentlichten ” Elemente – über das geschachtelte “ Eigenschaften ” Element innerhalb des Elements “ Inhalt ” in entsprechende OData zu formatieren. Standardmäßig entsprechen die Namen der auf den Entitäten werden (Groß-/Kleinschreibung wird ignoriert), dann die Zuordnung (und Typumwandlung) nur passieren. Beispielsweise, wenn eine Entität, die Title-Eigenschaft (wie unsere Post-Entität) enthält ausgesetzt, wird es das Atom “ ” Titelelement zugeordnet.

Andererseits, wenn keine automatische Zuordnung vorhanden ist, können Sie überschreiben dieses Verhalten durch eine explizite Zuordnung basierend auf den Entitätsnamen bereitstellen, wie wir die PublishDate-Eigenschaft für die Objekte in der Auflistung “ Beiträge ” “ veröffentlichten ” Atom-Eigenschaft zuordnen. Diese zwei Attribute sind ausreichend unsere OData feed in ein Atom-Feed erteilen uns die umfassende Ansicht der Daten wie in Abbildung 7 zu aktivieren.

Diese Zuordnung ist keine unidirektionale; es unterstützt alle HTTP-Methoden können somit das Protokoll AtomPub zum Erstellen, aktualisieren und Löschen von Elementen in der Auflistung Beiträge sowie lesen. Daher können Sie ein Tool wie Windows Live Writer (WLW), die AtomPub als ein Blog-API unterstützt, konfigurieren und verwenden Sie es für Ihre Beiträge Rich-Text-Bearbeitung. Beispielsweise erhält den Endpunkt atompub.svc in WLW, stehen auch Blogs | Blog-Konto hinzufügen, und geben Sie die folgenden Optionen in den Dialogfeldern, die folgen:

  • Welche Blogdienst verwenden Sie? Andere Blogdienst
  • Die Webadresse Ihres Blogs: http:// < Server >>: << Port >> /atompub.svc
  • Benutzername: < Benutzername >> (erforderlich und sollten auf Ihre AtomPub Endpunkt unter Verwendung von HTTP-Standardverfahren implementiert werden)
  • Kennwort: < Kennwort >>
  • Typ des Blogs, die Sie verwenden: Atom Publishing-Protokoll
  • Dokument-URL des Webdienstes: http:// < Server >>: << Port >> /atompub.svc
  • Blog-Pseudonym: << beliebig >>

Klicken Sie auf "Fertig stellen" und haben Sie ein Rich-Text-Editors zum Verwalten von Ihren Blogbeiträgen wie in Abbildung 9 .

Atom/OData Zuordnung erleichtert, erstellen ein Rich-Text-Editor zum Verwalten Ihrer Blogbeiträge

Abbildung 9 Atom/OData Zuordnung erleichtert, erstellen ein Rich-Text-Editor zum Verwalten Ihrer Blogbeiträge

Hier haben wir das Modul Data Services übernommen, die Lieferschein-Eigenschaften in das Atom “ Inhalte ” Element unterstützt vollständigen CRUD-Funktionalität und ein wenig Zuordnung zu erleichtern einfache alten Atom und AtomPub, zu unterstützen durchgeführt haben.

Wenig Beispielbibliothek, die ich verwendet, um diese arbeiten (das ich mit Phani Raj auf, eine Software Engineer bei Microsoft im Datendienst WCF-Team erstellt), führt barest Minimum, und geht nie alle werden, die Sie zum Erstellen eines echten Blogs benötigen. Hier ist eine Liste von der Oberseite von meinem Kopf der Dinge, die immer noch sehr einfach Atom und AtomPub unterstützt werden muss:

  • Zuordnen von Atom Autor Element Unterelemente wie z. B. Name, Uri und E-mail.
  • Behandlung von Bildern (Obwohl WLW, reicht u. u. für FTP, ermöglicht).
  • Offenlegen von Funktionen WLW erkennt diese Features machen.

Wenn Sie dieses Experiment weiter pushen interessiert sind, hat Joe Cheng, Mitglied des Teams WLW eine Reihe von Blogbeiträgen zur Unterstützung von AtomPub in WLW geschrieben, die diese Arbeit an erster Stelle inspiriert: jcheng.WordPress.com/2007/10/15/How-wlw-speaks-atompub-Introduction.

Viel Spaß!

Chris Sells ist ein Microsoft Programm Manager in der Business Platform Division. Er hat mehrere Bücher, einschließlich der mit Mitautorenschaft “ Programming WPF ” (O’Reilly Media, 2007), “ Windows Forms 2.0 Programming ” (Addison-Wesley Professional, 2006) und “ ATL Internals ” (Addison-Wesley Professional, 1999) geschrieben. In seiner Freizeit er enthält verschiedene Konferenzen und macht eine Pest von sich selbst auf Microsoft interne Teams Diskussion Produktlisten. Weitere Informationen über die Verkäufe und seinen diversen Projekten, steht unter sellsbrothers.com-.

*Dank an den folgenden technischen Experten für die Überprüfung der in diesem Artikel:*Pablo Castro