En esta sección, incorporará Microsoft Graph a la aplicación.In this section you will incorporate Microsoft Graph into the application. Para esta aplicación, usará la biblioteca de cliente de Microsoft Graph para .net para realizar llamadas a Microsoft Graph.For this application, you will use the Microsoft Graph Client Library for .NET to make calls to Microsoft Graph.

Obtener una vista de calendarioGet a calendar view

Una vista de calendario es un conjunto de eventos del calendario del usuario que se producen entre dos puntos de tiempo.A calendar view is a set of events from the user's calendar that occur between two points of time. Lo usará para obtener los eventos del usuario para la semana actual.You'll use this to get the user's events for the current week.

  1. Abra ./Controllers/CalendarController.CS y agregue la siguiente función a la clase CalendarController .Open ./Controllers/CalendarController.cs and add the following function to the CalendarController class.

    private DateTime GetUtcStartOfWeekInTimeZone(DateTime today, string timeZoneId)
    {
        // Time zone returned by Graph could be Windows or IANA style
        // TimeZoneConverter can take either
        TimeZoneInfo userTimeZone = TZConvert.GetTimeZoneInfo(timeZoneId);
    
        // Assumes Sunday as first day of week
        int diff = System.DayOfWeek.Sunday - today.DayOfWeek;
    
        // create date as unspecified kind
        var unspecifiedStart = DateTime.SpecifyKind(today.AddDays(diff), DateTimeKind.Unspecified);
    
        // convert to UTC
        return TimeZoneInfo.ConvertTimeToUtc(unspecifiedStart, userTimeZone);
    }
    
  2. Agregue la siguiente función para controlar las excepciones devueltas desde llamadas de Microsoft Graph.Add the following function to handle exceptions returned from Microsoft Graph calls.

    private async Task HandleGraphException(Exception exception)
    {
        if (exception is MicrosoftIdentityWebChallengeUserException)
        {
            _logger.LogError(exception, "Consent required");
            // This exception indicates consent is required.
            // Return a 403 with "consent_required" in the body
            // to signal to the tab it needs to prompt for consent
            HttpContext.Response.ContentType = "text/plain";
            HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            await HttpContext.Response.WriteAsync("consent_required");
        }
        else if (exception is ServiceException)
        {
            var serviceException = exception as ServiceException;
            _logger.LogError(serviceException, "Graph service error occurred");
            HttpContext.Response.ContentType = "text/plain";
            HttpContext.Response.StatusCode = (int)serviceException.StatusCode;
            await HttpContext.Response.WriteAsync(serviceException.Error.ToString());
        }
        else
        {
            _logger.LogError(exception, "Error occurred");
            HttpContext.Response.ContentType = "text/plain";
            HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            await HttpContext.Response.WriteAsync(exception.ToString());
        }
    }
    
  3. Reemplace la función Get existente por lo siguiente.Replace the existing Get function with the following.

    [HttpGet]
    public async Task<IEnumerable<Event>> Get()
    {
        // This verifies that the access_as_user scope is
        // present in the bearer token, throws if not
        HttpContext.VerifyUserHasAnyAcceptedScope(apiScopes);
    
        // To verify that the identity libraries have authenticated
        // based on the token, log the user's name
        _logger.LogInformation($"Authenticated user: {User.GetDisplayName()}");
    
        try
        {
            // Get the user's mailbox settings
            var me = await _graphClient.Me
                .Request()
                .Select(u => new {
                    u.MailboxSettings
                })
                .GetAsync();
    
            // Get the start and end of week in user's time
            // zone
            var startOfWeek = GetUtcStartOfWeekInTimeZone(
                DateTime.Today, me.MailboxSettings.TimeZone);
            var endOfWeek = startOfWeek.AddDays(7);
    
            // Set the start and end of the view
            var viewOptions = new List<QueryOption>
            {
                new QueryOption("startDateTime", startOfWeek.ToString("o")),
                new QueryOption("endDateTime", endOfWeek.ToString("o"))
            };
    
            // Get the user's calendar view
            var results = await _graphClient.Me
                .CalendarView
                .Request(viewOptions)
                // Send user time zone in request so date/time in
                // response will be in preferred time zone
                .Header("Prefer", $"outlook.timezone=\"{me.MailboxSettings.TimeZone}\"")
                // Get max 50 per request
                .Top(50)
                // Only return fields app will use
                .Select(e => new
                {
                    e.Subject,
                    e.Organizer,
                    e.Start,
                    e.End,
                    e.Location
                })
                // Order results chronologically
                .OrderBy("start/dateTime")
                .GetAsync();
    
            return results.CurrentPage;
        }
        catch (Exception ex)
        {
            await HandleGraphException(ex);
            return null;
        }
    }
    

    Revise los cambios.Review the changes. Esta nueva versión de la función:This new version of the function:

    • Devuelve IEnumerable<Event> en lugar de string .Returns IEnumerable<Event> instead of string.
    • Obtiene la configuración del buzón del usuario mediante Microsoft Graph.Gets the user's mailbox settings using Microsoft Graph.
    • Usa la zona horaria del usuario para calcular el inicio y el final de la semana actual.Uses the user's time zone to calculate the start and end of the current week.
    • Obtiene una vista de calendarioGets a calendar view
      • Usa la .Header() función para incluir un Prefer: outlook.timezone encabezado, lo que hace que los eventos devueltos tengan sus horas de inicio y finalización convertidas en la zona horaria del usuario.Uses the .Header() function to include a Prefer: outlook.timezone header, which causes the returned events to have their start and end times converted to the user's timezone.
      • Usa la .Top() función para solicitar como máximo 50 eventos.Uses the .Top() function to request at most 50 events.
      • Usa la .Select() función para solicitar solo los campos que usa la aplicación.Uses the .Select() function to request just the fields used by the app.
      • Usa la OrderBy() función para ordenar los resultados por la hora de inicio.Uses the OrderBy() function to sort the results by the start time.
  4. Guarde los cambios y reinicie la aplicación.Save your changes and restart the app. Actualice la pestaña en Microsoft Teams.Refresh the tab in Microsoft Teams. La aplicación muestra una lista JSON de los eventos.The app displays a JSON listing of the events.

