Name: O365-EDU-SDS-AspNetMVC-Samples
Owner: Office Developer
Description: Microsoft School Data Sync OneRoster API provider and Profile Management API implementation examples
Created: 2017-09-21 00:37:15.0
Updated: 2018-02-15 22:19:22.0
Pushed: 2018-01-17 23:45:59.0
Homepage: null
Size: 322
Language: C#
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
?# OneRoster REST Provider Sample
This project implements OneRoster v1.1 behaviors.
Specifically, it targets requirements for:
Table of contents
The sample demonstrates:
OneRosterProviderDemo is based on ASP.NET Core Web.
Deploying and running this sample requires:
Sign into the new azure portal: https://portal.azure.com/.
Click Azure Active Directory -> App registrations -> +Add.
Input a Name, and select Web app / API as Application Type.
Input Sign-on URL: https://localhost:44344/
Click Create.
Once completed, the app will show in the list.
Click it to view its details.
Click All settings, if the setting window did not show.
Click Properties, then set Multi-tenanted to Yes.
Copy aside Application ID, then Click Save.
Click Required permissions. Add the following permissions:
| API | Delegated Permissions |
| —————————— | —————————————- |
| Microsoft Graph | Read directory data
Read and write directory data
Access directory as the signed in user
Read education app settings
Manage education app settings |
| Windows Azure Active Directory | Sign in and read user profile |
Click Keys, then add a new key:
Click Save, then copy aside the VALUE of the key.
Close the Settings window.
This project can be opened with the edition of Visual Studio 2017 you already have, or download and install the Community edition to run, build and/or develop this application locally.
Debug OneRosterProviderDemo:
Configure appsettings.json.
AzureAd:Authority: “https://login.microsoftonline.com/{your-ad-tenant}.onmicrosoft.com/”
AzureAd:ClientId: use the Client Id of the app registration you created earlier.
AzureAd:ClientSecret: use the Key value of the app registration you created earlier.
AzureDomain: use your AD tenant domain, which should agree with the AzureAd:Authority entry
In the Package Manager Console, run the command EntityFrameworkCore\Update-Database
to generate the initial database. If this causes an error, try running the command Import-Package Microsoft.EntityFrameworkCore
.
Set OneRosterProviderDemo as StartUp project, and press F5.
Visit /seeds
to populate your database with sample entities. Make sure to access the endpoint using HTTPS.
Create a Publish Profile
Select Build > Publish OneRosterProviderDemo
Click Create new profile
Select Microsoft Azure App Service and Create New
Click Publish
Sign into your Azure account
Select a Resource Group for the deploy, or create a new one by clicking New
Select an App Service Plan for the deploy, or create a new one by clicking New
Click Create
Select Build > Publish OneRosterProviderDemo
Click Publish
Add REPLY URL to the app registration
After the deployment, open the resource group in Azure Portal
Click the web app.
Copy the URL aside and change the schema to https, and add /signin-oidc to the end. This is the reply URL and will be used in next step.
Navigate to the app registration in the new azure portal, then open the setting windows.
Add the reply URL:
Note: to debug the sample locally, make sure that https://localhost:44344/signin-oidc is in the reply URLs.
Click SAVE.
There are two synchronization options, via the OneRoster REST endpoints, and by uploading SDS compliant CSV files.
This web application is based on an ASP.NET Core Web project template.
The Middlewares/OAuth.cs
file defines a middleware that validates the OAuth1 or OAuth2 signature for each incoming request with a OneRoster route. This file also contains the hard-coded client ID and secret.
In order to make OAuth2 requests, first visit the /token endpoint using OAuth1 credentials to get the access token.
The Startup.cs
file configures the app to use this middleware.
The Startup.cs
file configures the app to use .NET Core's OpenIDConnect (oidc) library. This flow is handled by AccountController
.
Most of the OneRoster models have a corresponding model class in the Models
directory. Due to language naming conventions, some of these have been renamed. The mapping of models is shown in the table below.
| OneRoster Model | EFCore Model | |————————|——————-| | Base | BaseModel | | Academic Session | AcademicSession | | Class | IMSClass | | Course | Course | | Demographic Data | Demographic | | Enrollment | Enrollment | | Line Item | LineItem | | Line Item Category | LineItemCategory | | Org | Org | | Resource | Resource | | Result | Result | | User, Student, Teacher | User |
Additional models were created to support various needs:
| EFCore Model | Purpose | |————————-|————————————————-| | IMSClassAcademicSession | Join table for Class, Term (Academic Session) | | UserAgent | Join table for User, User | | UserOrg | Join table for User, Org | | UserId | Shape of user ids | | SeedData | Holds seed data for initial database population | | OauthNonce | Stores nonce values to disallow reuse |
Validation requirements are defined in the OneRoster model specification.
In addition to the validation attributes supplied by .NET and ASP Core, there are four custom validators for properties with specific requirements in the Validators
folder.
Vocabularies used by OneRoster, including enumerations, are provided by the Vocabulary/Vocabulary
class.
The subject code vocabulary “SCEDv4.0” is published by NCES; a conversion of the published spreadsheet is present in the Vocabulary/sced-v4.csv
file, which is parsed at startup time.
All response json objects are written using the NewtonSoft JSON nuget package, for the purposes of matching the prescribed json bindings.
All entities that can be serialized into a service endpoint response support two serialization methods, AsJson
and AsJsonReference
.
AsJson is used when the entity is the primary entity, or a member of the primary collection, that was requested.
AsJsonReference is used to express the entity as a GUIDRef.
The Controllers/BaseController
class hooks in paging, filtering, and sorting.
Filtering and sorting are implemented in the model classes via reflection in order to support the requirement that any data field be usable for filtering or sorting.
An SQLite database is assumed and configured in Startup.cs
.
You can create a new, empty database by running the EntityFrameworkCore\Update-Database
command in the Package Manager console, and seed it with sample data by visiting the /seeds
endpoint.
There are three OneRoster v1.1 service subsets, defined here. Of these, the Rostering (read-only) and Gradebook (read-and-write) subsets are implemented by this sample.
| Service Call | Endpoint | HTTP Verb | |——————————–|—————————————————–|———–| | getAllAcademicSessions | /academicSessions | GET | | getAcademicSession | /academicSessions/{id} | GET | | getAllClasses | /classes | GET | | getClass | /classes/{id} | GET | | getStudentsForClass | /classes/{class_id}/students | GET | | getTeachersForClass | /classes/{class_id}/teachers | GET | | getAllCourses | /courses | GET | | getCourse | /courses/{id} | GET | | getClassesForCourse | /courses/{course_id}/classes | GET | | getAllDemographics | /demographics | GET | | getDemographics | /demographics/{id} | GET | | getAllEnrollments | /enrollments | GET | | getEnrollment | /enrollments/{id} | GET | | getAllGradingPeriods | /gradingPeriods | GET | | getGradingPeriod | /gradingPeriods/{id} | GET | | getAllOrgs | /orgs | GET | | getOrg | /orgs/{id} | GET | | getAllSchools | /schools | GET | | getSchool | /schools/{id} | GET | | getCoursesForSchool | /schools/{id}/courses | GET | | getClassesForSchool | /schools/{school_id}/classes | GET | | getEnrollmentsForSchool | /schools/{school_id}/enrollments | GET | | getEnrollmentsForClassInSchool | /schools/{school_id}/classes/class_id}/enrollments | GET | | getStudentsForClassInSchool | /schools/{school_id}/classes/{class_id}/students | GET | | getStudentsForSchool | /schools/{school_id}/students | GET | | getTeachersForClassInSchool | /schools/{school_id}/classes/{class_id}/teachers | GET | | getTeachersForSchool | /schools/{school_id}/teachers | GET | | getTermsForSchool | /schools/{school_id}/terms | GET | | getAllStudents | /students | GET | | getStudent | /students/{id} | GET | | getClassesForStudent | /students/{id}/classes | GET | | getAllTeachers | /teachers | GET | | getTeacher | /teachers/{id} | GET | | getClassesForTeacher | /teachers/{id}/classes | GET | | getAllTerms | /terms | GET | | getTerm | /terms/{id} | GET | | getClassesForTerm | /terms/{id}/classes | GET | | getGradingPeriodsForTerm | /terms/{id}/gradingPeriods | GET | | getAllUsers | /users | GET | | getUser | /users/{id} | GET | | getClassesForUser | /users/{id}/classes | GET |
| Service Call | Endpoint | HTTP Verb | |——————————-|—————————————————|———–| | getAllCategories | /categories | GET | | getCategory | /categories/{id} | GET | | getAllLineItems | /lineItems | GET | | getLineItem | /lineItems/{id} | GET | | getAllResults | /results | GET | | getResult | /results/{id} | GET | | getResultsForClass | /classes/{class_id}/results | GET | | getLineItemsForClass | /classes/{class_id}/lineItems | GET | | getResultsForLineItemForClass | /classes/{class_id}/lineItems/{li_id}/results | GET | | getResultsForStudentForClass | /classes/{class_id}/students/{student_id}/results | GET |
| Service Call | Endpoint | HTTP Verb | |——————————-|—————————————————|———–| | deleteCategory | /categories/{id} | DELETE | | putCategory | /categories/{id} | PUT | | deleteLineItem | /lineItems/{id} | DELETE | | putLineItem | /lineItems/{id} | PUT | | deleteResult | /results/{id} | DELETE | | putResult | /results/{id} | PUT |
Currently, the following behaviors are not up to spec:
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
Copyright (c) 2018 Microsoft. All rights reserved.