Why does OneNote API pages request return empty page list? - onenote

Few days ago our applications (iOS, Android and Windows) stopped getting the list of Pages from Microsoft OneNote via OneNote API request https://www.onenote.com/api/v1.0/me/notes/pages. Request returns HTTP OK and empty content.
Source code Windows UWP appliaction C#-XAML (from Microsoft OneNote API example https://github.com/OneNoteDev/OneNoteAPISampleWinUniversal)
public static string GET_PAGES_REQEST = APIENDPOINT + "sections/{0}/pages";
public const string APIENDPOINT = "https://www.onenote.com/api/v1.0/me/notes/";
public const string AUTHMETHOD = "Bearer";
public const string APPJSON = "application/json";
/// <summary>
/// Get meta data for ALL pages under a given section
/// </summary>
/// <param name="sectionId">Id of the section for which the page are returned</param>
/// <param name="token">Authentication token</param>
/// <param name="isEncryptedOnly">View encrypted only notes</param>
/// <remarks> The sectionId can be fetched by querying the user's sections (e.g. GET https://www.onenote.com/api/v1.0/sections ).
/// NOTE: Using this approach, you can still query pages with ALL the different params shown in examples above.
/// </remarks>
/// <returns>The converted HTTP response message</returns>
public static async Task<List<PageApiResponse>> GetListAsync(string sectionId, string token, bool isEncryptedOnly)
{
var client = new HttpClient();
// Note: API only supports JSON response.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Common.APPJSON));
//client.DefaultRequestHeaders.Add("FavorDataRecency", "true");
// Not adding the Authentication header would produce an unauthorized call and the API will return a 401
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue
(
Common.AUTHMETHOD, token
);
// Prepare an HTTP GET request to the Pages endpoint
var getMessage = new HttpRequestMessage
(
HttpMethod.Get,
isEncryptedOnly ?
String.Format(Common.GET_PAGES_ENCRYPTED_REQEST, sectionId) :
String.Format(Common.GET_PAGES_REQEST, sectionId)
);
HttpResponseMessage response = await client.SendAsync(getMessage);
string body = await response.Content.ReadAsStringAsync();
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(Errors.TranslateError(response));
var content = JObject.Parse(body);
return JsonConvert.DeserializeObject<List<PageApiResponse>>(content["value"].ToString());
}
sectionId and token is correct. isEncryptedOnly = false;
Notebooks and Sections work fine. Anybody can help me?

Related

.Net Core TestClient cannot post with parameters

