Share via


Exemplarische Vorgehensweise: Erstellen einer Datenquellen-Erweiterung

Diese exemplarische Vorgehensweise veranschaulicht, wie eine Datenquellenerweiterung für LightSwitch erstellt wird. Eine Datenquellenerweiterung verwendet eine benutzerdefinierte Domänendienst-Adapterklasse für die Zusammenarbeit mit anderen Datenquellen. Damit können Sie auf nahezu alle Daten zugreifen, die sich in einer Datenquelle befinden, die nicht systemeigen von LightSwitch unterstützt wird.

Für die Erweiterbarkeit unterstützt LightSwitch den Aufruf einer benutzerdefinierten DomainService-Klasse als eine Art Datenadapter im Arbeitsspeicher. LightSwitch ruft die Instanz direkt von der Datendienstimplementierung auf, um Abfragen und Sendevorgänge auszuführen. Der benutzerdefinierte Domänendienst wird nicht als öffentlicher Dienst verfügbar gemacht, daher sollte das Attribut [EnableClientAccess] nicht angewendet werden. Mithilfe dieses Mechanismus können Sie eine DomainService-Klasse erstellen, die Entitätstypen verfügbar macht und die vorgeschriebenen Abfrage-, Einfüge-, Aktualisierungs- und Löschmethoden implementiert. LightSwitch leitet auf Grundlage der verfügbar gemachten Entitätstypen das LightSwitch-Entitätsmodell und aus dem Vorhandensein einer Standardabfrage eine Entitätenmenge ab.

Das Erstellen einer Datenquellenerweiterung umfasst die folgenden Aufgaben:

  • Erstellen eines Projekts für die Datenquellenerweiterung

  • Implementieren der Datenquellenklasse

  • Erstellen von Produkt- und Produktkategorieklassen

  • Testen der Datenquellenerweiterung

Vorbereitungsmaßnahmen

  • Visual Studio 2013 Professional

  • Visual Studio 2013 SDK

  • LightSwitch Extensibility Toolkit für Visual Studio 2013

Erstellen eines Projekts für die Datenquellenerweiterung

Der erste Schritt besteht darin, ein Projekt zu erstellen und eine LightSwitch-Datenquellenvorlage hinzuzufügen.

So erstellen Sie ein Erweiterungsprojekt

  1. Wählen Sie in der Visual Studio-Menüleiste Datei, Neu und Projekt aus.

  2. Erweitern Sie im Dialogfeld Neues Projekt den Knoten Visual Basic oder Visual C#, erweitern Sie den Knoten LightSwitch, wählen Sie dann den Knoten Erweiterungen und anschließend die Vorlage LightSwitch-Erweiterungsbibliothek aus.

  3. Geben Sie im Feld Name die Zeichenfolge DataSourceExtension ein. Dieser Name der Erweiterungsbibliothek erscheint auf der Registerkarte Erweiterungen des LightSwitch-Anwendungs-Designers.

  4. Wählen Sie die Schaltfläche OK, um eine Projektmappe zu erstellen, die die sieben Projekte enthält, die für die Erweiterung erforderlich sind.

So wählen Sie einen Erweiterungstyp aus

  1. Wählen Sie im Projektmappen-Explorer das Projekt DataSourceExtension.Lspkg aus.

  2. Wählen Sie in der Menüleiste Projekt, Neues Element hinzufügen aus.

  3. Wählen Sie im Dialogfeld Neues Element hinzufügen die Option LightSwitch-Datenquelle aus.

  4. Geben Sie im Feld Name die Zeichenfolge XMLDataSource ein. Dieser Erweiterungsname wird im Assistenten zum Hinzufügen von Datenquellen von LightSwitch angezeigt.

  5. Klicken Sie auf die Schaltfläche OK. Eine XMLDataSource.vb- oder XMLDataSource.cs-Datei wird dem Projekt DataSourceExtension.Server in der Projektmappe hinzugefügt.

Implementieren der Datenquellenklasse

Der Großteil der Logik für die Datenquellenerweiterung ist in der Klasse XMLDataSource enthalten, die in der XMLDataSource.vb- oder der XMLDataSource.cs-Datei erstellt wird. Die erforderlichen Verweise und Imports- oder using-Anweisungen wurden dem Projekt bereits hinzugefügt. Bei einer XML-Datenquelle sind weitere Namespaceverweise hinzuzufügen.

So fügen Sie Namespaceverweise hinzu

  • Öffnen Sie im Projektmappen-Explorer die XMLDataSource.vb- oder XMLDataSource.cs-Datei im Projekt DataSourceExtension.Server. Fügen Sie am Anfang der Datei die folgende Imports- oder using-Anweisung hinzu.

    Imports System.Xml.Linq
    Imports System.Configuration
    Imports System.Web.Configuration
    
    using System.Xml.Linq;
    using System.Configuration;
    using System.Web.Configuration;
    

Fügen Sie dann ein Description-Attribut hinzu, um eine Beschreibung im Assistenten zum Hinzufügen von Datenquellen von LightSwitch bereitzustellen.

So fügen Sie ein Beschreibungsattribut hinzu

  • Fügen Sie nach der Kommentarzeile // TODO: Create methods containing your application logic. folgenden Code hinzu.

    'The description attribute will be displayed in the LightSwitch data attach wizard.
        <Description("Please provide the path to the XML file.")> _
    
    //The description attribute will be displayed in the LightSwitch data attach wizard.
        [Description("Please provide the path to the XML file.")]
    

Anschließend geben Sie den Namespace an.

So geben Sie den Namespace an

  • Ersetzen Sie die vorhandene Namespacedeklaration durch die Folgende.

    Namespace DataSourceExtension.DataSources
    
    namespace DataSourceExtension.DataSources
    

Nun fügen Sie Code hinzu, um den Dateipfad und die Verbindungszeichenfolge festzulegen.

