2012-10-19 108 views
15

我意識到這個問題以前曾經被問過,但很少用示例代碼的方式,所以我再次問,但至少有一點點的方向。如何使用服務帳戶以.NET C#訪問Google Analytics API V3?

經過幾個小時的搜索,我想出了以下部分實現。

namespace GoogleAnalyticsAPITest.Console 
{ 
    using System.Security.Cryptography.X509Certificates; 
    using DotNetOpenAuth.OAuth2; 
    using Google.Apis.Analytics.v3; 
    using Google.Apis.Analytics.v3.Data; 
    using Google.Apis.Authentication.OAuth2; 
    using Google.Apis.Authentication.OAuth2.DotNetOpenAuth; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      log4net.Config.XmlConfigurator.Configure(); 
      string Scope = Google.Apis.Analytics.v3.AnalyticsService.Scopes.Analytics.ToString().ToLower(); 
      string scopeUrl = "https://www.googleapis.com/auth/" + Scope; 
      const string ServiceAccountId = "nnnnnnnnnnn.apps.googleusercontent.com"; 
      const string ServiceAccountUser = "[email protected]"; 
      AssertionFlowClient client = new AssertionFlowClient(
       GoogleAuthenticationServer.Description, new X509Certificate2(@"7039572692013fc5deada350904f55bad2588a2a-privatekey.p12", "notasecret", X509KeyStorageFlags.Exportable)) 
      { 
       Scope = scopeUrl, 
       ServiceAccountId = ServiceAccountId//,ServiceAccountUser = ServiceAccountUser 
      }; 
      IAuthorizationState state = AssertionFlowClient.GetState(client); 
      AnalyticsService service = new AnalyticsService(authenticator); 
      string profileId = "ga:xxxxxxxx"; 
      string startDate = "2010-10-01"; 
      string endDate = "2010-10-18"; 
      string metrics = "ga:visits"; 
      DataResource.GaResource.GetRequest request = service.Data.Ga.Get(profileId, startDate, endDate, metrics); 
      request.Dimensions = "ga:date"; 
      GaData data = request.Fetch(); 
     } 
    } 
} 

我有幾個問題。如見於的DotNetOpenAuth日誌中 「invalid_scope」 響應於AssertionFlowClient.GetState(client)結果呼叫

2012年10月19日13:27:36272(GMT-4)[8] INFO DotNetOpenAuth - DotNetOpenAuth,版本= 4.0 .0.11165,Culture = neutral,PublicKeyToken = 2780ccd10d57b246(官方) 2012-10-19 13:27:36,284(GMT-4)[8] DEBUG DotNetOpenAuth.Messaging.Channel - 準備發送AssertionFlowMessage(2.0)消息。 二〇一二年十月一十九日13:27:36294(GMT-4)[8] INFO DotNetOpenAuth.Messaging.Channel - 用於https://accounts.google.com/o/oauth2/token製備傳出AssertionFlowMessage(2.0)消息: grant_type:斷言 assertion_type:http://oauth.net/grant_type/jwt/1.0/bearer 斷言:(一束的編碼字符轉到此處)

2012-10-19 13:27:36,296(GMT-4)[8] DEBUG DotNetOpenAuth.Messaging.Channel - 發送AssertionFlowMessage請求。 2012-10-19 13:27:36,830(GMT-4)[8] DEBUG DotNetOpenAuth.Http - HTTP POST https://accounts.google.com/o/oauth2/token 2012-10-19 13:27:36,954(GMT-4)[8] ERROR DotNetOpenAuth.Http - 從https://accounts.google.com/o/oauth2/token引發WebException: { 「錯誤」: 「invalid_scope」 }

我已經試過指定沒有運氣的一個或兩個ServiceAccountId和ServiceAccountUser。

其次,即使我得到一個IAuthorizationState,我不知道如何獲得可傳遞給AnalyticsService構造函數的IAuthenticator。

以下是我用來啓用DotNetOpenAuth日誌記錄的web.config。

