SEC_ERROR_REVOKED_CERTIFICATE error while accesing the url in browser - ssl

Hi i am getting below error while trying to access the website which is hosted in IIS 8 for which the SSL certificate had got expired and i installed the new SSL certificate provided by GoDaddy, it was all working fine for 2 days and now it shows the below error. Let me know if anyone can figure out what is the issue
using Microsoft.CognitiveServices.Speech;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace SPT
{
class Program
{
public static async Task RecognizeSpeechAsync()
{
// Creates an instance of a speech config with specified subscription key and service region.
// Replace with your own subscription key // and service region (e.g., "westus").
var config = SpeechConfig.FromSubscription(" 7cf359266c964dc789960abe063cc65b", "westus");
// Creates a speech recognizer.
using (var recognizer = new SpeechRecognizer(config))
{
Console.WriteLine("Say something...");
// Starts speech recognition, and returns after a single utterance is recognized. The end of a
// single utterance is determined by listening for silence at the end or until a maximum of 15
// seconds of audio is processed. The task returns the recognition text as result.
// Note: Since RecognizeOnceAsync() returns only a single utterance, it is suitable only for single
// shot recognition like command or query.
// For long-running multi-utterance recognition, use StartContinuousRecognitionAsync() instead.
var result = await recognizer.RecognizeOnceAsync();
// Checks result.
if (result.Reason == ResultReason.RecognizedSpeech)
{
Console.WriteLine($"We recognized: {result.Text}");
}
else if (result.Reason == ResultReason.NoMatch)
{
Console.WriteLine($"NOMATCH: Speech could not be recognized.");
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = CancellationDetails.FromResult(result);
Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");
if (cancellation.Reason == CancellationReason.Error)
{
Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
Console.WriteLine($"CANCELED: ErrorDetails={cancellation.ErrorDetails}");
Console.WriteLine($"CANCELED: Did you update the subscription info?");
}
}
}
}
public static async Task SynthesisToSpeakerAsync()
{
// Creates an instance of a speech config with specified subscription key and service region.
// Replace with your own subscription key and service region (e.g., "westus").
// The default language is "en-us".
var config = SpeechConfig.FromSubscription("7cf359266c964dc789960abe063cc65b", "westus");
// Creates a speech synthesizer using speaker as audio output.
using (var synthesizer = new SpeechSynthesizer(config))
{
// Receive a text from console input and synthesize it to speaker.
Console.WriteLine("Type some text that you want to speak...");
Console.Write("> ");
string text = Console.ReadLine();
using (var result = await synthesizer.SpeakTextAsync(text))
{
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
Console.WriteLine($"Speech synthesized to speaker for text [{text}]");
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");
if (cancellation.Reason == CancellationReason.Error)
{
Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
Console.WriteLine($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
Console.WriteLine($"CANCELED: Did you update the subscription info?");
}
}
}
// This is to give some time for the speaker to finish playing back the audio
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public static async Task SynthesisToVideoAsync()
{
var apiUrl = "https://api.videoindexer.ai";
var accountId = "56fbb8f8-b9a8-4119-b46a-fa5fb6668ddd";
var location = "westus2";
var apiKey = "6f354f730bc141f9bc3e57e73c6001b0";
System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol | System.Net.SecurityProtocolType.Tls12;
// create the http client
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = false;
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
// obtain account access token
var accountAccessTokenRequestResult = client.GetAsync($"{apiUrl}/auth/{location}/Accounts/{accountId}/AccessToken?allowEdit=true").Result;
var accountAccessToken = accountAccessTokenRequestResult.Content.ReadAsStringAsync().Result.Replace("\"", "");
client.DefaultRequestHeaders.Remove("Ocp-Apim-Subscription-Key");
// upload a video
var content = new MultipartFormDataContent();
Debug.WriteLine("Uploading...");
// get the video from URL
var videoUrl = "VIDEO_URL"; // replace with the video URL
// as an alternative to specifying video URL, you can upload a file.
// remove the videoUrl parameter from the query string below and add the following lines:
//FileStream video =File.OpenRead(Globals.VIDEOFILE_PATH);
//byte[] buffer =newbyte[video.Length];
//video.Read(buffer, 0, buffer.Length);
//content.Add(newByteArrayContent(buffer));
var uploadRequestResult = client.PostAsync($"{apiUrl}/{location}/Accounts/{accountId}/Videos?accessToken={accountAccessToken}&name=some_name&description=some_description&privacy=private&partition=some_partition&videoUrl={videoUrl}", content).Result;
var uploadResult = uploadRequestResult.Content.ReadAsStringAsync().Result;
// get the video id from the upload result
var videoId = JsonConvert.DeserializeObject<dynamic>(uploadResult)["id"];
Debug.WriteLine("Uploaded");
Debug.WriteLine("Video ID: " + videoId);
// obtain video access token
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
var videoTokenRequestResult = client.GetAsync($"{apiUrl}/auth/{location}/Accounts/{accountId}/Videos/{videoId}/AccessToken?allowEdit=true").Result;
var videoAccessToken = videoTokenRequestResult.Content.ReadAsStringAsync().Result.Replace("\"", "");
client.DefaultRequestHeaders.Remove("Ocp-Apim-Subscription-Key");
// wait for the video index to finish
while (true)
{
Thread.Sleep(10000);
var videoGetIndexRequestResult = client.GetAsync($"{apiUrl}/{location}/Accounts/{accountId}/Videos/{videoId}/Index?accessToken={videoAccessToken}&language=English").Result;
var videoGetIndexResult = videoGetIndexRequestResult.Content.ReadAsStringAsync().Result;
var processingState = JsonConvert.DeserializeObject<dynamic>(videoGetIndexResult)["state"];
Debug.WriteLine("");
Debug.WriteLine("State:");
Debug.WriteLine(processingState);
// job is finished
if (processingState != "Uploaded" && processingState != "Processing")
{
Debug.WriteLine("");
Debug.WriteLine("Full JSON:");
Debug.WriteLine(videoGetIndexResult);
break;
}
}
// search for the video
var searchRequestResult = client.GetAsync($"{apiUrl}/{location}/Accounts/{accountId}/Videos/Search?accessToken={accountAccessToken}&id={videoId}").Result;
var searchResult = searchRequestResult.Content.ReadAsStringAsync().Result;
Debug.WriteLine("");
Debug.WriteLine("Search:");
Debug.WriteLine(searchResult);
// get insights widget url
var insightsWidgetRequestResult = client.GetAsync($"{apiUrl}/{location}/Accounts/{accountId}/Videos/{videoId}/InsightsWidget?accessToken={videoAccessToken}&widgetType=Keywords&allowEdit=true").Result;
var insightsWidgetLink = insightsWidgetRequestResult.Headers.Location;
Debug.WriteLine("Insights Widget url:");
Debug.WriteLine(insightsWidgetLink);
// get player widget url
var playerWidgetRequestResult = client.GetAsync($"{apiUrl}/{location}/Accounts/{accountId}/Videos/{videoId}/PlayerWidget?accessToken={videoAccessToken}").Result;
var playerWidgetLink = playerWidgetRequestResult.Headers.Location;
Debug.WriteLine("");
Debug.WriteLine("Player Widget url:");
Debug.WriteLine(playerWidgetLink);
}
static void Main()
{
RecognizeSpeechAsync().Wait();
SynthesisToSpeakerAsync().Wait();
SynthesisToVideoAsync().Wait();
Console.WriteLine("Please press a key to continue.");
Console.ReadLine();
}
}
}

Related

How to perform POST using .NET Core 6 Minimal API in Azure Blob Storage

I am new to .NET and I have to perform this. Assuming we have the connection string and the Environment variable setup, could someone give me resources or code or guide on how to do it?
I just need to upload a pdf file in Azure Blob Storage using Minimal API
From the Minimal API document, we can see that the Minimal API does not support the binding the IFormFile.
No support for binding from forms. This includes binding IFormFile. We plan to add support for IFormFile in the future.
So, to upload file in the Minimal API, you can get the upload file from the HttpRequest Form. Refer to the following code:
app.MapPost("/upload", (HttpRequest request) =>
{
if (!request.Form.Files.Any())
return Results.BadRequest("At least one fie is need");
//Do something with the file
foreach(var item in request.Form.Files)
{
var file = item;
//insert the file into the Azure storage
}
return Results.Ok();
});
The screenshot as below:
Then, to upload the file to Azure Blob Storage, refer the following tutorial:
Upload images/files to blob azure, via web api ASP.NET framework Web application
Code like this:
CloudStorageAccount storageAccount;
Dictionary<string, object> dict = new Dictionary<string, object>();
string strorageconn = ConfigurationManager.AppSettings.Get("MyBlobStorageConnectionString");
if (CloudStorageAccount.TryParse(strorageconn, out storageAccount))
{
try
{
// Create the CloudBlobClient that represents the
// Blob storage endpoint for the storage account.
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
// Create a container called 'quickstartblobs' and
// append a GUID value to it to make the name unique.
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("images");
await cloudBlobContainer.CreateIfNotExistsAsync();
// Set the permissions so the blobs are public.
BlobContainerPermissions permissions = new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
};
await cloudBlobContainer.SetPermissionsAsync(permissions);
var httpRequest = HttpContext.Current.Request;
foreach (string file in httpRequest.Files)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created);
var postedFile = httpRequest.Files[file];
string imageName = ("images" + serverTime.Year.ToString() + serverTime.Month.ToString() + serverTime.Day.ToString() +
serverTime.Hour.ToString() + serverTime.Minute.ToString() + serverTime.Second.ToString() + serverTime.Millisecond.ToString()
+ postedFile.FileName );
if (postedFile != null && postedFile.ContentLength > 0)
{
int MaxContentLength = 1024 * 1024 * 1; //Size = 1 MB
IList<string> AllowedFileExtensions = new List<string> { ".jpg", ".gif", ".png" };
var ext = postedFile.FileName.Substring(postedFile.FileName.LastIndexOf('.'));
var extension = ext.ToLower();
if (!AllowedFileExtensions.Contains(extension))
{
var message = string.Format("Please Upload image of type .jpg,.gif,.png.");
dict.Add("error", message);
return Request.CreateResponse(HttpStatusCode.BadRequest, dict);
}
else if (postedFile.ContentLength > MaxContentLength)
{
var message = string.Format("Please Upload a file upto 1 mb.");
dict.Add("error", message);
return Request.CreateResponse(HttpStatusCode.BadRequest, dict);
}
else
{
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(imageName);
cloudBlockBlob.Properties.ContentType = postedFile.ContentType;
await cloudBlockBlob.UploadFromStreamAsync(postedFile.InputStream);
}
}
var message1 = string.Format("Image Updated Successfully.");
return Request.CreateErrorResponse(HttpStatusCode.Created, message1);
}
var res3 = string.Format("Please Upload a image.");
dict.Add("error", res3);
return Request.CreateResponse(HttpStatusCode.NotFound, dict);
}
catch (Exception ex)
{
HttpResponseMessage response2 = Request.CreateResponse(HttpStatusCode.BadRequest, ex.InnerException.ToString());
return response2;
}
}
else
{
var res = string.Format("Did not connect successfull.");
dict.Add("error", res);
return Request.CreateResponse(HttpStatusCode.NotFound, dict);
}