So implementieren Sie die Initialisierungsmethode

  • Folgender Code ruft den Dateinamen und die Verbindungszeichenfolge aus der Datei "web.config" ab, überprüft die Datei und fügt bei Bedarf die XML-Elemente hinzu. Fügen Sie diesen Code zur XMLDataSource-Klasse hinzu.

    Private _db As XElement
            Private _filePath As String
    
            Public Overrides Sub Initialize(context As DomainServiceContext)
                MyBase.Initialize(context)
    
                'Get the file path from config.
                If WebConfigurationManager.ConnectionStrings(GetType(XMLDataSource).FullName) IsNot Nothing Then
                    _filePath = WebConfigurationManager.ConnectionStrings(GetType(XMLDataSource).FullName).ConnectionString
                End If
    
                If [String].IsNullOrWhiteSpace(_filePath) Then
                    Throw New Exception("The filepath must be provided in the web.config in the connection strings section under " & GetType(XMLDataSource).FullName)
                Else
                    If Not System.IO.File.Exists(_filePath) Then
                        Dim x As New XElement("DataRoot")
                        x.Save(_filePath)
                    End If
    
                    _db = XElement.Load(_filePath)
    
                    'Verify the file.
                    If _db.Name <> "DataRoot" Then
                        Throw New Exception("Corrupt file.")
                    End If
    
                    'Add a product categories node if one does not exist.
                    If _db.Element("ProductCategories") Is Nothing Then
                        _db.Add(New XElement("ProductCategories"))
                    End If
    
                    'Add a products node if one does not exist.
                    If _db.Element("Products") Is Nothing Then
                        _db.Add(New XElement("Products"))
                    End If
                End If
            End Sub
    
    private XElement _db;
            private string _filePath;
    
            public override void Initialize(DomainServiceContext context)
            {
                base.Initialize(context);
    
                //Get the file path from config.
                if (WebConfigurationManager.ConnectionStrings[typeof(XMLDataSource).FullName] != null)
                    _filePath = WebConfigurationManager.ConnectionStrings[typeof(XMLDataSource).FullName].ConnectionString;
    
                if (String.IsNullOrWhiteSpace(_filePath))
                {
                    throw new Exception("The filepath must be provided in the web.config in the connection strings section under " + typeof(XMLDataSource).FullName);
                }
                else
                {
                    if (!System.IO.File.Exists(_filePath))
                    {
                        XElement x = new XElement("DataRoot");
                        x.Save(_filePath);
                    }
    
                    _db = XElement.Load(_filePath);
    
                    //Verify the file.
                    if (_db.Name != "DataRoot")
                        throw new Exception("Corrupt file.");
    
                    //Add a product categories node if one does not exist.
                    if (_db.Element("ProductCategories") == null)
                        _db.Add(new XElement("ProductCategories"));
    
                    //Add a products node if one does not exist.
                    if (_db.Element("Products") == null)
                        _db.Add(new XElement("Products"));
                }
            }
    

Anschließend implementieren Sie die Methode Submit, um Änderungen an der Datei zu speichern.

So implementieren Sie die Sendemethode

  • Fügen Sie der XMLDataSource-Klasse folgenden Code hinzu.

    Public Overrides Function Submit(changeSet As ChangeSet) As Boolean
                Dim c As New ChangeSet(changeSet.ChangeSetEntries.OrderBy(Function(entry) entry.Entity, New ProductEntitiesComparer()))
    
                Dim baseResult As [Boolean] = MyBase.Submit(changeSet)
                If baseResult Then
                    _db.Save(_filePath)
                    Return True
                Else
                    Return False
                End If
            End Function
    
    public override bool Submit(ChangeSet changeSet)
            {
                ChangeSet c = new ChangeSet(changeSet.ChangeSetEntries.OrderBy(entry => entry.Entity, new ProductEntitiesComparer()));
    
                Boolean baseResult = base.Submit(changeSet);
                if (baseResult)
                {
                    _db.Save(_filePath);
                    return true;
                }
                else
                    return false;
            }
    

    Hinweis

    Zu diesen Zeitpunkt erhalten Sie eine Fehlermeldung, da die Klasse ProductEntitiesComparer noch nicht implementiert ist.Sie können diesen Fehler ignorieren, die Klasse wird später implementiert.

Als Nächstes implementieren Sie zwei standardmäßige Abfragemethoden in der Klasse, eine für Produkte und eine für Produktkategorien.

So implementieren Sie Abfragemethoden

  • Fügen Sie der Klasse XMLDataSource eine neue Region hinzu.

    #Region "Queries"
    
    #End Region
    
    #region Queries
    
            #endregion
    
  • Fügen Sie der Queries-Region folgenden Code hinzu.

    Protected Overrides Function Count(Of T)(query As IQueryable(Of T)) As Integer
                Return query.Count()
            End Function
    
            <Query(IsDefault:=True)> _
            Public Function GetProducts() As IQueryable(Of Product)
                Dim products As New List(Of Product)()
                For Each pElem As XElement In _db.Descendants("Product")
                    products.Add(GetProduct(pElem))
                Next
                Return products.AsQueryable()
            End Function
    
            <Query(IsDefault:=True)> _
            Public Function GetProductCategories() As IQueryable(Of ProductCategory)
                Dim categories As New List(Of ProductCategory)()
                For Each catElem As XElement In _db.Descendants("ProductCategory")
                    categories.Add(GetProductCategory(catElem))
                Next
    
                Return categories.AsQueryable()
            End Function
    
    protected override int Count<T>(IQueryable<T> query)
            {
                return query.Count();
            }
    
            [Query(IsDefault = true)]
            public IQueryable<Product> GetProducts()
            {
                List<Product> products = new List<Product>();
                foreach (XElement pElem in _db.Descendants("Product"))
                {
                    products.Add(GetProduct(pElem));
                }
                return products.AsQueryable();
            }
    
            [Query(IsDefault = true)]
            public IQueryable<ProductCategory> GetProductCategories()
            {
                List<ProductCategory> categories = new List<ProductCategory>();
                foreach (XElement catElem in _db.Descendants("ProductCategory"))
                {
                    categories.Add(GetProductCategory(catElem));
                }
    
                return categories.AsQueryable();
            }
    

    Hinweis

    Zu diesem Zeitpunkt werden weitere Fehler angezeigt.Sie können die Fehler ignorieren, denn sobald der gesamte Code für die exemplarische Vorgehensweise hinzugefügt wurde, werden die Fehler behoben.

Anschließend implementieren Sie zwei benutzerdefinierte Abfragen. Diese werden zur Entwurfszeit im Knoten Datenquellen von LightSwitch angezeigt.

