Microsoft Store-Übermittlungs-API für MSI- oder EXE-App
Verwenden Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App zum programmgesteuerten Abfragen und Erstellen von Übermittlungen für MSI- oder EXE-Apps für das Partner Center-Konto Ihrer Organisation. Diese API ist nützlich, wenn Ihr Konto viele Apps verwaltet und Sie den Übermittlungsvorgang für diese Objekte automatisieren und optimieren möchten. Diese API verwendet Azure Active Directory (Azure AD) zum Autorisieren der Aufrufe von Ihrer App oder Ihrem Dienst.
Die folgenden Schritte beschreiben den End-to-End-Prozess der Verwendung der Microsoft Store-Übermittlungs-API:
- Stellen Sie sicher, dass alle Voraussetzungen erfüllt sind.
- Rufen Sie vor dem Aufrufen einer Methode in der Microsoft Store-Übermittlungs-API ein Azure AD-Zugriffstoken ab. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
- Rufen Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App auf.
Schritt 1: Erfüllen der Voraussetzungen für die Verwendung der Microsoft Store-Übermittlungs-API
Stellen Sie sicher, dass die folgenden Voraussetzungen erfüllt sind, bevor Sie mit dem Schreiben von Code zum Aufrufen der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App beginnen.
- Sie (oder Ihre Organisation) müssen über ein Azure AD-Verzeichnis verfügen, und Ihnen müssen die Berechtigungen globaler Administrator für das Verzeichnis gewährt worden sein. Wenn Sie Microsoft 365 oder andere Unternehmensdienste von Microsoft verwenden, verfügen Sie bereits über ein Azure AD-Verzeichnis. Andernfalls können Sie ohne zusätzliche Kosten eine neue Azure AD-Instanz in Partner Center erstellen.
- Sie müssen Ihrem Partner Center-Konto eine Azure AD-Anwendung zuordnen und Ihre Mandanten-ID, die Client-ID und den Schlüssel abrufen. Sie benötigen diese Werte, um ein Azure AD-Zugriffstoken zu erhalten, das Sie in Aufrufen der Microsoft Store-Übermittlungs-API verwenden.
- Bereiten Sie Ihre App mit der Microsoft Store-Übermittlungs-API auf den Einsatz vor:
- Wenn Ihre App noch nicht im Partner Center vorhanden ist, müssen Sie im Partner Center Ihre App durch Reservieren eines Namens erstellen. Sie können die Microsoft Store-Übermittlungs-API nicht zum Erstellen einer App im Partner Center verwenden. Sie müssen für die Erstellung im Partner Center arbeiten und können danach über die API auf die App zugreifen und programmgesteuert Übermittlungen dafür erstellen.
- Bevor Sie eine Übermittlung für eine bestimmte App mit dieser API erstellen können, müssen Sie zuerst eine Übermittlung für die App im Partner Center erstellen, einschließlich der Beantwortung des Fragebogens für Altersfreigaben . Anschließend können Sie über die API programmgesteuert neue Übermittlungen für diese App erstellen.
- Wenn Sie eine App-Übermittlung erstellen oder aktualisieren und ein neues Paket aufnehmen müssen, müssen Sie die Paketdetails vorbereiten.
- Wenn Sie eine App-Übermittlung erstellen oder aktualisieren und Screenshots oder Bilder für den Store-Eintrag aufnehmen müssen, müssen Sie die Screenshots und Bilder für die App vorbereiten.
Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto
Bevor Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App verwenden können, müssen Sie Ihrem Partner Center-Konto eine Azure AD-Anwendung zuordnen, die Mandanten-ID und die Client-ID für die Anwendung abrufen und einen Schlüssel generieren. Die Azure AD-Anwendung stellt die App oder den Dienst dar, von der bzw. dem aus Sie die Microsoft Store-Übermittlungs-API aufrufen möchten. Sie benötigen die Mandanten-ID, die Client-ID und den Schlüssel, um ein Azure AD-Zugriffstoken zu erhalten, das Sie an die API übergeben.
Hinweis
Sie müssen diese Aufgabe nur einmal ausführen. Nachdem Sie über die Mandanten-ID, die Client-ID und den Schlüssel verfügen, können Sie diese jederzeit wiederverwenden, wenn Sie ein neues Azure AD-Zugriffstoken erstellen müssen.
- Verknüpfen Sie in Partner Center das Partner Center-Konto Ihrer Organisation mit dem Azure AD-Verzeichnis Ihrer Organisation.
- Als Nächstes müssen Sie auf der Seite „Benutzer“ im Abschnitt „Kontoeinstellungen“ von Partner Center die Azure AD-Anwendung hinzufügen, die die App oder den Dienst darstellt, mit der bzw. dem Sie auf die Übermittlungen Ihres Partner Center-Kontos zugreifen. Stellen Sie sicher, dass Sie dieser Anwendung die Rolle Manager zuweisen. Wenn die Anwendung noch nicht in Ihrem Azure AD-Verzeichnis vorhanden ist, können Sie in Partner Center eine neue Azure AD-Anwendung erstellen.
- Kehren Sie zur Seite Benutzer zurück, klicken Sie auf den Namen Ihrer Azure AD-Anwendung, um die Anwendungseinstellungen zu öffnen, und schreiben Sie die Werte Mandanten-ID und Client-ID auf.
- Informationen zum Hinzufügen eines neuen Schlüssels oder geheimen Clientschlüssels finden Sie in den folgenden Anweisungen oder in den Anweisungen zum Registrieren der App über das Azure-Portal:
So registrieren Sie Ihre App:
Melden Sie sich beim Azure-Portal an.
Wenn Sie Zugriff auf mehrere Mandanten haben, verwenden Sie im Menü am oberen Rand den Filter Verzeichnis + Abonnement , um den Mandanten auszuwählen, in dem Sie die Anwendung registrieren möchten.
Suchen Sie nach Azure Active Directory, und wählen Sie diese Option aus.
Wählen Sie unter „Verwalten“ die „App-Registrierungen“ aus > wählen Sie Ihre Anwendung aus.
Wählen Sie „Zertifikate und Geheimnisse“ > „Geheime Clientschlüssel“ > „Neuer geheimer Clientschlüssel“ aus.
Fügen Sie eine Beschreibung für Ihren geheimen Clientschlüssel hinzu.
Wählen Sie für das Geheimnis eine Ablauffrist aus, oder geben Sie eine benutzerdefinierte Lebensdauer an.
Die Lebensdauer eines geheimen Clientschlüssels ist auf maximal zwei Jahre (24 Monate) begrenzt. Das bedeutet, dass keine benutzerdefinierte Lebensdauer angegeben werden kann, die über die 24 Monate hinausgeht.
Hinweis
Microsoft empfiehlt, den Wert für die Ablauffrist auf maximal 12 Monate festzulegen.
Wählen Sie Hinzufügen.
Notieren Sie sich den Wert des Geheimnisses, das in Ihrem Clientanwendungscode verwendet werden soll. Dieser Geheimniswert kann nach Verlassen dieser Seite nicht erneut angezeigt werden.
Schritt 2: Abrufen eines Azure AD-Zugriffstokens
Bevor Sie eine der Methoden in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App aufrufen, müssen Sie zunächst ein Azure AD-Zugriffstoken abrufen, das Sie an den Autorisierungsheader jeder Methode in der API übergeben. Nachdem Sie ein Zugriffstoken erhalten haben, haben Sie 60 Minuten Zeit, es zu verwenden, bevor es abläuft. Nach dem Ablauf können Sie das Token aktualisieren, damit Sie es in weiteren Aufrufen der API weiterhin verwenden können.
Gehen Sie zum Abrufen des Zugriffstokens nach den Anweisungen unter [Dienst-zu-Dienst-Aufrufe mit Clientanmeldedaten]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) vor, um einen HTTP POST an den https://login.microsoftonline.com/<tenant_id>/oauth2/token-Endpunkt zu senden. Hier ist eine Beispielanforderung:
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8
grant_type=client_credentials
&client_id=<your_client_id>
&client_secret=<your_client_secret>
&scope=https://api.store.microsoft.com/.default
Geben Sie die Mandanten-ID, die Client-ID und den Schlüssel für die Anwendung, die Sie im vorherigen Abschnitt aus Partner Center abgerufen haben, für den Wert tenant_id
im POST-URI sowie die Parameter client_id
und client_secret
an. Für den Bereichsparameter müssen Sie https://api.store.microsoft.com/.default
angeben.
Nachdem Ihr Zugriffstoken abgelaufen ist, können Sie es nach den hier beschriebenen Anweisungen erneuern.
Beispiele zum Abrufen eines Zugriffstokens unter Verwendung von C# oder Node.js finden Sie in den Codebeispielen für die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App.
Schritt 3: Verwenden der Microsoft Store-Übermittlungs-API
Nachdem Sie über ein Azure AD-Zugriffstoken verfügen, können Sie in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App Methoden aufrufen. Die API enthält viele Methoden, die in Szenarien für Apps gruppiert sind. Zum Erstellen oder Aktualisieren von Übermittlungen werden in der Regel mehrere Methoden in einer bestimmten Reihenfolge aufgerufen. Informationen zu den einzelnen Szenarien und zur Syntax der einzelnen Methoden finden Sie in den folgenden Abschnitten:
Hinweis
Nach dem Abruf eines Zugriffstokens haben Sie 60 Minuten Zeit zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App, bevor es abläuft.
Basis-URL
Die Basis-URL für die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App ist: https://api.store.microsoft.com
API-Verträge
API zum Abrufen der aktuellen Metadaten für Übermittlungsentwürfe
Ruft Metadaten in jedem Modul (Listings, Eigenschaften oder Verfügbarkeit) zum aktuellen Übermittlungsentwurf ab.
Pfad [Alle Module]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Pfad [Einzelnes Modul]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Methode: GET
Pfadparameter
Parameter | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
moduleName | Partner Center-Modul – Listings, Eigenschaften oder Verfügbarkeit |
Abfrageparameter
Parameter | Beschreibung |
---|---|
languages | Optional Der Listingsprachenfilter als kommagetrennte Zeichenkette [maximal 200 Sprachen]. Wenn nicht vorhanden, werden die Metadaten der ersten 200 verfügbaren Listingsprachen abgerufen. [ z. B. „en-us, en-gb“]. |
includelanguagelist | Optional Boolean – wenn „true“, wird die Liste der hinzugefügten Listingsprachen und der Status ihrer Abgeschlossenheit zurückgegeben. |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Die im Partner Center-Konto registrierte Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
accessibilitySupport | Boolean | |
additionalLicenseTerms | String | |
Verfügbarkeit | Objekt | Daten des Verfügbarkeitsmoduls |
category | String | Siehe Liste der Kategorien unten |
certificationNotes | String | |
Code | String | Der Fehlercode der Meldung |
contactInfo | String | |
copyright | String | |
dependsOnDriversOrNT | Boolean | |
Beschreibung | String | |
developedBy | String | |
discoverability | String | [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
freeTrial | String | [NO_FREE_TRIAL; FREE_TRIAL] |
hardwareItemType | String | |
isPrivacyPolicyRequired | Boolean | |
isRecommended | Boolean | |
isRequired | Boolean | |
IsSuccess | Boolean | |
isSystemFeatureRequired | Array von Objekten | |
Sprache | String | Siehe Liste der Sprachen unten |
listings | Array von Objekten | Daten des Listingmoduls für jede Sprache |
Märkte | Array aus Zeichenfolgen | Siehe Liste der Märkte unten |
message | String | Die Beschreibung des Fehlers |
minimumHardware | String | |
minimumRequirement | String | |
penAndInkSupport | Boolean | |
Preise | String | [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
privacyPolicyUrl | String | |
productDeclarations | Objekt | |
productFeatures | Array aus Zeichenfolgen | |
properties | Objekt | Daten des Eigenschaftenmoduls |
recommendedHardware | String | |
recommendedRequirement | String | |
responseData | Objekt | Enthält die tatsächliche Antwort-Payload für die Anforderung. |
Anforderungen | Array von Objekten | |
searchTerms | Array aus Zeichenfolgen | |
shortDescription | String | |
subcategory | String | Siehe Liste der Unterkategorien unten |
supportContactInfo | String | |
systemRequirementDetails | Array von Objekten | |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
Website | String | |
whatsNew | String |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"availability":{
"markets": ["US"],
"discoverability": "DISCOVERABLE",
"enableInFutureMarkets": true,
"pricing": "PAID",
"freeTrial": "NO_FREE_TRIAL"
},
"properties":{
"isPrivacyPolicyRequired": true,
"privacyPolicyUrl": "http://contoso.com",
"website": "http://contoso.com",
"supportContactInfo": "http://contoso.com",
"certificationNotes": "Certification Notes",
"category": "DeveloperTools",
"subcategory": "Database",
"productDeclarations": {
"dependsOnDriversOrNT": false,
"accessibilitySupport": false,
"penAndInkSupport": false
},
"isSystemFeatureRequired": [
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Touch"
},
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Keyboard"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Mouse"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Camera"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_HCE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_Proximity"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Bluetooth_LE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Telephony"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Microphone"
}
],
"systemRequirementDetails": [
{
"minimumRequirement": "1GB",
"recommendedRequirement": "4GB",
"hardwareItemType": "Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "DirectX"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Video_Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Processor"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Graphics"
}
]
},
"listings":[{
"language": "en-us",
"description": "Description",
"whatsNew": "What's New",
"productFeatures": ["Feature 1"],
"shortDescription": "Short Description",
"searchTerms": ["Search Ter 1"],
"additionalLicenseTerms": "License Terms",
"copyright": "Copyright Information",
"developedBy": "Developer Details",
"sortTitle": "Product 101",
"requirements": [
{
"minimumHardware": "Pentium4",
"recommendedHardware": "Corei9"
}
],
"contactInfo": "contactus@contoso.com"
}],
"listingLanguages": [{"language":"en-us", "isComplete": true}]
}
}
API zum Aktualisieren der aktuellen Metadaten für Übermittlungsentwürfe
Aktualisiert Metadaten in jedem Modul des Übermittlungsentwurfs Die API-Prüfungen
- Für aktive Übermittlung. Wenn vorhanden, Fehler mit Fehlermeldung.
- Zum Zulassen des Vorgangs „Entwurf speichern“, wenn alle Module den Status „Bereit“ haben.
- Jedes Feld in der Übermittlung wird gemäß den Anforderungen des Store auf Gültigkeit geprüft.
- Gültigkeitsprüfungsregeln für Details der Systemanforderungen:
- Zulässige Werte in hardwareItemType = Memory: 300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB
- Zulässige Werte in hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
- Zulässige Werte in hardwareItemType = Video_Memory: 1GB, 2GB, 4GB, 6GB
Pfad [Vollständiges Update des Moduls]: /submission/v1/product/{productId}/metadata
Methode: PUT
Pfad [Patch-Update des Moduls]: /submission/v1/product/{productId}/metadata
Methode: PATCH
API-Verhalten
Im Fall der API für ein vollständiges Update des Moduls müssen für eine vollständige Aktualisierung jedes Felds sämtliche Moduldaten in der Anforderung vorhanden sein. Bei jedem in der Anforderung nicht vorhanden Feld wird zum Überschreiben des aktuellen Werts für das betreffende Modul der Standardwert verwendet.
Im Fall der API für ein Patch-Update des Moduls müssen nur die zu aktualisierenden Felder in der Anforderung vorhanden sein. Diese Feldwerte aus der Anforderung überschreiben die jeweils vorhandenen Werte, wobei alle anderen Felder, die in der Anforderung nicht vorhanden sind, für das betreffende Modul unverändert bleiben.
Pfadparameter
Parameter | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Die im Partner Center-Konto registrierte Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Anforderungsparameter
Name | Typ | BESCHREIBUNG |
---|---|---|
Verfügbarkeit | Objekt | Objekt zum Aufnehmen der Metadaten des Verfügbarkeitsmoduls |
Märkte | Array aus Zeichenfolgen | Erforderlich Siehe Liste der Märkte unten |
discoverability | String | Erforderlich [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Boolean | Erforderlich |
Preise | String | Erforderlich [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
freeTrial | String | Erforderlich, wenn für Preise PAID oder SUBSCRIPTION angegeben ist [NO_FREE_TRIAL, FREE_TRIAL] |
properties | Objekt | Objekt zum Aufnehmen der Metadaten des Eigenschaftenmoduls |
isPrivacyPolicyRequired | Boolean | Erforderlich |
privacyPolicyUrl | String | Erforderlich, wenn isPrivacyPolicyRequired = true Muss eine gültige URL sein |
Website | String | Muss eine gültige URL sein |
supportContactInfo | String | Muss eine gültige URL oder E-Mail Adresse sein |
certificationNotes | String | Empfohlen Maximal 2000 Zeichen |
category | String | Erforderlich Siehe Liste der Kategorien unten |
subcategory | String | Erforderlich Siehe Liste der Unterkategorien unten |
productDeclarations | Objekt | Erforderlich |
isSystemFeatureRequired | Array von Objekten | [Toucheingabe, Tastatur, Maus, Kamera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonie, Mikrofon] |
isRequired | Boolean | Erforderlich |
isRecommended | Boolean | Erforderlich |
hardwareItemType | String | Erforderlich |
systemRequirementDetails | Array von Objekten | [Prozessor, Grafiken, Arbeitsspeicher, DirectX, Video_Memory] |
minimumRequirement | String | Erforderlich Für systemRequirementsText, MaxLength = 200 Zulässige Werte in hardwareItemType = Memory: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB] Zulässige Werte in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Zulässige Werte in hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB] |
recommendedRequirement | String | Erforderlich Für systemRequirementsText, MaxLength = 200 Zulässige Werte in hardwareItemType = Memory: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB] Zulässige Werte in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Zulässige Werte in hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB] |
dependsOnDriversOrNT | Boolean | Erforderlich |
accessibilitySupport | Boolean | Erforderlich |
penAndInkSupport | Boolean | Erforderlich |
listings | Objekt | Objekt für die Daten des Listingmoduls für eine einzelne Sprache |
Sprache | String | Erforderlich Siehe Liste der Sprachen unten |
Beschreibung | String | Erforderlich Maximal 10000 Zeichen |
whatsNew | String | Maximal 1500 Zeichen |
productFeatures | Zeichenfolgenarray | 200 Zeichen pro Feature; bis zu 20 Features |
shortDescription | String | Maximal 1000 Zeichen |
searchTerms | Zeichenfolgenarray | 30 Zeichen pro Suchbegriff; bis zu 7 Suchbegriffe 21 eindeutige Wörter INSGESAMT für alle Suchbegriffe |
additionalLicenseTerms | String | Erforderlich Maximal 10000 Zeichen |
copyright | String | Maximal 200 Zeichen |
developedBy | String | Maximal 255 Zeichen |
Anforderungen | Array von Objekten | 200 Zeichen pro Element; bis zu 11 Elemente INSGESAMT zwischen Minimum und empfohlen] |
minimumHardware | String | Maximal 200 Zeichen |
recommendedHardware | String | Maximal 200 Zeichen |
contactInfo | String | Maximal 200 Zeichen |
listingsToAdd | Array aus Zeichenfolgen | Siehe Liste der Sprachen unten |
listingsToRemove | Array aus Zeichenfolgen | Siehe Liste der Sprachen unten |
Märkte
Markt | Abkürzung |
---|---|
Afghanistan | AF |
Albanien | AL |
Algerien | DZ |
Amerikanisch-Samoa | AS |
Andorra | AD |
Angola | AO |
Anguilla | KI |
Antarktis | AQ |
Antigua und Barbuda | Verfügbarkeitsgruppe |
Argentinien | AR |
Armenien | AM |
Aruba | AW |
Australien | AU |
Österreich | AT |
Aserbaidschan | RP |
Bahamas | BS |
Bahrain | BH |
Bangladesch | BD |
Barbados | BB |
Belarus | BY |
Belgien | BE |
Belize | BZ |
Benin | BJ |
Bermudas | BM |
Bhutan | BT |
Bolivarische Republik Venezuela | VE |
Bolivien | BO |
Bonaire | BQ |
Bosnien und Herzegowina | BA |
Botsuana | BW |
Bouvetinsel | BV |
Brasilien | BR |
Britisches Territorium im Indischen Ozean | IO |
Britische Jungferninseln | VG |
Brunei | BN |
Bulgarien | BG |
Burkina Faso | BF |
Burundi | BI |
Kambodscha | KH |
Kamerun | CM |
Canada | CA |
Cabo Verde | CV |
Kaimaninseln | HE |
Zentralafrikanische Republik | CF |
Tschad | TD |
Chile | CL |
China | CN |
Weihnachtsinsel | CX |
Kokosinseln | CC |
Kolumbien | CO |
Komoren | KM |
Kongo (Demokratische Republik) | CG |
Kongo (DRC) | CD |
Cookinseln | CK |
Costa Rica | CR |
Kroatien | HR |
Curaçao | CW |
Zypern | CY |
Tschechische Republik | CZ |
Côte d'Ivoire | CI |
Dänemark | DK |
Dschibuti | DJ |
Dominica | DM |
Dominikanische Republik | DO |
Ecuador | EC |
Ägypten | EG |
El Salvador | SV |
Äquatorialguinea | GQ |
Eritrea | ER |
Estland | EE |
Äthiopien | ET |
Falklandinseln | FS |
Färöer | FO |
Fidschi | FJ |
Finnland | FI |
Frankreich | BV |
Französisch-Guayana | GF |
Französisch-Polynesien | PF |
Französische Süd- und Antarktisgebiete | TF |
Gabun | Allgemein verfügbar |
Gambia | GM |
Georgien | GE |
Deutschland | DE |
Ghana | GH |
Gibraltar | GI |
Griechenland | GR |
Grönland | GL |
Grenada | GD |
Guadeloupe | GP |
Guam | GU |
Guatemala | GT |
Guernsey | GG |
Guinea | GN |
Guinea-Bissau | GW |
Guayana | GY |
Haiti | HT |
Heard und McDonaldinseln | HM |
Vatikanstadt | VA |
Honduras | HN |
Hongkong (SAR) | HK |
Ungarn | HU |
Island | IS |
Indien | IN |
Indonesien | Kennung |
Irak | IQ |
Irland | IE |
Israel | BY |
Italien | IT |
Jamaika | JM |
Japan | JP |
Jersey | JE |
Jordan | JO |
Kasachstan | KZ |
Kenia | KE |
Kiribati | KI |
Korea | KR |
Kuwait | KW |
Kirgisistan | KG |
Laos | LA |
Lettland | LV |
Libanon | LB |
Lesotho | LS |
Liberia | LR |
Libyen | LY |
Liechtenstein | LI |
Litauen | LT |
Luxemburg | LU |
Macau (SAR) | MO |
Nordmazedonien | MK |
Madagaskar | MG |
Malawi | MW |
Malaysia | MY |
Malediven | MV |
Mali | ML |
Malta | MT |
Isle of Man | IM |
Marshallinseln | MH |
Martinique | MQ |
Mauretanien | MR |
Mauritius | MU |
Mayotte | YT |
Mexiko | MX |
Mikronesien | FM |
Moldau | MD |
Monaco | MC |
Mongolei | BB |
Montenegro – ME | |
Montserrat | MS |
Marokko | NI |
Mosambik | MZ |
Myanmar | MM |
Namibia | Nicht verfügbar |
Nauru | NR |
Nepal | NP |
Niederlande | NL |
Neukaledonien | NC |
Neuseeland | NZ |
Nicaragua | NI |
Niger | NE |
Nigeria | NG |
Niue | NU |
Norfolkinsel | NF |
Nördliche Marianen | MP |
Norwegen | NEIN |
Oman | OM |
Pakistan | PK |
Palau | PW |
Palästinensische Autonomiegebiete | PS |
Panama | PA |
Papua-Neuguinea | PG |
Paraguay | PY |
Peru | PE |
Philippinen | PH |
Pitcairninseln | PN |
Polen | PL |
Portugal | PT |
Katar | QA |
Réunion | RE |
Rumänien | RO |
Russland | RU |
Ruanda | RW |
St. Barthélemy | BL |
St. Helena, Ascension und Tristan da Cunha | SH |
St. Kitts und Nevis | KN |
St. Lucia | LC |
St. Martin (französischer Teil) | MF |
St. Pierre und Miquelon | PM |
St. Vincent und die Grenadinen | VC |
Samoa | WS |
San Marino | SM |
Saudi-Arabien | SA |
Senegal | SN |
Serbien | RS |
Seychellen | SC |
Sierra Leone | SL |
Singapur | SG |
Sint Maarten (niederländischer Teil) | SX |
Slowakei | SK |
Slowenien | SI |
Salomonen | SB |
Somalia | SO |
Südafrika | ZA |
Südgeorgien und die Südlichen Sandwichinseln | GS |
Spanien | ES |
Sri Lanka | LK |
Surinam | SR |
Spitzbergen und Jan Mayen | SJ |
Swasiland | SZ |
Schweden | SE |
Schweiz | CH |
São Tomé und Príncipe | ST |
Taiwan | TW |
Tadschikistan | TJ |
Tansania | TZ |
Thailand | TH |
Timor-Leste | TL |
Togo – TG | |
Tokelau | TK |
Tonga | TO |
Trinidad und Tobago – TT | |
Tunesien | TN |
Türkiye | TR |
Turkmenistan | TM |
Turks- und Caicosinseln | TC |
Tuwalu | TV |
USA Kleinere Amerikanische Überseeinseln | UM |
Amerikanische Jungferninseln | VI |
Uganda | UG |
Ukraine | UA |
Vereinigte Arabische Emirate | AE |
United Kingdom | GB |
USA | US |
Uruguay | UY |
Usbekistan | UZ |
Vanuatu | VU |
Vietnam | VN |
Wallis und Futuna | WF |
Jemen | YE |
Sambia | ZM |
Simbabwe | ZW |
Ålandinseln | AX |
Kategorien und Unterkategorien
Kategorie | Unterkategorien |
---|---|
BooksAndReference | EReader, Fiction, Nonfiction, Reference |
Business | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses |
DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting |
Education | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids |
Entertainment | (Keine) |
FoodAndDining | (Keine) |
GovernmentAndPolitics | (Keine) |
HealthAndFitness | (Keine) |
KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel |
Lifestyle | Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion |
Medizin | (Keine) |
MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction |
Musik | (Keine) |
NavigationAndMaps | (Keine) |
NewsAndWeather | Nachrichten, Wetter |
PersonalFinance | BankingAndInvestments, BudgetingAndTaxes |
Personalisierung | RingtonesAndSounds, themes, WallpaperAndLockScreens |
PhotoAndVideo | (Keine) |
Produktivität | (Keine) |
Sicherheit | PCProtection, PersonalSecurity |
Shopping | (Keine) |
Soziale Netzwerke | (Keine) |
Sport | (Keine) |
Anfahrt | CityGuides, Hotels |
UtilitiesAndTools | BackupAndManage, FileManager |
Sprachen
Name der Sprache | Unterstützte Sprachcodes |
---|---|
Afrikaans | af, af-za |
Albanisch | sq, sq-al |
Amharisch | am, am-et |
Armenisch | hy, hy-am |
Assamesisch | as, as-in |
Aserbaidschanisch | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az |
Baskisch (Baskisch) | eu, eu-es |
Belarussisch | be, be-by |
Bengalisch | bn, bn-bd, bn-in |
Bosnisch | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba |
Bulgarisch | bg, bg-bg |
Katalanisch | ca, ca-es, ca-es-valencia |
Cherokee | chr-cher, chr-cher-us, chr-latn |
Chinesisch (vereinfacht) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg |
Chinesisch (traditionell) | zh-Hant, zh-hk, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw |
Kroatisch | hr, hr-hr, hr-ba |
Tschechisch | cs, cs-cz |
Dänisch | da, da-dk |
Dari | prs, prs-af, prs-arab |
Niederländisch | nl, nl-nl, nl-be |
Englisch | en, en-au, en-ca, en-gb, en-ie, en-in, en-nz, en-sg, en-us, en-za, en-bz, en-hk, en-id, en-jm, en-kz, en-mt, en-my, en-ph, en-pk, en-tt, en-vn, en-zw |
Estnisch | et, et-ee |
Philippinisch – fil, fil-latn, fil-ph | |
Finnisch | fi, fi-fi |
Französisch | fr, fr-be , fr-ca , fr-ch , fr-fr , fr-lu, fr-cd, fr-ci, fr-cm, fr-ht, fr-ma, fr-mc, fr-ml, fr-re, frc-latn, frp-latn |
Galicisch | gl, gl-es |
Georgisch | ka, ka-ge |
Deutsch | de, de-at, de-ch, de-de, de-lu, de-li |
Griechisch | el, el-gr |
Gujarati | gu, gu-in |
Haussa | ha, ha-latn, ha-latn-ng |
Hebräisch | he, he-il |
Hindi | hi, hi-in |
Ungarisch | hu, hu-hu |
Isländisch | is, is-is |
Igbo – ig-latn, ig-ng | |
Indonesisch | id, id-id |
Inuktitut (Lateinisch) | iu-cans, iu-latn, iu-latn-ca |
Irisch | ga, ga-ie |
isi Xhosa | xh, xh-za |
isi Zulu | zu, zu-za |
Italienisch | it, it-it, it-ch |
Japanisch | ja , ja-jp |
Kannada | kn, kn-in |
Kasachisch | kk, kk-kz |
Khmer | km, km-kh |
K'iche' | quc-latn, qut-gt, qut-latn |
Kinyarwanda | rw, rw-rw |
Kisuaheli | sw, sw-ke |
Konkani | kok, kok-in |
Koreanisch | ko, ko-kr |
Kurdisch | ku-arab, ku-arab-iq |
Kirgisisch | ky-kg, ky-cyrl |
Laotisch | lo, lo-la |
Lettisch | lv, lv-lv |
Litauisch | lt, lt-lt |
Luxemburgisch | lb, lb-lu |
Mazedonisch | mk, mk-mk |
Malaiisch | ms, ms-bn, ms-my |
Malayalam | ml, ml-in |
Maltesisch | mt, mt-mt |
Maori | mi, mi-latn, mi-nz |
Marathi | mr, mr-in |
Mongolisch (Kyrillisch) | mn-cyrl, mn-mong, mn-mn, mn-phag |
Nepalesisch | ne, ne-np |
Norwegisch | nb, nb-no, nn, nn-no, no, no-no |
Odia | or, or-in |
Persisch | fa, fa-ir |
Polnisch | pl, pl-pl |
Portugiesisch (Brasilien) | pt-br |
Portugiesisch (Portugal) | pt, pt-pt |
Pandschabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in |
Quechua | quz, quz-bo, quz-ec, quz-pe |
Rumänisch | ro, ro-ro |
Russisch | ru , ru-ru |
Schottisch-Gälisch | gd-gb, gd-latn |
Serbisch (Lateinisch) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs |
Serbisch (Kyrillisch) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs |
Nord-Sotho | nso, nso-za |
Tswana | tn, tn-bw, tn-za |
Sindhi | sd-arab, sd-arab-pk, sd-deva |
Singhalesisch | si, si-lk |
Slowakisch | sk, sk-sk |
Slowenisch | sl, sl-si |
Spanisch | es, es-cl, es-co, es-es, es-mx, es-ar, es-bo, es-cr, es-do, es-ec, es-gt, es-hn, es-ni, es-pa, es-pe, es-pr, es-py, es-sv, es-us, es-uy, es-ve |
Schwedisch | sv, sv-se, sv-fi |
Tadschikisch (Kyrillisch) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn |
Tamilisch | ta, ta-in |
Tatarisch | tt-arab, tt-cyrl, tt-latn, tt-ru |
Telugu | te, te-in |
Thailändisch | th, th-th |
Tigrinya | ti, ti-et |
Türkisch | tr, tr-tr |
Turkmenisch | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr |
Ukrainisch | uk, uk-ua |
Urdu | ur, ur-pk |
Uigurisch | ug-arab, ug-cn, ug-cyrl, ug-latn |
Usbekisch (Lateinisch) | uz, uz-cyrl, uz-latn, uz-latn-uz |
Vietnamesisch | vi, vi-vn |
Walisisch | cy, cy-gb |
Wolof | wo, wo-sn |
Yoruba | yo-latn, yo-ng |
Beispiel für eine Anforderung
{
"availability":{
"markets": ["US"],
"discoverability": "DISCOVERABLE",
"enableInFutureMarkets": true,
"pricing": "PAID",
"freeTrial": "NO_FREE_TRIAL"
},
"properties":{
"isPrivacyPolicyRequired": true,
"privacyPolicyUrl": "http://contoso.com",
"website": "http://contoso.com",
"supportContactInfo": "http://contoso.com",
"certificationNotes": "Certification Notes",
"category": "DeveloperTools",
"subcategory": "Database",
"productDeclarations": {
"dependsOnDriversOrNT": false,
"accessibilitySupport": false,
"penAndInkSupport": false
},
"isSystemFeatureRequired": [
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Touch"
},
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Keyboard"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Mouse"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Camera"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_HCE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_Proximity"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Bluetooth_LE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Telephony"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Microphone"
}
],
"systemRequirementDetails": [
{
"minimumRequirement": "1GB",
"recommendedRequirement": "4GB",
"hardwareItemType": "Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "DirectX"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Video_Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Processor"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Graphics"
}
]
},
"listings":{
"language": "en-us",
"description": "Description",
"whatsNew": "What's New",
"productFeatures": ["Feature 1"],
"shortDescription": "Short Description",
"searchTerms": ["Search Ter 1"],
"additionalLicenseTerms": "License Terms",
"copyright": "Copyright Information",
"developedBy": "Developer Details",
"sortTitle": "Product 101",
"requirements": [
{
"minimumHardware": "Pentium4",
"recommendedHardware": "Corei9"
}
],
"contactInfo": "contactus@contoso.com"
},
"listingsToAdd": ["en-au"],
"listingsToRemove": ["en-gb"]
}
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | Enthält die tatsächliche Antwort-Payload für die Anforderung. |
pollingUrl | String | Abruf-URL zum Abrufen des Status einer laufenden Übermittlung |
ongoingSubmissionId | String | Übermittlungs-ID einer bereits laufenden Übermittlung |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API zum Abrufen der aktuellen Paketentwürfe
Ruft Paketdetails zum aktuellen Übermittlungsentwurf ab.
Pfad [Alle Pakete]: /submission/v1/product/{productId}/packages
Methode: GET
Pfad [Einzelnes Paket]: /submission/v1/product/{productId}/packages/{packageId}
Methode: GET
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
packageId | Die eindeutige ID des abzurufenden Pakets |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
packages | Array von Objekten | Objekt zum Aufnehmen der Daten des Paketmoduls |
packageId | String | |
packageUrl | String | |
languages | Array aus Zeichenfolgen | |
architectures | Array aus Zeichenfolgen | [Neutral; X86; X64; Arm; Arm64] |
isSilentInstall | Boolean | Sollte als „true“ markiert sein, wenn das Installationsprogramm ohne erforderliche Switches im unbeaufsichtigten Modus ausgeführt wird, oder andernfalls als „false“ |
installerParameters | String | |
genericDocUrl | String | |
errorDetails | Array von Objekten | |
errorScenario | String | |
errorScenarioDetails | Array von Objekten | |
errorValue | String | |
errorUrl | String | |
packageType | String |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData":{
"packages":[{
"packageId": "pack0832",
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}]
}
}
API zum Aktualisieren der aktuellen Paketentwürfe
Aktualisiert Paketdetails zum aktuellen Übermittlungsentwurf.
Pfad [Vollständiges Update des Moduls]: /submission/v1/product/{productId}/packages
Methode: PUT
Pfad [Patch-Update eines einzelnen Pakets]: /submission/v1/product/{productId}/packages/{packageId}
Methode: PATCH
API-Verhalten
Im Fall der API für ein vollständiges Update des Moduls müssen für eine vollständige Aktualisierung jedes Felds sämtliche Paketdaten in der Anforderung vorhanden sein. Bei jedem in der Anforderung nicht vorhanden Feld wird zum Überschreiben des aktuellen Werts für das betreffende Modul der Standardwert verwendet. Dadurch werden alle vorhandenen Pakete mit einem neuen Satz von Paketen aus der Anforderung überschrieben. Dadurch werden Paket-IDs neu generiert, und der Benutzer sollte für die neuesten Paket-IDs die API zum Abrufen von Paketen aufrufen.
Im Fall der API für ein Patch-Update eines einzelnen Pakets müssen nur die für ein bestimmtes Paket zu aktualisierenden Felder in der Anforderung vorhanden sein. Diese Feldwerte aus der Anforderung überschreiben die jeweils vorhandenen Werte, wobei alle anderen Felder, die in der Anforderung nicht vorhanden sind, für das betreffende Paket unverändert bleiben. Andere Pakete im Satz bleiben unverändert.
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
packageId | Die eindeutige ID des Pakets |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Anforderungsparameter
Name | Typ | Beschreibung |
---|---|---|
packages | Array von Objekten | Objekt zum Aufnehmen der Daten des Paketmoduls [Nur erforderlich für vollständiges Update des Moduls] |
packageUrl | String | Erforderlich |
languages | Array aus Zeichenfolgen | Erforderlich |
architectures | Array aus Zeichenfolgen | Erforderlich Sollte eine einzelne Architektur enthalten – Neutral, X86, X64, Arm, Arm64 |
isSilentInstall | Boolean | Erforderlich Sollte als „true“ markiert sein, wenn das Installationsprogramm ohne erforderliche Switches im unbeaufsichtigten Modus ausgeführt wird, oder andernfalls als „false“ |
installerParameters | String | Erforderlich, wenn isSilentInstall „false“ ist |
genericDocUrl | String | Erforderlich, wenn packageType „exe“ ist Link zum Dokument mit Details der benutzerdefinierten Fehlercodes für das EXE-Typ-Installationsprogramm |
errorDetails | Array von Objekten | Metadaten zum Aufnehmen benutzerdefinierter Fehlercodes und Details für EXE-Typ-Installationsprogramme. |
errorScenario | String | Bestimmung des spezifischen Fehlerszenarios. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | Array von Objekten | |
errorValue | String | Fehlercode, der während der Installation vorhanden sein kann |
errorUrl | String | URL mit Details zum Fehler |
packageType | String | Erforderlich [exe, msi] |
Beispielanforderung [Vollständiges Update des Moduls]
{
"packages":[{
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}]
}
Beispielanforderung [Patch-Update eines einzelnen Pakets]
{
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | [Die Liste der eventuellen Fehler- oder Warnmeldungen] |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
pollingUrl | String | [Abruf-URL zum Abrufen des Status im Fall einer bereits laufenden Übermittlung] |
ongoingSubmissionId | String | [Übermittlungs-ID einer bereits laufenden Übermittlung] |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API zum Committen von Paketen
Committet den neuen Satz von Paketen, die mit den APIs zum Aktualisieren von Paketen zum aktuellen Übermittlungsentwurf aktualisiert wurden. Diese API gibt eine Abruf-URL zum Nachverfolgen des Paketuploads zurück.
Pfad: /submission/v1/product/{productId}/packages/commit
Methode: POST
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | [Die Liste der eventuellen Fehler- oder Warnmeldungen] |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
pollingUrl | String | [Abruf-URL zum Abrufen des Status von Paketuploads oder des Übermittlungsstatus im Fall einer bereits laufenden Übermittlung] |
ongoingSubmissionId | String | [Übermittlungs-ID einer bereits laufenden Übermittlung] |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/status",
"ongoingSubmissionId": ""
}
}
API zum Abrufen der aktuellen Listingentwurfsobjekte
Ruft Details zu Listingobjekten zum aktuellen Übermittlungsentwurf ab.
Pfad: /submission/v1/product/{productId}/listings/assets?languages={languages}
Methode: GET
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Abfrageparameter
Name | Beschreibung |
---|---|
languages | [Optional] Der Listingsprachenfilter als kommagetrennte Zeichenkette [maximal 200 Sprachen]. Wenn nicht vorhanden, werden die Objektdaten der ersten 200 verfügbaren Listingsprachen abgerufen. (z. B. „en-us, en-gb“) |
Erforderliche Header
Header | Wert |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Wert |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
listingAssets | Array von Objekten | Details zu Listingobjekten für jede Sprache |
Sprache | String | |
storeLogos | Array von Objekten | |
screenshots | Array von Objekten | |
id | String | |
assetUrl | String | Muss eine gültige URL sein |
imageSize | Objekt | |
width | Ganzzahl | |
Höhe | Ganzzahl |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData":{
"listingAssets": [{
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
"imageSize": {
"width": 2160,
"height": 2160
}
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
"imageSize": {
"width": 2160,
"height": 2160
}
}
]
}]
}
}
API zum Erstellen von Listingobjekten
Erstellt einen neuen Upload von Listingobjekten zum aktuellen Übermittlungsentwurf.
Aktualisieren von Listingobjekten
Die Microsoft Store-Übermittlungs-API für EXE- oder MSI-App verwendet laufzeitgenerierte SAS-URLs für Blob-Stores für die einzelnen Uploads von Bildobjekten zusammen mit einem Commit-API-Aufruf nach erfolgreichem Upload. Um die Möglichkeit zu haben, Listingobjekte zu aktualisieren und im Gegenzug Gebietsschemas im Listingmodul hinzuzufügen/zu entfernen, können Sie folgendermaßen vorgehen:
- Senden Sie über die API zum Erstellen von Listingobjekten eine Anforderung zum Ressourcenupload unter Angabe von Sprache, Typ und Anzahl der Ressourcen.
- Basierend auf der Anzahl der angeforderten Objekte werden Objekt-IDs nach Bedarf erstellt, und es wird eine kurzzeitige SAS-URL erstellt und im Antworttext unter dem Objekttyp zurückgesendet. Anhand dieser URL können Sie Bildobjekte des betreffenden Typs über HTTP-Clients hochladen [Put Blob (REST-API) – Azure Storage | Microsoft-Dokumentation].
- Nach dem Hochladen können Sie über die API zum Committen von Listingobjekten auch die zuvor aus dem vorherigen API-Aufruf empfangenen neuen Objekt-ID-Informationen senden. Die einzelne API führt nach der Validierung intern einen Commit für die Daten der Listingobjekte durch.
- Dadurch wird der gesamte Satz früherer Bilder des Objekttyps zu einer bestimmten Sprache aus der gesendeten Anforderung effektiv überschrieben. Daher werden zuvor hochgeladene Objekte entfernt.
Pfad: /submission/v1/product/{productId}/listings/assets/create
Methode: POST
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Beschreibung |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Anforderungsparameter
Name | Typ | BESCHREIBUNG |
---|---|---|
language | String | Erforderlich |
createAssetRequest | Objekt | Erforderlich |
Screenshot | Ganzzahl | Erforderlich, wenn ISV Screenshots aktualisieren oder eine neue Listingsprache hinzufügen muss [1 – 10] |
Logo | Ganzzahl | Erforderlich, wenn ISV Logos aktualisieren oder eine neue Listingsprache hinzufügen muss [1 oder 2] |
Antwortheader
Header | Beschreibung |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
listingAssets | Objekt | Objekt mit Details zu StoreLogos und Screenshots, die hochgeladen werden sollen |
Sprache | String | |
storeLogos | Array von Objekten | |
screenshots | Array von Objekten | |
id | String | |
primaryAssetUploadUrl | String | Primäre URL zum Hochladen eines Listingobjekts über die Azure Blob REST-API |
secondaryAssetUploadUrl | String | Sekundäre URL zum Hochladen eines Listingobjekts über die Azure Blob REST-API |
HTTP-Methode | HTTP-Methode | Die HTTP-Methode, die zum Hochladen von Objekten über die Objektupload-URLs verwendet werden muss – primär oder sekundär |
httpHeaders | Objekt | Ein Objekt mit Schlüsseln als erforderliche Header, das im Upload-API-Aufruf an Objektupload-URLs vorhanden sein muss. Wenn der Wert nicht leer ist, müssen die Header bestimmte Werte haben. Andernfalls werden während des API-Aufrufs Werte berechnet. |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"listingAssets": {
"language": "en-us",
"storeLogos":[{
"id": "1234567890abcdefgh",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=1234567890abcdefgh&sig=12345",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54326",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}],
"screenshots":[{
"id": "0987654321abcdfger",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54321",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54322",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}]
}
}
}
API zum Committen von Listingobjekten
Committet das neue hochgeladene Listingobjekt anhand der Details aus der API zum Erstellen von Objekten zum aktuellen Übermittlungsentwurf.
Pfad: /submission/v1/product/{productId}/listings/assets/commit
Methode: PUT
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Beschreibung |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Anforderungsparameter
Name | Typ | Beschreibung |
---|---|---|
listingAssets | Objekt | |
Sprache | String | |
storeLogos | Array von Objekten | |
screenshots | Array von Objekten | |
id | String | Sollte entweder eine vorhandene ID aus der API zum Abrufen der aktuellen Listingobjekte sein, die der Benutzer beibehalten möchte, oder eine neue ID, unter der ein neues Objekt in die API zum Erstellen von Listingobjekten hochgeladen wurde. |
assetUrl | String | Sollte entweder die URL des vorhandenen Objekts aus der API zum Abrufen der aktuellen Listingobjekte sein, die der Benutzer beibehalten möchte, oder die Upload-URL – primär oder sekundär –, mit der ein neues Objekt in die API zum Erstellen von Listingobjekten hochgeladen wurde. Muss eine gültige URL sein |
Beispiel für eine Anforderung
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
Antwortheader
Header | Beschreibung |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
pollingUrl | String | Abruf-URL zum Abrufen des Status einer laufenden Übermittlung |
ongoingSubmissionId | String | Übermittlungs-ID einer bereits laufenden Übermittlung |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API zum Abrufen des Modulstatus
API zum Überprüfen der Bereitschaft des Moduls, bevor die Übermittlung erstellt werden kann. Validiert außerdem den Uploadstatus des Pakets.
Pfad: /submission/v1/product/{productId}/status
Methode: GET
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Beschreibung |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Beschreibung |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
isReady | Boolean | Gibt an, ob alle Module den Status „Bereit“ haben, einschließlich Paketupload |
ongoingSubmissionId | String | Übermittlungs-ID einer bereits laufenden Übermittlung |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
API zum Erstellen von Übermittlungen
Erstellt eine Übermittlung aus dem aktuellen Entwurf für MSI- oder EXE-App. Die API überprüft:
- auf aktive Übermittlung und Fehler mit Fehlermeldung, es eine aktive Übermittlung gibt.
- ob alle Module den Status „Bereit“ haben, um die Übermittlung zu erstellen.
- Jedes Feld in der Übermittlung wird gemäß den Anforderungen des Store auf Gültigkeit geprüft.
Pfad:/submission/v1/product/{productId}/submit
Methode: POST
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Beschreibung |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Beschreibung |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
pollingUrl | String | Abruf-URL zum Abrufen des Status der Modulbereitschaft einschließlich Paketupload für Übermittlung |
submissionId | String | Die ID für die neu erstellte Übermittlung |
ongoingSubmissionId | String | Übermittlungs-ID einer bereits laufenden Übermittlung |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"submissionId": "1234567890",
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API zum Abrufen des Übermittlungsstatus
API zum Überprüfen des Übermittlungsstatus.
Pfad: /submission/v1/product/{productId}/submission/{submissionId}/status
Methode: GET
Pfadparameter
Name | Beschreibung |
---|---|
productId | Die Partner Center-ID des Produkts |
Erforderliche Header
Header | Beschreibung |
---|---|
Authorization: Bearer <Token> |
Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID |
X-Seller-Account-Id |
Verkäufer-ID des Partner Center-Kontos |
Antwortheader
Header | Beschreibung |
---|---|
X-Correlation-ID |
Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden. |
Retry-After |
Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft. |
Antwortparameter
Name | Typ | Beschreibung |
---|---|---|
IsSuccess | Boolean | |
errors | Array von Objekten | Die Liste der eventuellen Fehler- oder Warnmeldungen |
Code | String | Der Fehlercode der Meldung |
message | String | Die Beschreibung des Fehlers |
target | String | Die Entität, in der der Fehler seinen Ursprung hat |
responseData | Objekt | |
publishingStatus | String | Veröffentlichungsstatus der Übermittlung – [INPROGRESS, PUBLISHED, FAILED, UNKNOWN] |
hasFailed | Boolean | Gibt an, ob die Veröffentlichung fehlgeschlagen ist und nicht wiederholt wird. |
Beispiel für eine Antwort
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"publishingStatus": "INPROGRESS",
"hasFailed": false
}
}
Codebeispiele
Die folgenden Artikel enthalten detaillierte Codebeispiele, die veranschaulichen, wie die Microsoft Store-Übermittlungs-API in verschiedenen Programmiersprachen verwendet wird:
Beispiel für C#: Microsoft Store-Übermittlungs-API für MSI- oder EXE-App
Dieser Artikel enthält C#-Codebeispiele, die die Verwendung der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App veranschaulichen. Sie können jedes Beispiel durchgehen, um mehr über die beschriebene Aufgabe zu erfahren, oder Sie können alle Codebeispiele in diesem Artikel in einer Konsolenanwendung erstellen.
Voraussetzungen In diesen Beispielen wird die folgende Bibliothek verwendet:
- Newtonsoft.Json NuGet-Paket von Newtonsoft.
Standardprogramm Das folgende Beispiel implementiert ein Befehlszeilenprogramm, das die anderen Beispielmethoden in diesem Artikel aufruft, um verschiedene Möglichkeiten zur Verwendung der Microsoft Store-Übermittlungs-API zu veranschaulichen. So passen Sie dieses Programm für eigene Zwecke an:
- Weisen Sie die Eigenschaft SellerId der Verkäufer-ID Ihres Partner Center-Kontos zu.
- Weisen Sie die Eigenschaft ApplicationId der ID der zu verwaltenden App zu.
- Weisen Sie die Eigenschaften ClientId und ClientSecret der Client-ID und dem Schlüssel für Ihre App zu und ersetzen Sie die Zeichenkette „tenantid“ in der TokenEndpoint-URL durch die Mandanten-ID für Ihre App. Weitere Informationen finden Sie unter Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto.
using System;
using System.Threading.Tasks;
namespace Win32SubmissionApiCSharpSample
{
public class Program
{
static async Task Main(string[] args)
{
var config = new ClientConfiguration()
{
ApplicationId = "...",
ClientId = "...",
ClientSecret = "...",
Scope = "https://api.store.microsoft.com/.default",
ServiceUrl = "https://api.store.microsoft.com",
TokenEndpoint = "...",
SellerId = 0
};
await new AppSubmissionUpdateSample(config).RunAppSubmissionUpdateSample();
}
}
}
Hilfsprogrammklasse ClientConfiguration bei Verwendung von C#
Die Beispiel-App verwendet die Hilfsprogrammklasse ClientConfiguration, um Azure Active Directory-Daten und App-Daten an jede der Beispielmethoden zu übergeben, die die Microsoft Store-Übermittlungs-API verwenden.
using System;
using System.Collections.Generic;
using System.Text;
namespace Win32SubmissionApiCSharpSample
{
public class ClientConfiguration
{
/// <summary>
/// Client Id of your Azure Active Directory app.
/// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// Client secret of your Azure Active Directory app
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Service root endpoint.
/// Example: "https://api.store.microsoft.com"
/// </summary>
public string ServiceUrl { get; set; }
/// <summary>
/// Token endpoint to which the request is to be made. Specific to your Azure Active Directory app
/// Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token
/// </summary>
public string TokenEndpoint { get; set; }
/// <summary>
/// Resource scope. If not provided (set to null), default one is used for the production API
/// endpoint ("https://api.store.microsoft.com/.default")
/// </summary>
public string Scope { get; set; }
/// <summary>
/// Partner Center Application ID.
/// Example: 3e31a9f9-84e8-4d2d-9eba-487878d02ebf
/// </summary>
public string ApplicationId { get; set; }
/// <summary>
/// The Partner Center Seller Id
/// Example: 123456892
/// </summary>
public int SellerId { get; set; }
}
}
Erstellen einer App-Übermittlung bei Verwendung von C#
Das folgende Beispiel implementiert eine Klasse, die verschiedene Methoden in der Microsoft Store-Übermittlungs-API verwendet, um eine App-Übermittlung zu aktualisieren.
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace Win32SubmissionApiCSharpSample
{
public class AppSubmissionUpdateSample
{
private ClientConfiguration ClientConfig;
/// <summary>
/// Constructor
/// </summary>
/// <param name="configuration">An instance of ClientConfiguration that contains all parameters populated</param>
public AppSubmissionUpdateSample(ClientConfiguration configuration)
{
this.ClientConfig = configuration;
}
/// <summary>
/// Main method to Run the Sample Application
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task RunAppSubmissionUpdateSample()
{
// **********************
// SETTINGS
// **********************
var appId = this.ClientConfig.ApplicationId;
var clientId = this.ClientConfig.ClientId;
var clientSecret = this.ClientConfig.ClientSecret;
var serviceEndpoint = this.ClientConfig.ServiceUrl;
var tokenEndpoint = this.ClientConfig.TokenEndpoint;
var scope = this.ClientConfig.Scope;
// Get authorization token.
Console.WriteLine("Getting authorization token");
var accessToken = await SubmissionClient.GetClientCredentialAccessToken(
tokenEndpoint,
clientId,
clientSecret,
scope);
var client = new SubmissionClient(accessToken, serviceEndpoint);
client.DefaultHeaders = new Dictionary<string, string>()
{
{"X-Seller-Account-Id", this.ClientConfig.SellerId.ToString() }
};
Console.WriteLine("Getting Current Application Draft Status");
dynamic AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(AppDraftStatus.ToString());
Console.WriteLine("Getting Application Packages ");
dynamic PackagesResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackagesUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(PackagesResponse.ToString());
Console.WriteLine("Getting Single Package");
dynamic SinglePackageResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackageByIdUrlTemplate,
SubmissionClient.Version, appId, (string)PackagesResponse.responseData.packages[0].packageId), null);
Console.WriteLine(SinglePackageResponse.ToString());
Console.WriteLine("Updating Entire Package Set");
// Update data in Packages list to have final set of updated Packages
// Example - Updating Installer Parameters
PackagesResponse.responseData.packages[0].installerParameters = "/s /r new-args";
dynamic PackagesUpdateRequest = new
{
packages = PackagesResponse.responseData.packages
};
dynamic PackagesUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.PackagesUrlTemplate,
SubmissionClient.Version, appId), PackagesUpdateRequest);
Console.WriteLine(PackagesUpdateResponse.ToString());
Console.WriteLine("Updating Single Package's Download Url");
// Update data in the SinglePackage object
var SinglePackageUpdateRequest = SinglePackageResponse.responseData.packages[0];
// Example - Updating Installer Parameters
SinglePackageUpdateRequest.installerParameters = "/s /r /t new-args";
dynamic PackageUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Patch, string.Format(SubmissionClient.PackageByIdUrlTemplate,
SubmissionClient.Version, appId, SinglePackageUpdateRequest.packageId), SinglePackageUpdateRequest);
Console.WriteLine("Committing Packages");
dynamic PackageCommitResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.PackagesCommitUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(PackageCommitResponse.ToString());
Console.WriteLine("Polling Package Upload Status");
AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
SubmissionClient.Version, appId), null);
while (!((bool)AppDraftStatus.responseData.isReady))
{
AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine("Waiting for Upload to finish");
await Task.Delay(TimeSpan.FromSeconds(2));
if(AppDraftStatus.errors != null && AppDraftStatus.errors.Count > 0)
{
for(var index = 0; index < AppDraftStatus.errors.Count; index++)
{
if(AppDraftStatus.errors[index].code == "packageuploaderror")
{
throw new InvalidOperationException("Package Upload Failed. Please try committing packages again.");
}
}
}
}
Console.WriteLine("Getting Application Metadata - All Modules");
dynamic AppMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppMetadataUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(AppMetadata.ToString());
Console.WriteLine("Getting Application Metadata - Listings");
dynamic AppListingsMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppListingsFetchMetadataUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(AppListingsMetadata.ToString());
Console.WriteLine("Updating Listings Metadata - Description");
// Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]
// Example - Updating Description
AppListingsMetadata.responseData.listings[0].description = "New Description Updated By C# Sample Code";
dynamic ListingsUpdateRequest = new
{
listings = AppListingsMetadata.responseData.listings[0]
};
dynamic UpdateListingsMetadataResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.AppMetadataUrlTemplate,
SubmissionClient.Version, appId), ListingsUpdateRequest);
Console.WriteLine(UpdateListingsMetadataResponse.ToString());
Console.WriteLine("Getting All Listings Assets");
dynamic ListingAssets = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ListingAssetsUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(ListingAssets.ToString());
Console.WriteLine("Creating Listing Assets for 1 Screenshot");
dynamic AssetCreateRequest = new
{
language = ListingAssets.responseData.listingAssets[0].language,
createAssetRequest = new Dictionary<string, int>()
{
{"Screenshot", 1 },
{"Logo", 0 }
}
};
dynamic AssetCreateResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.ListingAssetsCreateUrlTemplate,
SubmissionClient.Version, appId), AssetCreateRequest);
Console.WriteLine(AssetCreateResponse.ToString());
Console.WriteLine("Uploading Listing Assets");
// Path to PNG File to be Uploaded as Screenshot / Logo
var PathToFile = "./Image.png";
var AssetToUpload = File.OpenRead(PathToFile);
await client.UploadAsset(AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string, AssetToUpload);
Console.WriteLine("Committing Listing Assets");
dynamic AssetCommitRequest = new
{
listingAssets = new
{
language = ListingAssets.responseData.listingAssets[0].language,
storeLogos = ListingAssets.responseData.listingAssets[0].storeLogos,
screenshots = JToken.FromObject(new List<dynamic>() { new
{
id = AssetCreateResponse.responseData.listingAssets.screenshots[0].id.Value as string,
assetUrl = AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string
}
}.ToArray())
}
};
dynamic AssetCommitResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.ListingAssetsCommitUrlTemplate,
SubmissionClient.Version, appId), AssetCommitRequest);
Console.WriteLine(AssetCommitResponse.ToString());
Console.WriteLine("Getting Current Application Draft Status before Submission");
AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(AppDraftStatus.ToString());
if (AppDraftStatus == null || !((bool)AppDraftStatus.responseData.isReady))
{
throw new InvalidOperationException("Application Current Status is not in Ready Status for All Modules");
}
Console.WriteLine("Creating Submission");
dynamic SubmissionCreationResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.CreateSubmissionUrlTemplate,
SubmissionClient.Version, appId), null);
Console.WriteLine(SubmissionCreationResponse.ToString());
Console.WriteLine("Current Submission Status");
dynamic SubmissionStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.SubmissionStatusPollingUrlTemplate,
SubmissionClient.Version, appId, SubmissionCreationResponse.responseData.submissionId.Value as string), null);
Console.Write(SubmissionStatus.ToString());
// User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
// This Process involves File Scanning, App Certification and Publishing and can take more than a day.
}
}
}
Hilfklasse IngestionClient bei Verwendung von C#
Die Hilfsprogrammklasse IngestionClient stellt Hilfsmethoden bereit, die von anderen Methoden in der Beispiel-App zum Ausführen der folgenden Aufgaben verwendet werden:
- Abrufen eines Azure AD-Zugriffstokens, das zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API verwendet werden kann. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
- Verarbeiten der HTTP-Anforderungen für die Microsoft Store-Übermittlungs-API.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Win32SubmissionApiCSharpSample
{
/// <summary>
/// This class is a proxy that abstracts the functionality of the API service
/// </summary>
public class SubmissionClient : IDisposable
{
public static readonly string Version = "1";
private HttpClient httpClient;
private HttpClient imageUploadClient;
private readonly string accessToken;
public static readonly string PackagesUrlTemplate = "/submission/v{0}/product/{1}/packages";
public static readonly string PackageByIdUrlTemplate = "/submission/v{0}/product/{1}/packages/{2}";
public static readonly string PackagesCommitUrlTemplate = "/submission/v{0}/product/{1}/packages/commit";
public static readonly string AppMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata";
public static readonly string AppListingsFetchMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata/listings";
public static readonly string ListingAssetsUrlTemplate = "/submission/v{0}/product/{1}/listings/assets";
public static readonly string ListingAssetsCreateUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/create";
public static readonly string ListingAssetsCommitUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/commit";
public static readonly string ProductDraftStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/status";
public static readonly string CreateSubmissionUrlTemplate = "/submission/v{0}/product/{1}/submit";
public static readonly string SubmissionStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/submission/{2}/status";
public const string JsonContentType = "application/json";
public const string PngContentType = "image/png";
public const string BinaryStreamContentType = "application/octet-stream";
/// <summary>
/// Initializes a new instance of the <see cref="SubmissionClient" /> class.
/// </summary>
/// <param name="accessToken">
/// The access token. This is JWT a token obtained from Azure Active Directory allowing the caller to invoke the API
/// on behalf of a user
/// </param>
/// <param name="serviceUrl">The service URL.</param>
public SubmissionClient(string accessToken, string serviceUrl)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new ArgumentNullException("accessToken");
}
if (string.IsNullOrEmpty(serviceUrl))
{
throw new ArgumentNullException("serviceUrl");
}
this.accessToken = accessToken;
this.httpClient = new HttpClient
{
BaseAddress = new Uri(serviceUrl)
};
this.imageUploadClient = new HttpClient();
this.DefaultHeaders = new Dictionary<string, string>();
}
/// <summary>
/// Gets or Sets the default headers.
/// </summary>
public Dictionary<string, string> DefaultHeaders { get; set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting
/// unmanaged resources.
/// </summary>
public void Dispose()
{
if (this.httpClient != null)
{
this.httpClient.Dispose();
this.httpClient = null;
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Gets the authorization token for the provided client id, client secret, and the scope.
/// This token is usually valid for 1 hour, so if your submission takes longer than that to complete,
/// make sure to get a new one periodically.
/// </summary>
/// <param name="tokenEndpoint">Token endpoint to which the request is to be made. Specific to your
/// Azure Active Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
/// <param name="clientId">Client Id of your Azure Active Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
/// <param name="clientSecret">Client secret of your Azure Active Directory app</param>
/// <param name="scope">Scope. If not provided, default one is used for the production API endpoint.</param>
/// <returns>Autorization token. Prepend it with "Bearer: " and pass it in the request header as the
/// value for "Authorization: " header.</returns>
public static async Task<string> GetClientCredentialAccessToken(
string tokenEndpoint,
string clientId,
string clientSecret,
string scope = null)
{
if (scope == null)
{
scope = "https://api.store.microsoft.com/.default";
}
dynamic result;
using (HttpClient client = new HttpClient())
{
string tokenUrl = tokenEndpoint;
using (
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Post,
tokenUrl))
{
string strContent =
string.Format(
"grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}",
clientId,
clientSecret,
scope);
request.Content = new StringContent(strContent, Encoding.UTF8,
"application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.SendAsync(request))
{
string responseContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject(responseContent);
}
}
}
return result.access_token;
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ServiceException"></exception>
public async Task<T> Invoke<T>(HttpMethod httpMethod,
string relativeUrl,
object requestContent)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
this.SetRequest(request, requestContent);
using (HttpResponseMessage response = await this.httpClient.SendAsync(request))
{
T result;
if (this.TryHandleResponse(response, out result))
{
return result;
}
if (response.IsSuccessStatusCode)
{
var resource = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
return resource;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Uploads a given Image Asset file to Asset Storage
/// </summary>
/// <param name="assetUploadUrl">Asset Storage Url</param>
/// <param name="fileStream">The Stream instance of file to be uploaded</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task UploadAsset(string assetUploadUrl, Stream fileStream)
{
using (var request = new HttpRequestMessage(HttpMethod.Put, assetUploadUrl))
{
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Content = new StreamContent(fileStream);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(PngContentType);
using (HttpResponseMessage response = await this.imageUploadClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
return;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Sets the request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="requestContent">Content of the request.</param>
protected virtual void SetRequest(HttpRequestMessage request, object requestContent)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);
foreach (var header in this.DefaultHeaders)
{
request.Headers.Add(header.Key, header.Value);
}
if (requestContent != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
Encoding.UTF8,
JsonContentType);
}
}
/// <summary>
/// Tries the handle response.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response">The response.</param>
/// <param name="result">The result.</param>
/// <returns>true if the response was handled</returns>
protected virtual bool TryHandleResponse<T>(HttpResponseMessage response, out T result)
{
result = default(T);
return false;
}
}
}
Beispiel für Node.js: Microsoft Store-Übermittlungs-API für MSI- oder EXE-App
Dieser Artikel enthält Node.js-Codebeispiele zeigt das Verwenden der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App. Sie können jedes Beispiel durchgehen, um mehr über die beschriebene Aufgabe zu erfahren, oder Sie können alle Codebeispiele in diesem Artikel in einer Konsolenanwendung erstellen.
Voraussetzungen In diesen Beispielen wird die folgende Bibliothek verwendet:
- node-fetch v2 [npm install node-fetch@2]
Erstellen einer App-Übermittlung bei Verwendung von node.js
Das folgende Beispiel ruft die anderen Beispielmethoden in diesem Artikel auf, um verschiedene Möglichkeiten zur Verwendung der Microsoft Store-Übermittlungs-API zu veranschaulichen. So passen Sie dieses Programm für eigene Zwecke an:
- Weisen Sie die Eigenschaft SellerId der Verkäufer-ID Ihres Partner Center-Kontos zu.
- Weisen Sie die Eigenschaft ApplicationId der ID der zu verwaltenden App zu.
- Weisen Sie die Eigenschaften ClientId und ClientSecret der Client-ID und dem Schlüssel für Ihre App zu und ersetzen Sie die Zeichenkette „tenantid“ in der TokenEndpoint-URL durch die Mandanten-ID für Ihre App. Weitere Informationen finden Sie unter Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto.
Das folgende Beispiel implementiert eine Klasse, die verschiedene Methoden in der Microsoft Store-Übermittlungs-API verwendet, um eine App-Übermittlung zu aktualisieren.
const config = require('./Configuration');
const submissionClient = require('./SubmissionClient');
const fs = require('fs');
var client = new submissionClient(config);
/**
* Main entry method to Run the Store Submission API Node.js Sample
*/
async function RunNodeJsSample(){
print('Getting Access Token');
await client.getAccessToken();
print('Getting Current Application Draft Status');
var currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
print(currentDraftStatus);
print('Getting Application Packages');
var currentPackages = await client.callStoreAPI(client.packagesUrlTemplate, 'get');
print(currentPackages);
print('Getting Single Package');
var packageId = currentPackages.responseData.packages[0].packageId;
var packageIdUrl = `${client.packageByIdUrlTemplate}`.replace('{packageId}', packageId);
var singlePackage = await client.callStoreAPI(packageIdUrl, 'get');
print(singlePackage);
print('Updating Entire Package Set');
// Update data in Packages list to have final set of updated Packages
currentPackages.responseData.packages[0].installerParameters = "/s /r new-args";
var packagesUpdateRequest = {
'packages': currentPackages.responseData.packages
};
print(packagesUpdateRequest);
var packagesUpdateResponse = await client.callStoreAPI(client.packagesUrlTemplate, 'put', packagesUpdateRequest);
print(packagesUpdateResponse);
print('Updating Single Package\'s Download Url');
// Update data in the SinglePackage object
singlePackage.responseData.packages[0].installerParameters = "/s /r /t new-args";
var singlePackageUpdateResponse = await client.callStoreAPI(packageIdUrl, 'patch', singlePackage.responseData.packages[0]);
print(singlePackageUpdateResponse);
print('Committing Packages');
var commitPackagesResponse = await client.callStoreAPI(client.packagesCommitUrlTemplate, 'post');
print(commitPackagesResponse);
await poll(async ()=>{
print('Waiting for Upload to finish');
return await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
}, 2);
print('Getting Application Metadata - All Modules');
var appMetadata = await client.callStoreAPI(client.appMetadataUrlTemplate, 'get');
print(appMetadata);
print('Getting Application Metadata - Listings');
var appListingMetadata = await client.callStoreAPI(client.appListingsFetchMetadataUrlTemplate, 'get');
print(appListingMetadata);
print('Updating Listings Metadata - Description');
// Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]
// Example - Updating Description
appListingMetadata.responseData.listings[0].description = 'New Description Updated By Node.js Sample Code';
var listingsUpdateRequest = {
'listings': appListingMetadata.responseData.listings[0]
};
var listingsMetadataUpdateResponse = await client.callStoreAPI(client.appMetadataUrlTemplate, 'put', listingsUpdateRequest);
print(listingsMetadataUpdateResponse);
print('Getting All Listings Assets');
var listingAssets = await client.callStoreAPI(client.listingAssetsUrlTemplate, 'get');
print(listingAssets);
print('Creating Listing Assets for 1 Screenshot');
var listingAssetCreateRequest = {
'language': listingAssets.responseData.listingAssets[0].language,
'createAssetRequest': {
'Screenshot': 1,
'Logo': 0
}
};
var listingAssetCreateResponse = await client.callStoreAPI(client.listingAssetsCreateUrlTemplate, 'post', listingAssetCreateRequest);
print(listingAssetCreateResponse);
print('Uploading Listing Assets');
const pathToFile = './Image.png';
const stats = fs.statSync(pathToFile);
const fileSize = stats.size;
const fileStream = fs.createReadStream(pathToFile);
await client.uploadAssets(listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl, fileStream, fileSize);
print('Committing Listing Assets');
var assetCommitRequest = {
'listingAssets': {
'language': listingAssets.responseData.listingAssets[0].language,
'storeLogos': listingAssets.responseData.listingAssets[0].storeLogos,
'screenshots': [{
'id': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].id,
'assetUrl': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl
}]
}
};
var assetCommitResponse = await client.callStoreAPI(client.listingAssetsCommitUrlTemplate, 'put', assetCommitRequest);
print(assetCommitResponse);
print('Getting Current Application Draft Status before Submission');
currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
print(currentDraftStatus);
if(!currentDraftStatus.responseData.isReady){
throw new Error('Application Current Status is not in Ready Status for All Modules');
}
print('Creating Submission');
var submissionCreationResponse = await client.callStoreAPI(client.createSubmissionUrlTemplate, 'post');
print(submissionCreationResponse);
print('Current Submission Status');
var submissionStatusUrl = `${client.submissionStatusPollingUrlTemplate}`.replace('{submissionId}', submissionCreationResponse.responseData.submissionId);
var submissionStatusResponse = await client.callStoreAPI(submissionStatusUrl, 'get');
print(submissionStatusResponse);
// User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
// This Process involves File Scanning, App Certification and Publishing and can take more than a day.
}
/**
* Utility Method to Poll using a given function and time interval in seconds
* @param {*} func
* @param {*} intervalInSeconds
* @returns
*/
async function poll(func, intervalInSeconds){
var result = await func();
if(result.responseData.isReady){
Promise.resolve(true);
}
else if(result.errors && result.errors.length > 0 && result.errors.find(element => element.code == 'packageuploaderror') != undefined){
throw new Error('Package Upload Failed');
}
else{
await new Promise(resolve => setTimeout(resolve, intervalInSeconds*1000));
return await poll(func, intervalInSeconds);
}
}
/**
* Utility function to Print a Json or normal string
* @param {*} json
*/
function print(json){
if(typeof(json) == 'string'){
console.log(json);
}
else{
console.log(JSON.stringify(json));
}
console.log("\n");
}
/** Run the Node.js Sample Application */
RunNodeJsSample();
Hilfsprogramm ClientConfiguration
Die Beispiel-App verwendet die Hilfsprogrammklasse ClientConfiguration, um Azure Active Directory-Daten und App-Daten an jede der Beispielmethoden zu übergeben, die die Microsoft Store-Übermittlungs-API verwenden.
/** Configuration Object for Store Submission API */
var config = {
version : "1",
applicationId : "...",
clientId : "...",
clientSecret : "...",
serviceEndpoint : "https://api.store.microsoft.com",
tokenEndpoint : "...",
scope : "https://api.store.microsoft.com/.default",
sellerId : "...",
jsonContentType : "application/json",
pngContentType : "image/png",
binaryStreamContentType : "application/octet-stream"
};
module.exports = config;
Hilfsprogramm IngestionClient bei Verwendung von node.js
Die Hilfsprogrammklasse IngestionClient stellt Hilfsmethoden bereit, die von anderen Methoden in der Beispiel-App zum Ausführen der folgenden Aufgaben verwendet werden:
- Abrufen eines Azure AD-Zugriffstokens, das zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API verwendet werden kann. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
- Verarbeiten der HTTP-Anforderungen für die Microsoft Store-Übermittlungs-API.
const fetch = require('node-fetch');
/**
* Submission Client to invoke all available Store Submission API and Asset Upload to Blob Store
*/
class SubmissionClient{
constructor(config){
this.configuration = config;
this.accessToken = "";
this.packagesUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages`;
this.packageByIdUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/{packageId}`;
this.packagesCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/commit`;
this.appMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata`;
this.appListingsFetchMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata/listings`;
this.listingAssetsUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets`;
this.listingAssetsCreateUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/create`;
this.listingAssetsCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/commit`;
this.productDraftStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/status`;
this.createSubmissionUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submit`;
this.submissionStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submission/{submissionId}/status`;
}
async getAccessToken(){
var params = new URLSearchParams();
params.append('grant_type','client_credentials');
params.append('client_id',this.configuration.clientId);
params.append('client_secret',this.configuration.clientSecret);
params.append('scope',this.configuration.scope);
var response = await fetch(this.configuration.tokenEndpoint,{
method: "POST",
body: params
});
var data = await response.json();
this.accessToken = data.access_token;
}
async callStoreAPI(url, method, data){
var request = {
method: method,
headers:{
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': this.configuration.jsonContentType,
'X-Seller-Account-Id': this.configuration.sellerId
},
};
if(data){
request.body = JSON.stringify(data);
}
var response = await fetch(`${this.configuration.serviceEndpoint}${url}`,request);
var jsonResponse = await response.json();
return jsonResponse;
}
async uploadAssets(url, stream, size){
var request = {
method: 'put',
headers:{
'Content-Type': this.configuration.pngContentType,
'x-ms-blob-type': 'BlockBlob',
"Content-length": size
},
body: stream
};
var response = await fetch(`${url}`,request);
if(response.ok){
return response;
}
else{
throw new Error('Uploading of assets failed');
}
}
}
module.exports = SubmissionClient;
Weitere Hilfe
Wenn Sie Fragen zur Microsoft Store-Übermittlungs-API haben oder Unterstützung beim Verwalten Ihrer Übermittlungen mit dieser API benötigen, können Sie die folgenden Ressourcen verwenden:
- Stellen Sie Fragen in unseren Foren.
- Besuchen Sie unsere Supportseite und fordern Sie eine der unterstützten Supportoptionen für Partner Center an. Wenn Sie aufgefordert werden, einen Problemtyp und eine Kategorie auszuwählen, wählen Sie „App-Übermittlung und -Zertifizierung“ bzw. „Übermitteln einer App“ aus.
Windows developer