I\'m working on a wrapper for the .net version of the Google Calendar API. The authentication is rather simple and working fine locally (localhost:port).
UserCr
I suspect the problem is that you're using AuthorizeAsync(...).Result
. Using the Result
property blocks the current thread... and I suspect that ASP.NET is trying to schedule the continuation (when authentication completes) in the same thread, leading to a deadlock.
Given that you're blocking anyway, is there any particular reason you want to use the AuthorizeAsync
call? You'd normally use that in the context of an async method, where you'd have:
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(...);
(Looking at GoogleWebAuthorizationBroker, I can't see a synchronous alternative at the moment, but that's what you should probably be looking for. My guess is that GoogleWebAuthorizationBroker
isn't designed to be used in this situation.)
Admittedly I don't know nearly as much as I probably should about either the ASP.NET synchronization context or the Google auth API, but hopefully explaining why there's a problem might be a good starting point... you probably want to read Stephen Cleary's article about synchronization contexts, too.
I am with you. For whatever reason, that also had happen to me. It was a calvary. The code below works for me. It is my own revision of Google API Simple Task ASP.NET sample.
Add these usings...
using System.IO;
using System.Threading;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Web;
using Google.Apis.Services;
using Google.Apis.Util.Store;
And these...
CalendarService service;
static string gFolder = System.Web.HttpContext.Current.Server.MapPath("/App_Data/MyGoogleStorage");
protected void Page_Load(object sender, EventArgs e)
{
IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = GetClientConfiguration().Secrets,
DataStore = new FileDataStore(gFolder),
Scopes = new[] { CalendarService.Scope.Calendar }
});
var uri = Request.Url.ToString();
var code = Request["code"];
if (code != null)
{
var token = flow.ExchangeCodeForTokenAsync(UserId, code,
uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result;
// Extract the right state.
var oauthState = AuthWebUtility.ExtracRedirectFromState(
flow.DataStore, UserId, Request["state"]).Result;
Response.Redirect(oauthState);
}
else
{
var result = new AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync(UserId,
CancellationToken.None).Result;
if (result.RedirectUri != null)
{
// Redirect the user to the authorization server.
Response.Redirect(result.RedirectUri);
}
else
{
// The data store contains the user credential, so the user has been already authenticated.
service = new CalendarService(new BaseClientService.Initializer
{
ApplicationName = "Calendar API Sample",
HttpClientInitializer = result.Credential
});
}
}
}
public static GoogleClientSecrets GetClientConfiguration()
{
using (var stream = new FileStream(gFolder + @"\client_secrets.json", FileMode.Open, FileAccess.Read))
{
return GoogleClientSecrets.Load(stream);
}
}
Hope that helps.
First of the all: See Google MVC tutorial
Step by step
1) Create method in your controller:
public async Task<ActionResult> Test()
{
//your code
}
2) Create controller :
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
}
3) Configure Google Console