ক্লাউড স্টোরেজ দিয়ে শুরু করুন

Google Display & Video 360 স্বয়ংক্রিয়ভাবে Google ক্লাউড স্টোরেজে এন্টিটি রিড ফাইল সঞ্চয় করে। এই ফাইলগুলি শুধুমাত্র সেই অ্যাকাউন্টগুলিতে অ্যাক্সেসযোগ্য যেগুলিকে অ্যাক্সেস দেওয়া হয়েছে৷

একটি প্রকল্প তৈরি করুন

নিম্নলিখিত হিসাবে একটি প্রকল্প তৈরি এবং কনফিগার করুন:

  1. Google API কনসোল সক্ষম APIs পৃষ্ঠাতে যান।

    আপনি যদি ইতিমধ্যেই Google-এ সাইন ইন না করে থাকেন, তাহলে আপনাকে সাইন ইন করতে বলা হবে৷

  2. প্রকল্প ড্রপ-ডাউন থেকে, একটি বিদ্যমান প্রকল্প নির্বাচন করুন বা একটি নতুন তৈরি করুন৷
    • আপনার যদি একাধিক বিদ্যমান প্রকল্প থাকে, তাহলে আপনি যে প্রকল্পটির জন্য Google ক্লাউড স্টোরেজ সক্রিয় করতে চান সেটি নির্বাচন করতে ভুলবেন না, তারপর Continue নির্বাচন করুন।
    • অথবা, যদি আপনার কোনো প্রকল্প না থাকে, একটি নতুন প্রকল্প তৈরি করুন নির্বাচন করুন, একটি প্রকল্পের নাম লিখুন, তারপর তৈরি করুন নির্বাচন করুন।

      দ্রষ্টব্য: আপনার সচেতন হওয়া উচিত যে কিছু রিসোর্স আইডেন্টিফায়ার (যেমন প্রোজেক্ট আইডি) আপনার প্রোজেক্টের জীবনকালের বাইরেও রাখা যেতে পারে। এই কারণে, রিসোর্স আইডেন্টিফায়ারে সংবেদনশীল তথ্য সংরক্ষণ করা এড়িয়ে চলুন।

  3. সক্রিয় API- এর তালিকায়, নিশ্চিত করুন যে Google ক্লাউড স্টোরেজ উপাদান তালিকাভুক্ত আছে। যদি এটি তালিকাভুক্ত না থাকে, Google APIs ট্যাবে ক্লিক করুন, অনুসন্ধান করুন এবং Google ক্লাউড স্টোরেজ উপাদান নির্বাচন করুন এবং API সক্ষম করুন ক্লিক করুন।

    মনে রাখবেন যে বেশিরভাগ প্রকল্পের জন্য, Google ক্লাউড স্টোরেজ উপাদান ইতিমধ্যে সক্ষম করা আছে। আপনি যদি JSON API ব্যবহার করে Google ক্লাউড স্টোরেজ অ্যাক্সেস করার পরিকল্পনা করেন, তাহলে আপনাকে Google ক্লাউড স্টোরেজ JSON API সক্ষম করা আছে কিনা তাও যাচাই করতে হবে।

  4. প্রকল্পের জন্য বিলিং সক্ষম করুন৷

    আপনি Google ক্লাউড স্টোরেজ ব্যবহার করার আগে, আপনি যদি ইতিমধ্যে এটি না করে থাকেন তবে আপনার প্রকল্পের জন্য বিলিং সক্ষম করতে হবে৷ বিলিং সক্ষম করার অর্থ এই নয় যে আপনাকে চার্জ করা হবে৷ আরও তথ্যের জন্য, মূল্য দেখুন।

    1. এখনও ক্লাউড স্টোরেজ প্রকল্পের মধ্যে, উপরের বাম কোণে গ্যালারি মেনুতে ক্লিক করুন, তারপরে বিলিং নির্বাচন করুন।
    2. আপনার যদি এখনও কোনো বিলিং অ্যাকাউন্ট না থাকে, তাহলে একটি নতুন বিলিং অ্যাকাউন্ট তৈরি করতে নির্দেশাবলী অনুসরণ করুন।
    3. আপনার যদি একটি বিদ্যমান বিলিং অ্যাকাউন্ট থাকে তবে এটি নির্বাচন করুন, তারপরে অ্যাকাউন্ট সেট করুন নির্বাচন করুন।