Mostrar los resultadosDisplay the results

Ahora puede mostrar la lista de eventos de una forma más sencilla de uso.Now you can display the list of events in a more user friendly way.

  1. Abra ./pages/index.cshtml y agregue las siguientes funciones dentro de la <script> etiqueta.Open ./Pages/Index.cshtml and add the following functions inside the <script> tag.

    function renderSubject(subject) {
      if (!subject || subject.length <= 0) {
        subject = '<No subject>';
      }
    
      return $('<div/>', {
          class: 'ms-fontSize-18 ms-fontWeight-bold',
          text: subject
      });
    }
    
    function renderOrganizer(organizer) {
      return $('<div/>', {
        class: 'ms-fontSize-14 ms-fontWeight-semilight',
        text: organizer.emailAddress.name
      }).append($('<i/>', {
        class: 'ms-Icon ms-Icon--PartyLeader',
        style: 'margin-right: 10px;'
      }));
    }
    
    function renderTimeSpan(start, end) {
      return $('<div/>', {
        class: 'ms-fontSize-14 ms-fontWeight-semilight',
        text: `${formatDateTime(start.dateTime)} - ${formatDateTime(end.dateTime)}`
      }).append($('<i/>', {
        class: 'ms-Icon ms-Icon--DateTime2',
        style: 'margin-right: 10px;'
      }));
    }
    
    function formatDateTime(dateTime) {
      const date = new Date(dateTime);
    
      // Format like 10/14/2020 4:00 PM
      let hours = date.getHours();
      const minutes = date.getMinutes();
      const ampm = hours >= 12 ? 'PM' : 'AM';
      hours = hours % 12;
      hours = hours ? hours : 12;
      const minStr = minutes < 10 ? `0${minutes}` : minutes;
    
      return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()} ${hours}:${minStr} ${ampm}`;
    }
    
    function renderLocation(location) {
      if (!location || location.displayName.length <= 0) {
        return null;
      }
    
      return $('<div/>', {
        class: 'ms-fontSize-14 ms-fontWeight-semilight',
        text: location.displayName
      }).append($('<i/>', {
        class: 'ms-Icon ms-Icon--MapPin',
        style: 'margin-right: 10px;'
      }));
    }
    
  2. Reemplace la función renderCalendar existente por lo siguiente.Replace the existing renderCalendar function with the following.

    function renderCalendar(events) {
      $('#tab-container').empty();
    
      // Add title
      $('<div/>', {
        class: 'tab-title ms-fontSize-42',
        text: 'Week at a glance'
      }).appendTo('#tab-container');
    
      // Render each event
      events.map(event => {
        const eventCard = $('<div/>', {
          class: 'event-card ms-depth-4',
        });
    
        eventCard.append(renderSubject(event.subject));
        eventCard.append(renderOrganizer(event.organizer));
        eventCard.append(renderTimeSpan(event.start, event.end));
    
        const location = renderLocation(event.location);
        if (location) {
          eventCard.append(location);
        }
    
        eventCard.appendTo('#tab-container');
      });
    }
    
  3. Guarde los cambios y reinicie la aplicación.Save your changes and restart the app. Actualice la pestaña en Microsoft Teams.Refresh the tab in Microsoft Teams. La aplicación muestra los eventos en el calendario del usuario.The app displays events on the user's calendar.

    Una captura de pantalla de la aplicación que muestra el calendario del usuario