So implementieren Sie benutzerdefinierte Abfragen

  1. Fügen Sie eine CustomQueries-Region zur XMLDataSource-Klasse hinzu.

    #Region "CustomQueries"
    
    #End Region
    
    #region CustomQueries
    
    #endregion
    
  2. Fügen Sie der CustomQueries-Region folgenden Code hinzu.

    'All query parameters need to be nullable. 
            Public Function GetProductsByCategory(categoryID As Nullable(Of Guid)) As IQueryable(Of Product)
                Dim products As New List(Of Product)()
    
                'Return no products if categoryID is as null.
                If categoryID.HasValue Then
                    For Each pElem As XElement In _db.Descendants("Product")
                        Dim p As Product = GetProduct(pElem)
                        If p.CategoryID = categoryID.Value Then
                            products.Add(p)
                        End If
                    Next
                End If
                Return products.AsQueryable()
            End Function
    
            'Query that returns a single item.
            'Mark queries that return as single item as composable = false.
            <Query(IsComposable:=False)> _
            Public Function GetProductByID(productID As Nullable(Of Guid)) As Product
                Dim product As Product = Nothing
    
                'Only return a result if you are passed a value.
                If productID.HasValue Then
                    Dim pElem As XElement = (From p In _db.Descendants("Product") Where p.Element("ProductID").Value = productID.Value.ToString() Select p).FirstOrDefault()
                    If pElem IsNot Nothing Then
                        product = GetProduct(pElem)
                    End If
                End If
                Return product
    
            End Function
    
    //All query parameters need to be nullable. 
            public IQueryable<Product> GetProductsByCategory(Nullable<Guid> categoryID)
            {
                List<Product> products = new List<Product>();
    
                //Return no products if categoryID is as null.
                if (categoryID.HasValue)
                {
                    foreach (XElement pElem in _db.Descendants("Product"))
                    {
                        Product p = GetProduct(pElem);
                        if (p.CategoryID == categoryID.Value)
                        {
                            products.Add(p);
                        }
                    }
                }
                return products.AsQueryable();
            }
    
            //Query that returns a single item.
            //Mark queries that return as single item as composable = false.
            [Query(IsComposable = false)]
            public Product GetProductByID(Nullable<Guid> productID)
            {
                Product product = null;
    
                //Only return a result if you are passed a value.
                if (productID.HasValue)
                {
                    XElement pElem = (from XElement p in _db.Descendants("Product")
                                      where p.Element("ProductID").Value == productID.Value.ToString()
                                      select p).FirstOrDefault();
                    if (pElem != null)
                    {
                        product = GetProduct(pElem);
                    }
                }
                return product;
    
            }
    

Anschließend definieren Sie die Methoden Update, Delete und Insert für Produktkategorien.

So fügen Sie Aktualisierungs-, Lösch- und Einfügemethoden hinzu

  1. Fügen Sie eine Category Update/Delete/Insert Methods-Region zur XMLDataSource-Klasse hinzu.

    #Region "Category Update/Delete/Insert Methods"
    
    #End Region
    
    #region Category Update/Delete/Insert Methods
    
    #endregion
    
  2. Fügen Sie der Category Update/Delete/Insert Methods-Region folgenden Code hinzu.

    Public Sub InsertProductCategory(pc As ProductCategory)
                Try
                    pc.CategoryID = Guid.NewGuid()
                    Dim catElem As XElement = GetProductCategoryElem(pc)
    
                    'Update the category ID on any related product entities.
                    For Each e As ChangeSetEntry In ChangeSet.ChangeSetEntries
                        If TypeOf e.Entity Is Product Then
                            If CObj(e.Entity).Category = CObj(pc) Then
                                DirectCast(e.Entity, Product).CategoryID = pc.CategoryID
                            End If
                        End If
                    Next
    
    
                    'Update the xml doc.
                    _db.Element("ProductCategories").Add(catElem)
                Catch ex As Exception
                    Throw New Exception("Error inserting ProductCategory " & Convert.ToString(pc.CategoryName), ex)
                End Try
            End Sub
    
            Public Sub UpdateProductCategory(pc As ProductCategory)
                Try
                    'Get existing item from the XML db.
                    Dim storeCatElem As XElement = (From c In _db.Descendants("ProductCategory") Where c.Element("CategoryID").Value = pc.CategoryID.ToString() Select c).FirstOrDefault()
    
                    If storeCatElem Is Nothing Then
                        'Category does not exist.  Indicate that item has already been deleted.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(pc) Select e).First()
                        entry.IsDeleteConflict = True
                    Else
                        Dim storeCategory As ProductCategory = GetProductCategory(storeCatElem)
    
                        'Find entry in the changeset to compare original values.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(pc) Select e).First()
                        'List of conflicting fields.
                        Dim conflictMembers As New List(Of [String])()
    
                        If storeCategory.CategoryName <> DirectCast(entry.OriginalEntity, ProductCategory).CategoryName Then
                            conflictMembers.Add("CategoryName")
                        End If
                        If storeCategory.Description <> DirectCast(entry.OriginalEntity, ProductCategory).Description Then
                            conflictMembers.Add("Description")
                        End If
    
                        'Set conflict members.
                        entry.ConflictMembers = conflictMembers
                        entry.StoreEntity = storeCategory
    
                        If conflictMembers.Count < 1 Then
                            'Update the xml _db.
                            storeCatElem.ReplaceWith(GetProductCategoryElem(pc))
                        End If
                    End If
                Catch ex As Exception
                    Throw New Exception("Error updating Category " & pc.CategoryID.ToString() & ":" & Convert.ToString(pc.CategoryName), ex)
                End Try
            End Sub
    
            Public Sub DeleteProductCategory(pc As ProductCategory)
                Try
                    Dim storeCatElem As XElement = (From c In _db.Descendants("ProductCategory") Where c.Element("CategoryID").Value = pc.CategoryID.ToString() Select c).FirstOrDefault()
    
                    If storeCatElem Is Nothing Then
                        'Category does not exist.  Indicate that item has already been deleted.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(pc) Select e).First()
                        entry.IsDeleteConflict = True
                    Else
                        storeCatElem.Remove()
                    End If
                Catch ex As Exception
                    Throw New Exception("Error deleting Category " & pc.CategoryID.ToString() & ":" & Convert.ToString(pc.CategoryName), ex)
                End Try
            End Sub
    
    public void InsertProductCategory(ProductCategory pc)
            {
                try
                {
                    pc.CategoryID = Guid.NewGuid();
                    XElement catElem = GetProductCategoryElem(pc);
    
                    //Update the category ID on any related product entities.
                    foreach (ChangeSetEntry e in ChangeSet.ChangeSetEntries)
                    {
                        if (e.Entity is Product)
                        {
                            if (((Product)e.Entity).Category == pc)
                            {
                                ((Product)e.Entity).CategoryID = pc.CategoryID;
                            }
                        }
                    }
    
    
                    //Update the xml doc.
                    _db.Element("ProductCategories").Add(catElem);
                }
                catch (Exception ex)
                {
                    throw new Exception("Error inserting ProductCategory " + pc.CategoryName, ex);
                }
            }
    
            public void UpdateProductCategory(ProductCategory pc)
            {
                try
                {
                    //Get existing item from the XML db.
                    XElement storeCatElem =
                        (from c in _db.Descendants("ProductCategory")
                         where c.Element("CategoryID").Value == pc.CategoryID.ToString()
                         select c).FirstOrDefault();
    
                    if (storeCatElem == null)
                    {
                        //Category does not exist.  Indicate that the item has already been deleted.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == pc
                             select e).First();
                        entry.IsDeleteConflict = true;
                    }
                    else
                    {
                        ProductCategory storeCategory = GetProductCategory(storeCatElem);
    
                        //Find entry in the changeset to compare original values.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == pc
                             select e).First();
    
                        //List of conflicting fields.
                        List<String> conflictMembers = new List<String>();
    
                        if (storeCategory.CategoryName != ((ProductCategory)entry.OriginalEntity).CategoryName)
                            conflictMembers.Add("CategoryName");
                        if (storeCategory.Description != ((ProductCategory)entry.OriginalEntity).Description)
                            conflictMembers.Add("Description");
    
                        //Set conflict members>
                        entry.ConflictMembers = conflictMembers;
                        entry.StoreEntity = storeCategory;
    
                        if (conflictMembers.Count < 1)
                        {
                            //Update the xml _db.
                            storeCatElem.ReplaceWith(GetProductCategoryElem(pc));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error updating Category " + pc.CategoryID.ToString() + ":" + pc.CategoryName, ex);
                }
            }
    
            public void DeleteProductCategory(ProductCategory pc)
            {
                try
                {
                    XElement storeCatElem =
                        (from c in _db.Descendants("ProductCategory")
                         where c.Element("CategoryID").Value == pc.CategoryID.ToString()
                         select c).FirstOrDefault();
    
                    if (storeCatElem == null)
                    {
                        //Category does not exist.  Indicate that the item has already been deleted.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == pc
                             select e).First();
                        entry.IsDeleteConflict = true;
                    }
                    else
                    {
                        storeCatElem.Remove();
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error deleting Category " + pc.CategoryID.ToString() + ":" + pc.CategoryName, ex);
                }
            }
    