Google API কনসোলে, একই প্রকল্পের মধ্যে থাকুন এবং পরবর্তী বিভাগে যান।

ক্লাউড স্টোরেজ অ্যাক্সেস সেট আপ করুন

  1. প্রয়োজনীয় প্রকল্পের মধ্যে এখনও Google API কনসোলে, উপরের বাম কোণে গ্যালারি মেনুতে ক্লিক করুন, APIs এবং পরিষেবাগুলি নির্বাচন করুন এবং তারপরে শংসাপত্রে ক্লিক করুন। শংসাপত্র পৃষ্ঠায়, পরিষেবা অ্যাকাউন্ট কীগুলি সন্ধান করুন।

    পরিষেবা অ্যাকাউন্ট কী ইমেল ঠিকানা খুঁজুন:

    1. পরিষেবা অ্যাকাউন্টগুলি পরিচালনা করুন লিঙ্কটি নির্বাচন করুন (পরিষেবা অ্যাকাউন্ট কী বিভাগের ডানদিকে)।
    2. ইমেল ঠিকানাটি ফলাফলের অনুমতি পৃষ্ঠায় দেখা যায়।

    যদি কোনও পরিষেবা অ্যাকাউন্ট কী না থাকে তবে একটি নতুন পরিষেবা অ্যাকাউন্ট তৈরি করুন:

    1. শংসাপত্র তৈরি করুন ড্রপ-ডাউন নির্বাচন করুন, তারপর পরিষেবা অ্যাকাউন্ট কী চয়ন করুন।
    2. পরিষেবা অ্যাকাউন্ট ড্রপ-ডাউনে, নতুন পরিষেবা অ্যাকাউন্ট নির্বাচন করুন।
    3. পরিষেবা অ্যাকাউন্টের জন্য একটি নাম লিখুন। পরিষেবা অ্যাকাউন্ট আইডি স্বয়ংক্রিয়ভাবে নাম এবং প্রকল্পের নাম থেকে তৈরি হয়।
    4. পরিষেবা অ্যাকাউন্ট আইডি gserviceaccount.com ইমেল ঠিকানা একটি নোট করুন । আপনি তৈরি করুন নির্বাচন করার পরে এটি শংসাপত্র পৃষ্ঠায় প্রদর্শিত হয় না।
    5. কী টাইপ বিভাগে, JSON নির্বাচন করুন।
    6. তৈরি করুন ক্লিক করুন। অ্যাকাউন্টের সর্বজনীন/ব্যক্তিগত কী জোড়া সহ JSON ফাইলটি আপনার ডাউনলোড ফোল্ডারে সংরক্ষিত হয়। এই কীটি API-তে আপনার আবেদনকে প্রমাণীকরণ করতে এবং এটি API-তে পাঠানো সমস্ত অনুরোধে স্বাক্ষর করতে ব্যবহৃত হয়। জেনারেট করা JSON ফাইলটিকে একটি নিরাপদ জায়গায় সংরক্ষণ করুন, যেখানে আপনার অ্যাপ্লিকেশন এটি অ্যাক্সেস করতে সক্ষম হবে৷
  2. এন্টিটি রিড ফাইল এবং/অথবা Google বিড ম্যানেজার API সক্ষম করার অনুরোধ করতে Display & Video 360 সাপোর্ট টিমের সাথে যোগাযোগ করুন।

    সাপোর্ট টিম অ্যাক্সেস নিশ্চিত করার পরে, একটি ডেডিকেটেড Google গ্রুপ (বা গোষ্ঠী) তৈরি করুন এবং Display & Video 360 অংশীদারের বিবরণে নিম্নলিখিত ক্ষেত্রগুলি আপডেট করুন (মনে রাখবেন যে শুধুমাত্র অংশীদার-স্তরের অ্যাক্সেস সহ ব্যবহারকারীরা এই আপডেটগুলি করতে সক্ষম হবেন):

    • লগ রিড গুগল গ্রুপ
      শুধুমাত্র পঠনযোগ্য গোষ্ঠীর কাছে ফাইলগুলি পড়ার এবং স্টোরেজ বালতিগুলির বিষয়বস্তু তালিকাভুক্ত করার অনুমতি রয়েছে৷
    • লগ ম্যানেজমেন্ট গুগল গ্রুপ
      ম্যানেজমেন্ট গ্রুপের কাছে শুধুমাত্র পঠনযোগ্য গোষ্ঠীর সমস্ত অনুমতি রয়েছে, তবে বাকেটের মধ্যে ফাইলগুলির ACL পরিবর্তন করতেও সক্ষম। মনে রাখবেন যে এমনকি ম্যানেজমেন্ট গ্রুপের কাছে বালতি ACL পরিবর্তন করার অনুমতি নেই, বা তাদের ফাইল তৈরি, পরিবর্তন বা মুছে ফেলার অনুমতি নেই।

    Google গোষ্ঠী যুক্ত হওয়ার পরে, আপনি Display & Video 360 সমর্থন দল থেকে আর কোনো সম্পৃক্ততা ছাড়াই আপনার Google গ্রুপ থেকে ব্যবহারকারীদের যোগ করতে এবং সরাতে পারেন; শুধুমাত্র আপনার গ্রুপে থাকা ব্যবহারকারীরা আপনার ডেটা অ্যাক্সেস করতে পারবে।