<?xml version="1.0"?> 
<configuration> 
    <configSections> 
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.10.0, Culture=neutral, publicKeyToken=1b44e1d426115821" /> 
    <!--<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false"/>--> 
    <sectionGroup name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection, DotNetOpenAuth"> 
     <section name="openid" type="DotNetOpenAuth.Configuration.OpenIdElement, DotNetOpenAuth" requirePermission="false" allowLocation="true"/> 
     <section name="oauth" type="DotNetOpenAuth.Configuration.OAuthElement, DotNetOpenAuth" requirePermission="false" allowLocation="true"/> 
     <section name="messaging" type="DotNetOpenAuth.Configuration.MessagingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true"/> 
     <section name="reporting" type="DotNetOpenAuth.Configuration.ReportingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true"/> 
    </sectionGroup> 
    </configSections> 
    <log4net> 
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 
     <file value="DotNetOpenAuth.log"/> 
     <appendToFile value="true"/> 
     <rollingStyle value="Size"/> 
     <maxSizeRollBackups value="10"/> 
     <maximumFileSize value="100KB"/> 
     <staticLogFileName value="true"/> 
     <layout type="log4net.Layout.PatternLayout"> 
     <conversionPattern value="%date (GMT%date{%z}) [%thread] %-5level %logger - %message%newline"/> 
     </layout> 
    </appender> 
    <appender name="TracePageAppender" type="OpenIdProviderWebForms.Code.TracePageAppender, OpenIdProviderWebForms"> 
     <layout type="log4net.Layout.PatternLayout"> 
     <conversionPattern value="%date (GMT%date{%z}) [%thread] %-5level %logger - %message%newline"/> 
     </layout> 
    </appender> 
    <!-- Setup the root category, add the appenders and set the default level --> 
    <root> 
     <level value="ALL"/> 
     <appender-ref ref="RollingFileAppender"/> 
     <appender-ref ref="TracePageAppender"/> 
    </root> 
    <!-- Specify the level for some specific categories --> 
    <logger name="DotNetOpenAuth"> 
     <level value="ALL"/> 
    </logger> 
    </log4net> 
    <dotNetOpenAuth> 
    <!-- This is an optional configuration section where aspects of dotnetopenauth can be customized. --> 
    <!-- For a complete set of configuration options see http://www.dotnetopenauth.net/developers/code-snippets/configuration-options/ --> 
    <!--<messaging clockSkew="00:10:00" lifetime="00:03:00" strict="true">--> 
    <!--<messaging> 
     <untrustedWebRequest timeout="00:00:30" readWriteTimeout="00:00:01.500" maximumBytesToRead="1048576" maximumRedirections="10"> 
     <whitelistHosts> 
      --> 
    <!-- Uncomment to enable communication with localhost (should generally not activate in production!) --> 
    <!-- 
      <add name="localhost"/>    
     </whitelistHosts> 
     </untrustedWebRequest> 
    </messaging>--> 
    <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. --> 
    <reporting enabled="false"/> 
    </dotNetOpenAuth> 
    <appSettings> 
    <!--<add key="log4net.Internal.Debug" value="true" />--> 
    </appSettings> 
    <runtime> 
    </runtime> 
    <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
    </startup> 
</configuration> 

回答

11

下面的代碼,從我原來的問題修正,是基於由伊恩·弗雷澤在所提供的例子:

https://groups.google.com/forum/#!msg/google-search-api-for-shopping/4uUGirzH4Rw/__c0e4hj0ekJ

他的代碼解決三個問題:

  1. 看來好像AnalyticsService.Scopes.AnalyticsReadonly不起作用,至少不適合我或我正在做這件事的方式。
  2. 出於某種原因,必須將ServiceAccountUser分配給AssertionFlowClient實例的ServiceAccountId屬性。
  3. OAuth2Authenticator提供了我一直在尋找的IAuthenticator。

在您的項目,包括對引用:

  • 庫\ DotNetOpenAuth.dll
  • 庫\ Google.Apis.dll
  • 庫\ Google.Apis.Authentication.OAuth2.dll
  • 服務\ AnalyticsService \ Google.Apis.Analytics.v3.dll

-

namespace GoogleAnalyticsAPITest.Console 
{ 
    using System.Security.Cryptography.X509Certificates; 
    using Google.Apis.Analytics.v3; 
    using Google.Apis.Analytics.v3.Data; 
    using Google.Apis.Authentication.OAuth2; 
    using Google.Apis.Authentication.OAuth2.DotNetOpenAuth; 
    using Google.Apis.Util; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      log4net.Config.XmlConfigurator.Configure();    
      const string ServiceAccountId = "nnnnnnnnnnn.apps.googleusercontent.com"; 
      const string ServiceAccountUser = "[email protected]"; 
      AssertionFlowClient client = new AssertionFlowClient(
       GoogleAuthenticationServer.Description, new X509Certificate2(@"value-privatekey.p12", "notasecret", X509KeyStorageFlags.Exportable)) 
      { 
       Scope = AnalyticsService.Scopes.AnalyticsReadonly.GetStringValue(), 
       ServiceAccountId = ServiceAccountUser //Bug, why does ServiceAccountUser have to be assigned to ServiceAccountId 
       //,ServiceAccountUser = ServiceAccountUser 
      }; 
      OAuth2Authenticator<AssertionFlowClient> authenticator = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);    
      AnalyticsService service = new AnalyticsService(authenticator);    
      string profileId = "ga:64968920"; 
      string startDate = "2010-10-01"; 
      string endDate = "2010-10-31"; 
      string metrics = "ga:visits"; 
      DataResource.GaResource.GetRequest request = service.Data.Ga.Get(profileId, startDate, endDate, metrics); 
      request.Dimensions = "ga:date"; 
      GaData data = request.Fetch();    
     } 

    } 
} 
+0