Nun implementieren Sie einen vergleichbaren Methodensatz für Produkte.

So fügen Sie Methoden hinzu

  1. Fügen Sie eine Product Update/Delete/Insert Methods-Region zur XMLDataSource-Klasse hinzu.

    #Region "Product Update/Delete/Insert Methods"
    
    #End Region
    
    #region Product Update/Delete/Insert Methods
    
    #endregion
    
  2. Fügen Sie der Product Update/Delete/Insert Methods-Region folgenden Code hinzu.

    Public Sub InsertProduct(p As Product)
                Try
                    p.ProductID = Guid.NewGuid()
                    Dim productElem As XElement = GetProductElem(p)
                    _db.Element("Products").Add(productElem)
                Catch ex As Exception
                    Throw New Exception("Error inserting Product " & Convert.ToString(p.ProductName), ex)
                End Try
            End Sub
    
            Public Sub UpdateProduct(p As Product)
                Try
                    Dim storeProductElem As XElement = (From c In _db.Descendants("Product") Where c.Element("ProductID").Value = p.ProductID.ToString() Select c).FirstOrDefault()
    
                    If storeProductElem Is Nothing Then
                        'Product does not exist.  Indicate that the item has already been deleted.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(p) Select e).First()
                        entry.IsDeleteConflict = True
                    Else
                        Dim storeProduct As Product = GetProduct(storeProductElem)
    
                        'Find the entry in the changeset to compare original values.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(p) Select e).First()
    
                        'List of conflicting fields.
                        Dim conflictMembers As New List(Of [String])()
    
                        If storeProduct.ProductName <> DirectCast(entry.OriginalEntity, Product).ProductName Then
                            conflictMembers.Add("ProductName")
                        End If
                        If storeProduct.CategoryID <> DirectCast(entry.OriginalEntity, Product).CategoryID Then
                            conflictMembers.Add("CategoryID")
                        End If
                        If storeProduct.QuantityPerUnit <> DirectCast(entry.OriginalEntity, Product).QuantityPerUnit Then
                            conflictMembers.Add("QuantityPerUnit")
                        End If
                        If storeProduct.UnitPrice <> DirectCast(entry.OriginalEntity, Product).UnitPrice Then
                            conflictMembers.Add("UnitPrice")
                        End If
                        If storeProduct.UnitsInStock <> DirectCast(entry.OriginalEntity, Product).UnitsInStock Then
                            conflictMembers.Add("UnitsInStock")
                        End If
                        If storeProduct.ReorderLevel <> DirectCast(entry.OriginalEntity, Product).ReorderLevel Then
                            conflictMembers.Add("ReorderLevel")
                        End If
                        If storeProduct.Discontinued <> DirectCast(entry.OriginalEntity, Product).Discontinued Then
                            conflictMembers.Add("Discontinued")
                        End If
    
                        'Set conflict members.
                        entry.ConflictMembers = conflictMembers
                        entry.StoreEntity = storeProduct
    
                        If conflictMembers.Count < 1 Then
                            'Update the xml _db.
                            storeProductElem.ReplaceWith(GetProductElem(p))
                        End If
                    End If
                Catch ex As Exception
                    Throw New Exception("Error updating Product " & p.ProductID.ToString() & ":" & Convert.ToString(p.ProductName), ex)
                End Try
            End Sub
    
            Public Sub DeleteProduct(p As Product)
                Try
                    Dim storeProductElem As XElement = (From c In _db.Descendants("Product") Where c.Element("ProductID").Value = p.ProductID.ToString() Select c).FirstOrDefault()
    
                    If storeProductElem Is Nothing Then
                        'Product does not exist.  Indicate that the item has already been deleted.
                        Dim entry As ChangeSetEntry = (From e In ChangeSet.ChangeSetEntries Where e.Entity = CObj(p) Select e).First()
                        entry.IsDeleteConflict = True
                    Else
                        'Remove it.
                        storeProductElem.Remove()
                    End If
                Catch ex As Exception
                    Throw New Exception("Error deleting Product " & p.ProductID.ToString() & ":" & Convert.ToString(p.ProductName), ex)
                End Try
            End Sub
    
    public void InsertProduct(Product p)
            {
                try
                {
                    p.ProductID = Guid.NewGuid();
                    XElement productElem = GetProductElem(p);
                    _db.Element("Products").Add(productElem);
                }
                catch (Exception ex)
                {
                    throw new Exception("Error inserting Product " + p.ProductName, ex);
                }
            }
    
            public void UpdateProduct(Product p)
            {
                try
                {
                    XElement storeProductElem =
                        (from c in _db.Descendants("Product")
                         where c.Element("ProductID").Value == p.ProductID.ToString()
                         select c).FirstOrDefault();
    
                    if (storeProductElem == null)
                    {
                        //Product does not exist.  Indicate that the item has already been deleted.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == p
                             select e).First();
                        entry.IsDeleteConflict = true;
                    }
                    else
                    {
                        Product storeProduct = GetProduct(storeProductElem);
    
                        //Find the entry in the changeset to compare original values.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == p
                             select e).First();
    
                        //List of conflicting fields.
                        List<String> conflictMembers = new List<String>();
    
                        if (storeProduct.ProductName != ((Product)entry.OriginalEntity).ProductName)
                            conflictMembers.Add("ProductName");
                        if (storeProduct.CategoryID != ((Product)entry.OriginalEntity).CategoryID)
                            conflictMembers.Add("CategoryID");
                        if (storeProduct.QuantityPerUnit != ((Product)entry.OriginalEntity).QuantityPerUnit)
                            conflictMembers.Add("QuantityPerUnit");
                        if (storeProduct.UnitPrice != ((Product)entry.OriginalEntity).UnitPrice)
                            conflictMembers.Add("UnitPrice");
                        if (storeProduct.UnitsInStock != ((Product)entry.OriginalEntity).UnitsInStock)
                            conflictMembers.Add("UnitsInStock");
                        if (storeProduct.ReorderLevel != ((Product)entry.OriginalEntity).ReorderLevel)
                            conflictMembers.Add("ReorderLevel");
                        if (storeProduct.Discontinued != ((Product)entry.OriginalEntity).Discontinued)
                            conflictMembers.Add("Discontinued");
    
                        //Set conflict members.
                        entry.ConflictMembers = conflictMembers;
                        entry.StoreEntity = storeProduct;
    
                        if (conflictMembers.Count < 1)
                        {
                            //Update the xml _db.
                            storeProductElem.ReplaceWith(GetProductElem(p));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error updating Product " + p.ProductID.ToString() + ":" + p.ProductName, ex);
                }
            }
    
            public void DeleteProduct(Product p)
            {
                try
                {
                    XElement storeProductElem =
                        (from c in _db.Descendants("Product")
                         where c.Element("ProductID").Value == p.ProductID.ToString()
                         select c).FirstOrDefault();
    
                    if (storeProductElem == null)
                    {
                        //The product does not exist.  Indicate that the item has already been deleted.
                        ChangeSetEntry entry =
                            (from e in ChangeSet.ChangeSetEntries
                             where e.Entity == p
                             select e).First();
                        entry.IsDeleteConflict = true;
                    }
                    else
                    {
                        //Remove it.
                        storeProductElem.Remove();
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error deleting Product " + p.ProductID.ToString() + ":" + p.ProductName, ex);
                }
            }
    

Als Nächstes fügen Sie einige Hilfsfunktionen hinzu.

So implementieren Sie Hilfsfunktionen

  • Fügen Sie der Klasse XMLDataSource eine neue Region hinzu.

    #Region “HelperFunctions”
    
    #End Region
    
    #region HelperFunctions
    
    #endregion
    
  • Fügen Sie der Queries-Region folgenden Code hinzu.

    Private Function GetProductElem(p As Product) As XElement
                Dim productElem As New XElement("Product", New XElement("ProductID", New Object() {New XAttribute("DataType", "Guid"), p.ProductID}), New XElement("ProductName", New Object() {New XAttribute("DataType", "String"), p.ProductName}), New XElement("CategoryID", New Object() {New XAttribute("DataType", "Guid"), p.CategoryID}), New XElement("QuantityPerUnit", New Object() {New XAttribute("DataType", "String"), p.QuantityPerUnit}), New XElement("UnitPrice", New Object() {New XAttribute("DataType", "Decimal"), p.UnitPrice}), _
                 New XElement("UnitsInStock", New Object() {New XAttribute("DataType", "Int32"), p.UnitsInStock}), New XElement("ReorderLevel", New Object() {New XAttribute("DataType", "Int32?"), p.ReorderLevel}), New XElement("Discontinued", New Object() {New XAttribute("DataType", "Boolean"), p.Discontinued}))
                Return productElem
            End Function
    
            Private Function GetProduct(pElem As XElement) As Product
                Dim p As New Product()
    
                p.ProductID = New Guid(pElem.Element("ProductID").Value)
                p.ProductName = pElem.Element("ProductName").Value
                p.CategoryID = New Guid(pElem.Element("CategoryID").Value)
                p.QuantityPerUnit = pElem.Element("QuantityPerUnit").Value
                p.UnitPrice = Decimal.Parse(pElem.Element("UnitPrice").Value)
                p.UnitsInStock = Int32.Parse(pElem.Element("UnitsInStock").Value)
                If Not [String].IsNullOrWhiteSpace(pElem.Element("ReorderLevel").Value) Then
                    p.ReorderLevel = Int32.Parse(pElem.Element("ReorderLevel").Value)
                End If
                p.Discontinued = [Boolean].Parse(pElem.Element("Discontinued").Value)
    
                Return p
            End Function
    
            Private Function GetProductCategory(catElem As XElement) As ProductCategory
                Dim pc As New ProductCategory()
                pc.CategoryID = New Guid(catElem.Element("CategoryID").Value)
                pc.CategoryName = catElem.Element("CategoryName").Value
                pc.Description = catElem.Element("Description").Value
    
                Return pc
            End Function
    
            Private Function GetProductCategoryElem(pc As ProductCategory) As XElement
                Dim catElem As New XElement("ProductCategory", New XElement("CategoryID", New Object() {New XAttribute("DataType", "Guid"), pc.CategoryID}), New XElement("CategoryName", New Object() {New XAttribute("DataType", "String"), pc.CategoryName}), New XElement("Description", New Object() {New XAttribute("DataType", "String"), pc.Description}))
                Return catElem
            End Function
    
    private XElement GetProductElem(Product p)
            {
                XElement productElem = new XElement("Product",
                    new XElement("ProductID", new object[] { new XAttribute("DataType", "Guid"), p.ProductID }),
                    new XElement("ProductName", new object[] { new XAttribute("DataType", "String"), p.ProductName }),
                    new XElement("CategoryID", new object[] { new XAttribute("DataType", "Guid"), p.CategoryID }),
                    new XElement("QuantityPerUnit", new object[] { new XAttribute("DataType", "String"), p.QuantityPerUnit }),
                    new XElement("UnitPrice", new object[] { new XAttribute("DataType", "Decimal"), p.UnitPrice }),
                    new XElement("UnitsInStock", new object[] { new XAttribute("DataType", "Int32"), p.UnitsInStock }),
                    new XElement("ReorderLevel", new object[] { new XAttribute("DataType", "Int32?"), p.ReorderLevel }),
                    new XElement("Discontinued", new object[] { new XAttribute("DataType", "Boolean"), p.Discontinued })
                    );
                return productElem;
            }
    
            private Product GetProduct(XElement pElem)
            {
                Product p = new Product();
    
                p.ProductID = new Guid(pElem.Element("ProductID").Value);
                p.ProductName = pElem.Element("ProductName").Value;
                p.CategoryID = new Guid(pElem.Element("CategoryID").Value);
                p.QuantityPerUnit = pElem.Element("QuantityPerUnit").Value;
                p.UnitPrice = decimal.Parse(pElem.Element("UnitPrice").Value);
                p.UnitsInStock = Int32.Parse(pElem.Element("UnitsInStock").Value);
                if (!String.IsNullOrWhiteSpace(pElem.Element("ReorderLevel").Value))
                {
                    p.ReorderLevel = Int32.Parse(pElem.Element("ReorderLevel").Value);
                }
                p.Discontinued = Boolean.Parse(pElem.Element("Discontinued").Value);
    
                return p;
            }
    
            private ProductCategory GetProductCategory(XElement catElem)
            {
                ProductCategory pc = new ProductCategory();
                pc.CategoryID = new Guid(catElem.Element("CategoryID").Value);
                pc.CategoryName = catElem.Element("CategoryName").Value;
                pc.Description = catElem.Element("Description").Value;
    
                return pc;
            }
    
            private XElement GetProductCategoryElem(ProductCategory pc)
            {
                XElement catElem = new XElement("ProductCategory",
                   new XElement("CategoryID", new object[] { new XAttribute("DataType", "Guid"), pc.CategoryID }),
                   new XElement("CategoryName", new object[] { new XAttribute("DataType", "String"), pc.CategoryName }),
                   new XElement("Description", new object[] { new XAttribute("DataType", "String"), pc.Description })
                   );
                return catElem;
            }
    

Fügen Sie nun eine Comparer-Klasse zur XMLDataSource.vb- oder XMLDataSource.cs-Datei hinzu.

So fügen Sie eine Vergleichsklasse hinzu

  • Folgender Code ruft den Dateinamen und die Verbindungszeichenfolge aus der Datei "web.config" ab, überprüft die Datei und fügt bei Bedarf die XML-Elemente hinzu. Fügen Sie den Code nach der XMLDataSource-Klasse im DataSourceExtension.DataSources-Namespace ein.

    Public Class ProductEntitiesComparer
            Inherits Comparer(Of Object)
            Public Overrides Function Compare(x As Object, y As Object) As Integer
                If TypeOf x Is Product AndAlso TypeOf y Is ProductCategory Then
                    Return 1
                ElseIf TypeOf x Is ProductCategory AndAlso TypeOf y Is Product Then
                    Return -1
                Else
                    Return 0
                End If
            End Function
        End Class
    
    public class ProductEntitiesComparer : Comparer<object>
        {
            public override int Compare(object x, object y)
            {
                if (x is Product && y is ProductCategory)
                    return 1;
                else if (x is ProductCategory && y is Product)
                    return -1;
                else
                    return 0;
            }
        }
    

Mit diesen Schritten ist die Klasse XMLDataSource beendet. Der Code in dieser Klasse verfügt nicht nur über dienstverbindungsbezogenen Code, sondern auch über zwei Abfragen, eine zum Abrufen des Produkts nach ID und die zweite zum Abrufen des Produkts nach Kategorie. Diese Abfragen können ebenfalls in einer LightSwitch-Anwendung verwendet werden.

Der nächste Schritt besteht darin, zwei Klassen zum Speichern der Product- und ProductCategory-Daten zu erstellen.

Erstellen von Produkt- und Produktkategorieklassen

Neben der Klasse XMLDataSource benötigen Sie zwei weitere Klassen zur Abbildung der Product- und ProductCategory-Entitäten. Diese beiden Klassen werden dem Projekt DataSourceExtension.Server hinzugefügt.

So fügen Sie die Produktklasse hinzu

  1. Wählen Sie im Projektmappen-Explorer das Projekt DataSourceExtension.Server aus.

  2. Wählen Sie im Menü Projekt den Eintrag Klasse hinzufügen aus.

  3. Im Dialogfeld Neues Element hinzufügen wählen Sie das Feld Name aus und geben Product ein. Wählen Sie dann die Schaltfläche Hinzufügen aus.

  4. Ersetzen Sie in der Datei Product den vorhandenen Inhalt durch folgenden Code.

    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports System.ComponentModel
    Imports System.ComponentModel.DataAnnotations
    
    
    Namespace DataSourceExtension
        Public Class Product
            <Key()> _
            <[ReadOnly](True)> _
            <Display(Name:="Product ID")> _
            <ScaffoldColumn(False)> _
            Public Property ProductID() As Guid
                Get
                    Return m_ProductID
                End Get
                Set(value As Guid)
                    m_ProductID = value
                End Set
            End Property
            Private m_ProductID As Guid
    
            <Required()> _
            <Display(Name:="Product Name")> _
            Public Property ProductName() As String
                Get
                    Return m_ProductName
                End Get
                Set(value As String)
                    m_ProductName = value
                End Set
            End Property
            Private m_ProductName As String
    
            <Required()> _
            <Display(Name:="Category ID")> _
            Public Property CategoryID() As Guid
                Get
                    Return m_CategoryID
                End Get
                Set(value As Guid)
                    m_CategoryID = value
                End Set
            End Property
            Private m_CategoryID As Guid
    
            <Display(Name:="Quantity Per Unit")> _
            Public Property QuantityPerUnit() As String
                Get
                    Return m_QuantityPerUnit
                End Get
                Set(value As String)
                    m_QuantityPerUnit = value
                End Set
            End Property
            Private m_QuantityPerUnit As String
    
            <Range(0, Double.MaxValue, ErrorMessage:="The specified price must be greater than zero.")> _
            <Display(Name:="Unit Price")> _
            Public Property UnitPrice() As [Decimal]
                Get
                    Return m_UnitPrice
                End Get
                Set(value As [Decimal])
                    m_UnitPrice = value
                End Set
            End Property
            Private m_UnitPrice As [Decimal]
    
            <Display(Name:="Units In Stock")> _
            <Range(0, Int32.MaxValue, ErrorMessage:="Cannot have a negative quantity of products.")> _
            Public Property UnitsInStock() As Int32
                Get
                    Return m_UnitsInStock
                End Get
                Set(value As Int32)
                    m_UnitsInStock = value
                End Set
            End Property
            Private m_UnitsInStock As Int32
    
            <Display(Name:="Reorder Level")> _
            Public Property ReorderLevel() As Nullable(Of Int32)
                Get
                    Return m_ReorderLevel
                End Get
                Set(value As Nullable(Of Int32))
                    m_ReorderLevel = value
                End Set
            End Property
            Private m_ReorderLevel As Nullable(Of Int32)
    
            <Display(Name:="Discontinued")> _
            Public Property Discontinued() As [Boolean]
                Get
                    Return m_Discontinued
                End Get
                Set(value As [Boolean])
                    m_Discontinued = value
                End Set
            End Property
            Private m_Discontinued As [Boolean]
    
            <Association("Product_Category", "CategoryID", "CategoryID", IsForeignKey:=True)> _
            <Display(Name:="Category")> _
            Public Property Category() As ProductCategory
                Get
                    Return m_Category
                End Get
                Set(value As ProductCategory)
                    m_Category = value
                End Set
            End Property
            Private m_Category As ProductCategory
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    
    
    namespace DataSourceExtension
    {
        public class Product
        {
            [Key()]
            [ReadOnly(true)]
            [Display(Name = "Product ID")]
            [ScaffoldColumn(false)]
            public Guid ProductID { get; set; }
    
            [Required()]
            [Display(Name = "Product Name")]
            public string ProductName { get; set; }
    
            [Required()]
            [Display(Name = "Category ID")]
            public Guid CategoryID { get; set; }
    
            [Display(Name = "Quantity Per Unit")]
            public string QuantityPerUnit { get; set; }
    
            [Range(0, double.MaxValue, ErrorMessage = "The specified price must be greater than zero.")]
            [Display(Name = "Unit Price")]
            public Decimal UnitPrice { get; set; }
    
            [Display(Name = "Units In Stock")]
            [Range(0, Int32.MaxValue, ErrorMessage = "Cannot have a negative quantity of products.")]
            public Int32 UnitsInStock { get; set; }
    
            [Display(Name = "Reorder Level")]
            public Nullable<Int32> ReorderLevel { get; set; }
    
            [Display(Name = "Discontinued")]
            public Boolean Discontinued { get; set; }
    
            [Association("Product_Category", "CategoryID", "CategoryID", IsForeignKey = true)]
            [Display(Name = "Category")]
            public ProductCategory Category { get; set; }
        }
    }
    

So fügen Sie die ProductCategory-Klasse hinzu

  1. Wählen Sie im Projektmappen-Explorer das Projekt DataSourceExtension.Server aus.

  2. Wählen Sie im Menü Projekt den Eintrag Klasse hinzufügen aus.

  3. Im Dialogfeld Neues Element hinzufügen wählen Sie das Feld Name aus und geben ProductCategory ein. Wählen Sie dann die Schaltfläche Hinzufügen aus.

  4. Ersetzen Sie in der Datei ProductCategory den vorhandenen Inhalt durch folgenden Code.

    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports System.ComponentModel
    Imports System.ComponentModel.DataAnnotations
    
    Namespace DataSourceExtension
        Public Class ProductCategory
            <[ReadOnly](True)> _
            <Key()> _
            <Display(Name:="Category ID")> _
            <ScaffoldColumn(False)> _
            Public Property CategoryID() As Guid
                Get
                    Return m_CategoryID
                End Get
                Set(value As Guid)
                    m_CategoryID = Value
                End Set
            End Property
            Private m_CategoryID As Guid
    
            <Required()> _
            <Display(Name:="Category Name")> _
            Public Property CategoryName() As String
                Get
                    Return m_CategoryName
                End Get
                Set(value As String)
                    m_CategoryName = Value
                End Set
            End Property
            Private m_CategoryName As String
    
            <Display(Name:="Description")> _
            Public Property Description() As [String]
                Get
                    Return m_Description
                End Get
                Set(value As [String])
                    m_Description = Value
                End Set
            End Property
            Private m_Description As [String]
    
            <Display(Name:="Products")> _
            <Association("Product_Category", "CategoryID", "CategoryID")> _
            Public Property Products() As ICollection(Of Product)
                Get
                    Return m_Products
                End Get
                Set(value As ICollection(Of Product))
                    m_Products = Value
                End Set
            End Property
            Private m_Products As ICollection(Of Product)
        End Class
    End Namespace
    
     using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    
    namespace DataSourceExtension
    {
        public class ProductCategory
        {
            [ReadOnly(true)]
            [Key()]
            [Display(Name = "Category ID")]
            [ScaffoldColumn(false)]
            public Guid CategoryID { get; set; }
    
            [Required()]
            [Display(Name = "Category Name")]
            public string CategoryName { get; set; }
    
            [Display(Name = "Description")]
            public String Description { get; set; }
    
            [Display(Name = "Products")]
            [Association("Product_Category", "CategoryID", "CategoryID")]
            public ICollection<Product> Products { get; set; }
        }
    }
    

Mit diesen Schritten ist der Code für die Datenquellenerweiterung beendet. Jetzt können Sie einen Test in einer experimentellen Instanz von Visual Studio vornehmen.

Testen der Datenquellenerweiterung

Sie können die Datenquellenerweiterung in einer experimentellen Instanz von Visual Studio testen. Falls Sie nicht bereits ein anderes LightSwitch-Erweiterungsprojekt getestet haben, müssen Sie die experimentelle Instanz zunächst aktivieren.

So aktivieren Sie eine experimentelle Instanz

  1. Wählen Sie im Projektmappen-Explorer das BusinessTypeExtension.Vsix-Projekt aus.

  2. Wählen Sie in der Menüleiste Projekt und dann die Option für Eigenschaften von BusinessTypeExtension.Vsix aus.

  3. Wählen Sie auf der Registerkarte Debuggen unter Startaktion die Option Externes Programm starten aus.

  4. Geben Sie den Pfad der ausführbaren Visual Studio-Datei (devenv.exe) ein.

    Auf einem 32-Bit-System ist der Standardpfad C:\Programme\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe, und auf einem 64-Bit-System ist der Pfad C:\Programme (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe.

  5. Geben Sie im Feld Befehlszeilenargumente die Zeichenfolge /rootsuffix Exp ein.

    Hinweis

    Alle folgenden LightSwitch-Erweiterungsprojekte verwenden standardmäßig ebenfalls diese Einstellung.

So testen Sie die Datenquellenerweiterung

  1. Klicken Sie in der Menüleiste auf Debuggen und dann auf Debuggen starten. Eine experimentelle Instanz von Visual Studio wird geöffnet.

  2. Wählen Sie in der experimentellen Instanz in der Menüleiste Datei, Neu und Projekt aus.

  3. Erweitern Sie im Dialogfeld Neues Projekt den Knoten Visual Basic oder Visual C#, wählen Sie dann den Knoten LightSwitch und nachfolgend die Vorlage LightSwitch-Desktopanwendung aus.

  4. Geben Sie im Feld Name die Zeichenfolge DataSourceTest ein. Wählen Sie dann die Schaltfläche OK aus, um ein Testprojekt zu erstellen.

  5. Wählen Sie in der Menüleiste Projekt und die Option für Eigenschaften von DataSourceTest aus.

  6. Aktivieren Sie im Projekt-Designer auf der Registerkarte Erweiterungen das Kontrollkästchen DataSourceExtension.

  7. Wählen Sie in der Menüleiste die Optionen Projekt und Datenquelle hinzufügen aus.

  8. Wählen Sie im Assistenten zum Hinzufügen von Datenquellen die Option WCF RIA-Dienst aus, und wählen Sie dann die Schaltfläche Weiter.

  9. Wählen Sie DataSourceExtension.DataSources.XMLDataSource und dann Weiter aus.

  10. Erweitern Sie den Knoten Entitäten, und wählen Sie Product und ProductCategory aus.

  11. Im Feld Verbindungszeichenfolge geben Sie C:\Temp\Products.xml ein und wählen Fertig stellen aus.

    Die Datenquelle wird dem Knoten Datenquellen im Projektmappen-Explorer hinzugefügt. Beachten Sie, dass die Tabellen ProductCategory und Products angezeigt werden und die Abfragen GetProductByID und GetProductsByCategory unter Products abgebildet sind.

  12. Erstellen Sie eine Anwendung mit Bildschirmen zur Verwendung der Tabellen und Abfragen. Führen Sie die Anwendung anschließend aus, um das Verhalten zu prüfen.

    Beachten Sie, dass die Datenquelle wie jede andere Datenquelle funktioniert. Dies ermöglicht es Ihnen, Daten hinzuzufügen, zu löschen und zu aktualisieren.

Nächste Schritte

Damit ist die exemplarische Vorgehensweise für die Datenquelle beendet. Sie sollten nun über eine voll funktionsfähige Datenquellenerweiterung verfügen, die Sie in jedem LightSwitch-Projekt einsetzen können. Das war nur ein Beispiel für eine Datenquelle, möglicherweise möchten Sie eine Datenquelle erstellen, die auf einen anderen Datentyp zugreift. Dabei gelten die gleichen Schritte und Grundsätze.

Wenn Sie die Erweiterung verteilen möchten, sind einige zusätzliche Schritte erforderlich. Um die Richtigkeit der Informationen sicherzustellen, die für die Erweiterung im Projekt-Designer und Erweiterungs-Manager angezeigt werden, können die Eigenschaften für das VSIX-Paket aktualisiert werden. Weitere Informationen finden Sie unter Gewusst wie: VSIX-Paketeigenschaften. Außerdem sollten bei einer geplanten öffentlichen Verteilung der Erweiterung einige Punkte berücksichtigt werden. Weitere Informationen finden Sie unter Gewusst wie: Verteilen einer LightSwitch-Erweiterung.

Siehe auch

Aufgaben

Gewusst wie: VSIX-Paketeigenschaften

Gewusst wie: Verteilen einer LightSwitch-Erweiterung

Konzepte

LightSwitch-Erweiterbarkeits-Toolkit für Visual Studio 2013