Quickstart: Search for images using C# and Bing Image Search API
Use this quickstart to make your first call to Bing Image Search API. This C# console application sends a search request to Bing and parses the response. Since it's a console application, it displays a text-based version of the response for illustrative purposes only. The source code for this sample is available on GitHub.
Grab your favorite .NET editor, JSON library, and Create Bing Search Service resource for Bing Image Search and let's get started.
Create a project and declare dependencies
Create a new project and declare the code's dependencies. This example uses Newtonsoft to parse the JSON response. Use Newtonsoft's NuGet package to install its libraries.
using System;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
Declare a namespace and class for your program
Add a namespace and class. This example uses ImageSearchQuickstart
for the namespace and Program
for the class.
namespace ImageSearchQuickstart
{
class Program
{
// The code in the following sections goes here.
}
}
Define variables
Add a few variables to the Program
class. For simplicity, this example hardcodes the subscription key, but make sure you're pulling it from secured storage instead.
// In production, make sure you're pulling the subscription key from secured storage.
private static string _subscriptionKey = "<your key goes here>";
private static string _baseUri = "https://api.bing.microsoft.com/v7.0/images/search";
// The user's search string.
private static string searchString = "hummingbird";
// To page through the images, you'll need the next offset that Bing returns.
private static int _nextOffset = 0;
// To get additional insights about the image, you'll need the image's
// insights token (see Visual Search API).
private static string _insightsToken = null;
// Bing uses the X-MSEdge-ClientID header to provide users with consistent
// behavior across Bing API calls. See the reference documentation
// for usage.
private static string _clientIdHeader = null;
Here are all the query parameters you can add to the base URI. The q parameter is required and you should always include the mkt parameter too. The rest are optional. For information about these parameters, see Query parameters.
private const string QUERY_PARAMETER = "?q="; // Required
private const string MKT_PARAMETER = "&mkt="; // Strongly suggested
private const string COUNT_PARAMETER = "&count=";
private const string OFFSET_PARAMETER = "&offset=";
private const string ID_PARAMETER = "&id=";
private const string SAFE_SEARCH_PARAMETER = "&safeSearch=";
Use these query parameters to filter the images that Bing returns. For information about these parameters, see Filter query parameters.
private const string ASPECT_PARAMETER = "&aspect=";
private const string COLOR_PARAMETER = "&color=";
private const string FRESHNESS_PARAMETER = "&freshness=";
private const string HEIGHT_PARAMETER = "&height=";
private const string WIDTH_PARAMETER = "&width=";
private const string IMAGE_CONTENT_PARAMETER = "&imageContent=";
private const string IMAGE_TYPE_PARAMETER = "&imageType=";
private const string LICENSE_PARAMETER = "&license=";
private const string MAX_FILE_SIZE_PARAMETER = "&maxFileSize=";
private const string MIN_FILE_SIZE_PARAMETER = "&minFileSize=";
private const string MAX_HEIGHT_PARAMETER = "&maxHeight=";
private const string MIN_HEIGHT_PARAMETER = "&minHeight=";
private const string MAX_WIDTH_PARAMETER = "&maxWidth=";
private const string MIN_WIDTH_PARAMETER = "&minWidth=";
private const string SIZE_PARAMETER = "&size=";
Declare the Main method
Our Main()
method is pretty simple since we're going to implement the HTTP requests asynchronously.
static void Main()
{
RunAsync().Wait();
}
Where all the work happens
The RunAsync
method is where all the work happens. It builds the query string that's appended to the base URI, waits for the asynchronous HTTP request to return, deserializes the response, and either prints the search results or an error message.
This example uses dictionaries instead of objects to access the response data.
static async Task RunAsync()
{
try
{
// Remember to encode the q query parameter.
var queryString = QUERY_PARAMETER + Uri.EscapeDataString(searchString);
queryString += MKT_PARAMETER + "en-us";
HttpResponseMessage response = await MakeRequestAsync(queryString);
_clientIdHeader = response.Headers.GetValues("X-MSEdge-ClientID").FirstOrDefault();
// This example uses dictionaries instead of objects to access the response data.
var contentString = await response.Content.ReadAsStringAsync();
Dictionary<string, object> searchResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(contentString);
if (response.IsSuccessStatusCode)
{
PrintImages(searchResponse);
}
else
{
PrintErrors(response.Headers, searchResponse);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("\nPress ENTER to exit...");
Console.ReadLine();
}
The HTTP call
Here's the HTTP request. It's your basic HTTP GET request. Use whatever HTTP client works for you.
// Makes the request to the Image Search endpoint.
static async Task<HttpResponseMessage> MakeRequestAsync(string queryString)
{
var client = new HttpClient();
// Request headers. The subscription key is the only required header but you should
// include User-Agent (especially for mobile), X-MSEdge-ClientID, X-Search-Location
// and X-MSEdge-ClientIP (especially for local aware queries).
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _subscriptionKey);
return (await client.GetAsync(_baseUri + queryString));
}
That's all the more there is to sending a search request and getting back search results. To see what the answer looks like in the JSON response, see Handling the images search response.
The rest of the sections walk you through one way of parsing the JSON response and displaying the search results. Be sure to read the use and display requirements to make sure you comply with all display requirements.
For information about resizing the thumbnails, see Resizing and cropping thumbnails.
Displaying the images
The response's value
field contains the list of images. The example shows the fields you're most likely to use. For the full list of fields, see the Image object.
The ImageAnswer object contains a number of fields like pivotSuggestions
, queryExpansions
, and relatedSearches
that this example doesn't address.
// Prints the list of images in the JSON response.
static void PrintImages(Dictionary<string, object> response)
{
Console.WriteLine("The response contains the following images:\n");
// This example prints the first page of images but if you want to page
// through the images, you need to capture the next offset that Bing returns.
_nextOffset = (long) response["nextOffset"];
var images = response["value"] as Newtonsoft.Json.Linq.JToken;
foreach (Newtonsoft.Json.Linq.JToken image in images)
{
Console.WriteLine("Thumbnail: " + image["thumbnailUrl"]);
Console.WriteLine("Thumbnail size: {0} (w) x {1} (h) ", image["thumbnail"]["width"], image["thumbnail"]["height"]);
Console.WriteLine("Original image: " + image["contentUrl"]);
Console.WriteLine("Original image size: {0} (w) x {1} (h) ", image["width"], image["height"]);
Console.WriteLine("Host: {0} ({1})", image["hostPageDomainFriendlyName"], image["hostPageDisplayUrl"]);
Console.WriteLine();
// If you want to get additional insights about the image, capture the
// image token that you use when calling Visual Search API.
_insightsToken = (string) image["imageInsightsToken"];
}
}
Handling errors
This section shows an option for handling errors that the service may return. For example, the service returns an error if your subscription key is not valid or is not valid for the specified endpoint. The service may also return an error if you specify a parameter value that's not valid.
// Print any errors that occur. Depending on which part of the service is
// throwing the error, the response may contain different error formats.
static void PrintErrors(HttpResponseHeaders headers, Dictionary<String, object> response)
{
Console.WriteLine("The response contains the following errors:\n");
object value;
if (response.TryGetValue("error", out value)) // typically 401, 403
{
PrintError(response["error"] as Newtonsoft.Json.Linq.JToken);
}
else if (response.TryGetValue("errors", out value))
{
// Bing API error
foreach (Newtonsoft.Json.Linq.JToken error in response["errors"] as Newtonsoft.Json.Linq.JToken)
{
PrintError(error);
}
// Included only when HTTP status code is 400; not included with 401 or 403.
IEnumerable<string> headerValues;
if (headers.TryGetValues("BingAPIs-TraceId", out headerValues))
{
Console.WriteLine("\nTrace ID: " + headerValues.FirstOrDefault());
}
}
}
static void PrintError(Newtonsoft.Json.Linq.JToken error)
{
string value = null;
Console.WriteLine("Code: " + error["code"]);
Console.WriteLine("Message: " + error["message"]);
if ((value = (string)error["parameter"]) != null)
{
Console.WriteLine("Parameter: " + value);
}
if ((value = (string)error["value"]) != null)
{
Console.WriteLine("Value: " + value);
}
}
Next steps
- For a more in depth web app example, see the Image web app tutorial.