diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml deleted file mode 100644 index c30512233074..000000000000 --- a/aspnetcore/toc.yml +++ /dev/null @@ -1,1091 +0,0 @@ -- name: ASP.NET Core documentation - href: /aspnet/#pivot=core -- name: Overview - items: - - name: About ASP.NET Core - uid: index - - name: Compare ASP.NET Core and ASP.NET - uid: fundamentals/choose-between-aspnet-and-aspnetcore - - name: Compare .NET Core and .NET Framework - href: /dotnet/standard/choosing-core-framework-server?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json -- name: Get started - uid: getting-started -- name: What's new - items: - - name: What's new in 2.2 - uid: aspnetcore-2.2 - - name: What's new in 2.1 - uid: aspnetcore-2.1 - - name: What's new in 2.0 - uid: aspnetcore-2.0 - - name: What's new in 1.1 - uid: aspnetcore-1.1 -- name: Tutorials - items: - - name: Web apps - items: - - name: Razor Pages - displayName: tutorial - items: - - name: Overview - uid: tutorials/razor-pages/index - - name: Get started - uid: tutorials/razor-pages/razor-pages-start - - name: Add a model - uid: tutorials/razor-pages/model - - name: Scaffolding - uid: tutorials/razor-pages/page - - name: Work with a database - uid: tutorials/razor-pages/sql - - name: Update the pages - uid: tutorials/razor-pages/da1 - - name: Add search - uid: tutorials/razor-pages/search - - name: Add a new field - uid: tutorials/razor-pages/new-field - - name: Add validation - uid: tutorials/razor-pages/validation - - name: MVC - displayName: tutorial - items: - - name: Overview - uid: tutorials/first-mvc-app/index - - name: Get started - uid: tutorials/first-mvc-app/start-mvc - - name: Add a controller - uid: tutorials/first-mvc-app/adding-controller - - name: Add a view - uid: tutorials/first-mvc-app/adding-view - - name: Add a model - uid: tutorials/first-mvc-app/adding-model - - name: Work with a database - uid: tutorials/first-mvc-app/working-with-sql - - name: Controller actions and views - uid: tutorials/first-mvc-app/controller-methods-views - - name: Add search - uid: tutorials/first-mvc-app/search - - name: Add a new field - uid: tutorials/first-mvc-app/new-field - - name: Add validation - uid: tutorials/first-mvc-app/validation - - name: Examine the Details and Delete methods - uid: tutorials/first-mvc-app/details - - name: Web API apps - items: - - name: Create a web API - displayName: tutorial - uid: tutorials/first-web-api - - name: Web API with MongoDB - displayName: tutorial - uid: tutorials/first-mongo-app - - name: Backend for mobile - displayName: tutorial - uid: mobile/native-mobile-backend - - name: Real-time web apps - items: - - name: SignalR with JavaScript - displayName: tutorial - uid: tutorials/signalr - - name: SignalR with TypeScript - displayName: tutorial - uid: tutorials/signalr-typescript-webpack - - name: Remote Procedure Call apps - items: - - name: Get started with gRPC service in ASP.NET Core - uid: tutorials/grpc/grpc-start - - name: Data access - items: - - name: EF Core with Razor Pages - displayName: tutorial - items: - - name: Overview - uid: data/ef-rp/index - - name: Get started - uid: data/ef-rp/intro - - name: Create, Read, Update, and Delete - uid: data/ef-rp/crud - - name: Sort, filter, page, and group - uid: data/ef-rp/sort-filter-page - - name: Migrations - uid: data/ef-rp/migrations - - name: Create a complex data model - uid: data/ef-rp/complex-data-model - - name: Read related data - uid: data/ef-rp/read-related-data - - name: Update related data - uid: data/ef-rp/update-related-data - - name: Handle concurrency conflicts - uid: data/ef-rp/concurrency - - name: EF Core with MVC, existing database - displayName: tutorial - href: /ef/core/get-started/aspnetcore/existing-db?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: EF Core with MVC, new database - displayName: tutorial - href: /ef/core/get-started/aspnetcore/new-db?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: EF Core with MVC, 10 tutorials - items: - - name: Overview - uid: data/ef-mvc/index - - name: Get started - uid: data/ef-mvc/intro - - name: Create, Read, Update, and Delete - uid: data/ef-mvc/crud - - name: Sort, filter, page, and group - uid: data/ef-mvc/sort-filter-page - - name: Migrations - uid: data/ef-mvc/migrations - - name: Create a complex data model - uid: data/ef-mvc/complex-data-model - - name: Read related data - uid: data/ef-mvc/read-related-data - - name: Update related data - uid: data/ef-mvc/update-related-data - - name: Handle concurrency conflicts - uid: data/ef-mvc/concurrency - - name: Inheritance - uid: data/ef-mvc/inheritance - - name: Advanced topics - uid: data/ef-mvc/advanced -- name: Fundamentals - items: - - name: Overview - uid: fundamentals/index - - name: The Startup class - uid: fundamentals/startup - - name: Dependency injection (services) - uid: fundamentals/dependency-injection - - name: Middleware - uid: fundamentals/middleware/index - - name: Host - items: - - name: Web Host - uid: fundamentals/host/web-host - - name: Generic Host - uid: fundamentals/host/generic-host - - name: Servers - uid: fundamentals/servers/index - - name: Configuration - uid: fundamentals/configuration/index - - name: Options - uid: fundamentals/configuration/options - - name: Environments (dev, stage, prod) - uid: fundamentals/environments - - name: Logging - uid: fundamentals/logging/index - - name: Routing - uid: fundamentals/routing - - name: Handle errors - uid: fundamentals/error-handling - - name: Make HTTP requests - displayName: httpclient, httpclientfactory - uid: fundamentals/http-requests - - name: Static files - uid: fundamentals/static-files -- name: Web apps - items: - - name: Razor Pages - items: - - name: Introduction - uid: razor-pages/index - - name: Tutorial - items: - - name: Overview - uid: tutorials/razor-pages/index - - name: Get started - uid: tutorials/razor-pages/razor-pages-start - - name: Add a model - uid: tutorials/razor-pages/model - - name: Scaffolding - uid: tutorials/razor-pages/page - - name: Work with a database - uid: tutorials/razor-pages/sql - - name: Update the pages - uid: tutorials/razor-pages/da1 - - name: Add search - uid: tutorials/razor-pages/search - - name: Add a new field - uid: tutorials/razor-pages/new-field - - name: Add validation - uid: tutorials/razor-pages/validation - - name: Filters - uid: razor-pages/filter - - name: Razor Class Libraries - uid: razor-pages/ui-class - - name: Route and app conventions - uid: razor-pages/razor-pages-conventions - - name: Upload files - uid: razor-pages/upload-files - - name: Razor SDK - uid: razor-pages/sdk - - name: MVC - items: - - name: Overview - uid: mvc/overview - - name: Tutorial - uid: tutorials/first-mvc-app/index - items: - - name: Get started - uid: tutorials/first-mvc-app/start-mvc - - name: Add a controller - uid: tutorials/first-mvc-app/adding-controller - - name: Add a view - uid: tutorials/first-mvc-app/adding-view - - name: Add a model - uid: tutorials/first-mvc-app/adding-model - - name: Work with a database - uid: tutorials/first-mvc-app/working-with-sql - - name: Controller actions and views - uid: tutorials/first-mvc-app/controller-methods-views - - name: Add search - uid: tutorials/first-mvc-app/search - - name: Add a new field - uid: tutorials/first-mvc-app/new-field - - name: Add validation - uid: tutorials/first-mvc-app/validation - - name: Examine the Details and Delete methods - uid: tutorials/first-mvc-app/details - - name: Views - uid: mvc/views/overview - - name: Partial views - uid: mvc/views/partial - - name: Controllers - uid: mvc/controllers/actions - - name: Routing - uid: mvc/controllers/routing - - name: File uploads - uid: mvc/models/file-uploads - - name: Dependency injection - controllers - uid: mvc/controllers/dependency-injection - - name: Dependency injection - views - uid: mvc/views/dependency-injection - - name: Unit test - uid: mvc/controllers/testing - - name: Razor Components - uid: razor-components/index - - name: Session and app state - uid: fundamentals/app-state - - name: Tag Helpers - items: - - name: Overview - uid: mvc/views/tag-helpers/intro - - name: Create Tag Helpers - uid: mvc/views/tag-helpers/authoring - - name: Use Tag Helpers in forms - uid: mvc/views/working-with-forms - - name: Tag Helper Components - uid: mvc/views/tag-helpers/th-components - - name: Built-in Tag Helpers - items: - - name: Anchor - uid: mvc/views/tag-helpers/builtin-th/anchor-tag-helper - - name: Cache - uid: mvc/views/tag-helpers/builtin-th/cache-tag-helper - - name: Distributed Cache - uid: mvc/views/tag-helpers/builtin-th/distributed-cache-tag-helper - - name: Environment - uid: mvc/views/tag-helpers/builtin-th/environment-tag-helper - - name: Form - href: mvc/views/working-with-forms.md#the-form-tag-helper - - name: Image - uid: mvc/views/tag-helpers/builtin-th/image-tag-helper - - name: Input - href: mvc/views/working-with-forms.md#the-input-tag-helper - - name: Label - href: mvc/views/working-with-forms.md#the-label-tag-helper - - name: Partial - uid: mvc/views/tag-helpers/builtin-th/partial-tag-helper - - name: Select - href: mvc/views/working-with-forms.md#the-select-tag-helper - - name: Textarea - href: mvc/views/working-with-forms.md#the-textarea-tag-helper - - name: Validation Message - href: mvc/views/working-with-forms.md#the-validation-message-tag-helper - - name: Validation Summary - href: mvc/views/working-with-forms.md#the-validation-summary-tag-helper - - name: Layout - uid: mvc/views/layout - - name: Model binding - uid: mvc/models/model-binding - - name: Model validation - uid: mvc/models/validation - - name: Razor syntax - uid: mvc/views/razor - - name: Advanced - items: - - name: View components - uid: mvc/views/view-components - - name: View compilation - uid: mvc/views/view-compilation - - name: App model - uid: mvc/controllers/application-model - - name: Filters - uid: mvc/controllers/filters - - name: Areas - uid: mvc/controllers/areas - - name: App parts - uid: mvc/extensibility/app-parts - - name: Custom model binding - uid: mvc/advanced/custom-model-binding - - name: Compatibility version - uid: mvc/compatibility-version -- name: Web API apps - items: - - name: Overview - uid: web-api/index - - name: Tutorials - items: - - name: Create a web API - uid: tutorials/first-web-api - - name: Web API with MongoDB - uid: tutorials/first-mongo-app - - name: Swagger / OpenAPI - items: - - name: Overview - uid: tutorials/web-api-help-pages-using-swagger - - name: Get started with Swashbuckle - uid: tutorials/get-started-with-swashbuckle - - name: Get started with NSwag - uid: tutorials/get-started-with-nswag - - name: Action return types - uid: web-api/action-return-types - - name: Format response data - uid: web-api/advanced/formatting - - name: Custom formatters - uid: web-api/advanced/custom-formatters - - name: Analyzers - uid: web-api/advanced/analyzers - - name: Conventions - uid: web-api/advanced/conventions -- name: Real-time apps - displayName: signalr - items: - - name: SignalR overview - uid: signalr/introduction - - name: Supported platforms - uid: signalr/supported-platforms - displayName: signalr - - name: Tutorials - items: - - name: SignalR with JavaScript - uid: tutorials/signalr - - name: SignalR with TypeScript - uid: tutorials/signalr-typescript-webpack - - name: Samples - href: https://github.com/aspnet/SignalR-samples - displayName: signalr - - name: Server concepts - displayName: signalr - items: - - name: Hubs - uid: signalr/hubs - displayName: signalr - - name: Send from outside a hub - uid: signalr/hubcontext - displayName: signalr - - name: Users and groups - uid: signalr/groups - displayName: signalr - - name: Publish to Azure - uid: signalr/publish-to-azure-web-app - displayName: signalr - - name: API design considerations - uid: signalr/api-design - displayName: signalr - - name: Clients - displayName: signalr - items: - - name: .NET client - uid: signalr/dotnet-client - displayName: signalr - - name: .NET API reference - href: /dotnet/api/microsoft.aspnetcore.signalr.client - displayName: signalr - - name: Java client - uid: signalr/java-client - displayName: signalr - - name: Java API reference - href: /java/api/com.microsoft.signalr?view=aspnet-signalr-java - displayName: signalr - - name: JavaScript client - uid: signalr/javascript-client - displayName: signalr - - name: JavaScript API reference - href: /javascript/api/?view=signalr-js-latest - displayName: signalr - - name: Hosting and scaling - displayName: signalr - items: - - name: Overview - displayName: signalr - uid: signalr/scale - - name: Azure SignalR Service - displayName: signalr - href: /azure/azure-signalr/signalr-overview?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Redis backplane - displayName: signalr - uid: signalr/redis-backplane - - name: SignalR with background services - uid: signalr/background-services - - name: Configuration - uid: signalr/configuration - displayName: signalr - - name: Authentication and authorization - uid: signalr/authn-and-authz - displayName: signalr - - name: Security considerations - uid: signalr/security - displayName: signalr - - name: MessagePack Hub Protocol - uid: signalr/messagepackhubprotocol - displayName: signalr - - name: Streaming - uid: signalr/streaming - displayName: signalr - - name: Compare SignalR and SignalR Core - uid: signalr/version-differences - displayName: signalr - - name: WebSockets without SignalR - displayName: signalr - uid: fundamentals/websockets - - name: Logging and diagnostics - displayName: signalr - uid: signalr/diagnostics -- name: Remote Procedure Call apps - items: - - name: Introduction to gRPC services - uid: grpc/index - - name: gRPC services with C# - uid: grpc/basics - - name: gRPC services with ASP.NET Core - uid: grpc/aspnetcore - - name: Migrating gRPC services from C Core to ASP.NET Core - uid: grpc/migration - - name: Comparing gRPC services with HTTP APIs - uid: grpc/comparison - - name: Tutorials - items: - - name: Get started with gRPC service in ASP.NET Core - uid: tutorials/grpc/grpc-start -- name: Test, debug, and troubleshoot - items: - - name: Unit testing - href: /dotnet/core/testing/unit-testing-with-dotnet-test?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Razor Pages unit tests - uid: test/razor-pages-tests - - name: Test controllers - uid: mvc/controllers/testing - - name: Remote debugging - href: /visualstudio/debugger/remote-debugging-azure - - name: Snapshot debugging - href: /azure/azure-monitor/app/snapshot-debugger?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Snapshot debugging in Visual Studio - href: /visualstudio/debugger/debug-live-azure-applications - - name: Integration tests - uid: test/integration-tests - - name: Load and stress testing - uid: test/loadtests - - name: Troubleshoot - uid: test/troubleshoot - - name: Logging - uid: fundamentals/logging/index -- name: Data access - items: - - name: Tutorials - items: - - name: EF Core with Razor Pages - items: - - name: Overview - uid: data/ef-rp/index - - name: Get started - uid: data/ef-rp/intro - - name: Create, Read, Update, and Delete - uid: data/ef-rp/crud - - name: Sort, filter, page, and group - uid: data/ef-rp/sort-filter-page - - name: Migrations - uid: data/ef-rp/migrations - - name: Create a complex data model - uid: data/ef-rp/complex-data-model - - name: Read related data - uid: data/ef-rp/read-related-data - - name: Update related data - uid: data/ef-rp/update-related-data - - name: Handle concurrency conflicts - uid: data/ef-rp/concurrency - - name: EF Core with MVC, new database - href: /ef/core/get-started/aspnetcore/new-db?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: EF Core with MVC, existing database - href: /ef/core/get-started/aspnetcore/existing-db?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: EF Core with MVC, 10 tutorials - items: - - name: Overview - uid: data/ef-mvc/index - - name: Get started - uid: data/ef-mvc/intro - - name: Create, Read, Update, and Delete - uid: data/ef-mvc/crud - - name: Sort, filter, page, and group - uid: data/ef-mvc/sort-filter-page - - name: Migrations - uid: data/ef-mvc/migrations - - name: Create a complex data model - uid: data/ef-mvc/complex-data-model - - name: Read related data - uid: data/ef-mvc/read-related-data - - name: Update related data - uid: data/ef-mvc/update-related-data - - name: Handle concurrency conflicts - uid: data/ef-mvc/concurrency - - name: Inheritance - uid: data/ef-mvc/inheritance - - name: Advanced topics - uid: data/ef-mvc/advanced - - name: EF 6 with ASP.NET Core - uid: data/entity-framework-6 - - name: Azure Storage with Visual Studio - items: - - name: Connected Services - href: /visualstudio/azure/vs-azure-tools-connected-services-storage - - name: Blob storage - href: /azure/visual-studio/vs-storage-aspnet5-getting-started-blobs?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Queue storage - href: /azure/visual-studio/vs-storage-aspnet5-getting-started-queues?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Table storage - href: /azure/visual-studio/vs-storage-aspnet5-getting-started-tables?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json -- name: Client-side development - items: - - name: Razor Components - items: - - name: Overview - uid: razor-components/index - - name: Get started - uid: razor-components/get-started - - name: Hosting models - uid: razor-components/hosting-models - - name: Build your first app - uid: tutorials/first-razor-components-app - - name: Components - uid: razor-components/components - - name: Forms and validation - uid: razor-components/forms-validation - - name: Component libraries - uid: razor-components/class-libraries - - name: Layouts - uid: razor-components/layouts - - name: Dependency injection - uid: razor-components/dependency-injection - - name: Routing - uid: razor-components/routing - - name: JavaScript interop - uid: razor-components/javascript-interop - - name: Debug - uid: razor-components/debug - - name: Host and deploy - items: - - name: Overview - uid: host-and-deploy/razor-components-blazor/index - - name: Razor Components - uid: host-and-deploy/razor-components-blazor/razor-components - - name: Single Page Apps - items: - - name: Blazor - items: - - name: Overview - uid: spa/blazor/index - - name: Get started - uid: spa/blazor/get-started - - name: Hosting models - uid: razor-components/hosting-models - - name: Build your first app - uid: tutorials/first-razor-components-app - - name: Components - uid: razor-components/components - - name: Forms and validation - uid: razor-components/forms-validation - - name: Component libraries - uid: razor-components/class-libraries - - name: Layouts - uid: razor-components/layouts - - name: Dependency injection - uid: razor-components/dependency-injection - - name: Routing - uid: razor-components/routing - - name: JavaScript interop - uid: razor-components/javascript-interop - - name: Debug - uid: razor-components/debug - - name: Host and deploy - items: - - name: Overview - uid: host-and-deploy/razor-components-blazor/index - - name: Blazor - uid: host-and-deploy/razor-components-blazor/blazor - - name: Configure the Linker - uid: host-and-deploy/razor-components-blazor/configure-linker - - name: Angular - uid: spa/angular - - name: React - uid: spa/react - - name: React with Redux - uid: spa/react-with-redux - - name: JavaScriptServices - uid: client-side/spa-services - - name: LibMan - items: - - name: Overview - uid: client-side/libman/index - - name: CLI - uid: client-side/libman/libman-cli - - name: Visual Studio - uid: client-side/libman/libman-vs - - name: Gulp - uid: client-side/using-gulp - - name: Grunt - uid: client-side/using-grunt - - name: Bower - uid: client-side/bower - - name: Bundle and minify - uid: client-side/bundling-and-minification - - name: Browser Link - uid: client-side/using-browserlink -- name: Hosting and deployment - displayName: publish - items: - - name: Overview - displayName: azure, deploy, publish - uid: host-and-deploy/index - - name: Host on Azure App Service - displayName: deploy, publish - items: - - name: Overview - displayName: azure, deploy, publish - uid: host-and-deploy/azure-apps/index - - name: Publish with Visual Studio - displayName: azure, deploy, publish - uid: tutorials/publish-to-azure-webapp-using-vs - - name: Publish with Visual Studio for Mac - displayName: azure, deploy, publish - href: /visualstudio/mac/publish-app-svc?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Publish with CLI tools - displayName: azure, deploy, publish - href: /azure/app-service/app-service-web-tutorial-dotnetcore-sqldb?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Publish with Visual Studio and Git - displayName: azure, deploy, publish - uid: host-and-deploy/azure-apps/azure-continuous-deployment - - name: Continuous deployment with Azure Pipelines - displayName: azure, deploy, publish - href: /azure/devops/pipelines/get-started-yaml - - name: ASP.NET Core Module - displayName: azure, deploy, publish - uid: host-and-deploy/aspnet-core-module - - name: Troubleshoot - displayName: azure, deploy, publish - uid: host-and-deploy/azure-apps/troubleshoot - - name: Errors reference - displayName: azure, deploy, publish - uid: host-and-deploy/azure-iis-errors-reference - - name: DevOps - items: - - name: Overview - displayName: azure, deploy, publish - uid: azure/devops/index - - name: Tools and downloads - displayName: azure, deploy, publish - uid: azure/devops/tools-and-downloads - - name: Deploy to App Service - displayName: azure, deploy, publish - uid: azure/devops/deploy-to-app-service - - name: Continuous integration and deployment - displayName: azure, deploy, publish - uid: azure/devops/cicd - - name: Monitor and troubleshoot - displayName: azure, deploy, publish - uid: azure/devops/monitor - - name: Next steps - displayName: azure, deploy, publish - uid: azure/devops/next-steps - - name: Host on Windows with IIS - displayName: deploy, publish - items: - - name: Overview - displayName: deploy, publish - uid: host-and-deploy/iis/index - - name: ASP.NET Core Module - displayName: deploy, publish - uid: host-and-deploy/aspnet-core-module - - name: IIS support in Visual Studio - displayName: deploy, publish - uid: host-and-deploy/iis/development-time-iis-support - - name: IIS Modules - displayName: deploy, publish - uid: host-and-deploy/iis/modules - - name: Troubleshoot - displayName: deploy, publish - uid: host-and-deploy/iis/troubleshoot - - name: Errors reference - displayName: deploy, publish - uid: host-and-deploy/azure-iis-errors-reference - - name: Transform web.config - displayName: deploy, publish - uid: host-and-deploy/iis/transform-webconfig - - name: Kestrel - uid: fundamentals/servers/kestrel - displayName: deploy, publish, server - - name: HTTP.sys - displayName: deploy, publish, server - uid: fundamentals/servers/httpsys - - name: Host in a Windows service - displayName: deploy, publish - uid: host-and-deploy/windows-service - - name: Host on Linux with Nginx - displayName: deploy, publish - uid: host-and-deploy/linux-nginx - - name: Host on Linux with Apache - displayName: deploy, publish - uid: host-and-deploy/linux-apache - - name: Host in Docker - displayName: deploy, publish - items: - - name: Overview - displayName: deploy, publish, docker - uid: host-and-deploy/docker/index - - name: Visual Studio Tools - displayName: deploy, publish, docker - uid: host-and-deploy/docker/visual-studio-tools-for-docker - - name: Publish to a Docker image - displayName: deploy, publish, docker - href: /visualstudio/containers/vs-azure-tools-docker-hosting-web-apps-in-docker - - name: Sample Docker images - displayName: deploy, publish, docker - href: https://github.com/dotnet/dotnet-docker/blob/master/samples/aspnetapp/README.md - - name: Proxy and load balancer configuration - displayName: deploy, publish - uid: host-and-deploy/proxy-load-balancer - - name: Host in a web farm - displayName: deploy, publish - uid: host-and-deploy/web-farm - - name: Visual Studio publish profiles - displayName: deploy, publish - uid: host-and-deploy/visual-studio-publish-profiles - - name: Visual Studio for Mac publish to folder - displayName: deploy, publish - href: /visualstudio/mac/publish-folder?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Directory structure - displayName: deploy, publish - uid: host-and-deploy/directory-structure - - name: Health checks - uid: host-and-deploy/health-checks - displayName: deploy, publish - - name: Razor Components/Blazor - items: - - name: Overview - uid: host-and-deploy/razor-components-blazor/index - - name: Blazor - uid: host-and-deploy/razor-components-blazor/blazor - - name: Razor Components - uid: host-and-deploy/razor-components-blazor/razor-components - - name: Configure the Linker - uid: host-and-deploy/razor-components-blazor/configure-linker -- name: Security and Identity - displayName: authentication, authorization - items: - - name: Overview - uid: security/index - - name: Authentication - items: - - name: Introduction to Identity - uid: security/authentication/identity - - name: Identity with SPA - uid: security/authentication/identity/spa - - name: Scaffold Identity - uid: security/authentication/scaffold-identity - - name: Add custom user data to Identity - uid: security/authentication/add-user-data - - name: Authentication samples - uid: security/authentication/samples - - name: Customize Identity - uid: security/authentication/customize_identity_model - - name: Community OSS authentication options - uid: security/authentication/community - - name: Configure Identity - uid: security/authentication/identity-configuration - - name: Configure Windows Authentication - uid: security/authentication/windowsauth - - name: Custom storage providers for Identity - uid: security/authentication/identity-custom-storage-providers - - name: Google, Facebook ... - items: - - name: Overview - uid: security/authentication/social/index - - name: Google authentication - uid: security/authentication/google-logins - - name: Facebook authentication - uid: security/authentication/facebook-logins - - name: Microsoft authentication - uid: security/authentication/microsoft-logins - - name: Twitter authentication - uid: security/authentication/twitter-logins - - name: Other providers - uid: security/authentication/otherlogins - - name: Additional claims - uid: security/authentication/social/additional-claims - - name: Policy schemes - uid: security/authentication/policyschemes - - name: WS-Federation authentication - uid: security/authentication/ws-federation - - name: Account confirmation and password recovery - uid: security/authentication/accconfirm - - name: Enable QR code generation in Identity - uid: security/authentication/identity-enable-qrcodes - - name: Two-factor authentication with SMS - uid: security/authentication/2fa - - name: Use Cookie Authentication without Identity - uid: security/authentication/cookie - - name: Azure Active Directory - items: - - name: Overview - uid: security/authentication/azure-active-directory/index - - name: Integrate Azure AD into a web app - href: https://azure.microsoft.com/documentation/samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/ - - name: Integrate Azure AD B2C into a web app - uid: security/authentication/azure-ad-b2c - - name: Integrate Azure AD B2C into a web API - uid: security/authentication/azure-ad-b2c-webapi - - name: Call a web API from WPF - href: https://azure.microsoft.com/documentation/samples/active-directory-dotnet-native-aspnetcore/ - - name: Call a web API in a web app using Azure AD - href: https://azure.microsoft.com/documentation/samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore/ - - name: Secure ASP.NET Core apps with IdentityServer4 - href: https://identityserver4.readthedocs.io/ - - name: Secure ASP.NET Core apps with Azure App Service authentication (Easy Auth) - href: /azure/app-service/overview-authentication-authorization?toc=/aspnet/core/toc.json&bc=/aspnet/core/breadcrumb/toc.json - - name: Individual user accounts - uid: security/authentication/individual - - name: Authorization - items: - - name: Overview - uid: security/authorization/introduction - - name: Create a web app with authorization - uid: security/authorization/secure-data - - name: Razor Pages authorization conventions - uid: security/authorization/razor-pages-authorization - - name: Simple authorization - uid: security/authorization/simple - - name: Role-based authorization - uid: security/authorization/roles - - name: Claims-based authorization - uid: security/authorization/claims - - name: Policy-based authorization - uid: security/authorization/policies - - name: Authorization policy providers - uid: security/authorization/iauthorizationpolicyprovider - - name: Dependency injection in requirement handlers - uid: security/authorization/dependencyinjection - - name: Resource-based authorization - uid: security/authorization/resourcebased - - name: View-based authorization - uid: security/authorization/views - - name: Limit identity by scheme - uid: security/authorization/limitingidentitybyscheme - - name: Data protection - displayName: encryption - items: - - name: Overview - uid: security/data-protection/introduction - - name: Data protection APIs - uid: security/data-protection/using-data-protection - - name: Consumer APIs - items: - - name: Overview - uid: security/data-protection/consumer-apis/overview - - name: Purpose strings - uid: security/data-protection/consumer-apis/purpose-strings - - name: Purpose hierarchy and multi-tenancy - uid: security/data-protection/consumer-apis/purpose-strings-multitenancy - - name: Hash passwords - uid: security/data-protection/consumer-apis/password-hashing - - name: Limit the lifetime of protected payloads - uid: security/data-protection/consumer-apis/limited-lifetime-payloads - - name: Unprotect payloads whose keys have been revoked - uid: security/data-protection/consumer-apis/dangerous-unprotect - - name: Configuration - items: - - name: Overview - uid: security/data-protection/configuration/index - - name: Configure data protection - uid: security/data-protection/configuration/overview - - name: Default settings - uid: security/data-protection/configuration/default-settings - - name: Machine-wide policy - uid: security/data-protection/configuration/machine-wide-policy - - name: Non-DI aware scenarios - uid: security/data-protection/configuration/non-di-scenarios - - name: Extensibility APIs - items: - - name: Overview - uid: security/data-protection/extensibility/index - - name: Core cryptography extensibility - uid: security/data-protection/extensibility/core-crypto - - name: Key management extensibility - uid: security/data-protection/extensibility/key-management - - name: Miscellaneous APIs - uid: security/data-protection/extensibility/misc-apis - - name: Implementation - items: - - name: Overview - uid: security/data-protection/implementation/index - - name: Authenticated encryption details - uid: security/data-protection/implementation/authenticated-encryption-details - - name: Subkey derivation and authenticated encryption - uid: security/data-protection/implementation/subkeyderivation - - name: Context headers - uid: security/data-protection/implementation/context-headers - - name: Key management - uid: security/data-protection/implementation/key-management - - name: Key storage providers - uid: security/data-protection/implementation/key-storage-providers - - name: Key encryption at rest - uid: security/data-protection/implementation/key-encryption-at-rest - - name: Key immutability and settings - uid: security/data-protection/implementation/key-immutability - - name: Key storage format - uid: security/data-protection/implementation/key-storage-format - - name: Ephemeral data protection providers - uid: security/data-protection/implementation/key-storage-ephemeral - - name: Compatibility - items: - - name: Overview - uid: security/data-protection/compatibility/index - - name: Replace machineKey in ASP.NET - uid: security/data-protection/compatibility/replacing-machinekey - - name: Protect secrets in development - displayName: password - uid: security/app-secrets - - name: Enforce HTTPS - uid: security/enforcing-ssl - - name: EU General Data Protection Regulation (GDPR) support - uid: security/gdpr - - name: Azure Key Vault Configuration Provider - uid: security/key-vault-configuration - - name: Anti-request forgery - uid: security/anti-request-forgery - - name: Prevent open redirect attacks - uid: security/preventing-open-redirects - - name: Prevent Cross-Site Scripting - uid: security/cross-site-scripting - - name: Enable Cross-Origin Requests (CORS) - uid: security/cors - - name: Share cookies among apps - uid: security/cookie-sharing - - name: IP safelist - uid: security/ip-safelist - - name: Application security - OWASP - href: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/DotNet_Security_Cheat_Sheet.md -- name: Performance - items: - - name: Overview - uid: performance/performance-best-practices - - name: Response caching - items: - - name: Overview - uid: performance/caching/response - - name: In-memory cache - uid: performance/caching/memory - - name: Distributed caching - uid: performance/caching/distributed - - name: Response caching middleware - uid: performance/caching/middleware - - name: Response compression - uid: performance/response-compression - - name: Diagnostic tools - uid: performance/diagnostic-tools - - name: Load and stress testing - uid: test/loadtests -- name: Globalization and localization - items: - - name: Overview - displayName: globalization, localization - uid: fundamentals/localization - - name: Portable Object localization - uid: fundamentals/portable-object-localization - - name: Troubleshoot - uid: fundamentals/troubleshoot-aspnet-core-localization -- name: Advanced - items: - - name: Write middleware - uid: fundamentals/middleware/write - - name: Request and response operations - displayName: middleware - uid: fundamentals/middleware/request-response - - name: URL rewriting - uid: fundamentals/url-rewriting - - name: File providers - uid: fundamentals/file-providers - - name: Request-feature interfaces - uid: fundamentals/request-features - - name: Access HttpContext - uid: fundamentals/httpcontext - - name: Change tokens - uid: fundamentals/change-tokens - - name: Open Web Interface for .NET (OWIN) - uid: fundamentals/owin - - name: Background tasks with hosted services - uid: fundamentals/host/hosted-services - - name: Hosting startup assemblies - uid: fundamentals/configuration/platform-specific-configuration - - name: Microsoft.AspNetCore.App metapackage - uid: fundamentals/metapackage-app - - name: Microsoft.AspNetCore.All metapackage - uid: fundamentals/metapackage - - name: Logging with LoggerMessage - uid: fundamentals/logging/loggermessage - - name: Use a file watcher - uid: tutorials/dotnet-watch - - name: Factory-based middleware - uid: fundamentals/middleware/extensibility - - name: Factory-based middleware with third-party container - uid: fundamentals/middleware/extensibility-third-party-container -- name: Migration - items: - - name: 2.2 to 3.0 - displayName: migrate, migration - uid: migration/22-to-30 - - name: 2.1 to 2.2 - displayName: migrate, migration - uid: migration/21-to-22 - - name: 2.0 to 2.1 - displayName: migrate, migration - uid: migration/20_21 - - name: 1.x to 2.0 - displayName: migrate, migration - items: - - name: Overview - uid: migration/1x-to-2x/index - - name: Authentication and Identity - uid: migration/1x-to-2x/identity-2x - - name: ASP.NET to ASP.NET Core - displayName: migrate, migration - items: - - name: Overview - uid: migration/proper-to-2x/index - - name: MVC - uid: migration/mvc - - name: Web API - uid: migration/webapi - - name: Configuration - uid: migration/configuration - - name: Authentication and Identity - uid: migration/identity - - name: ClaimsPrincipal.Current - uid: migration/claimsprincipal-current - - name: Membership to Identity - uid: migration/proper-to-2x/membership-to-core-identity - - name: HTTP modules to middleware - uid: migration/http-modules - - name: Logging (not ASP.NET Core) - displayName: migrate, migration - uid: migration/logging-nonaspnetcore -- name: API reference - href: /dotnet/api/?view=aspnetcore-2.2 -- name: Contribute - href: https://github.com/aspnet/Docs/blob/master/CONTRIBUTING.md diff --git a/aspnetcore/tutorials/first-odata-api.md b/aspnetcore/tutorials/first-odata-api.md new file mode 100644 index 000000000000..c8e5ae5a9bdd --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api.md @@ -0,0 +1,265 @@ +--- +title: "Tutorial: Build web APIs with OData support using ASP.NET Core" +author: FIVIL +description: This tutorial demonstrates how to add OData support to your existing ASP.NET Core web API. +#ms.author: riande +ms.custom: mvc +ms.date: 04/13/2019 +uid: tutorials/first-odata-api +--- + +# Tutorial: Build web APIs with OData support using ASP.NET Core + +By [FIVIL](https://github.com/fivil) + +This tutorial demonstrates how you can add OData Query Options support on top of your existing ASP.NET Core Web API. + +In this tutorial, you learn how to: + +> [!div class="checklist"] +> * Opening an existing project or solution. +> * Update the model class. +> * Register the required services. +> * Configure middleware. +> * Update the controller. +> * Query resources using OData. + +At the end, you have a web API that can Query, filter and sort data. + +## Overview + +The Open Data Protocol (OData) is a data access protocol for the web. OData provides a uniform way to query and manipulate data sets through CRUD operations (create, read, update, and delete). + +For this tutorial we use [to-do Web API](xref:tutorials/first-web-api) as an existing Web API. + +[!INCLUDE[](~/includes/net-core-prereqs-all-2.2.md)] + +## Opening an existing ASP.NET Core project + +# [Visual Studio](#tab/visual-studio) + +1. Go to **File** > **Open** > **Project/Solution**. +1. Find and select **TodoApi.csproj**, and click **Open**. +1. Visit the [NuGet Gallery: Microsoft.AspNetCore.OData](https://www.nuget.org/packages/Microsoft.AspNetCore.OData/) to determine the latest stable version of the .NET Core OData package. In the **Package Manager Console** window, navigate to the project root. Run the following command to install the .NET Core OData package: + + ```powershell + Install-Package Microsoft.AspNetCore.OData -Version {VERSION} + ``` + +# [Visual Studio Code](#tab/visual-studio-code) + +1. Open a command shell +1. Navigate to **TodoApi** root Directory inside your command shell +1. Run the following command: + + ```console + code . + ``` + + TodoApi is opened in Visual Studio Code. + +1. Click **Yes** when the *Required assets to build and debug are missing from 'TodoApi'. Add them?* notification appears. +1. Visit the [NuGet Gallery: Microsoft.AspNetCore.OData](https://www.nuget.org/packages/Microsoft.AspNetCore.OData/) to determine the latest stable version of the .NET Core OData package. Open **Integrated Terminal** and navigate to the project root. Run the following command to install the .NET Core OData package: + + ```console + dotnet add TodoApi.csproj package Microsoft.AspNetCore.OData -Version {VERSION} + ``` + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +1. Go to **File** > **Open**. +1. Find and select **TodoApi.csproj**, and click **Open**. +1. In the **Solution** pad, right-click the project's **Dependencies** node and select **Add Packages**. +1. Enter *Microsoft.AspNetCore.OData* in the search box, select the *Microsoft.AspNetCore.OData* package, and click **Add Package**. +1. Click the **Accept** button in the **License Acceptance** dialog. + +--- + +## Update the model class + +Open the model class *TodoItem.cs* under *Models* directory. + +The model class contains three properties: + + [!code-csharp[](first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs?name=OldProps)] + +However for better demonstration of OData capabilities, you should add below properties as well: + + [!code-csharp[](first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs?name=NewProps)] + +Finally your *TodoItem.cs* class should look like: + + [!code-csharp[](first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs)] + +> [!TIP] +> Since this tutorial uses **InMemoryDatabase** you dont need to add migrations, however if you want to use other type of database providers such as **SqlServer** you must migrate your database. for more information about migrations visit: @data/ef-mvc/migrations + +## Register the required services + +In ASP.NET Core you should register OData service inside [dependency injection (DI)](xref:fundamentals/dependency-injection) container. + +Update the `ConfigureServices` method in *Startup.cs* with the following highlighted code: + + [!code-csharp[](first-odata-api/samples/2.2/TodoApi/Startup.cs?highlight=6&name=snippet_dic)] + +You should also add the *Microsoft.AspNet.OData.Extensions* Directive to your *Startup.cs*: + +```csharp +using Microsoft.AspNet.OData.Extensions; +``` + +## Configure middleware + +OData can preform sorting, filtering, querying related data and etc. You can enable/disable each of these capabilities using a middleware. + +Update the `Configure` method in *Startup.cs* with the following highlighted code: + + [!code-csharp[](first-odata-api/samples/2.2/TodoApi/Startup.cs?highlight=17-21&name=snippet_configure)] + +Finally your *Startup.cs* class should look like: + +[!code-csharp[](first-odata-api/samples/2.2/TodoApi/Startup.cs?highlight=8,28,48-52&name=snippet_all)] + +## Update the controller + +Update *TodoController.cs* under *Controllers* directory, add `[EnableQuery()]` attribute: + +[!code-csharp[](first-odata-api/samples/2.2/TodoApi/Controllers/TodoController.cs?highlight=7,32-36&name=all)] + +> [!TIP] +> Returning `IQueryable` or `ActionResult` enables **OData** to translate your queries to **SQL** queries using *ef core* capabilities, you may also return other types such as `IEnumerable` which makes **OData** to preform queries inside your app. + +## Query resources using OData + +First post some data to your web API: + +> [!TIP] +> You can use Postman to post data, for more information visit: [How to use Postman](xref:tutorials/first-web-api#test-the-gettodoitems-method) + +![Postman with Post request](first-odata-api/_static/SendData.png) + +Open your Postman and send a Post request to `https://localhost:5001/api/todo` and include each of the items below **separately** in your request body. + +```json +{ + "name": "test OData", + "isComplete": false, + "Type": "work", + "priority": 1, + "DueDate": "2019-04-18 00:00:01" +}, +{ + "name": "test 2", + "isComplete": true, + "Type": "shopping", + "priority": 2, + "DueDate": "2019-04-18 08:00:01" +}, +{ + "name": "test 3", + "isComplete": true, + "Type": "work", + "priority": 1, + "DueDate": "2019-04-18 09:00:01" +}, +{ + "name": "test 4", + "isComplete": false, + "Type": "shopping", + "priority": 3, + "DueDate": "2019-04-18 12:00:01" +}, +{ + "name": "test 5", + "isComplete": false, + "Type": "work", + "priority": 2, + "DueDate": "2019-04-18 15:00:01" +} +``` + +Now you can use OData to query data, but let's test our API without OData query. + +Open your Postman and send a Get request to `https://localhost:5001/api/todo`: + +![Postman with Get request](first-odata-api/_static/getData.png) + +### $select + +The **$select** option specifies a subset of properties to include in the response body. For example, to get only the *name* and *isComplete* of each item, add `?$select=name,isComplete` at the end of your request path: + +![Postman with Get request and $select query](first-odata-api/_static/selectQuery.png) + +### $orderBy + +The **$orderBy** option sorts your data based on one or more properties. For example, to order your data based on *priority* of each item, add `?$orderBy=priority` at the end of your request path: + +![Postman with Get request and $orderBy query](first-odata-api/_static/orderby.png) + +> [!TIP] +> You can sort your data based on multiple properties, for example `?$orderBy=type,priority desc` first sorts items based on their *type* and then based on their *priority* in **descending** order. + +### $filter + +The **$filter** filters your data, based on a Boolean condition. For example, to get only the items with *priority* greater than 1, add `?$filter=priority gt 1` at the end of your request path: + +![Postman with Get request and $filter greater than query](first-odata-api/_static/filtergt.png) + +You can use the following Boolean conditions with OData $filter: + +|Condition | Description | Example | +|--- | ---- | ---- | +| eq | Equals to | $filter=priority et 1 | +| ne | Not equals to | $filter=priority ne 1 | +| gt | Greater than | $filter=priority gt 1 | +| ge | Greater than or equal | $filter=priority ge 1 | +| lt | Less than | $filter=priority lt 1 | +| le | Less than or equal | $filter=priority le 1 | +| and | Logical and | $filter=priority gt 1 and priority lt 10 | +| or | Logical or | $filter=priority gt 1 or priority lt 10| +| not | Logical negation | $filter=not endswith(name,'task') | + +You can also use string functions with OData $filter, for more information visit [OData URI Conventions'](https://www.odata.org/documentation/odata-version-2-0/uri-conventions/) *$filter* section. + +### $skip + +The **$skip** skips some of your data records. For example, to skip first two items, add `$skip=2` at the end of your request path: + +![Postman with Get request and $skip query](first-odata-api/_static/skip.png) + +Finally you can mix OData queries together to make a complex query: + +![Postman with Get request and complex query](first-odata-api/_static/complex.png) + +## Security concerns + +A malicious or naive client may be able to construct a query that takes a very long time to execute. In the worst case this can disrupt access to your service. + +The `[Queryable]` attribute is an action filter that parses, validates, and applies the query. The filter converts the query options into a LINQ expression. When the OData controller returns an **IQueryable** type, the **IQueryable** LINQ provider converts the LINQ expression into a query. Therefore, performance depends on the LINQ provider that is used, and also on the particular characteristics of your dataset or database schema. + +If you know that all clients are trusted (for example, in an enterprise environment), or if your dataset is small, query performance might not be an issue. Otherwise, you should consider the following recommendations. + +* Enable server-driven paging, to avoid returning a large data set in one query. + +[!code-csharp[](first-odata-api/samples/2.2/TodoApi/Controllers/TodoController2.cs?name=PageSizeOption)] + +With server-driven paging enabled, your endpoint returns only a limited number of records (for example 3), you can get more records using `$Skip` option. + +* Consider restricting $orderby to properties in a clustered index. Sorting large data without a clustered index is slow. + +[!code-csharp[](first-odata-api/samples/2.2/TodoApi/Controllers/TodoController2.cs?name=orderOption)] + +* Test your service with various queries and profile the DB. + +* You can prevent or allow more options using `[Queryable]` attribute filters, be sure to disallow all unnecessary demanding functionalities. + +## Additional resources + +[View or download sample code for this tutorial](https://github.com/aspnet/Docs/tree/master/aspnetcore/tutorials/first-odata-api/samples). See [how to download](xref:index#how-to-download-a-sample). + +For more information, see the following resources: + +* [OData official website](https://www.odata.org/) + +>[!div class="step-by-step"] +>[Previous](./first-web-api.md) \ No newline at end of file diff --git a/aspnetcore/tutorials/first-odata-api/_static/SendData.png b/aspnetcore/tutorials/first-odata-api/_static/SendData.png new file mode 100644 index 000000000000..0070deab8d0a Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/SendData.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/complex.png b/aspnetcore/tutorials/first-odata-api/_static/complex.png new file mode 100644 index 000000000000..e38855e6862a Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/complex.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/filtergt.png b/aspnetcore/tutorials/first-odata-api/_static/filtergt.png new file mode 100644 index 000000000000..9501f9899891 Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/filtergt.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/getData.png b/aspnetcore/tutorials/first-odata-api/_static/getData.png new file mode 100644 index 000000000000..e06a35091edc Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/getData.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/orderby.png b/aspnetcore/tutorials/first-odata-api/_static/orderby.png new file mode 100644 index 000000000000..c2b9e5f34dd1 Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/orderby.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/selectQuery.png b/aspnetcore/tutorials/first-odata-api/_static/selectQuery.png new file mode 100644 index 000000000000..cfec9751cb0d Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/selectQuery.png differ diff --git a/aspnetcore/tutorials/first-odata-api/_static/skip.png b/aspnetcore/tutorials/first-odata-api/_static/skip.png new file mode 100644 index 000000000000..3710d3df9bb6 Binary files /dev/null and b/aspnetcore/tutorials/first-odata-api/_static/skip.png differ diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController.cs new file mode 100644 index 000000000000..880b4c374c57 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController.cs @@ -0,0 +1,111 @@ +#define Primary +#if Primary +#region all +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TodoApi.Models; +using Microsoft.AspNet.OData; + +#region TodoController +namespace TodoApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TodoController : ControllerBase + { + private readonly TodoContext _context; + #endregion + + public TodoController(TodoContext context) + { + _context = context; + + if (_context.TodoItems.Count() == 0) + { + // Create a new TodoItem if collection is empty, + // which means you can't delete all TodoItems. + _context.TodoItems.Add(new TodoItem { Name = "Item1" }); + _context.SaveChanges(); + } + } + + #region snippet_GetAll + // GET: api/Todo + [HttpGet] + [EnableQuery()] + public ActionResult> GetTodoItems() + { + return _context.TodoItems; + } + + #region snippet_GetByID + // GET: api/Todo/5 + [HttpGet("{id}")] + public async Task> GetTodoItem(long id) + { + var todoItem = await _context.TodoItems.FindAsync(id); + + if (todoItem == null) + { + return NotFound(); + } + + return todoItem; + } + #endregion + #endregion + + #region snippet_Create + // POST: api/Todo + [HttpPost] + public async Task> PostTodoItem(TodoItem item) + { + _context.TodoItems.Add(item); + await _context.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item); + } + #endregion + + #region snippet_Update + // PUT: api/Todo/5 + [HttpPut("{id}")] + public async Task PutTodoItem(long id, TodoItem item) + { + if (id != item.Id) + { + return BadRequest(); + } + + _context.Entry(item).State = EntityState.Modified; + await _context.SaveChangesAsync(); + + return NoContent(); + } + #endregion + + #region snippet_Delete + // DELETE: api/Todo/5 + [HttpDelete("{id}")] + public async Task DeleteTodoItem(long id) + { + var todoItem = await _context.TodoItems.FindAsync(id); + + if (todoItem == null) + { + return NotFound(); + } + + _context.TodoItems.Remove(todoItem); + await _context.SaveChangesAsync(); + + return NoContent(); + } + #endregion + } +} +#endregion +#endif \ No newline at end of file diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController2.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController2.cs new file mode 100644 index 000000000000..79e180437076 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/TodoController2.cs @@ -0,0 +1,55 @@ +//#define NEVER +#if NEVER +// This controller is used only for documentation purposes. +#region snippet_todo1 +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TodoApi.Models; +using Microsoft.AspNet.OData; + +namespace TodoApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TodoController : ControllerBase + { + private readonly TodoContext _context; + + public TodoController(TodoContext context) + { + _context = context; + + if (_context.TodoItems.Count() == 0) + { + // Create a new TodoItem if collection is empty, + // which means you can't delete all TodoItems. + _context.TodoItems.Add(new TodoItem { Name = "Item1" }); + _context.SaveChanges(); + } + } + + +#region orderOption + [HttpGet] + [EnableQuery(AllowedOrderByProperties=nameof(TodoItem.Name))] + public ActionResult> GetTodoItemsOrderBy() + { + return _context.TodoItems; + } +#endregion + +#region PageSizeOption + [HttpGet] + [EnableQuery(PageSize = 3)] + public ActionResult> GetTodoItemsPageSize() + { + return _context.TodoItems; + } +#endregion + } +} +#endregion +#endif diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/ValuesController.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/ValuesController.cs new file mode 100644 index 000000000000..579608a93a40 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Controllers/ValuesController.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace TodoAp.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ValuesController : ControllerBase + { + // GET api/values + [HttpGet] + public ActionResult> Get() + { + return new string[] { "value1", "value2" }; + } + + // GET api/values/5 + [HttpGet("{id}")] + public ActionResult Get(int id) + { + return "value"; + } + + // POST api/values + [HttpPost] + public void Post([FromBody] string value) + { + } + + // PUT api/values/5 + [HttpPut("{id}")] + public void Put(int id, [FromBody] string value) + { + } + + // DELETE api/values/5 + [HttpDelete("{id}")] + public void Delete(int id) + { + } + } +} diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoContext.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoContext.cs new file mode 100644 index 000000000000..6e59e3637896 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace TodoApi.Models +{ + public class TodoContext : DbContext + { + public TodoContext(DbContextOptions options) + : base(options) + { + } + + public DbSet TodoItems { get; set; } + } +} \ No newline at end of file diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs new file mode 100644 index 000000000000..24dc1822ca28 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Models/TodoItem.cs @@ -0,0 +1,17 @@ +namespace TodoApi.Models +{ + public class TodoItem + { + #region OldProps + public long Id { get; set; } + public string Name { get; set; } + public bool IsComplete { get; set; } + #endregion + + #region NewProps + public string Type { get; set; } + public int priority { get; set; } + public System.DateTime DueDate { get; set; } + #endregion + } +} \ No newline at end of file diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Program.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Program.cs new file mode 100644 index 000000000000..f8eb8f2f6320 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace TodoApi +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup.cs new file mode 100644 index 000000000000..908c6fad69d0 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup.cs @@ -0,0 +1,61 @@ +#region snippet_all +// Unused usings removed +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNet.OData.Extensions; +using TodoApi.Models; + +namespace TodoApi +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the + //container. + #region snippet_dic + public void ConfigureServices(IServiceCollection services) + { + services.AddDbContext(opt => + opt.UseInMemoryDatabase("TodoList")); + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddOData(); + } + #endregion + // This method gets called by the runtime. Use this method to configure the HTTP + //request pipeline. + #region snippet_configure + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for + // production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseDefaultFiles(); + app.UseStaticFiles(); + app.UseHttpsRedirection(); + app.UseMvc(routeBuilder => + { + routeBuilder.EnableDependencyInjection(); + routeBuilder.Select().OrderBy().Filter(); + }); + } + #endregion + } +} +#endregion diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup1.cs b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup1.cs new file mode 100644 index 000000000000..9ed517805e90 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/Startup1.cs @@ -0,0 +1,61 @@ +#if This_is_a_copy_of_Startup_without_UseDefaultFiles_UseStaticFiles +#region snippet_all +// Unused usings removed +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNet.OData.Extensions; +using TodoApi.Models; + +namespace TodoApi +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the + //container. + public void ConfigureServices(IServiceCollection services) + { + services.AddDbContext(opt => + opt.UseInMemoryDatabase("TodoList")); + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddOData(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP + //request pipeline. +#region snippet_configure + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for + // production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseMvc(routeBuilder => + { + routeBuilder.EnableDependencyInjection(); + routeBuilder.Select().OrderBy().Filter(); + }); + } +#endregion + } +} +#endregion +#endif diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/TodoApi.csproj b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/TodoApi.csproj new file mode 100644 index 000000000000..114addfb7755 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/TodoApi.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp2.2 + InProcess + + + + + + + + diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.Development.json b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.Development.json new file mode 100644 index 000000000000..e203e9407e74 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.json b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.json new file mode 100644 index 000000000000..def9159a7d94 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/index.html b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/index.html new file mode 100644 index 000000000000..6d7062bb3c84 --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/index.html @@ -0,0 +1,68 @@ + + + + + To-do CRUD + + + +

