In this lab, you will use the Microsoft Graph SDK to work with Office 365 calendars as part of an ASP.NET MVC5 application.
- You must have an Office 365 tenant and Microsoft Azure subscription to complete this lab. If you do not have one, the lab for O3651-7 Setting up your Developer environment in Office 365 shows you how to obtain a trial.
- You must have Visual Studio 2015.
- Using the browser, navigate to https://outlook.office365.com and log into your Office 365 mailbox.
- Click the waffle icon in the top-left corner to open the App Launcher and click the Calendar tile.
- Add some calendar items to your calendar if you don't have any in your mailbox.
- Once you have verified that you have a set of calendar events for testing, you can move on to the next exercise.
In this exercise, you will create the ASP.NET MVC5 application and register it with Azure active Directory.
- Launch Visual Studio 2015 as administrator.
- In Visual Studio, click File/New/Project.
- In the New Project dialog
- Select Templates/Visual C#/Web.
- Select ASP.NET Web Application.
![Screenshot of the previous step](Images/01.png)
- Give the project the name Office365Calendar and Click OK.
- In the New ASP.NET Project dialog
- Click MVC.
- Click Change Authentication.
- Select Work And School Accounts.
- Select Cloud - Single Organization
- Input Domain of your O365 tenancy
- Check Read directory data under Directory Access Permissions
- Click OK.
- Uncheck Host in the cloud
- Click OK.
![Screenshot of the previous step](Images/03.png)
![Screenshot of the previous step](Images/02.png)
- Ensure the web project uses SSL by default:
- In the Solution Explorer tool window, select the project and look at the Properties tool window.
- Ensure SSL Enabled is set to TRUE.
- Copy the SSL URL property to the clipboard for use in the next step.
![Screenshot of the previous step](Images/SslEnabled.png)
> It is important to do this now because in the next step when you create the application in Azure AD, you want the reply URL to use HTTPS. If you did not do this now, you would have to manually make the changes the Visual Studio wizard is going to do for you in creating the app.
- Configure the project always goes to the homepage of the web application when debugging:
- In the Solution Explorer tool window, right-click the project and select Properties.
- Select the Web tab in the left margin.
- Find the section Start Action.
- Click the radio button Start URL and enter the SSL URL of the web project that you copied from the previous step.
![Screenshot of the previous step](Images/StartUrl.png)
- At this point you can test the authentication flow for your application.
- In Visual Studio, press F5. The browser will automatically launch taking you to the HTTPS start page for the web application.
Note: If you receive an error that indicates ASP.NET could not connect to the SQL database, please see the SQL Server Database Connection Error Resolution document to quickly resolve the issue.
- To sign in, click the Sign In link in the upper-right corner.
- Login using your Organizational Account.
- Upon a successful login, since this will be the first time you have logged into this app, Azure AD will present you with the common consent dialog that looks similar to the following image:
![Screenshot of the previous step](Images/ConsentDialog.png)
- Click Accept to approve the app's permission request on your data in Office 365.
- You will then be redirected back to your web application. However notice in the upper right corner, it now shows your email address & the Sign Out link.
Congratulations... at this point your app is configured with Azure AD and leverages OpenID Connect and OWIN to facilitate the authentication process!
In this exercise you will take the ASP.NET MVC web application you created in the previous exercise and configure it to use Azure AD & OpenID Connect for user & app authentication. You will do this by utilizing the OWIN framework. Once authenticated, you can use the access token returned by Azure AD to access the Microsoft Graph.
-
Grant App Necessary Permissions.
-
Browse to the Azure Management Portal and sign in with your Organizational Account.
-
In the left-hand navigation, click Active Directory.
-
Select the directory you share with your Office 365 subscription.
-
Select the application you created for this lab.
-
Open Configure tab
-
Scroll down to the permissions to other applications section.
-
Click the Add Application button.
-
In the Permissions to other applications dialog, click the PLUS icon next to the Microsoft Graph option.
-
Click the CHECK icon in the lower right corner.
-
For the new Microsoft Graph application permission entry, select the Delegated Permissions dropdown on the same line and then select the following permissions: * Have full access to user calendars
-
Click the Save button at the bottom of the page.
-
Add a helper class that will be used to harvest settings out of the
web.config
and create the necessary strings that will be used for authentication: -
Right-click the project and select Add/New Folder. Give the folder the name Utils.
-
Locate the [\\O3653-13 Deep Dive into Office 365 with the Microsoft Graph API for Calendar\Lab Files](./Lab Files) folder provided with this lab and find the [
SettingsHelper.cs
](./Lab Files/SettingsHelper.cs) file . Drag the [SettingsHelper.cs
](./Lab Files/SettingsHelper.cs) file to the Utils folder in the project. -
Update _Layout file to add Events link:
- Open the _Layout.cshtml file found in the Views/Shared folder.
- Locate the part of the file that includes a few links at the top of the page... it should look similar to the following code:
````asp <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> <li>@Html.ActionLink("Contact", "Contact", "Home")</li> </ul> @Html.Partial("_LoginPartial") </div> ````
- Update that navigation to have a new link (the Events link added below) as well as a reference to the login control you just created:
````asp <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> <li>@Html.ActionLink("Contact", "Contact", "Home")</li> <li>@Html.ActionLink("Events", "Index", "Calendar")</li> </ul> @Html.Partial("_LoginPartial") </div> ```` > The **Events** link will not work yet... you will add that in the next exercise.
In this exercise, you will create a repository object for wrapping CRUD operations associated with the Calendar API.
-
In the Solution Explorer, locate the Models folder in the Office365Calendar project.
-
Right-click the Models folder and select Add/Class.
-
In the Add New Item dialog, name the new class MyEvent and click Add to create the new source file for the class.
- At the top of the source file MyEvent.cs, add the following using statement just after the using statements that are already there.
using System.ComponentModel; using System.ComponentModel.DataAnnotations;
- Implement the new class MyEvent using the following class definition.
public class MyEvent { public string Id { get; set; } [DisplayName("Subject")] public string Subject { get; set; } [DisplayName("Start Time")] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] public DateTimeOffset? Start { get; set; } [DisplayName("End Time")] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] public DateTimeOffset? End { get; set; } [DisplayName("Location")] public string Location { get; set; } [DisplayName("Body")] public string Body { get; set; } }
-
Assembly references are not added to the shared projects in ASP.NET MVC, rather they are added to the actual client projects. Therefore you need to add the following NuGet packages manually.
-
Open the Package Manager Console: View/Other Windows/Package Manager Console.
-
Enter each line below in the console, one at a time, pressing ENTER after each one. NuGet will install the package and all dependent packages:
PM> Install-Package Microsoft.Graph
-
-
Right-click the Models folder and select Add/Class. In the Add New Item dialog, name the new class MyEventsRepository and click Add to create the new source file for the class.
- Use the following using statements instead of the MyEventsRepository class old using statements.
using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using Office365Calendar.Utils; using System.Net.Http.Headers; using Microsoft.IdentityModel.Clients.ActiveDirectory; using System.Linq; using Microsoft.Graph;
- Add a function named GetGraphAccessTokenAsync to the MyEventsRepository class with the following implementation to get access token for Microsoft Graph Authentication.
private async Task<string> GetGraphAccessTokenAsync() { var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; var userObjectId = ClaimsPrincipal.Current.FindFirst(SettingsHelper.ClaimTypeObjectIdentifier).Value; var clientCredential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret); var userIdentifier = new UserIdentifier(userObjectId, UserIdentifierType.UniqueId); AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureAdAuthority, new ADALTokenCache(signInUserId)); var result = await authContext.AcquireTokenSilentAsync(SettingsHelper.AzureAdGraphResourceURL, clientCredential, userIdentifier); return result.AccessToken; }
- Add a function named GetGraphServiceAsync to the MyEventsRepository class with the following implementation to get Graph service client.
private async Task<GraphServiceClient> GetGraphServiceAsync() { var accessToken = await GetGraphAccessTokenAsync(); var graphserviceClient = new GraphServiceClient(SettingsHelper.GraphResourceUrl, new DelegateAuthenticationProvider( (requestMessage) => { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken); return Task.FromResult(0); })); return graphserviceClient; }
- Add a function named GetEvents to the MyEventsRepository class to retrieve and return a list of MyEvent objects.
public async Task<List<MyEvent>> GetEvents(int pageIndex, int pageSize) { try { var graphServiceClient = await GetGraphServiceAsync(); var requestEvents = await graphServiceClient.Me.Events.Request().Top(pageSize).Skip(pageIndex * pageSize).GetAsync(); var eventsResults = requestEvents.CurrentPage.Select(x => new MyEvent { Id = x.Id, Subject = x.Subject, Body = x.Body.Content, Location = x.Location.DisplayName, Start = DateTime.SpecifyKind(DateTime.Parse(x.Start.DateTime), x.Start.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local).ToLocalTime(), End = DateTime.SpecifyKind(DateTime.Parse(x.End.DateTime), x.End.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local).ToLocalTime(), }).ToList(); return eventsResults; } catch { return null; } }
- Add a GetEvent function to the MyEventsRepository class to get a specific event:
public async Task<MyEvent> GetEvent(string id) { try { var graphServiceClient = await GetGraphServiceAsync(); var requestEvent = await graphServiceClient.Me.Events[id].Request().GetAsync(); var eventResult = new MyEvent { Id = requestEvent.Id, Subject = requestEvent.Subject, Body = requestEvent.Body.Content, Location = requestEvent.Location.DisplayName, Start = DateTime.SpecifyKind(DateTime.Parse(requestEvent.Start.DateTime), requestEvent.Start.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local).ToLocalTime(), End = DateTime.SpecifyKind(DateTime.Parse(requestEvent.End.DateTime), requestEvent.End.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local).ToLocalTime(), }; return eventResult; } catch { return null; } }
- Add a DeleteEvent function to the MyEventsRepository class to delete an event.
public async Task DeleteEvent(string id) { try { var graphServiceClient = await GetGraphServiceAsync(); await graphServiceClient.Me.Events[id].Request().DeleteAsync(); } catch { } return; }
- Add an AddEvent function to the MyEventsRepository class to create a new event.
public async Task AddEvent(MyEvent myEvent) { try { var graphServiceClient = await GetGraphServiceAsync(); var requestEvent = new Microsoft.Graph.Event { Subject = myEvent.Subject, Start = new DateTimeTimeZone() { DateTime = myEvent.Start.ToString(), TimeZone = DateTimeKind.Local.ToString() }, End = new DateTimeTimeZone { DateTime = myEvent.End.ToString(), TimeZone = DateTimeKind.Local.ToString() }, Location = new Microsoft.Graph.Location { DisplayName = myEvent.Location }, Body = new ItemBody { Content = myEvent.Body } }; await graphServiceClient.Me.Events.Request().AddAsync(requestEvent); } catch { } return; }
- Finally, add a Search function to the MyEventsRepository class to add search functionality:
public async Task<List<MyEvent>> Search(string searchTerm) { try { var graphServiceClient = await GetGraphServiceAsync(); var requestEvents = await graphServiceClient.Me.Events.Request().Filter(string.Format("startswith(subject,+'{0}')", searchTerm)).GetAsync(); var eventsResults = requestEvents.CurrentPage.Select(x => new MyEvent { Id = x.Id, Subject = x.Subject, Body = x.Body.Content, Location = x.Location.DisplayName, Start = DateTime.SpecifyKind(DateTime.Parse(x.Start.DateTime), x.Start.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local), End = DateTime.SpecifyKind(DateTime.Parse(x.End.DateTime), x.End.TimeZone == "UTC" ? DateTimeKind.Utc : DateTimeKind.Local), }).OrderBy(x=>x.Start).ToList(); return eventsResults; } catch { return null; } }
At this point you have created the repository that will be used to talk to the Microsoft Graph SDK.
In this exercise, you will code the CalendarController of the MVC application to display events as well as adding behavior for adding and deleting events.
-
Right-click the Controllers folder and select Add/Controller.
-
In the Add Scaffold dialog, select MVC 5 Controller - Empty.
-
Click Add.
-
When prompted for a name, enter CalendarController.
-
Click Add.
-
Within the CalendarController file, use the following
using
statements instead of the old using statements :using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Office365Calendar.Models; using System.Threading.Tasks;
-
Within the
CalendarController
class, add the following field to get a reference to the repository you previously created:MyEventsRepository _repo = new MyEventsRepository();
-
Within the
CalendarController
class, add a route handler and view to list all the events: -
Replace the Index method with the following code to read events.
````c#
[Authorize]
public async Task<ActionResult> Index(int? pageNumber)
{
// setup paging
const int pageSize = 5;
if (pageNumber == null)
pageNumber = 1;
List<MyEvent> events = null;
events = await _repo.GetEvents((int)pageNumber - 1, pageSize);
ViewBag.pageNumber = pageNumber;
if(events != null)
ViewBag.morePagesAvailable = events.Count < pageSize ? false : true;
return View(events);
}
````
> Notice how the route handler takes in an optional parameter for the page number. This will be used to implement paging for the controller. Right now the page size is small, set to 5, for demonstration purposes.
-
Finally, update the view to display the results. 1. Within the
CalendarController
class, right click theView(events)
at the end of theIndex()
action method and select Add View. 1. Within the Add View dialog, set the following values:- View Name: Index.
- Template: Empty (without model).
Leave all other fields blank & unchecked.
- Click Add. 1. Within the Views/Calendar/Index.cshtml file, delete all the code in the file and replace it with the following code:
@model IEnumerable<Office365Calendar.Models.MyEvent> @{ ViewBag.Title = "My Events"; } <h2>My Events</h2> <p> @Html.ActionLink("Create New", "Create") | @Html.ActionLink("Search Events", "Search") </p> <table id="eventsTable" class="table table-striped table-bordered"> <tr> <th>@Html.DisplayNameFor(model => model.Subject)</th> <th>@Html.DisplayNameFor(model => model.Start)</th> <th>@Html.DisplayNameFor(model => model.End)</th> <th>@Html.DisplayNameFor(model => model.Location)</th> <th></th> </tr> @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.Subject)</td> <td>@Html.DisplayFor(modelItem => item.Start)</td> <td>@Html.DisplayFor(modelItem => item.End)</td> <td>@Html.DisplayFor(modelItem => item.Location)</td> <td> @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> </tr> } </table> <div class="row"> <h4>Paging Control</h4> <div class="btn btn-group-sm"> @{ var pageLinkAttributes = new Dictionary<string, object> { { "class", "btn btn-default" } }; int pageNumber = ViewBag.pageNumber; // do prev link if not on first page if (pageNumber > 1) { var routeValues = new RouteValueDictionary { { "pageNumber", pageNumber - 1 } }; @Html.ActionLink("Previous Page", "Index", "Calendar", routeValues, pageLinkAttributes); } // do next link if current page = max page size if (ViewBag.morePagesAvailable) { var routeValues = new RouteValueDictionary { { "pageNumber", pageNumber + 1 } }; @Html.ActionLink("Next Page", "Index", "Calendar", routeValues, pageLinkAttributes); } } </div> </div>
-
Test the new view:
-
In Visual Studio, hit F5 to begin debugging.
Note: If you receive an error that indicates ASP.NET could not connect to the SQL database, please see the SQL Server Database Connection Error Resolution document to quickly resolve the issue.
- When prompted, log in with your Organizational Account.
- Once the application is loaded click the Events link in the top menu bar.
- Verify that your application displays calendar events from your Office 365 account.
![Screenshot of the previous step](Images/04.png)
-
Close the browser window, terminate the debugging session and return to Visual Studio.
-
Add a route handler to delete an event:
-
In the CalendarController.cs file, add an action method named Delete using the following code to delete an event.
````c#
[Authorize]
public async Task<ActionResult> Delete(string id)
{
if (id != null)
{
await _repo.DeleteEvent(id);
}
return Redirect("/Calendar");
}
````
- Add a route handler and views to handle creating events:
- In the CalendarController.cs file, add an action method named Create using the following code to create a new event. Notice how you are adding two items, when the create form is requested (the
HttpGet
option) and one for when the form is submitted (theHttpPost
option).
````c#
[HttpGet]
[Authorize]
public async Task<ActionResult> Create()
{
var myEvent = new MyEvent
{
Start = DateTimeOffset.Now,
End = DateTimeOffset.Now.AddDays(1)
};
return View(myEvent);
}
[HttpPost]
[Authorize]
public async Task<ActionResult> Create(MyEvent myEvent)
{
await _repo.AddEvent(myEvent);
return Redirect("/Calendar");
}
````
- Within the
CalendarController
class, right click theView(myEvent)
at the end of theCreate()
action method and select Add View. - In the Add View dialog, set the following options on the dialog and click Add. + View name: Create + Template: Create + Model class: MyEvent (Office365Calendar.Models) + Create as partial view: unchecked + Reference script libraries: unchecked + Use a layout page: checked + Click Add
- Open the Create.cshtml file. Delete all the code in the file and replace it with the following code:
````html
@model Office365Calendar.Models.MyEvent
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>MyEvent</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Subject, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Subject, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Subject, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Start, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Start, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Start, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.End, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.End, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.End, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Location, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Location, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Location, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Body, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Body, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Body, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
````
- Test the new view:
- In Visual Studio, hit F5 to begin debugging.
Note: If you receive an error that indicates ASP.NET could not connect to the SQL database, please see the SQL Server Database Connection Error Resolution document to quickly resolve the issue.
- When Prompted, log in with your Organizational Account.
- Once the application is loaded click the Events link in the top menu bar.
- Click the Delete link. The event would be deleted successfully.
- Click the Create New link. You should see the form below. Fill the form out to add a new item:
![Screenshot of the previous step](Images/05.png)
-
Close the browser window, terminate the debugging session and return to Visual Studio.
-
Add a route handler and view to handle showing the details of a selected event:
-
In the CalendarController.cs file, add an action method named Details using the following code to view an event.
````c#
[Authorize]
public async Task<ActionResult> Details(string id)
{
MyEvent myEvent = null;
myEvent = await _repo.GetEvent(id);
return View(myEvent);
}
````
-
Within the
CalendarController
class, right click theView(myEvent)
at the end of theDetails()
action method and select Add View. -
In the Add View dialog, set the following options on the dialog and click Add. + View name: Details + Template: Details + Model class: MyEvent (Office365Calendar.Models) + Create as partial view: unchecked + Reference script libraries: unchecked + Use a layout page: checked + Click Add
-
Open the Details.cshtml file. Find the following code and remove it:
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
-
Test the new view:
-
In Visual Studio, hit F5 to begin debugging.
Note: If you receive an error that indicates ASP.NET could not connect to the SQL database, please see the SQL Server Database Connection Error Resolution document to quickly resolve the issue.
- When Prompted, log in with your Organizational Account.
- Once the application is loaded click the Events link in the top menu bar.
- Click the Details link for one of the items.
![Screenshot of the previous step](Images/06.png)
-
Close the browser window, terminate the debugging session and return to Visual Studio.
-
Add a route handler and view to handle search for events:
-
In the CalendarController.cs file, add two action methods named Search using the following code to search events.
````c#
[HttpGet]
[Authorize]
public async Task<ActionResult> Search()
{
return View();
}
[HttpPost]
[Authorize]
public async Task<ActionResult> Search(string searchTerm)
{
var events = await _repo.Search(searchTerm);
return View(events);
}
````
- Within the
CalendarController
class, right click theView()
at the end of theSearch()
action method and select Add View. - In the Add View dialog, set the following options on the dialog and click Add. + View name: Search + Template: Empty + Create as partial view: unchecked + Reference script libraries: unchecked + Use a layout page: checked + Click Add
- Open the generated Search.cshtml view and replace the markup with the following code:
````html
@model IEnumerable<Office365Calendar.Models.MyEvent>
@{
ViewBag.Title = "Search";
}
<h2>Search</h2>
@using (Html.BeginForm("Search", "Calendar", FormMethod.Post))
{
<p>
<div class="form-horizontal">
<div class="form-group">
<div class="col-md-10">
<input type="text" id="searchTerm" name="searchTerm" class="form-control" /><br />
<button type="submit">search for events</button>
</div>
</div>
</div>
</p>
}
<table class="table">
<tr>
<th>@Html.DisplayNameFor(model => model.Subject)</th>
<th>@Html.DisplayNameFor(model => model.Start)</th>
<th>@Html.DisplayNameFor(model => model.End)</th>
<th></th>
</tr>
@if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>@Html.DisplayFor(modelItem => item.Subject)</td>
<td>@Html.DisplayFor(modelItem => item.Start)</td>
<td>@Html.DisplayFor(modelItem => item.End)</td>
<td>
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
}
</table>
<p>
@Html.ActionLink("Back to List", "Index")
</p>
````
- Test the new view:
- In Visual Studio, hit F5 to begin debugging.
Note: If you receive an error that indicates ASP.NET could not connect to the SQL database, please see the SQL Server Database Connection Error Resolution document to quickly resolve the issue.
- When Prompted, log in with your Organizational Account.
- Once the application is loaded click the Events link in the top menu bar.
- Click the Search Events link and enter a search term on the next page. You should see a filtered set of results:
![Screenshot of the previous step](Images/07.png)
- Close the browser window, terminate the debugging session and return to Visual Studio.
Congratulations! You have completed working with the Microsoft Graph APi for Calendar.