I am creating Web API integration test with MSTest Test Server. I can request data. However when I post with data, request routed to Test Server without parameters. Below is my codes, where I am wrong?
/// <summary>
///
/// </summary>
/// <returns></returns>
protected async Task TestDataInitializeAsync()
{
_factory = new WebApplicationFactory<MyWebApi.Startup>();
_client = _factory.CreateClient();
_client.DefaultRequestHeaders.Clear();
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username", "userABC"),
new KeyValuePair<string, string>("password","password123")
});
var response = await _client.PostAsync("/account/login", content);
}
Here is my Controller method:
/// <summary>
/// Account controller ASP.NET identity authentication
/// </summary>
[Produces("application/json")]
[Route("[controller]")]
[ApiController]
[Authorize]
public class AccountController : ControllerBase
{
[HttpPost]
[AllowAnonymous]
[Route("login")]
public async Task<object> Login(string userName, string password)
{
try
{
var result = await _signInManager.PasswordSignInAsync(userName, password, false, false);
if (result.Succeeded)
{
var appUser = _userManager.Users.SingleOrDefault(r => r.UserName == userName);
return GenerateJwtToken(userName, appUser);
}
else
{
return BadRequest(new { message = "No user found! Please check user name and password." });
}
}
catch (Exception ex)
{
return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError, ex.Message);
}
}
}
}
Parameters, username and password always null.
You should edit your controller's action to get post parameters from your request's body using FromBody :
[HttpPost]
[AllowAnonymous]
[Route("login")]
public async Task<object> Login([FromBody]LoginVm model)
{
...
}
With the LoginVm class containing Username and Password as string properties.
Hope it helps.
I know the reason after read ASP.NET Core 2.2 Microsoft Document carefully. The key point is [ApiController] attribute. It does not related with TestClient.
In .NET Core 2.2, if you put [ApiController] attribute in Class level or Assembly level, .NET Core framework will do parameter binding automatically. We no need to define as [FromBody] in front of the object parameters for complex type. However, for simple type such as int, string, bool, we need to put [FromBody], [FromForm], [FromQuery], [FromHeader], [FromRoute], [FromServices], accordingly.
In my case, I just put [FromFrom] attributes in front of two simple type parameters as below and problem was solved.
<summary>
/// To log-in to the system by using userName and password.
/// If authentication is successed, bearer token will response from server.
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns>Bearer Token</returns>
/// <remarks>
/// </remarks>
[HttpPost]
[AllowAnonymous]
[Route("login")]
public async Task<object> Login([FromForm] string userName, [FromForm] string password)
{
try
{
var result = await _signInManager.PasswordSignInAsync(userName, password, false, false);
if (result.Succeeded)
{
var appUser = _userManager.Users.SingleOrDefault(r => r.UserName == userName);
return GenerateJwtToken(userName, appUser);
}
else
{
return BadRequest(new { message = "No user found! Please check user name and password." });
}
}
catch (Exception ex)
{
return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError, ex.Message);
}
}

Microsoft Vision API unable to process OCR

I am using the project from https://github.com/microsoft/cognitive-vision-windows, I am able to upload image but the OCR is unable to be processed. It just stays on "Performing OCR..." Same for other functions except "Recognize Handwriting Text"
//
// Perform OCR on the given url
//
Log("Calling VisionServiceClient.RecognizeTextAsync()...");
OcrResults ocrResult = await VisionServiceClient.RecognizeTextAsync(imageUrl, language);
return ocrResult;
// -----------------------------------------------------------------------
// KEY SAMPLE CODE ENDS HERE
// -----------------------------------------------------------------------
}
/// <summary>
/// Perform the work for this scenario
/// </summary>
/// <param name="imageUri">The URI of the image to run against the scenario</param>
/// <param name="upload">Upload the image to Project Oxford if [true]; submit the Uri as a remote url if [false];</param>
/// <returns></returns>
protected override async Task DoWork(Uri imageUri, bool upload)
{
_status.Text = "Performing OCR...";
string languageCode = (languageComboBox.SelectedItem as RecognizeLanguage).ShortCode;
//
// Either upload an image, or supply a url
//
OcrResults ocrResult;
if (upload)
{
ocrResult = await UploadAndRecognizeImage(imageUri.LocalPath, languageCode);
}
else
{
ocrResult = await RecognizeUrl(imageUri.AbsoluteUri, languageCode);
}
_status.Text = "OCR Done";
//
// Log analysis result in the log window
//
Log("");
Log("OCR Result:");
LogOcrResults(ocrResult);
}

System.web name space does not exist error