আপনার ডেটা অ্যাক্সেস করুন

Gsutil ব্যবহার করে ডেটা অ্যাক্সেস করুন

gsutil টুল হল একটি কমান্ড-লাইন অ্যাপ্লিকেশন যা আপনাকে কোনো প্রোগ্রামিং অভিজ্ঞতা ছাড়াই সহজেই আপনার Google ক্লাউড স্টোরেজ ডেটা অ্যাক্সেস করতে দেয়। আপনি, উদাহরণস্বরূপ, কাস্টম অ্যাপ্লিকেশন তৈরি করার পরিবর্তে একটি স্ক্রিপ্ট বা ব্যাচ ফাইলের অংশ হিসাবে gsutil ব্যবহার করতে পারেন।

gsutil দিয়ে শুরু করতে, gsutil ডকুমেন্টেশন পড়ুন। আপনাকে এখনও আগের মতো OAuth 2 ব্যবহার করে প্রমাণীকরণ করতে হবে, কিন্তু আপনি যখন প্রথমবার এটি ব্যবহার করেন তখন gsutil নিজেই আপনাকে শংসাপত্রের জন্য অনুরোধ করবে এবং তারপরে সেগুলি পরে ব্যবহারের জন্য সংরক্ষণ করবে।

প্রোগ্রামগতভাবে ডেটা অ্যাক্সেস করুন

Google ক্লাউড স্টোরেজের অনেকগুলি প্রোগ্রামিং ভাষার জন্য API রয়েছে যা আপনাকে প্রোগ্রামেটিক উপায়ে আপনার ডেটা অ্যাক্সেস করতে দেয়। নীচের নমুনাটি আপনাকে দেখায় কিভাবে Google ক্লাউড স্টোরেজ থেকে সত্তা রিড ফাইলগুলির একটির একটি সহজ ডাউনলোড সম্পাদন করতে হয়৷ মনে রাখবেন যে শুধুমাত্র পাবলিক এন্টিটি রিড ফাইলগুলি gdbm-public bucket-এ সংরক্ষণ করা হয়; আপনার ব্যক্তিগত সত্তা রিড ফাইলগুলি অংশীদার- এবং বিজ্ঞাপনদাতা-নির্দিষ্ট বালতিতে সংরক্ষণ করা হবে৷

জাভা

