다음을 통해 공유


Trabajando con la API de OneNote

OneNote es nuestro programa ideal para tomar notas, una libreta virtual en la cual podemos escribir, incrustar documentos, tomar apuntes o incluso dibujar.
Esta herramienta tiene una API muy interesante que podemos utilizar en nuestros programas, apps o webs. Con la cual vamos a poder crear secciones, notas o incluso incrustar imágenes o documentos en una libreta de OneNote.

 

image[6][1]

Preparando para el proyecto

En mi caso voy a crear una app de ejemplo para Windows 8 con C#, podrás ver en la documentación cómo se hace en otros ámbitos.
Antes de empezar necesitamos algunas cosas:

 

Iniciando Sesión

Ahora que ya tenemos todo listo podemos empezar con nuestra app.
Lo primero va a ser hacer la parte de login mediante el Live SDK, hemos de tener en cuenta que si el usuario ya inició sesión, esta debería iniciarse sola y si no debería iniciarla y pedir los permisos necesario para OneNote.

Vamos a hacerlo bastante simple todo, primero un botón en MainPage.xaml con un botón asociado a un evento, en este caso uno para Login y otro para Logout.

  1: <Button
  2:     Click="LoginButton_Click">
  3:     Log In
  4: </Button>
  5:  
  6: <Button
  7:     Click="LogoutButton_Click">
  8:     Log Out
  9: </Button>

En MainPage.xaml.cs el método asíncrono que nos hará iniciar sesión al el botón antes creado y el de cerrar sesión.

  1: private async void LoginButton_Click(object sender, RoutedEventArgs e)
  2:     {
  3:         await SignIn();
  4:     }
  5:  
  6:     private async void LogoutButton_Click(object sender, RoutedEventArgs e)
  7:     {
  8:         await SignOut();
  9:     }

Ahora preparamos algunas propiedades que va a necesitar esta clase de ejemplo:

  • SignInName Guardaremos el nombre del usuario
  • IsSignedIn Para guardarnos si ha iniciado sesión
  • AuthClient Una propiedad donde gestionaremos el objeto para manejar las sesiones que se utilizan en este SDK
  1: public string SignInName { get; set; }
  2:         public bool IsSignedIn { get; set; }
  3:         private LiveAuthClient _authClient;
  4:         public LiveAuthClient AuthClient
  5:         {
  6:             get
  7:             {
  8:                 if (_authClient == null)
  9:                 {
  10:                     _authClient = new LiveAuthClient();
  11:                 }
  12:                 return _authClient;
  13:             }
  14:         }public string SignInName { get; set; }
  15:         public bool IsSignedIn { get; set; }
  16:         private LiveAuthClient _authClient;
  17:         public LiveAuthClient AuthClient
  18:         {
  19:             get
  20:             {
  21:                 if (_authClient == null)
  22:                 {
  23:                     _authClient = new LiveAuthClient();
  24:                 }
  25:                 return _authClient;
  26:             }
  27:         }

La última propiedad que necesitamos en este punto es la de permisos que vamos a pedir, en este caso:

  1: private static readonly string[] Scopes = new[] { "wl.signin", "wl.offline_access", "Office.OneNote_Create" };

 