I am trying to use Gmail API for windows phone 8.1 app.This is the code which I got from https://developers.google.com/gmail/api/quickstart/quickstart-cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Compilation;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Routing;
using System.Web.SessionState;
using Newtonsoft.Json;
// TODO(class) Reorder, this gets messy with alt+shift+F10
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util;
using Google.Apis.Gmail;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Oauth2;
using Google.Apis.Oauth2.v2;
using Google.Apis.Oauth2.v2.Data;
using Google.Apis.Plus.v1;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Auth.OAuth2.Flows;
using System.Threading;
namespace GmailQuickstart
{
/// <summary>
/// This is a minimal implementation of GMail demonstrating:
/// - Using the Google+ Sign-In button to get an OAuth 2.0 refresh token.
/// - Exchanging the refresh token for an access token.
/// - Making GMail API requests with the access token, including
/// getting a list GMail threads.
/// - Disconnecting the app from the user's Google account and revoking
/// tokens.
/// </summary>
/// #author class#google.com (Gus Class)
public class Signin : IHttpHandler, IRequiresSessionState, IRouteHandler
{
// These come from the APIs console:
// https://code.google.com/apis/console
public static ClientSecrets secrets = new ClientSecrets()
{
ClientId = "YOUR_CLIENT_ID",
ClientSecret = "YOUR_CLIENT_SECRET"
};
// Configuration that you probably don't need to change.
static public string APP_NAME = "GMail .NET Quickstart";
// Stores token response info such as the access token and refresh token.
private TokenResponse token;
// Used to peform API calls against Google APIs.
private PlusService ps = null;
private GmailService gs = null;
/// <summary>Processes the request based on the path.</summary>
/// <param name="context">Contains the request and response.</param>
public void ProcessRequest(HttpContext context)
{
// Redirect base path to signin.
if (context.Request.Path.EndsWith("/"))
{
context.Response.RedirectPermanent("signin.ashx");
}
// This is reached when the root document is passed. Return HTML
// using index.html as a template.
if (context.Request.Path.EndsWith("/signin.ashx"))
{
String state = (String)context.Session["state"];
// Store a random string in the session for verifying
// the responses in our OAuth2 flow.
if (state == null)
{
Random random = new Random((int)DateTime.Now.Ticks);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 13; i++)
{
builder.Append(Convert.ToChar(
Convert.ToInt32(Math.Floor(
26 * random.NextDouble() + 65))));
}
state = builder.ToString();
context.Session["state"] = state;
}
// Render the templated HTML.
String templatedHTML = File.ReadAllText(
context.Server.MapPath("index.html"));
templatedHTML = Regex.Replace(templatedHTML,
"[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}", APP_NAME);
templatedHTML = Regex.Replace(templatedHTML,
"[{]{2}\\s*CLIENT_ID\\s*[}]{2}", secrets.ClientId);
templatedHTML = Regex.Replace(templatedHTML,
"[{]{2}\\s*STATE\\s*[}]{2}", state);
context.Response.ContentType = "text/html";
context.Response.Write(templatedHTML);
return;
}
if (context.Session["authState"] == null)
{
// The connect action exchanges a code from the sign-in button,
// verifies it, and creates OAuth2 credentials.
if (context.Request.Path.Contains("/connect"))
{
// Get the code from the request POST body.
StreamReader sr = new StreamReader(
context.Request.InputStream);
string code = sr.ReadToEnd();
string state = context.Request["state"];
// Test that the request state matches the session state.
if (!state.Equals(context.Session["state"]))
{
context.Response.StatusCode = 401;
return;
}
// Use the code exchange flow to get an access and refresh token.
IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets,
Scopes = new string[] { PlusService.Scope.PlusLogin, GmailService.Scope.GmailReadonly}
});
token = flow.ExchangeCodeForTokenAsync("", code, "postmessage",
CancellationToken.None).Result;
// Create an authorization state from the returned token.
context.Session["authState"] = token;
// Get tokeninfo for the access token if you want to verify.
Oauth2Service service = new Oauth2Service(
new Google.Apis.Services.BaseClientService.Initializer());
Oauth2Service.TokeninfoRequest request = service.Tokeninfo();
request.AccessToken = token.AccessToken;
Tokeninfo info = request.Execute();
string gplus_id = info.UserId;
}
else
{
// No cached state and we are not connecting.
context.Response.StatusCode = 400;
return;
}
}
else if (context.Request.Path.Contains("/connect"))
{
// The user is already connected and credentials are cached.
context.Response.ContentType = "application/json";
context.Response.StatusCode = 200;
context.Response.Write(JsonConvert.SerializeObject("Current user is already connected."));
return;
}
else
{
// Register the authenticator and construct the Plus service
// for performing API calls on behalf of the user.
token = (TokenResponse)context.Session["authState"];
IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets,
Scopes = new string[] { PlusService.Scope.PlusLogin, GmailService.Scope.GmailReadonly }
});
UserCredential credential = new UserCredential(flow, "me", token);
bool success = credential.RefreshTokenAsync(CancellationToken.None).Result;
token = credential.Token;
ps = new PlusService(
new Google.Apis.Services.BaseClientService.Initializer()
{
ApplicationName = ".NET Quickstart",
HttpClientInitializer = credential
});
gs = new GmailService(
new Google.Apis.Services.BaseClientService.Initializer()
{
ApplicationName = ".NET Quickstart",
HttpClientInitializer = credential
});
}
// Perform an authenticated API request to retrieve the list of
// people that the user has made visible to the app.
if (context.Request.Path.Contains("/mail"))
{
// List the GMail threads for the current user.
IList<Google.Apis.Gmail.v1.Data.Thread> threadFeed =
gs.Users.Threads.List("me").Execute().Threads;
string jsonContent =
Newtonsoft.Json.JsonConvert.SerializeObject(threadFeed);
context.Response.ContentType = "application/json";
context.Response.Write(jsonContent);
return;
}
// Disconnect the user from the application by revoking the tokens
// and removing all locally stored data associated with the user.
if (context.Request.Path.Contains("/disconnect"))
{
// Perform a get request to the token endpoint to revoke the
// refresh token.
token = (TokenResponse)context.Session["authState"];
string tokenToRevoke = (token.RefreshToken != null) ?
token.RefreshToken : token.AccessToken;
WebRequest request = WebRequest.Create(
"https://accounts.google.com/o/oauth2/revoke?token=" +
token);
WebResponse response = request.GetResponse();
// Remove the cached credentials.
context.Session["authState"] = null;
// You could reset the state in the session but you must also
// reset the state on the client.
// context.Session["state"] = null;
context.Response.Write(
response.GetResponseStream().ToString().ToCharArray());
return;
}
}
/// <summary>
/// Implements IRouteHandler interface for mapping routes to this
/// IHttpHandler.
/// </summary>
/// <param name="requestContext">Information about the request.
/// </param>
/// <returns></returns>
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
var page = BuildManager.CreateInstanceFromVirtualPath
("~/signin.ashx", typeof(IHttpHandler)) as IHttpHandler;
return page;
}
public bool IsReusable { get { return false; } }
}
}
So I keep getting this error System.web,System.Web.Compilation namespaces are not available.So What can I do to fix this?
The error is correct. System.Web is not available to Windows Phone apps (either Silverlight or Runtime). If the Gmail API depends on it then it is probably designed for the full .Net Framework and not for Windows Phone. Instead you'll need to connect directly to the Gmail web API. It looks like google has docs for it at https://developers.google.com/gmail/api/v1/reference/
See .NET API for Windows Phone for .Net classes available in WP8 Silverlight apps.