Cant play byte array video on apple devices

I am trying to play a video file which gets sent as a byte array to the client.
It works on android and PC but not on apple devices.
I already tried adding the content range header(not quite sure if this is right), but this didn't do the trick either.
uploading/saving file
var file = await RegisterFileAsync(formFile, uploaderId, categories, packages);
try
{
var filePath = FileStorePath + file.Id;
if (formFile.Length > 0)
{
using (var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
{
await formFile.CopyToAsync(stream);
}
}
if (!System.IO.File.Exists(filePath))
{
throw new System.IO.FileNotFoundException($"File not found ({filePath}) trying to register a file in the database.");
}
}
catch
{
await UnregisterFileAsync(file.Id);
}
return file;
Looks like this:
Backend, sending file to the client:
[HttpHead("[controller]/[action]/{id}")]
[HttpGet("[controller]/[action]/{id}"), HttpGet("[controller]/{id}", Order = 1)]
public async Task<IActionResult> Index(Guid? id)
{
if (id == null)
{
return View();
}
var file = await fileService.GetFileById(id.Value, loadContent: true);
if (file.ContentType.Equals("video/mp4"))
{
Response.Headers.Add("Content-Range", "bytes 0-" + (file.Size - 1) + "/" + file.Size);
}
return File(file.Content, file.ContentType);
}
Response Headers
HTML video player

youtube live broadcast lifeCycleStatus stuck on 'liveStarting'

I'm trying to figure out what i'm doing wrong when broadcast to live. I have my apk on my android phone stream to youtube. I have no problem streaming for the first time. But if I stop it for about 2 - 3 minutes, and stream again, the lifeCycleStatus of the boardcast keep stay at "liveStarting" and my video is not visible to audience. If I stop long enough, restart stream, the status will go 'live' in about 10 seconds. I have enableMonitorStream disable, and also try LiveBroadcasts.Transition, but it return error redundantTransition. But the lifeCycleStatus wouldn't turn to 'live'. I also try create a new live broadcast and live stream and change the status to 'live' manually, but both get stuck on 'liveStarting'.
public class YoutubeService {
private WeakReference<Context> context;
private static final String PREF_ACCOUNT_NAME = "youtube_account_name";
private static final String[] SCOPES = {YouTubeScopes.YOUTUBE};
private GoogleAccountCredential mCredential;
private YouTube mService;
public YoutubeService(Context context) {
this.context = new WeakReference<Context>(context);
// create account credential
mCredential = GoogleAccountCredential.usingOAuth2(
context, Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
mCredential.setSelectedAccountName("xxxx#gmail.com");
// create youtube builder
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new YouTube.Builder(
transport, jsonFactory, mCredential)
.setApplicationName("My App Name")
.build();
}
// AsyncTask<Void, Void, Map<String, String>>
private void getRtmpUrl() {
try {
// get livebroadcast list
YouTube.LiveBroadcasts.List liveBroadcastRequest = mService.liveBroadcasts().list("id,snippet,contentDetails,status");
liveBroadcastRequest.setBroadcastType("persistent");
liveBroadcastRequest.setMine(true);
LiveBroadcastListResponse liveBroadcastListResponse = liveBroadcastRequest.execute();
List<LiveBroadcast> liveBroadcastList = liveBroadcastListResponse.getItems();
if (liveBroadcastList != null && liveBroadcastList.size() > 0) {
LiveBroadcast liveBroadcast = liveBroadcastList.get(0);
String streamId = liveBroadcast.getContentDetails().getBoundStreamId();
// get livestream list
YouTube.LiveStreams.List livestreamRequest = mService.liveStreams().list("id,cdn");
livestreamRequest.setId(streamId);
LiveStreamListResponse liveStreamListResponse = livestreamRequest.execute();
List<LiveStream> liveStreamList = liveStreamListResponse.getItems();
if (liveStreamList != null && liveStreamList.size() > 0) {
LiveStream liveStream = liveStreamList.get(0);
String serverUrl = liveStream.getCdn().getIngestionInfo().getIngestionAddress();
String streamName = liveStream.getCdn().getIngestionInfo().getStreamName();
String rtmpUrl = serverUrl + "/" + streamName;
// use this rtmpUrl for streaming
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// call 30 seconds after press start streaming
private void checkStatus() {
try {
// get livebroadcast list
YouTube.LiveBroadcasts.List liveBroadcastRequest = mService.liveBroadcasts().list("id,snippet,contentDetails,status");
liveBroadcastRequest.setBroadcastType("persistent");
liveBroadcastRequest.setMine(true);
LiveBroadcastListResponse liveBroadcastListResponse = liveBroadcastRequest.execute();
List<LiveBroadcast> liveBroadcastList = liveBroadcastListResponse.getItems();
if (liveBroadcastList != null && liveBroadcastList.size() > 0) {
LiveBroadcast liveBroadcast = liveBroadcastList.get(0);
// get lifeCycleStatus
String lifeCycleStatus = liveBroadcast.getStatus().getLifeCycleStatus();
String recordingStatus = liveBroadcast.getStatus().getRecordingStatus();
if (lifeCycleStatus != null && lifeCycleStatus.equalsIgnoreCase("live") && recordingStatus != null && recordingStatus.equalsIgnoreCase("recording")) {
String videoId = liveBroadcast.getId();
// the url to watch is www.youtube.com/watch?v=videoId
// video is visible to audience
} else {
// the status is stuck at 'liveStarting', video is not visible to audience
// "status":{"lifeCycleStatus":"liveStarting","privacyStatus":"public","recordingStatus":"recording"}
// check the status of livestream
String boundStreamId = liveBroadcast.getContentDetails().getBoundStreamId();
YouTube.LiveStreams.List livestreamRequest = mService.liveStreams().list("id,cdn,status");
livestreamRequest.setId(boundStreamId);
LiveStreamListResponse liveStreamListResponse = livestreamRequest.execute();
List<LiveStream> liveStreamList = liveStreamListResponse.getItems();
if (liveStreamList != null && liveStreamList.size() > 0) {
LiveStream liveStream = liveStreamList.get(0);
String streamStatus = liveStream.getStatus().getStreamStatus();
if (streamStatus.equalsIgnoreCase("active")) {
// Log.e(TAG,"need to transite to live, liveBroadcastId = " + liveBroadcast.getId());
YouTube.LiveBroadcasts.Transition liveBroadcastTransitionRequest =
mService.liveBroadcasts().transition("live", liveBroadcast.getId(), "id,status");
LiveBroadcast liveBroadcastTransitionResponse = liveBroadcastTransitionRequest.execute();
// get error here
// error 403 Forbidden
// {
// "code" : 403,
// "errors" : [ {
// "domain" : "youtube.liveBroadcast",
// "message" : "Redundant transition",
// "reason" : "redundantTransition"
// } ],
// "message" : "Redundant transition"
// }
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// also try to create livebroadcast and live stream instead of the default one
private void createLiveBroadcast() {
try {
// step 1 create live broadcast
LiveBroadcastSnippet broadcastSnippet = new LiveBroadcastSnippet();
broadcastSnippet.setTitle("Test live broadcast title");
Date currentTime = Calendar.getInstance().getTime();
broadcastSnippet.setScheduledStartTime(new DateTime(currentTime));
LiveBroadcastStatus status = new LiveBroadcastStatus();
status.setPrivacyStatus("public");
// disable MonitorStreamInfo to change transition from ready to live
// refrence https://stackoverflow.com/questions/35003786/cannot-make-transition-of-my-youtube-broadcast-to-live-using-youtube-api
LiveBroadcastContentDetails contentDetails = new LiveBroadcastContentDetails();
MonitorStreamInfo monitorStream = new MonitorStreamInfo();
monitorStream.setEnableMonitorStream(false);
contentDetails.setMonitorStream(monitorStream);
LiveBroadcast broadcast = new LiveBroadcast();
broadcast.setKind("youtube#liveBroadcast");
broadcast.setSnippet(broadcastSnippet);
broadcast.setStatus(status);
broadcast.setContentDetails(contentDetails);
YouTube.LiveBroadcasts.Insert liveBroadcastInsert =
mService.liveBroadcasts().insert("snippet,contentDetails,status", broadcast);
LiveBroadcast returnedBroadcast = liveBroadcastInsert.execute();
// step 2 create live stream
String streamTitle = "Test Live Stream title";
LiveStreamSnippet streamSnippet = new LiveStreamSnippet();
streamSnippet.setTitle(streamTitle);
CdnSettings cdnSettings = new CdnSettings();
cdnSettings.setFormat("720p");
cdnSettings.setIngestionType("rtmp");
LiveStream stream = new LiveStream();
stream.setKind("youtube#liveStream");
stream.setSnippet(streamSnippet);
stream.setCdn(cdnSettings);
YouTube.LiveStreams.Insert liveStreamInsert =
mService.liveStreams().insert("snippet,cdn", stream);
LiveStream returnedStream = liveStreamInsert.execute();
if (returnedStream != null) {
YouTube.LiveBroadcasts.Bind liveBroadcastBind =
mService.liveBroadcasts().bind(returnedBroadcast.getId(), "id,snippet,contentDetails,status");
liveBroadcastBind.setStreamId(returnedStream.getId());
returnedBroadcast = liveBroadcastBind.execute();
String serverUrl = returnedStream.getCdn().getIngestionInfo().getIngestionAddress();
String streamName = returnedStream.getCdn().getIngestionInfo().getStreamName();
String rtmpUrl = serverUrl + "/" + streamName;
// use this rtmpUrl for streaming
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

PostAsync request with Array parameter on MVC Web API

I have Xamarin application that has POST request with array list of parameter and on my MVC WEB API we used code first Entity framework. Both was separated project solutions (.sln).
On my Xamarin project, I have PostAsync request which supplies List of array values.
using (var client = new HttpClient())
{
Parameter = string.Format("type={0}&param={1}",type, param[]);
var data = JsonConvert.SerializeObject(parameters);
var content = new StringContent(data, Encoding.UTF8, "application/json");
using (var response = await client.PostAsync(url, content))
{
using (var responseContent = response.Content)
{
result = await responseContent.ReadAsStringAsync();
}
}
}
Then In my Web API controller I have same parameter with my client side also.
[System.Web.Http.AcceptVerbs("GET", "POST")]
[System.Web.Http.HttpPost]
[Route("type={type}&param={param}")]
public BasicResponse applog([FromUri] ProfilingType type , List<string> param)
{
if (ModelState.IsValid == false)
{
throw new ModelValidationException("Model state is invalid.");
}
try
{
if(type == ProfilingType.Login)
{
var command = new SendDataProfilingCommand(param);
CommandHandler.Execute(command);
}
else
{
var command = new UpdateDataProfilingCommand(type,param);
CommandHandler.Execute(command);
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return new BasicResponse
{
Status = true,
Message = Ok().ToString()
};
}
Since I'm not with the API, I want to test it first on Postman or even in the URL. but my problem was when i Try to test it using this url below
http://localhost:59828/api/users/applog?type=1&param=[1,Caloocan,Metro Manila,Philippines,0,0]
I received this message : No HTTP resource was found that matches the request URI ......
My Question is, How can I test my Web API with List Parameter on URL or in the Postman ? and What Format I can use when sending a post request into my Xamarin PostAsync request?
You don't need to send as Content.
using (var client = new HttpClient())
{
Parameter = string.Format("type={0}&param={1}",type, param[]);
url = url + "?" + Parameter;
using (var response = await client.PostAsync(url))
{
using (var responseContent = response.Content)
{
result = await responseContent.ReadAsStringAsync();
}
}
}

Google+ unable to insert moment - A Year and 6 Revisions After

NOTE: Using the Sign-in button is NOT an option
A year ago I was having a problem creating a moment. Back then I was using version 1.2 of the Google+ API .Net client. As I described in this post, I had it working although the code failed to insert a moment from time to time. I was hoping that the process is more stable and easier to implement now, and it seems like it as can be seen in the example that you can download here - the current version as of this writing is v1.8. So I created a simple project following the SimpleOAuth2 sample in the download, but implementing Google+. This is the code I came up:
public partial class _Default : System.Web.UI.Page
{
private PlusService service;
// Application logic should manage users authentication.
// This sample works with only one user. You can change
// it by retrieving data from the session.
private const string UserId = "user-id";
protected void Page_Load(object sender, EventArgs e)
{
GoogleAuthorizationCodeFlow flow;
var assembly = Assembly.GetExecutingAssembly();
using (var stream = assembly.GetManifestResourceStream(
"GPlusSample.client_secrets.json"))
{
flow = new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore("GPlusSample.Store"),
ClientSecretsStream = stream,
//
// Tried only this scope but it did not work
//Scopes = new[] { PlusService.Scope.PlusMe }
//
// I tried the following: but did not work either
//Scopes = new[] { PlusService.Scope.PlusMe,
// "https://www.googleapis.com/auth/plus.moments.write" }
//
// I tried this as well and it failed
//Scopes = new[] { PlusService.Scope.PlusLogin }
//
// Maybe this... but still no joy
Scopes = new[] { PlusService.Scope.PlusLogin,
PlusService.Scope.PlusMe }
});
}
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 PlusService(new BaseClientService.Initializer
{
ApplicationName = "Plus API Sample",
HttpClientInitializer = result.Credential
});
}
}
}
/// <summary>Gets the TasksLists of the user.</summary>
public async System.Threading.Tasks.Task InsertMoment()
{
try
{
var me = service.People.Get("me").Execute();
var request = service.Moments.Insert(new Moment()
{
Target = new ItemScope {
Id=Guid.NewGuid().ToString(),
Image="http://www.google.com/s2/static/images/GoogleyEyes.png",
Type="",
Name = "test message",
Description="test",
Text="test message",
},
Type = "http://schemas.google.com/AddActivity",
}, me.Id, MomentsResource.InsertRequest.CollectionEnum.Vault);
var response =await request.ExecuteAsync();
output.Text = "<h1>" + response.Id + "</h1>";
}
catch (Exception ex)
{
var str = ex.ToString();
str = str.Replace(Environment.NewLine, Environment.NewLine + "<br/>");
str = str.Replace(" ", " ");
output.Text = string.Format("<font color=\"red\">{0}</font>", str);
}
}
protected async void createMomentButton_Click(object sender, EventArgs e)
{
await InsertMoment();
}
}
That code always give me a 401 Unauthorized error, even if I have the Google+ API turned on for my project. Here's the actual error I got:
The service plus has thrown an exception: Google.GoogleApiException:
Google.Apis.Requests.RequestError Unauthorized [401] Errors [
Message[Unauthorized] Location[ - ] Reason[unauthorized]
Domain[global] ]
It's interesting to see that the insert moment is failing even though the call to People.Get("me") works - get("me") works with all of the scope combinations I listed above. It's important to note that each time I try a new scope, I first log out of my Google account and delete the access token that is stored in GPlusSample.Store.
EDIT
I tried setting just the Url instead of individual items as suggested by Ian and I got the exact same error.
var request = service.Moments.Insert(new Moment()
{
Target = new ItemScope {
Url = "https://developers.google.com/+/web/snippet/examples/thing"
},
Type = "http://schemas.google.com/AddActivity",
}, me.Id, MomentsResource.InsertRequest.CollectionEnum.Vault);
var response =await request.ExecuteAsync();
https://www.googleapis.com/auth/plus.login is the right scope for writing moments, but you need to have requested the specific app activity types you want to write as well. The parameter for this is request_visible_actions, and it takes a space separated list of arguments of the types (Listed on https://developers.google.com/+/api/moment-types/ - e.g. http://schemas.google.com/AddActivity).
The client library may not have a method for adding request_visible_actions, so you may have to add it on to the auth URL you redirect the user to manually (remember to URLencode the app activity type URLs!)