Quickstart: Get image insights using the Bing Visual Search REST API and C#
Warning
On October 30, 2020, the Bing Search APIs moved from Azure AI services to Bing Search Services. This documentation is provided for reference only. For updated documentation, see the Bing search API documentation. For instructions on creating new Azure resources for Bing search, see Create a Bing Search resource through the Azure Marketplace.
This quickstart demonstrates how to upload an image to the Bing Visual Search API and view the insights that it returns.
Prerequisites
- Any edition of Visual Studio 2019.
- The Json.NET framework, available as a NuGet package.
- If you're using Linux/MacOS, you can run this application using Mono.
Create an Azure resource
Start using the Bing Visual Search API by creating one of the following Azure resources:
- Available through the Azure portal until you delete the resource.
- Select the
S9
pricing tier.
- Available through the Azure portal until you delete the resource.
- Use the same key and endpoint for your applications, across multiple Azure AI services.
Create and initialize a project
In Visual Studio, create a new console solution named BingSearchApisQuickStart. Add the following namespaces to the main code file:
using System; using System.Text; using System.Net; using System.IO; using System.Collections.Generic;
Add variables for your subscription key, endpoint, and path to the image you want to upload. For the
uriBase
value, you can use the global endpoint in the following code, or use the custom subdomain endpoint displayed in the Azure portal for your resource.const string accessKey = "<my_subscription_key>"; const string uriBase = "https://api.cognitive.microsoft.com/bing/v7.0/images/visualsearch"; static string imagePath = @"<path_to_image>";
Create a method named
GetImageFileName()
to get the path for your image.static string GetImageFileName(string path) { return new FileInfo(path).Name; }
Create a method to get the binary data of the image.
static byte[] GetImageBinary(string path) { return File.ReadAllBytes(path); }
Build the form data
To upload a local image, first build the form data to send to the API. The form data includes the
Content-Disposition
header, thename
parameter set to "image", and thefilename
parameter set to the file name of the image. The contents of the form contain the binary data of the image. The maximum image size you can upload is 1 MB.--boundary_1234-abcd Content-Disposition: form-data; name="image"; filename="myimagefile.jpg" ÿØÿà JFIF ÖÆ68g-¤CWŸþ29ÌÄøÖ‘º«™æ±èuZiÀ)"óÓß°Î= ØJ9á+*G¦... --boundary_1234-abcd--
Add boundary strings to format the POST form data. Boundary strings determine the start, end, and newline characters for the data.
// Boundary strings for form data in body of POST. const string CRLF = "\r\n"; static string BoundaryTemplate = "batch_{0}"; static string StartBoundaryTemplate = "--{0}"; static string EndBoundaryTemplate = "--{0}--";
Use the following variables to add parameters to the form data:
const string CONTENT_TYPE_HEADER_PARAMS = "multipart/form-data; boundary={0}"; const string POST_BODY_DISPOSITION_HEADER = "Content-Disposition: form-data; name=\"image\"; filename=\"{0}\"" + CRLF +CRLF;
Create a function named
BuildFormDataStart()
to create the start of the form data by using the boundary strings and image path.static string BuildFormDataStart(string boundary, string filename) { var startBoundary = string.Format(StartBoundaryTemplate, boundary); var requestBody = startBoundary + CRLF; requestBody += string.Format(POST_BODY_DISPOSITION_HEADER, filename); return requestBody; }
Create a function named
BuildFormDataEnd()
to create the end of the form data by using the boundary strings.static string BuildFormDataEnd(string boundary) { return CRLF + CRLF + string.Format(EndBoundaryTemplate, boundary) + CRLF; }
Call the Bing Visual Search API
Create a function to call the Bing Visual Search endpoint and return the JSON response. The function takes the start and end of the form data, a byte array containing the image data, and a
contentType
value.Use a
WebRequest
to store your URI, contentType value, and headers.Use
request.GetRequestStream()
to write your form and image data, and then get the response. Your function should be similar to the following code:static string BingImageSearch(string startFormData, string endFormData, byte[] image, string contentTypeValue) { WebRequest request = HttpWebRequest.Create(uriBase); request.ContentType = contentTypeValue; request.Headers["Ocp-Apim-Subscription-Key"] = accessKey; request.Method = "POST"; // Writes the boundary and Content-Disposition header, then writes // the image binary, and finishes by writing the closing boundary. using (Stream requestStream = request.GetRequestStream()) { StreamWriter writer = new StreamWriter(requestStream); writer.Write(startFormData); writer.Flush(); requestStream.Write(image, 0, image.Length); writer.Write(endFormData); writer.Flush(); writer.Close(); } HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result; string json = new StreamReader(response.GetResponseStream()).ReadToEnd(); return json; }
Create the Main method
In the
Main()
method of your application, get the filename and binary data of your image.var filename = GetImageFileName(imagePath); var imageBinary = GetImageBinary(imagePath);
Set up the POST body by formatting its boundary. Then, call
BuildFormDataStart()
andBuildFormDataEnd()
to create the form data.// Set up POST body. var boundary = string.Format(BoundaryTemplate, Guid.NewGuid()); var startFormData = BuildFormDataStart(boundary, filename); var endFormData = BuildFormDataEnd(boundary);
Create the
ContentType
value by formattingCONTENT_TYPE_HEADER_PARAMS
and the form data boundary.var contentTypeHdrValue = string.Format(CONTENT_TYPE_HEADER_PARAMS, boundary);
Get the API response by calling
BingImageSearch()
, and then print the response.var json = BingImageSearch(startFormData, endFormData, imageBinary, contentTypeHdrValue); Console.WriteLine(json); Console.WriteLine("enter any key to continue"); Console.readKey();
Using HttpClient
If you use HttpClient
, you can use the MultipartFormDataContent
class to build the form data. Use the following sections of code to replace the corresponding methods in the previous example:
Replace the
Main()
method with the following code:static void Main() { try { Console.OutputEncoding = System.Text.Encoding.UTF8; if (accessKey.Length == 32) { if (IsImagePathSet(imagePath)) { var filename = GetImageFileName(imagePath); Console.WriteLine("Getting image insights for image: " + filename); var imageBinary = GetImageBinary(imagePath); var boundary = string.Format(BoundaryTemplate, Guid.NewGuid()); var json = BingImageSearch(imageBinary, boundary, uriBase, accessKey); Console.WriteLine("\nJSON Response:\n"); Console.WriteLine(JsonPrettyPrint(json)); } } else { Console.WriteLine("Invalid Bing Visual Search API subscription key!"); Console.WriteLine("Please paste yours into the source code."); } Console.Write("\nPress Enter to exit "); Console.ReadLine(); } catch (Exception e) { Console.WriteLine(e.Message); } }
Replace the
BingImageSearch()
method with the following code:/// <summary> /// Calls the Bing visual search endpoint and returns the JSON response. /// </summary> static string BingImageSearch(byte[] image, string boundary, string uri, string subscriptionKey) { var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri); requestMessage.Headers.Add("Ocp-Apim-Subscription-Key", accessKey); var content = new MultipartFormDataContent(boundary); content.Add(new ByteArrayContent(image), "image", "myimage"); requestMessage.Content = content; var httpClient = new HttpClient(); Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None); HttpResponseMessage httpResponse = httpRequest.Result; HttpStatusCode statusCode = httpResponse.StatusCode; HttpContent responseContent = httpResponse.Content; string json = null; if (responseContent != null) { Task<String> stringContentsTask = responseContent.ReadAsStringAsync(); json = stringContentsTask.Result; } return json; }