看起來像正確的只讀範圍是https://www.googleapis.com/auth/analytics.readonly。這與將枚舉值轉換爲字符串不同。另外,我不必設置ServiceAccountUser。 –

+0

@BenMills你能澄清你如何驗證?我猜你是在說你將ServiceAccountId設置爲nnnnnnnnnnn.apps.googleusercontent.com的值,但我不確定這是什麼意思。我編輯了代碼將範圍設置爲「analytics.readonly」,因爲這可能是人們使用這種方法的主要方式。 –

+0

對不起,你是對的。我將ServiceAccountId設置爲[email protected]。我不需要以任何方式考慮nnnnnnnnnnn.apps.googleusercontent.com。 –

2

這是我在這裏[1]發佈工作示例:Automated use of google-api-dotnet-client with OAuth 2.0我投入了大量的研究,發現和拼湊的代碼放在一起希望這可以節省一些時間。

+0

我確保你花費大量的時間來解決這個問題。看起來你必須進入比我使用的API更低的級別。但是,您的示例使用NativeApplicationClient而不是AssertionFlowClient。我很欣賞這些反饋。 –

1

關於理查德·科萊特的答案,如果你要使用Google Analytics API以只讀模式要小心使用他的方法,使用它的正確方法是:

string Scope = "analytics.readonly" 

,而不是

string Scope = AnalyticsService.Scopes.AnalyticsReadOnly.ToString().ToLower() 

,因爲他似乎告訴有一個錯誤。實際上,錯誤在於.toString()方法返回analyticsreadonly而不是analytics.readonly這是Google喜歡的方式。而已。

+1

偉大的信息。我會說這是枚舉中的一個錯誤。如果你不能使用它們,這些枚舉有什麼意義? –

+1

@RichardCollette 在名稱空間Google.Apis.Util中有一個擴展方法,用於從AnalyticsService.Scopes枚舉AnalyticsService.Scopes.AnalyticsReadonly.GetStringValue()中檢索字符串值。 –

3
string scope = Google.Apis.Util.Utilities.GetStringValue(AnalyticsService.Scopes.AnalyticsReadonly); 
+0

這是一種擴展方法。你不需要這樣稱呼它。看到上面的解決方案。 –

4

我被檢查出的分析API昨天,發現它是多麼無證,無樣品等

任何方式,我已經創建了,你可以用幾行輕鬆使用訪問分析庫並進行直接數據綁定的DataTable的數據返回它在GitHub的開源可以隨意貢獻:)

https://github.com/rmostafa/DotNetAnalyticsAPI

使用

Analytics.AnalyticsManager manager = new Analytics.AnalyticsManager(Server.MapPath("~/bin/privatekey.p12"), "YOUR_EMAIL"); 
      manager.LoadAnalyticsProfiles(); 


List<Analytics.Data.DataItem> metrics = new List<Analytics.Data.DataItem>(); 
metrics.Add(Analytics.Data.Visitor.Metrics.visitors); 
metrics.Add(Analytics.Data.Session.Metrics.visits); 
List<Analytics.Data.DataItem> dimensions = new List<Analytics.Data.DataItem>(); 
dimensions.Add(Analytics.Data.GeoNetwork.Dimensions.country); 
dimensions.Add(Analytics.Data.GeoNetwork.Dimensions.city); 


System.Data.DataTable table = manager.GetGaDataTable(DateTime.Today.AddDays(-3), DateTime.Today, metrics, dimensions, null, metrics); 

所有Google API報告命令都有直接的代碼映射,與API類似,所以即使沒有讀取API文檔,也可以根據這些代碼進行分類,因爲所有功能都在屬性中記錄,我寫了代碼解析完整的API文檔和資源的指標,維度,因爲我是從物理類生成的,上面很好玩,你可以直接使用,如例如XML計算的特徵與:)享受

https://github.com/rmostafa/DotNetAnalyticsAPI

相關問題