নিম্নলিখিত উদাহরণটি Java এর জন্য Google APIs ক্লায়েন্ট লাইব্রেরি ব্যবহার করে, যা Google ক্লাউড স্টোরেজে থাকা ডেটা অ্যাক্সেস করা সহজ করে তোলে। প্রধান সাধারণ Google API ক্লায়েন্ট লাইব্রেরি ছাড়াও, আপনাকে ক্লাউড স্টোরেজ API-এর জন্য আলাদা লাইব্রেরি ডাউনলোড করতে হবে।

আপনার ডেটা অ্যাক্সেস করার অনুমোদন পেতে API-এর সাথে যোগাযোগ করার সময় আপনাকে প্রথমে ব্যবহার করার জন্য শংসাপত্রগুলি সেট আপ করতে হবে। এটি একটি Credential অবজেক্ট তৈরি করে করা হয় যা সার্ভিস অ্যাকাউন্টের developer.gserviceaccount.com ইমেল ঠিকানাটিকে ServiceAccountId হিসাবে ব্যবহার করে এবং পরিষেবা অ্যাকাউন্ট তৈরি করার সময় Google API কনসোল থেকে ডাউনলোড করা ব্যক্তিগত কী ফাইলটিও লোড করে৷ এটি নিশ্চিত করবে যে API-তে সমস্ত ভবিষ্যতের অনুরোধগুলি পরিষেবা অ্যাকাউন্টের ব্যক্তিগত কী দিয়ে স্বাক্ষরিত হয়েছে:

NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JacksonFactory JSON_FACTORY = new JacksonFactory();

...

Credential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
   .setJsonFactory(JSON_FACTORY)
   .setServiceAccountId("...@developer.gserviceaccount.com")
   .setServiceAccountScopes(StorageScopes.DEVSTORAGE_READ_ONLY)
   .setServiceAccountPrivateKeyFromP12File(new File("...-privatekey.p12"))
   .build();

আপনি Credential অবজেক্ট তৈরি করার পরে, আপনি এটিকে একটি নতুন Storage অবজেক্ট ইনস্ট্যান্টিয়েট করতে ব্যবহার করতে পারেন যা আপনি Google ক্লাউড স্টোরেজ API এ ভবিষ্যতের সমস্ত অনুরোধের জন্য ব্যবহার করতে পারেন:

Storage storage = new Storage(HTTP_TRANSPORT, JSON_FACTORY, credential);

এখন আপনার কাছে একটি নতুন Storage অবজেক্ট আছে, আপনি API এ অনুরোধ করা শুরু করতে প্রস্তুত। এখানে আপনি বাকেট bucket থেকে একটি নির্দিষ্ট আইটেম bucketObjectName পুনরুদ্ধার করার জন্য একটি অনুরোধ করছেন। লাইব্রেরি Google ক্লাউড স্টোরেজ থেকে ফাইলের HTTP ডাউনলোড পরিচালনা করে এবং তারপরে আপনি কনসোলে বিষয়বস্তু মুদ্রণ করেন:

Get bucketObject = storage.objects().get(bucketName, bucketObjectName);

ByteArrayOutputStream output = new ByteArrayOutputStream();
bucketObject.getMediaHttpDownloader().setDirectDownloadEnabled(true);
bucketObject.executeAndDownloadTo(output);

System.out.println(output.toString());

bucket এবং bucketObjectName এর জন্য আপনার মানগুলি আপনি API-এর কোন অংশ অ্যাক্সেস করছেন তার উপর নির্ভর করে পরিবর্তিত হবে; নামকরণ প্রথার উপযুক্ত বিভাগ পড়ুন।

সি#

নিম্নলিখিত উদাহরণটি .NET-এর জন্য Google APIs ক্লায়েন্ট লাইব্রেরি ব্যবহার করে, যা Google ক্লাউড স্টোরেজে থাকা ডেটা অ্যাক্সেস করা সহজ এবং সহজ করে তোলে৷

আপনার ডেটা অ্যাক্সেস করার অনুমোদন পেতে API-এর সাথে যোগাযোগ করার সময় আপনাকে প্রথমে ব্যবহার করার জন্য শংসাপত্রগুলি সেট আপ করতে হবে। এটি একটি AssertionFlowClient অবজেক্ট তৈরি করে করা হয় যা ServiceAccountId হিসাবে পরিষেবা অ্যাকাউন্টের developer.gserviceaccount.com ইমেল ঠিকানা ব্যবহার করে এবং পরিষেবা অ্যাকাউন্ট তৈরি করার সময় Google API কনসোল থেকে ডাউনলোড করা ব্যক্তিগত কী ফাইলটিও লোড করে৷