Ahora implementamos el método para iniciar sesión.
Si nunca has iniciado sesión te va a pedir los permisos correspondientes y si ya lo has hecho va a iniciar sesión y actualizar nuestras propiedades de usuario.

  1: public async Task SignIn()
  2: {
  3:     
  4:     LiveLoginResult loginResult;
  5:     try
  6:     {
  7:         loginResult = await AuthClient.InitializeAsync(Scopes);
  8:     }
  9:     catch (Exception ex)
  10:     {
  11:         // App not associated with the store
  12:         throw;
  13:     }
  14:     
  15:     // If is the first time
  16:     if (loginResult.Status != LiveConnectSessionStatus.Connected)
  17:     {
  18:         loginResult = await AuthClient.LoginAsync(Scopes);
  19:     }
  20:     UpdateAuthProperties(loginResult.Status);
  21: }
  22:  
  23: public async Task SignOut()
  24: {
  25:     LiveLoginResult loginResult = await AuthClient.InitializeAsync(Scopes);
  26:  
  27:     // Sign the user out, if they are connected
  28:     if (loginResult.Status != LiveConnectSessionStatus.NotConnected)
  29:     {
  30:         try
  31:         {
  32:             AuthClient.Logout();
  33:         }
  34:         catch (Exception ex)
  35:         {
  36:             // App not associated with the store
  37:             throw;
  38:         }
  39:     }
  40:     UpdateAuthProperties(LiveConnectSessionStatus.NotConnected);
  41: }
  1: public async Task SignIn()
  2:         {
  3:             
  4:             LiveLoginResult loginResult;
  5:             try
  6:             {
  7:                 loginResult = await AuthClient.InitializeAsync(Scopes);
  8:             }
  9:             catch (Exception ex)
  10:             {
  11:                 // App not associated with the store
  12:                 throw;
  13:             }
  14:             
  15:             // If is the first time
  16:             if (loginResult.Status != LiveConnectSessionStatus.Connected)
  17:             {
  18:                 loginResult = await AuthClient.LoginAsync(Scopes);
  19:             }
  20:             UpdateAuthProperties(loginResult.Status);
  21:         }

image

 

Una vez hemos iniciado nuestra sesión actualizamos los datos cómo hemos visto en el código anterior, este es el método que implementamos para ello, además de obtener el nombre del usuario que ha iniciado sesión.

 

 

 

  1: private async void UpdateAuthProperties(LiveConnectSessionStatus loginStatus)
  2: {
  3:     IsSignedIn = loginStatus == LiveConnectSessionStatus.Connected;
  4:     if (IsSignedIn)
  5:     {
  6:         SignInName = await RetrieveName();
  7:         Debug.WriteLine(SignInName);
  8:     }
  9:     else
  10:     {
  11:         SignInName = null;
  12:         Debug.WriteLine("Logout");
  13:     }
  14: }
  15:  
  16: private async Task<string> RetrieveName()
  17: {
  18:     // Create a client session to get the profile data.
  19:     var lcConnect = new LiveConnectClient(AuthClient.Session);
  20:  
  21:     // Get the profile info of the user.
  22:     LiveOperationResult operationResult = await lcConnect.GetAsync("me");
  23:     dynamic result = operationResult.Result;
  24:     if (result != null)
  25:     {
  26:         return (string)result.name;
  27:     }
  28:     else
  29:     {
  30:         // Handle the case where the user name was not returned. 
  31:         throw new InvalidOperationException();
  32:     }
  33: }

Nos falta implementar el cierre de sesión, un método parecido al de inicio.

 

  1:  
  2: public async Task SignOut()
  3: {
  4:     LiveLoginResult loginResult = await AuthClient.InitializeAsync(Scopes);
  5:  
  6:     // Sign the user out, if they are connected
  7:     if (loginResult.Status != LiveConnectSessionStatus.NotConnected)
  8:     {
  9:         try
  10:         {
  11:             AuthClient.Logout();
  12:         }
  13:         catch (Exception ex)
  14:         {
  15:             // App not associated with the store
  16:             throw;
  17:         }
  18:     }
  19:     UpdateAuthProperties(LiveConnectSessionStatus.NotConnected);
  20: }