To-do CRUD

+

Add

+
+ + +
+ +
+

Edit

+
+ + + + + +
+
+ +

+ + + + + + + + + +
Is CompleteName
+ + + + + diff --git a/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/site.js b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/site.js new file mode 100644 index 000000000000..bbe456f6454d --- /dev/null +++ b/aspnetcore/tutorials/first-odata-api/samples/2.2/TodoApi/wwwroot/site.js @@ -0,0 +1,144 @@ +// +const uri = "api/todo"; +let todos = null; +function getCount(data) { + const el = $("#counter"); + let name = "to-do"; + if (data) { + if (data > 1) { + name = "to-dos"; + } + el.text(data + " " + name); + } else { + el.text("No " + name); + } +} + +// +$(document).ready(function() { + getData(); +}); + +function getData() { + $.ajax({ + type: "GET", + url: uri, + cache: false, + success: function(data) { + const tBody = $("#todos"); + + $(tBody).empty(); + + getCount(data.length); + + $.each(data, function(key, item) { + const tr = $("") + .append( + $("").append( + $("", { + type: "checkbox", + disabled: true, + checked: item.isComplete + }) + ) + ) + .append($("").text(item.name)) + .append( + $("").append( + $("").on("click", function() { + editItem(item.id); + }) + ) + ) + .append( + $("").append( + $("").on("click", function() { + deleteItem(item.id); + }) + ) + ); + + tr.appendTo(tBody); + }); + + todos = data; + } + }); +} +// + +// +function addItem() { + const item = { + name: $("#add-name").val(), + isComplete: false + }; + + $.ajax({ + type: "POST", + accepts: "application/json", + url: uri, + contentType: "application/json", + data: JSON.stringify(item), + error: function(jqXHR, textStatus, errorThrown) { + alert("Something went wrong!"); + }, + success: function(result) { + getData(); + $("#add-name").val(""); + } + }); +} +// + +function deleteItem(id) { + // + $.ajax({ + url: uri + "/" + id, + type: "DELETE", + success: function(result) { + getData(); + } + }); + // +} + +function editItem(id) { + $.each(todos, function(key, item) { + if (item.id === id) { + $("#edit-name").val(item.name); + $("#edit-id").val(item.id); + $("#edit-isComplete")[0].checked = item.isComplete; + } + }); + $("#spoiler").css({ display: "block" }); +} + +$(".my-form").on("submit", function() { + const item = { + name: $("#edit-name").val(), + isComplete: $("#edit-isComplete").is(":checked"), + id: $("#edit-id").val() + }; + + // + $.ajax({ + url: uri + "/" + $("#edit-id").val(), + type: "PUT", + accepts: "application/json", + contentType: "application/json", + data: JSON.stringify(item), + success: function(result) { + getData(); + } + }); + // + + closeInput(); + return false; +}); + +function closeInput() { + $("#spoiler").css({ display: "none" }); +} +//