string keyPath = @"...-privatekey.p12";
X509Certificate2 certificate = new X509Certificate2(keyPath, "notasecret", X509KeyStorageFlags.Exportable);
var provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, certificate)
{
    ServiceAccountId = "...@developer.gserviceaccount.com",
    Scope = StorageService.Scopes.DevstorageRead_only.GetStringValue()
};

আপনি AssertionFlowClient অবজেক্ট তৈরি করার পরে, আপনি এটিকে একটি নতুন OAuth2Authenticator অবজেক্ট ইনস্ট্যান্টিয়েট করতে ব্যবহার করতে পারেন যা আপনি Google ক্লাউড স্টোরেজ API-তে সমস্ত ভবিষ্যতের অনুরোধের জন্য একটি নতুন Storage ইনস্ট্যান্স ইনস্ট্যান্ট করতে ব্যবহার করতে পারেন:

var auth = new OAuth2Authenticator<AssertionFlowClient>(provider, AssertionFlowClient.GetState);
StorageService service = new StorageService(auth);

এখন আপনার কাছে একটি নতুন Storage অবজেক্ট আছে, আপনি API এ অনুরোধ করা শুরু করতে প্রস্তুত। এখানে আপনি একটি নির্দিষ্ট আইটেম পুনরুদ্ধার করার জন্য একটি অনুরোধ করছেন, bucketObjectName , বালতি bucket থেকে। আমরা Google ক্লাউড স্টোরেজ থেকে HTTP ডাউনলোড পরিচালনা করার জন্য স্ট্যান্ডার্ড .NET ক্লায়েন্ট লাইব্রেরি ক্লাস ব্যবহার করি, কিন্তু অনুরোধে সর্বদা সঠিক Authorization শিরোনাম উপস্থিত রয়েছে তা নিশ্চিত করার জন্য একটি পুনঃনির্দেশ আছে এমন ক্ষেত্রে আপনাকে ম্যানুয়ালি পরিচালনা করতে হবে:

var results = service.Objects.Get(bucketName, bucketObjectName).Fetch();

HttpWebRequest request = createRequest(results.Media.Link, auth);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

// Handle redirects manually to ensure that the Authorization header is present if
// your request is redirected.
if (response.StatusCode == HttpStatusCode.TemporaryRedirect)
{
    request = createRequest(response.Headers["Location"], auth);
    response = (HttpWebResponse)request.GetResponse();
}

প্রতিক্রিয়ার বিষয়বস্তু তারপর যথারীতি GetResponseStream মাধ্যমে HttpWebResponse অবজেক্ট থেকে পড়া যাবে। bucket এবং bucketObjectName এর জন্য আপনার মানগুলি আপনি API-এর কোন অংশ অ্যাক্সেস করছেন তার উপর নির্ভর করে পরিবর্তিত হবে; নামকরণ প্রথার উপযুক্ত বিভাগ পড়ুন।

পরিশিষ্ট: সম্পূর্ণ নমুনা

জাভা

/*
 * Copyright (c) 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.bidmanager.api.samples;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStreamReader;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.Storage.Objects.Get;
import com.google.api.services.storage.StorageScopes;

/**
 * A simple class that demonstrates how to download a specific object from a bucket using a
 * service account
 */
public class ServiceDownload {

  /**
   * This is the HTTP Transport object used for automatically refreshing access tokens.
   */
  static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  /**
   * This is the JSON factory used for parsing refresh token responses.Your first requirement
   */
  static final JacksonFactory JSON_FACTORY = new JacksonFactory();

