Aktualisieren von Preisen und Verfügbarkeit für ein einzelnes Produkt

In diesem Desktopkonsolenbeispiel wird gezeigt, wie Sie die Ressource Bestand verwenden, um Preise und Verfügbarkeit für ein einzelnes Produkt zu aktualisieren. Informationen zum Arbeiten mit der Ressource Bestand finden Sie unter Verwalten von Produktpreisen.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Net;
using Content.OAuth;             // Reference to CodeGrantFlow DLL simple OAuth example
using Newtonsoft.Json;           // NuGet Json.NET
using System.Globalization;

namespace Catalogs
{
    class Program
    {
        // The application ID that you were given when you
        // registered your application.

        private static string clientId = "<APPLICATIONIDGOESHERE>";
        private static string storedRefreshToken = "<REFRESHTOKENGOESHERE>";
        private static CodeGrantOauth tokens = null;
        private static DateTime tokenExpiration;

        private static string devToken = "<DEVELOPERTOKENGOESHERE>";

        private static string storeCode = "online";
        private static string productId = "<PRODUCTIDGOESHERE>";

        // URI templates used to update product pricing.

        public const string BaseUri = "https://content.api.bingads.microsoft.com/shopping/v9.1";
        public static string BmcUri = BaseUri + "/bmc/{0}";
        public static string InventorySetUri = BmcUri + "/inventory/{1}/products/{2}";

        // Your store ID.

        public static ulong merchantId = <STOREIDGOESHERE>;

        // Suppress NULL when serializing objects.

        public static JsonSerializerSettings jsonSettings = new JsonSerializerSettings()
        { NullValueHandling = NullValueHandling.Ignore };


        static void Main(string[] args)
        {
            try
            {
                var headers = GetCredentialHeaders();

                // Build the inventory endpoint.

                var url = string.Format(InventorySetUri, merchantId, storeCode, productId);

                // Create a product. Must specify both price and availability.
                // May also set sale price and effective date. If missing,
                // sale price and effective data are removed.

                var product = new Product()
                {
                    Price = new Price()
                    {
                        Value = 1234,
                        Currency = "USD"
                    },
                    Availability = "out of stock"
                };

                // Update the product's price and availability. The response
                // body is empty. The Location response header contains the URL
                // of the product that was updated. 

                var response = AddResource(url, headers, product);
            }
            catch (WebException e)
            {
                Console.WriteLine("\n" + e.Message);

                HttpWebResponse response = (HttpWebResponse)e.Response;

                // If the request is bad, the API returns the errors in the 
                // body of the request. For cases where the path may be valid, but
                // the resource does not belong to the user, the API returns not found.

                if (HttpStatusCode.BadRequest == response.StatusCode ||
                    HttpStatusCode.NotFound == response.StatusCode ||
                    HttpStatusCode.InternalServerError == response.StatusCode)
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        StreamReader reader = new StreamReader(stream);
                        string json = reader.ReadToEnd();
                        reader.Close();

                        // Deserialize error string into errors object.

                        try
                        {
                            var errors = JsonConvert.DeserializeObject<ContentError>(json);

                            PrintErrors(errors);
                        }
                        catch (Exception deserializeError)
                        {
                            // This case occurs when the path is not valid.

                            if (HttpStatusCode.NotFound == response.StatusCode)
                            {
                                Console.WriteLine("Path not found: " + response.ResponseUri);
                            }
                            else
                            {
                                Console.WriteLine(deserializeError.Message);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("\n" + e.Message);
            }
        }


        // Update a product's pricing and availability.

        private static Product AddResource(string uri, WebHeaderCollection headers, Product product)
        {
            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "POST";
            request.Headers = headers;
            request.ContentType = "application/json";

            var json = JsonConvert.SerializeObject(product, jsonSettings);
            request.ContentLength = json.Length;
            using (Stream requestStream = request.GetRequestStream())
            {
                StreamWriter writer = new StreamWriter(requestStream);
                writer.Write(json);
                writer.Close();
            }

            var response = (HttpWebResponse)request.GetResponse();

            Product productOut = null;

            using (Stream responseStream = response.GetResponseStream())
            {
                var reader = new StreamReader(responseStream);
                var jsonOut = reader.ReadToEnd();
                reader.Close();
                productOut = JsonConvert.DeserializeObject<Product>(jsonOut);
            }

            return productOut;
        }


        // Print errors.

        private static void PrintErrors(ContentError contentError)
        {
            Console.WriteLine("HTTP status code: " + contentError.Error.Code);

            foreach (Error error in contentError.Error.Errors)
            {
                Console.WriteLine("reason: {0}\nmessage: {1}\n",
                    error.Reason, error.Message);
            }
        }


        // Gets the AuthenticationToken and DeveloperToken headers 
        // that are required to call the API. 

        private static WebHeaderCollection GetCredentialHeaders()
        {
            // TODO: Add logic to get the logged on user's refresh token 
            // from secured storage. 

            tokens = GetOauthTokens(storedRefreshToken, clientId);

            var headers = new WebHeaderCollection();
            headers.Add("AuthenticationToken", tokens.AccessToken);
            headers.Add("DeveloperToken", devToken);

            return headers;
        }

        // Gets the OAuth tokens. If the refresh token doesn't exist, get 
        // the user's consent and a new access and refresh token.

        private static CodeGrantOauth GetOauthTokens(string refreshToken, string clientId)
        {
            CodeGrantOauth auth = new CodeGrantOauth(clientId);

            if (string.IsNullOrEmpty(refreshToken))
            {
                auth.GetAccessToken();
            }
            else
            {
                auth.RefreshAccessToken(refreshToken);

                // Refresh tokens can become invalid for several reasons
                // such as the user's password changed.

                if (!string.IsNullOrEmpty(auth.Error))
                {
                    auth = GetOauthTokens(null, clientId);
                }
            }

            // TODO: Store the new refresh token in secured storage
            // for the logged on user.

            if (!string.IsNullOrEmpty(auth.Error))
            {
                throw new Exception(auth.Error);
            }
            else
            {
                storedRefreshToken = auth.RefreshToken;
                tokenExpiration = DateTime.Now.AddSeconds(auth.Expiration);
            }

            return auth;
        }
    }
}


// Classes used to update a product's price and availability.

public class Price
{
    [JsonProperty("currency")]
    public string Currency { get; set; }

    [JsonProperty("value")]
    public decimal? Value { get; set; }
}

// The product fields you may update. Price and
// availability are required and sale price and
// effective date are optional.

public class Product
{
    public Product() { }

    [JsonProperty("availability")]
    public string Availability { get; set; }

    [JsonProperty("price")]
    public Price Price { get; set; }


    [JsonProperty("salePrice")]
    public Price SalePrice { get; set; }

    [JsonProperty("salePriceEffectiveDate")]
    public string SalePriceEffectiveDate { get; set; }
}


// Classes used to handle errors.

public class Error
{
    [JsonProperty("domain")]
    public string Domain { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }

    [JsonProperty("reason")]
    public string Reason { get; set; }
}

public class ErrorCollection
{
    [JsonProperty("code")]
    public string Code { get; set; }

    [JsonProperty("errors")]
    public List<Error> Errors { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }

}

public class ContentError
{
    [JsonProperty("error")]
    public ErrorCollection Error { get; set; }
}