Store class instance - Windows store application

I'm a bit new to programing a windows store app.So the question is how can I save an instance of a class in to an xml or binary file.I tried some code but it isn't working.
Hope that some one can steer me in the right direction .
You can serialize your instance by using this code
/// <summary>
/// Deserializes the XML.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xml">The XML.</param>
/// <returns>The instance</returns>
public static T DeserializeXml<T>(this String xml)
{
var bytes = Encoding.UTF8.GetBytes(xml);
using (var stream = new MemoryStream(bytes))
{
var serializer = new DataContractSerializer(typeof(T));
return (T)serializer.ReadObject(stream);
}
}
/// <summary>
/// Serializes the specified instance.
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>Xml</returns>
public static String SerializeXml(this Object instance)
{
using (var stream = new MemoryStream())
{
var serializer = new DataContractSerializer(instance.GetType());
serializer.WriteObject(stream, instance);
stream.Position = 0;
using (var reader = new StreamReader(stream))
{
var result = "<?xml version='1.0' encoding='UTF-8' ?>";
result += reader.ReadToEnd();
return result;
}
}
}
Next step is to save the serialized instance text to a file.
var filename = "instance.txt";
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
var content = yourInstance.SerializeXml();
await FileIO.WriteTextAsync(file, content, Windows.Storage.Streams.UnicodeEncoding.Utf8);
Now there should be a file in your AppPackage-Local-Folder called instance.txt which contains the current instance serialized to xml.
You can use Windows.Storage to store any file, the usage is like IO operation. MSDN
IsolatedStorage is similar to this for Windows Phone apps.