  /**
   * The main method will attempt to download a specific named object from the gdbm-public bucket
   * using a service account.
   *
   * @param args Not used.
   */
  public static void main(String[] args) {

    try {
      // Prompt the user for the details of the object to download.
      System.out.print("Name of object to download, e.g. entity/20130430.0.Browser.json:");
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      String bucketObjectName = in.readLine();
      in.close();
      String bucketName = "gdbm-public";

      Credential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
           .setJsonFactory(JSON_FACTORY)
           .setServiceAccountId("...@developer.gserviceaccount.com")
           .setServiceAccountScopes(StorageScopes.DEVSTORAGE_READ_ONLY)
           .setServiceAccountPrivateKeyFromP12File(
               new File("...-privatekey.p12"))
           .build();

      Storage storage = new Storage(HTTP_TRANSPORT, JSON_FACTORY, credential);

      Get bucketObject = storage.objects().get(bucketName, bucketObjectName);

      ByteArrayOutputStream output = new ByteArrayOutputStream();
      bucketObject.getMediaHttpDownloader().setDirectDownloadEnabled(true);
      bucketObject.executeAndDownloadTo(output);
      System.out.println(output.toString());

    } catch (Exception e) {
      System.err.println("Unexpected exception caught: " + e.getMessage());
      e.printStackTrace();
    }

  }


}

সি#

/*
 * Copyright (c) 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;

using DotNetOpenAuth.OAuth2;

using Google.Apis;
using Google.Apis.Requests;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using Google.Apis.Storage.v1beta1;
using Google.Apis.Storage.v1beta1.Data;
using Google.Apis.Util;

namespace ApiSamples
{
    /// <summary>
    /// A simple class that demonstrates how to download a specific object from a bucket using a
    /// service account
    /// </summary>
    class ServiceDownload
    {
        /// <summary>
        /// The main method will attempt to download a specific named object from the
        /// gdbm-public bucket using a service account.
        /// </summary>
        /// <param name="args">Not used.</param>
        public static void Main(string[] args)
        {

            // Prompt the user for the details of the object to download
            Console.WriteLine("Name of object to download, e.g. entity/20130430.0.Browser.json:");
            string bucketObjectName = Console.ReadLine();
            string bucketName = "gdbm-public";

            try
            {
                string keyPath = @"...-privatekey.p12";
                X509Certificate2 certificate = new X509Certificate2(keyPath, "notasecret", X509KeyStorageFlags.Exportable);
                var provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, certificate)
                {
                    ServiceAccountId = "...@developer.gserviceaccount.com",
                    Scope = StorageService.Scopes.DevstorageRead_only.GetStringValue()
                };
                var auth = new OAuth2Authenticator<AssertionFlowClient>(provider, AssertionFlowClient.GetState);

                StorageService service = new StorageService(auth);
                var results = service.Objects.Get(bucketName, bucketObjectName).Fetch();

                HttpWebRequest request = createRequest(results.Media.Link, auth);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                // Handle redirects manully to ensure that the Authorization header is present if
                // our request is redirected.
                if (response.StatusCode == HttpStatusCode.TemporaryRedirect)
                {
                    request = createRequest(response.Headers["Location"], auth);
                    response = (HttpWebResponse)request.GetResponse();
                }

                Stream stream = response.GetResponseStream();
                StreamReader reader = new StreamReader(stream);
                String data = reader.ReadToEnd();
                Console.Write(data);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception caught: " + e.Message);
                Console.Write(e.StackTrace);
            }
            Console.ReadKey();
        }

        /// <summary>
        /// Generate a HttpWebRequest for the given URL with the appropriate OAuth2 authorization
        /// header applied.  The HttpWebRequest object returned has its AllowAutoRedirect option
        /// disabled to allow us to manually handle redirects.
        /// </summary>
        /// <param name="url">URL that is to be requested with this object</param>
        /// <param name="auth">The OAuth2Authenticator instance that contains the appropriate keys.</param>
        /// <returns>HttpWebRequest object ready to be used to make requests to the API</returns>
        private static HttpWebRequest createRequest(string url, OAuth2Authenticator<AssertionFlowClient> auth)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Headers.Add("Authorization", "Bearer " + auth.State.AccessToken);
            request.AllowAutoRedirect = false;
            return request;
        }

    }
}