Hasta ahora esto es lo que tenemos implementado, nos puede servir para cualquier app en la que necesitemos implementar un inicio de sesión con LiveSDK

 

 

 

  1: public string SignInName { get; set; }
  2: public bool IsSignedIn { get; set; }
  3: private LiveAuthClient _authClient;
  4: public LiveAuthClient AuthClient
  5: {
  6:     get
  7:     {
  8:         if (_authClient == null)
  9:         {
  10:             _authClient = new LiveAuthClient();
  11:         }
  12:         return _authClient;
  13:     }
  14: }
  15:  
  16: // Permisos para el Login
  17: private static readonly string[] Scopes = new[] { "wl.signin", "wl.offline_access", "Office.OneNote_Create" };
  18: public MainPage()
  19: {
  20:     this.InitializeComponent();
  21: }
  22:  
  23: private async void LoginButton_Click(object sender, RoutedEventArgs e)
  24: {
  25:     await SignIn();
  26: }
  27:  
  28: private async void LogoutButton_Click(object sender, RoutedEventArgs e)
  29: {
  30:     await SignOut();
  31: }
  32:  
  33: public async Task SignIn()
  34: {
  35:     
  36:     LiveLoginResult loginResult;
  37:     try
  38:     {
  39:         loginResult = await AuthClient.InitializeAsync(Scopes);
  40:     }
  41:     catch (Exception ex)
  42:     {
  43:         // App not associated with the store
  44:         throw;
  45:     }
  46:     
  47:     // If is the first time
  48:     if (loginResult.Status != LiveConnectSessionStatus.Connected)
  49:     {
  50:         loginResult = await AuthClient.LoginAsync(Scopes);
  51:     }
  52:     UpdateAuthProperties(loginResult.Status);
  53: }
  54:  
  55: public async Task SignOut()
  56: {
  57:     LiveLoginResult loginResult = await AuthClient.InitializeAsync(Scopes);
  58:  
  59:     // Sign the user out, if they are connected
  60:     if (loginResult.Status != LiveConnectSessionStatus.NotConnected)
  61:     {
  62:         try
  63:         {
  64:             AuthClient.Logout();
  65:         }
  66:         catch (Exception ex)
  67:         {
  68:             // App not associated with the store
  69:             throw;
  70:         }
  71:     }
  72:     UpdateAuthProperties(LiveConnectSessionStatus.NotConnected);
  73: }
  74:  
  75: private async void UpdateAuthProperties(LiveConnectSessionStatus loginStatus)
  76: {
  77:     IsSignedIn = loginStatus == LiveConnectSessionStatus.Connected;
  78:     if (IsSignedIn)
  79:     {
  80:         SignInName = await RetrieveName();
  81:         Debug.WriteLine(SignInName);
  82:     }
  83:     else
  84:     {
  85:         SignInName = null;
  86:         Debug.WriteLine("Logout");
  87:     }
  88: }
  89:  
  90: private async Task<string> RetrieveName()
  91: {
  92:     // Create a client session to get the profile data.
  93:     var lcConnect = new LiveConnectClient(AuthClient.Session);
  94:  
  95:     // Get the profile info of the user.
  96:     LiveOperationResult operationResult = await lcConnect.GetAsync("me");
  97:     dynamic result = operationResult.Result;
  98:     if (result != null)
  99:     {
  100:         return (string)result.name;
  101:     }
  102:     else
  103:     {
  104:         // Handle the case where the user name was not returned. 
  105:         throw new InvalidOperationException();
  106:     }
  107: }

Gestionando las secciones

En OneNote, nuestras secciones son cómo las categorias que tiene el bloc de notas, dentro de cada sección vamos a tener varios artículos o páginas.
La idea es que cuando creamos una nueva página le asignamos la categoria deseada y si no existe simplemente se va a crear.
Puede ser que por alguna razón queramos crear expresamente una sección o categoría con lo que podemos crear una página en blanco en esa sección.

Primero de todo añadimos un TextBox donde pondremos el nombre de la sección y un botón para crearla.

  1: <StackPanel>
  2:     <TextBox Name="NotebookBox"/>
  3:     <Button
  4:         Click="CreateNotebook_Click">
  5:         Create Notebook
  6:     </Button>
  7: </StackPanel>

 

Una vez tenemos la parte de la UI volvemos a la parte de C# e implementamos el método que captura el evento de click.
Básicamente hace una llamada a la api de OneNote diciendo que hemos de crear una nueva página en blanco para la sección con título el que hemos puesto en el input.

  1: private async void CreateNotebook_Click(object sender, RoutedEventArgs e)
  2: {
  3:     var client = new HttpClient();
  4:  
  5:     // Note: API only supports JSON return type.
  6:     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  7:  
  8:     // This allows you to see what happens when an unauthenticated call is made.
  9:     if (IsSignedIn)
  10:     {
  11:         client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _authClient.Session.AccessToken);
  12:     }
  13:  
  14:     string date = DateTime.Now.ToString("o");
  15:     string simpleHtml = "<html>" +
  16:                         "<head>" +
  17:                         "<title></title>" +
  18:                         "<meta name=\"created\" content=\"" + date + "\" />" +
  19:                         "</head>" +
  20:                         "<body>" +
  21:                         "</body>" +
  22:                         "</html>";
  23:  
  24:     var createMessage = new HttpRequestMessage(HttpMethod.Post, new System.Uri(PagesEndPoint + "/?sectionName=" + NotebookBox.Text))
  25:     {
  26:         Content = new StringContent(simpleHtml, System.Text.Encoding.UTF8, "text/html")
  27:     };
  28:  
  29:     HttpResponseMessage response = await client.SendAsync(createMessage);
  30: }

 