Create empty file using Document List API 3.0

I am developing a feature which need to create a new empty file(not document) to Google drive, now I am using document list API 3.0 and I am referring to the document: https://developers.google.com/google-apps/documents-list/#uploading_a_new_document_or_file_with_both_metadata_and_content.
I will upload a zero byte file to the Google drive to generate the empty file.
Now I have a problem during request step 1 and request step 2. After the first Post[resumable-create-media link] request I successfully got the upload location. Then when I request put method to the location, I got a 404 not found error. All of the requests have "GData-Version: 3.0" and "Authorization: accessToken" headers.
I searched a lot from the forum and figured out how to create empty document but could not figure out how to create empty file. Here is my code, could anybody help to see which part is wrong? Thanks in advance.
private final static String PARAM_CONTENT_TYPE = "Content-Type";
private final static String PARAM_UPLOAD_LENGTH = "X-Upload-Content-Length";
private final static String PARAM_UPLOAD_TYPE = "X-Upload-Content-Type";
private final static String CONTENT_TYPE_XML = "application/atom+xml";
private final static String URI_RESUMABLE_RESOURCE = "https://docs.google.com/feeds/upload/create-session/default/private/full";
private final static String ENTITY_NEW_FILE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" "
+ "xmlns:docs=\"http://schemas.google.com/docs/2007\"><title>{0}</title></entry>";
#Override
public boolean createNewFile() throws IOException {
String uri = null;
if (ROOT.equals(parentResourceId))
uri = URI_RESUMABLE_RESOURCE;
else
uri = URI_RESUMABLE_RESOURCE + "/%3A" + parentResourceId + "/contents";
try {
StringEntity entity = new StringEntity(MessageFormat.format(ENTITY_NEW_FILE, getName()), Constants.ENCODING);
Map<String, String> headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, CONTENT_TYPE_XML);
headers.put(PARAM_UPLOAD_LENGTH, "0");
headers.put(PARAM_UPLOAD_TYPE, "text/plain");
Map<String, String> params = new HashMap<String, String>();
params.put("convert", "false");
HttpResponse response = helper.execMethodAsResponse(uri, new PostMethod(entity), headers, params);
String location = null;
if ((location = response.getFirstHeader("Location").getValue()) != null) {
headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, "text/plain");
headers.put("Content-Range", "bytes 0-0/0");
//FIXME: Problem occurs here, this put invocation will return 404 not found error.
JsonObject obj = helper.execMethodAsJson(location, new PutMethod(new ByteArrayEntity(new byte[0])), headers, null);
if (obj != null) {
decorateFile(this, obj.get("entry").getAsJsonObject());
return true;
}
}
} catch (UnsupportedEncodingException e) {
}
return false;
}
The easiest way to create an empty file on Google Drive is to use the Google Drive API v2 and send a service.files.insert(File content) request.
You can use the Java sample from the Reference Guide and edit it to not include a MediaContent: https://developers.google.com/drive/v2/reference/files/insert
I have figured out the problem, according to this link: Google Documents List API file upload 400 response
The second put request does not need any additional headers such as "GData-Version: 3.0" and "Authorization: Bearer ****", etc. The only thing need to do is new a put request with the location URI, then it will return response with 201 status code.
Thanks all.