Ejecutamos para ver el resultado:

- Primero pulsamos en Login

- Escribímos un nomre en el TextBox

- Pulsamos en el botón

- Abrimos Onenote y en unos segundos tendremos la nueva sección sincronizada

De la variable response podemos sacar varios datos interesantes:
- response.StatusCode => Si se ha creado correctamente o no.

- response.Headers.Date => La fecha de creación de esta página.

Además podemos obtener el enlace para abrir esta sección en tu OneNote local o desde la web, para ello tenemos que trabajar con response en un método cómo el siguiente, que nos ayude a leer la respuesta correctamente.

  1: private async Task TranslateResponse(HttpResponseMessage response)
  2: {
  3:     dynamic responseObject = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
  4:     var OneNoteClientUrl = responseObject.links.oneNoteClientUrl.href;
  5:     var OneNoteWebUrl = responseObject.links.oneNoteWebUrl.href;
  6: }

image

Añadiendo páginas

 

 

 

 

 

Con lo que hemos visto hasta ahora deberíamos ser capaces de crear una página, recuerda que para crear una sección básicamente hemos creado una página en blanco y si esa sección no existe la crea.
Nos faltaría por terminar de ver la variable que hemos nombrado cómo simpleHtml en la que en este nuevo método vamos a poner algo más de contexto de ejemplo.

  1: string simpleHtml = @"<html>" +
  2: "<head>" +
  3: "<title>A page created with an image from a URL on it</title>" +
  4: "<meta name=\"created\" content=\"" + date + "\" />" +
  5: "</head>" +
  6: "<body>" +
  7: "<p>This is a page with an image of an html page rendered from a URL on it.</p>" +
  8: "<img data-render-src=\"https://www.onenote.com\" alt=\"An important web page\"/>" +
  9: "</body>" +
  10: "</html>";

Correcto, es html normal y corriente, finalmente nuestro método quedaría así:

  1: private async void CreateNotebook_Click(object sender, RoutedEventArgs e)
  2: {
  3:    var client = new HttpClient();
  4:  
  5:    // Note: API only supports JSON return type.
  6:    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  7:  
  8:    // This allows you to see what happens when an unauthenticated call is made.
  9:    if (IsSignedIn)
  10:    {
  11:        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _authClient.Session.AccessToken);
  12:    }
  13:  
  14:    string date = DateTime.Now.ToString("o");
  15:    string simpleHtml = @"<html>" +
  16:                        "<head>" +
  17:                        "<title>A page created with an image from a URL on it</title>" +
  18:                        "<meta name=\"created\" content=\"" + date + "\" />" +
  19:                        "</head>" +
  20:                        "<body>" +
  21:                        "<p>This is a page with an image of an html page rendered from a URL on it.</p>" +
  22:                        "<img data-render-src=\"https://www.onenote.com\" alt=\"An important web page\"/>" +
  23:                        "</body>" +
  24:                        "</html>";
  25:  
  26:    var createMessage = new HttpRequestMessage(HttpMethod.Post, new System.Uri(PagesEndPoint + "/?sectionName=" + NotebookBox.Text))
  27:    {
  28:        Content = new StringContent(simpleHtml, System.Text.Encoding.UTF8, "text/html")
  29:    };
  30:  
  31:    HttpResponseMessage response = await client.SendAsync(createMessage);
  32:    await TranslateResponse(response);
  33: }
  34:  
  35: private async Task TranslateResponse(HttpResponseMessage response)
  36: {
  37:    dynamic responseObject = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
  38:    var OneNoteClientUrl = responseObject.links.oneNoteClientUrl.href;
  39:    var OneNoteWebUrl = responseObject.links.oneNoteWebUrl.href;
  40: }

 

Y al probarlo..

imageimage

_____________________________

Quique Fernández

Technical Evangelist Intern

@CKGrafico