├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Lab Resources ├── Build Managed Solution.json ├── Deploy to Production.json ├── Export From Dev.json ├── Hands-on with Power Apps and Azure.pptx ├── Hands-on with PowerApps and Azure-Lab Document.docx ├── Hands-on with PowerApps and Azure-Lab Document.pdf ├── Product.svg ├── Products_list_icon.jpg └── Swagger.json ├── README.md ├── SECURITY.md └── src ├── ProductListAPI.sln └── ProductListAPI ├── App_Start ├── GenericStorage.cs ├── SwaggerConfig.cs └── WebApiConfig.cs ├── Controllers └── ProductsController.cs ├── Global.asax ├── Global.asax.cs ├── Models └── Product.cs ├── ProductListAPI.csproj ├── ProductListAPI.csproj.user ├── Properties └── AssemblyInfo.cs ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── apiapp.json └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /src/.vs/ProductListAPI 6 | /src/packages 7 | /src/ProductListAPI/bin 8 | /src/ProductListAPI/obj 9 | /src/ProductListAPI/Properties/PublishProfiles 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /Lab Resources/Build Managed Solution.json: -------------------------------------------------------------------------------- 1 | {"options":[{"enabled":false,"definition":{"id":"5d58cc01-7c75-450c-be18-a388ddb129ec"},"inputs":{"branchFilters":"[\"+refs/heads/*\"]","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"a9db38f9-9fdc-478c-b0f9-464221e58316"},"inputs":{"workItemType":"Bug","assignToRequestor":"true","additionalFields":"{}"}}],"variables":{"SolutionName":{"value":"AssetManagement"},"system.debug":{"value":"false","allowOverride":true}},"properties":{},"tags":[],"_links":{"self":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/Definitions/7?revision=3"},"web":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_build/definition?definitionId=7"},"editor":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_build/designer?id=7&_a=edit-build-definition"},"badge":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/status/7"}},"jobAuthorizationScope":1,"jobTimeoutInMinutes":60,"jobCancelTimeoutInMinutes":5,"process":{"phases":[{"steps":[{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Tool Installer ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"20f1587d-7424-466b-9208-baa837bb020f","versionSpec":"0.*","definitionType":"task"},"inputs":{"XrmOnlineManagementApiVersion":"1.1.0.9053","XrmToolingCrmConnectorVersion":"3.3.0.834","XrmToolingPackageDeploymentVersion":"3.3.0.833","MicrosoftPowerAppsCheckerVersion":"1.0.2","CrmSdkCoreToolsVersion":"9.0.3.1"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Pack Solution ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"bfde445b-beda-4a1d-8459-a1869f3f63af","versionSpec":"0.*","definitionType":"task"},"inputs":{"SolutionSourceFolder":"CdsConfig","SolutionOutputFile":"$(Build.ArtifactStagingDirectory)\\$(SolutionName).zip","SolutionType":"Unmanaged"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Import Solution ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"89fa86fd-4b50-4d77-8c5f-a876e7a3e2dd","versionSpec":"0.*","definitionType":"task"},"inputs":{"PowerAppsEnvironment":"f0570fb5-349f-4762-9eda-35dfccebd127","SolutionInputFile":"$(Build.ArtifactStagingDirectory)\\$(SolutionName).zip","ConvertToManaged":"false","HoldingSolution":"false","OverwriteUnmanagedCustomizations":"false","PublishWorkflows":"false","SkipProductUpdateDependencies":"false","AsyncOperation":"true"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Export Solution ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"c8b391bf-3134-4c03-9965-3af46ce54a4d","versionSpec":"0.*","definitionType":"task"},"inputs":{"PowerAppsEnvironment":"f0570fb5-349f-4762-9eda-35dfccebd127","SolutionName":"$(SolutionName)","SolutionOutputFile":"$(Build.ArtifactStagingDirectory)\\$(SolutionName)_managed.zip","Managed":"true","ExportAutoNumberingSettings":"false","ExportCalendarSettings":"false","ExportCustomizationSettings":"false","ExportEmailTrackingSettings":"false","ExportGeneralSettings":"false","ExportIsvConfig":"false","ExportMarketingSettings":"false","ExportOutlookSynchronizationSettings":"false","ExportRelationshipRoles":"false","ExportSales":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Publish Pipeline Artifact","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"ecdc45f6-832d-4ad9-b52b-ee49e94659be","versionSpec":"1.*","definitionType":"task"},"inputs":{"path":"$(Pipeline.Workspace)","artifactName":"drop","artifactType":"pipeline","fileSharePath":"","parallel":"false","parallelCount":"8"}}],"name":"Agent job 1","refName":"Job_1","condition":"succeeded()","target":{"executionOptions":{"type":0},"allowScriptsAuthAccessOption":false,"type":1},"jobAuthorizationScope":1}],"target":{"agentSpecification":{"identifier":"vs2017-win2016"}},"type":1},"repository":{"properties":{"cleanOptions":"0","labelSources":"0","labelSourcesFormat":"$(build.buildNumber)","reportBuildStatus":"true","gitLfsSupport":"false","skipSyncSource":"false","checkoutNestedSubmodules":"false","fetchDepth":"0"},"id":"c45bae99-de15-4ff8-8716-792433bcc295","type":"TfsGit","name":"Assets-Demo","url":"https://dev.azure.com/shandemo/Assets-Demo/_git/Assets-Demo","defaultBranch":"refs/heads/master","clean":"false","checkoutSubmodules":false},"processParameters":{},"quality":1,"authoredBy":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"},"drafts":[],"queue":{"_links":{"self":{"href":"https://dev.azure.com/shandemo/_apis/build/Queues/24"}},"id":24,"name":"Azure Pipelines","url":"https://dev.azure.com/shandemo/_apis/build/Queues/24","pool":{"id":9,"name":"Azure Pipelines","isHosted":true}},"id":7,"name":"Build Managed Solution","url":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/Definitions/7?revision=3","uri":"vstfs:///Build/Definition/7","path":"\\","type":2,"queueStatus":0,"revision":3,"createdDate":"2019-10-23T17:26:54.683Z","project":{"id":"005fdef2-7157-447c-a363-f9f4148741eb","name":"Assets-Demo","description":"Azure DevOps demo for Dynamics 365 CDS","url":"https://dev.azure.com/shandemo/_apis/projects/005fdef2-7157-447c-a363-f9f4148741eb","state":1,"revision":20,"visibility":0,"lastUpdateTime":"2019-02-07T19:32:01.537Z"}} -------------------------------------------------------------------------------- /Lab Resources/Deploy to Production.json: -------------------------------------------------------------------------------- 1 | {"source":2,"revision":5,"description":null,"createdBy":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"},"createdOn":"2019-10-14T19:48:53.227Z","modifiedBy":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"},"modifiedOn":"2019-10-14T19:58:12.250Z","isDeleted":false,"lastRelease":{"id":23,"name":"Release-3","artifacts":[],"_links":{},"description":"","releaseDefinition":{"id":4,"projectReference":null,"_links":{}},"createdOn":"2019-10-14T19:58:15.680Z","createdBy":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"variables":{"SolutionName":{"value":"AssetManagement"}},"variableGroups":[],"environments":[{"id":5,"name":"Stage 1","rank":1,"owner":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"},"variables":{},"variableGroups":[],"preDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":13}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":1}},"deployStep":{"id":14},"postDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":15}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":2}},"deployPhases":[{"deploymentInput":{"parallelExecution":{"parallelExecutionType":0},"agentSpecification":{"identifier":"vs2017-win2016"},"skipArtifactsDownload":false,"artifactsDownloadInput":{"downloadInputs":[]},"queueId":24,"demands":[],"enableAccessToken":false,"timeoutInMinutes":0,"jobCancelTimeoutInMinutes":1,"condition":"succeeded()","overrideInputs":{}},"rank":1,"phaseType":1,"name":"Agent job","refName":null,"workflowTasks":[{"environment":{},"taskId":"20f1587d-7424-466b-9208-baa837bb020f","version":"0.*","name":"PowerApps Tool Installer ","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"XrmOnlineManagementApiVersion":"1.1.0.9053","XrmToolingCrmConnectorVersion":"3.3.0.834","XrmToolingPackageDeploymentVersion":"3.3.0.833","MicrosoftPowerAppsCheckerVersion":"1.0.2","CrmSdkCoreToolsVersion":"9.0.3.1"}},{"environment":{},"taskId":"d9bafed4-0b18-4f58-968d-86655b4d2ce9","version":"2.*","name":"Command Line Script","refName":"","enabled":false,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"script":"echo Write your commands here\n\ndir /s\n","workingDirectory":"","failOnStderr":"false"}},{"environment":{},"taskId":"89fa86fd-4b50-4d77-8c5f-a876e7a3e2dd","version":"0.*","name":"PowerApps Import Solution ","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"PowerAppsEnvironment":"9432d45d-1f69-42d2-abc9-beee4d378a7d","SolutionInputFile":"$(System.DefaultWorkingDirectory)/drop/drop/a/$(SolutionName)_managed.zip","ConvertToManaged":"false","HoldingSolution":"false","OverwriteUnmanagedCustomizations":"false","PublishWorkflows":"false","SkipProductUpdateDependencies":"false"}}]}],"environmentOptions":{"emailNotificationType":"OnlyOnFailure","emailRecipients":"release.environment.owner;release.creator","skipArtifactsDownload":false,"timeoutInMinutes":0,"enableAccessToken":false,"publishDeploymentStatus":true,"badgeEnabled":false,"autoLinkWorkItems":false,"pullRequestDeploymentEnabled":false},"demands":[],"conditions":[{"name":"ReleaseStarted","conditionType":1,"value":""}],"executionPolicy":{"concurrencyCount":1,"queueDepthCount":0},"schedules":[],"currentRelease":{"id":23,"url":"https://vsrm.dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/Release/releases/23","_links":{}},"retentionPolicy":{"daysToKeep":30,"releasesToKeep":3,"retainBuild":true},"processParameters":{},"properties":{"BoardsEnvironmentType":{"$type":"System.String","$value":"unmapped"},"LinkBoardsWorkItems":{"$type":"System.String","$value":"False"}},"preDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"postDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"environmentTriggers":[],"badgeUrl":"https://vsrm.dev.azure.com/shandemo/_apis/public/Release/badge/005fdef2-7157-447c-a363-f9f4148741eb/4/5"}],"artifacts":[{"sourceId":"005fdef2-7157-447c-a363-f9f4148741eb:7","type":"Build","alias":"drop","definitionReference":{"artifactSourceDefinitionUrl":{"id":"https://dev.azure.com/shandemo/_permalink/_build/index?collectionId=a882f0f1-f3fb-4129-ac9a-d4b7956ca289&projectId=005fdef2-7157-447c-a363-f9f4148741eb&definitionId=7","name":""},"defaultVersionBranch":{"id":"","name":""},"defaultVersionSpecific":{"id":"","name":""},"defaultVersionTags":{"id":"","name":""},"defaultVersionType":{"id":"latestType","name":"Latest"},"definition":{"id":"7","name":"Build Managed Solution"},"definitions":{"id":"","name":""},"IsMultiDefinitionType":{"id":"False","name":"False"},"project":{"id":"005fdef2-7157-447c-a363-f9f4148741eb","name":"Assets-Demo"},"repository":{"id":"","name":""}},"isPrimary":true,"isRetained":false}],"triggers":[],"releaseNameFormat":"Release-$(rev:r)","tags":[],"properties":{"DefinitionCreationSource":{"$type":"System.String","$value":"ReleaseNew"},"IntegrateBoardsWorkItems":{"$type":"System.String","$value":"False"},"IntegrateJiraWorkItems":{"$type":"System.String","$value":"false"}},"id":4,"name":"Deploy to Production","path":"\\","projectReference":null,"url":"https://vsrm.dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/Release/definitions/4","_links":{"self":{"href":"https://vsrm.dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/Release/definitions/4"},"web":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_release?definitionId=4"}}} -------------------------------------------------------------------------------- /Lab Resources/Export From Dev.json: -------------------------------------------------------------------------------- 1 | {"options":[{"enabled":false,"definition":{"id":"5d58cc01-7c75-450c-be18-a388ddb129ec"},"inputs":{"branchFilters":"[\"+refs/heads/*\"]","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"a9db38f9-9fdc-478c-b0f9-464221e58316"},"inputs":{"workItemType":"Bug","assignToRequestor":"true","additionalFields":"{}"}}],"variables":{"SolutionName":{"value":"AssetManagement"},"system.debug":{"value":"false","allowOverride":true}},"properties":{},"tags":[],"_links":{"self":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/Definitions/9?revision=2"},"web":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_build/definition?definitionId=9"},"editor":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_build/designer?id=9&_a=edit-build-definition"},"badge":{"href":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/status/9"}},"jobAuthorizationScope":1,"jobTimeoutInMinutes":60,"jobCancelTimeoutInMinutes":5,"process":{"phases":[{"steps":[{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Tool Installer ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"20f1587d-7424-466b-9208-baa837bb020f","versionSpec":"0.*","definitionType":"task"},"inputs":{"XrmOnlineManagementApiVersion":"1.1.0.9053","XrmToolingCrmConnectorVersion":"3.3.0.834","XrmToolingPackageDeploymentVersion":"3.3.0.833","MicrosoftPowerAppsCheckerVersion":"1.0.2","CrmSdkCoreToolsVersion":"9.0.3.1"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Export Solution ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"c8b391bf-3134-4c03-9965-3af46ce54a4d","versionSpec":"0.*","definitionType":"task"},"inputs":{"PowerAppsEnvironment":"86248b74-fa5d-4574-a3ad-08a3e3f53a1c","SolutionName":"$(SolutionName)","SolutionOutputFile":"$(Build.ArtifactStagingDirectory)\\$(SolutionName).zip","Managed":"false","ExportAutoNumberingSettings":"false","ExportCalendarSettings":"false","ExportCustomizationSettings":"false","ExportEmailTrackingSettings":"false","ExportGeneralSettings":"false","ExportIsvConfig":"false","ExportMarketingSettings":"false","ExportOutlookSynchronizationSettings":"false","ExportRelationshipRoles":"false","ExportSales":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerApps Unpack Solution ","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"9d571c2a-157d-4987-8e52-842e741a9256","versionSpec":"0.*","definitionType":"task"},"inputs":{"SolutionInputFile":"$(Build.ArtifactStagingDirectory)\\$(SolutionName).zip","SolutionTargetFolder":"CdsConfig","SolutionType":"Unmanaged","OverwriteFiles":"true"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Command Line Script","timeoutInMinutes":0,"condition":"succeeded()","task":{"id":"d9bafed4-0b18-4f58-968d-86655b4d2ce9","versionSpec":"2.*","definitionType":"task"},"inputs":{"script":"echo commit all changes\ngit config user.email \"admin@shandemo.onmicrosoft.com\"\ngit config user.name \"Automated Build\"\ngit checkout master\ngit add --all\ngit commit -m \"solution init\"\necho push code to new repo\ngit -c http.extraheader=\"AUTHORIZATION: bearer $(System.AccessToken)\" push origin master","workingDirectory":"","failOnStderr":"false"}}],"name":"Agent job 1","refName":"Job_1","condition":"succeeded()","target":{"executionOptions":{"type":0},"allowScriptsAuthAccessOption":true,"type":1},"jobAuthorizationScope":1}],"target":{"agentSpecification":{"identifier":"vs2017-win2016"}},"type":1},"repository":{"properties":{"cleanOptions":"0","labelSources":"0","labelSourcesFormat":"$(build.buildNumber)","reportBuildStatus":"true","gitLfsSupport":"false","skipSyncSource":"false","checkoutNestedSubmodules":"false","fetchDepth":"0"},"id":"c45bae99-de15-4ff8-8716-792433bcc295","type":"TfsGit","name":"Assets-Demo","url":"https://dev.azure.com/shandemo/Assets-Demo/_git/Assets-Demo","defaultBranch":"refs/heads/master","clean":"false","checkoutSubmodules":false},"processParameters":{},"quality":1,"authoredBy":{"displayName":"Shan McArthur","url":"https://spsprodcus1.vssps.visualstudio.com/A28f9aaa1-72fe-494d-8879-af0ab6f31dd1/_apis/Identities/ebef9cf4-497d-6997-9524-f7e2ac32df22","_links":{"avatar":{"href":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"}},"id":"ebef9cf4-497d-6997-9524-f7e2ac32df22","uniqueName":"admin@shandemo.onmicrosoft.com","imageUrl":"https://dev.azure.com/shandemo/_apis/GraphProfile/MemberAvatars/aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy","descriptor":"aad.ZWJlZjljZjQtNDk3ZC03OTk3LTk1MjQtZjdlMmFjMzJkZjIy"},"drafts":[],"queue":{"_links":{"self":{"href":"https://dev.azure.com/shandemo/_apis/build/Queues/24"}},"id":24,"name":"Azure Pipelines","url":"https://dev.azure.com/shandemo/_apis/build/Queues/24","pool":{"id":9,"name":"Azure Pipelines","isHosted":true}},"id":9,"name":"Export From Dev","url":"https://dev.azure.com/shandemo/005fdef2-7157-447c-a363-f9f4148741eb/_apis/build/Definitions/9?revision=2","uri":"vstfs:///Build/Definition/9","path":"\\","type":2,"queueStatus":0,"revision":2,"createdDate":"2019-10-14T20:29:47.753Z","project":{"id":"005fdef2-7157-447c-a363-f9f4148741eb","name":"Assets-Demo","description":"Azure DevOps demo for Dynamics 365 CDS","url":"https://dev.azure.com/shandemo/_apis/projects/005fdef2-7157-447c-a363-f9f4148741eb","state":1,"revision":20,"visibility":0,"lastUpdateTime":"2019-02-07T19:32:01.537Z"}} -------------------------------------------------------------------------------- /Lab Resources/Hands-on with Power Apps and Azure.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/PowerApps-Azure-Lab/2af6a6bbaa235f1e3aec38743703a6eae9dda665/Lab Resources/Hands-on with Power Apps and Azure.pptx -------------------------------------------------------------------------------- /Lab Resources/Hands-on with PowerApps and Azure-Lab Document.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/PowerApps-Azure-Lab/2af6a6bbaa235f1e3aec38743703a6eae9dda665/Lab Resources/Hands-on with PowerApps and Azure-Lab Document.docx -------------------------------------------------------------------------------- /Lab Resources/Hands-on with PowerApps and Azure-Lab Document.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/PowerApps-Azure-Lab/2af6a6bbaa235f1e3aec38743703a6eae9dda665/Lab Resources/Hands-on with PowerApps and Azure-Lab Document.pdf -------------------------------------------------------------------------------- /Lab Resources/Product.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Lab Resources/Products_list_icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/PowerApps-Azure-Lab/2af6a6bbaa235f1e3aec38743703a6eae9dda665/Lab Resources/Products_list_icon.jpg -------------------------------------------------------------------------------- /Lab Resources/Swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "version": "v1", 5 | "title": "ProductListAPI" 6 | }, 7 | "host": "UseYourWebAppName.azurewebsites.net", 8 | "schemes": [ "http" ], 9 | "paths": { 10 | "/products": { 11 | "get": { 12 | "tags": [ "Products" ], 13 | "summary": "Gets the list of products", 14 | "description": "This operation returns the list of products along with their current stock", 15 | "operationId": "GetAllProducts", 16 | "consumes": [], 17 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 18 | "responses": { 19 | "200": { 20 | "description": "OK", 21 | "schema": { 22 | "type": "array", 23 | "items": { "$ref": "#/definitions/Product" } 24 | } 25 | } 26 | } 27 | }, 28 | "post": { 29 | "tags": [ "Products" ], 30 | "summary": "Creates a new product", 31 | "description": "This operation creates a new product along with it's current stock", 32 | "operationId": "CreateProduct", 33 | "consumes": [ "application/json", "text/json", "application/xml", "text/xml", "application/x-www-form-urlencoded" ], 34 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 35 | "parameters": [ 36 | { 37 | "name": "product", 38 | "in": "body", 39 | "description": "The new product", 40 | "required": true, 41 | "schema": { "$ref": "#/definitions/Product" } 42 | } 43 | ], 44 | "responses": { 45 | "200": { 46 | "description": "OK", 47 | "schema": { "$ref": "#/definitions/Product" } 48 | }, 49 | "201": { 50 | "description": "Created", 51 | "schema": { "$ref": "#/definitions/Product" } 52 | } 53 | } 54 | }, 55 | "delete": { 56 | "tags": [ "Products" ], 57 | "summary": "Deletes all products", 58 | "description": "This operation deletes all the products from the inventory", 59 | "operationId": "DeleteAllProducts", 60 | "consumes": [], 61 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 62 | "responses": { 63 | "200": { 64 | "description": "OK", 65 | "schema": { "type": "boolean" } 66 | } 67 | } 68 | } 69 | }, 70 | "/products/{id}": { 71 | "get": { 72 | "tags": [ "Products" ], 73 | "summary": "Gets a specific product", 74 | "description": "This operation returns the specific product based on the ID along with it's current stock", 75 | "operationId": "GetProductById", 76 | "consumes": [], 77 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 78 | "parameters": [ 79 | { 80 | "name": "id", 81 | "in": "path", 82 | "description": "Identifier for the product", 83 | "required": true, 84 | "type": "integer", 85 | "format": "int32" 86 | } 87 | ], 88 | "responses": { 89 | "200": { 90 | "description": "OK", 91 | "schema": { "$ref": "#/definitions/Product" } 92 | }, 93 | "404": { 94 | "description": "Product not found", 95 | "schema": { "$ref": "#/definitions/Product" } 96 | } 97 | } 98 | }, 99 | "delete": { 100 | "tags": [ "Products" ], 101 | "summary": "Deletes a product", 102 | "description": "This operation deletes the product from the inventory", 103 | "operationId": "DeleteProductById", 104 | "consumes": [], 105 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 106 | "parameters": [ 107 | { 108 | "name": "id", 109 | "in": "path", 110 | "description": "Identifier of the product to be deleted", 111 | "required": true, 112 | "type": "integer", 113 | "format": "int32" 114 | } 115 | ], 116 | "responses": { 117 | "200": { 118 | "description": "OK", 119 | "schema": { "type": "boolean" } 120 | }, 121 | "404": { 122 | "description": "Product not found", 123 | "schema": { "type": "boolean" } 124 | } 125 | } 126 | } 127 | }, 128 | "/products/{ProductId}": { 129 | "post": { 130 | "tags": [ "Products" ], 131 | "summary": "Update a specific product", 132 | "description": "This operation updates the specific product based on the ID along with it's current stock", 133 | "operationId": "UpdateProduct", 134 | "consumes": [ "application/json", "text/json", "application/xml", "text/xml", "application/x-www-form-urlencoded" ], 135 | "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], 136 | "parameters": [ 137 | { 138 | "name": "product", 139 | "in": "body", 140 | "description": "Product to update inluding ID", 141 | "required": true, 142 | "schema": { "$ref": "#/definitions/Product" } 143 | }, 144 | { 145 | "name": "ProductId", 146 | "in": "path", 147 | "description": "Product Id to update", 148 | "required": true, 149 | "type": "integer", 150 | "format": "int32" 151 | } 152 | ], 153 | "responses": { 154 | "200": { 155 | "description": "OK", 156 | "schema": { "type": "boolean" } 157 | }, 158 | "404": { 159 | "description": "Product not found", 160 | "schema": { "type": "boolean" } 161 | } 162 | } 163 | } 164 | } 165 | }, 166 | "definitions": { 167 | "Product": { 168 | "description": "Product", 169 | "type": "object", 170 | "properties": { 171 | "Id": { 172 | "format": "int32", 173 | "description": "The ID of the product.", 174 | "type": "integer" 175 | }, 176 | "Name": { 177 | "description": "Product name.", 178 | "type": "string" 179 | }, 180 | "CurrentInventory": { 181 | "format": "int32", 182 | "description": "Current Inventory", 183 | "type": "integer" 184 | }, 185 | "Unit": { 186 | "description": "The Product's unit.", 187 | "type": "string" 188 | } 189 | } 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Power Apps & Azure Lab 2 | 3 | 10 | This repository contains a source code for an API App and a lab manual for demonstrating a simple example for integrating Power Apps Canvas apps with an API app hosted on an Azure Web App using a custom-connector. This scenario can be used to unlock the potential of untapped assets within an enterprise (legacy APIs, data sources, processes etc..) 11 | 12 | ## Lab Overview & Objective 13 | 14 | ### Overview 15 | 16 | Most enterprises have a majority of their core business data trapped in several silos (legacy databases & apps - Systems of Records). It is essential for digital transformation to break those data silos and make the information trapped in those systems available to employees and business teams as needed. 17 | 18 | It is also important to modernize the user experience of the enterprise apps in order to drive productivity. 19 | 20 | [Microsoft Power Apps](https://docs.microsoft.com/en-us/powerapps/powerapps-overview) along with [Azure](https://docs.microsoft.com/en-us/azure/guides/developer/azure-developer-guide) could be an effective way to bridge this gap, by enabling an RESTful API layer powered by Azure which could encapsulate and standardize the enterprise data for use with apps + Power Apps as the rapid application development User interface where business apps can be built with agility and in collaboration with the business. 21 | 22 | ### Objectives 23 | 24 | This lab has two key objectives: 25 | - To demonstrate how Power Apps platform can help unlock the potential of untapped assets within an Enterprise ( legacy APIs, data sources, processes) with a low-code / no code approach. 26 | - Learn to create a cross-platform application user experience using Microsoft Power Apps to consume these RESTful APIs through custom connectors 27 | - `[Optional/Bonus Lab]` Learn how to enable Application Lifecycle Management (ALM) and setup Azure DevOps for the application 28 | 29 | ## Prerequisites 30 | 31 | The lab requires: 32 | - Visual Studio 2017 or 2019 to compile the code and publish to Azure 33 | - Access to an Azure Subscription to create an API app to serve as the RESTful API 34 | - Access to a Power Apps environment with Maker permission to create apps and custom connectors 35 | 36 | ## Lab Manual 37 | 38 | Refer to the [Lab Document](https://github.com/microsoft/PowerApps-Azure-Lab/blob/master/Lab%20Resources/Hands-on%20with%20PowerApps%20and%20Azure-Lab%20Document.pdf) for the step-by-step guidance for this lab. 39 | 40 | ## Key concepts 41 | 42 | - [Microsoft Power Apps](https://docs.microsoft.com/en-us/powerapps/powerapps-overview) 43 | - [Custom Connectors](https://docs.microsoft.com/en-us/connectors/custom-connectors/) 44 | - [ALM for Power Apps](https://docs.microsoft.com/en-us/power-platform/admin/automate-alm) 45 | 46 | ## Contents 47 | 48 | | File/folder | Description | 49 | |-------------------|--------------------------------------------| 50 | | `Lab Resources` | Lab Resources including Lab Manual. | 51 | | `src` | Source code for the API App. | 52 | | `README.md` | This README file. | 53 | | `LICENSE` | The license for the lab. | 54 | 55 | 56 | ## Contributing 57 | 58 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 59 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 60 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 61 | 62 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 63 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 64 | provided by the bot. You will only need to do this once across all repos using our CLA. 65 | 66 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 67 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 68 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 69 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/ProductListAPI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29424.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProductListAPI", "ProductListAPI\ProductListAPI.csproj", "{12B6DD58-3A99-4DDE-9013-3720DEC683F4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {12B6DD58-3A99-4DDE-9013-3720DEC683F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {12B6DD58-3A99-4DDE-9013-3720DEC683F4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {12B6DD58-3A99-4DDE-9013-3720DEC683F4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {12B6DD58-3A99-4DDE-9013-3720DEC683F4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C1F00C5E-7405-4B1B-9034-14A365D850BB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/ProductListAPI/App_Start/GenericStorage.cs: -------------------------------------------------------------------------------- 1 | using ProductListAPI.Models; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace ProductListAPI 12 | { 13 | internal class GenericStorage 14 | { 15 | private string _filePath; 16 | 17 | public GenericStorage() 18 | { 19 | var webAppsHome = Environment.GetEnvironmentVariable("HOME")?.ToString(); 20 | if (String.IsNullOrEmpty(webAppsHome)) 21 | { 22 | _filePath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath) + "\\"; 23 | } 24 | else 25 | { 26 | _filePath = webAppsHome + "\\site\\wwwroot\\"; 27 | } 28 | } 29 | 30 | public void Save(IEnumerable target, string filename) 31 | { 32 | var json = JsonConvert.SerializeObject(target); 33 | File.WriteAllText(_filePath + filename, json); 34 | } 35 | 36 | public IEnumerable Get(string filename) 37 | { 38 | var records = String.Empty; 39 | if (File.Exists(_filePath + filename)) 40 | { 41 | records = File.ReadAllText(_filePath + filename); 42 | } 43 | 44 | var Products = JsonConvert.DeserializeObject(records); 45 | return Products; 46 | } 47 | 48 | public void Delete(string filename) 49 | { 50 | File.Delete(filename); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ProductListAPI/App_Start/SwaggerConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using System.Web.Http.Description; 3 | using Swashbuckle.Application; 4 | using Swashbuckle.Swagger; 5 | using WebActivatorEx; 6 | using ProductListAPI; 7 | using System; 8 | using System.Reflection; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Globalization; 12 | 13 | [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")] 14 | 15 | namespace ProductListAPI 16 | { 17 | /// 18 | /// Swagger Config file 19 | /// 20 | internal class SwaggerConfig 21 | { 22 | internal static void Register() 23 | { 24 | var thisAssembly = typeof(SwaggerConfig).Assembly; 25 | 26 | GlobalConfiguration.Configuration 27 | .EnableSwagger(c => 28 | { 29 | // By default, the service root url is inferred from the request used to access the docs. 30 | // However, there may be situations (e.g. proxy and load-balanced environments) where this does not 31 | // resolve correctly. You can workaround this by providing your own code to determine the root URL. 32 | // 33 | //c.RootUrl(req => GetRootUrlFromAppConfig()); 34 | 35 | // If schemes are not explicitly provided in a Swagger 2.0 document, then the scheme used to access 36 | // the docs is taken as the default. If your API supports multiple schemes and you want to be explicit 37 | // about them, you can use the "Schemes" option as shown below. 38 | // 39 | //c.Schemes(new[] { "http", "https" }); 40 | 41 | // Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to 42 | // hold additional metadata for an API. Version and title are required but you can also provide 43 | // additional fields by chaining methods off SingleApiVersion. 44 | // 45 | c.SingleApiVersion("v1", "ProductListAPI"); 46 | 47 | // If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option. 48 | // 49 | //c.PrettyPrint(); 50 | 51 | // If your API has multiple versions, use "MultipleApiVersions" instead of "SingleApiVersion". 52 | // In this case, you must provide a lambda that tells Swashbuckle which actions should be 53 | // included in the docs for a given API version. Like "SingleApiVersion", each call to "Version" 54 | // returns an "Info" builder so you can provide additional metadata per API version. 55 | // 56 | //c.MultipleApiVersions( 57 | // (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion), 58 | // (vc) => 59 | // { 60 | // vc.Version("v2", "Swashbuckle Dummy API V2"); 61 | // vc.Version("v1", "Swashbuckle Dummy API V1"); 62 | // }); 63 | 64 | // You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API. 65 | // See https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md for more details. 66 | // NOTE: These only define the schemes and need to be coupled with a corresponding "security" property 67 | // at the document or operation level to indicate which schemes are required for an operation. To do this, 68 | // you'll need to implement a custom IDocumentFilter and/or IOperationFilter to set these properties 69 | // according to your specific authorization implementation 70 | // 71 | //c.BasicAuth("basic") 72 | // .Description("Basic HTTP Authentication"); 73 | // 74 | // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section 75 | //c.ApiKey("apiKey") 76 | // .Description("API Key Authentication") 77 | // .Name("apiKey") 78 | // .In("header"); 79 | // 80 | //c.OAuth2("oauth2") 81 | // .Description("OAuth2 Implicit Grant") 82 | // .Flow("implicit") 83 | // .AuthorizationUrl("http://petstore.swagger.wordnik.com/api/oauth/dialog") 84 | // //.TokenUrl("https://tempuri.org/token") 85 | // .Scopes(scopes => 86 | // { 87 | // scopes.Add("read", "Read access to protected resources"); 88 | // scopes.Add("write", "Write access to protected resources"); 89 | // }); 90 | 91 | // Set this flag to omit descriptions for any actions decorated with the Obsolete attribute 92 | //c.IgnoreObsoleteActions(); 93 | 94 | // Each operation be assigned one or more tags which are then used by consumers for various reasons. 95 | // For example, the swagger-ui groups operations according to the first tag of each operation. 96 | // By default, this will be controller name but you can use the "GroupActionsBy" option to 97 | // override with any value. 98 | // 99 | //c.GroupActionsBy(apiDesc => apiDesc.HttpMethod.ToString()); 100 | 101 | // You can also specify a custom sort order for groups (as defined by "GroupActionsBy") to dictate 102 | // the order in which operations are listed. For example, if the default grouping is in place 103 | // (controller name) and you specify a descending alphabetic sort order, then actions from a 104 | // ProductsController will be listed before those from a CustomersController. This is typically 105 | // used to customize the order of groupings in the swagger-ui. 106 | // 107 | //c.OrderActionGroupsBy(new DescendingAlphabeticComparer()); 108 | 109 | // If you annotate Controllers and API Types with 110 | // Xml comments (http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx), you can incorporate 111 | // those comments into the generated docs and UI. You can enable this by providing the path to one or 112 | // more Xml comment files. 113 | // 114 | c.IncludeXmlComments(GetXmlCommentsPath()); 115 | 116 | // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types 117 | // exposed in your API. However, there may be occasions when more control of the output is needed. 118 | // This is supported through the "MapType" and "SchemaFilter" options: 119 | // 120 | // Use the "MapType" option to override the Schema generation for a specific type. 121 | // It should be noted that the resulting Schema will be placed "inline" for any applicable Operations. 122 | // While Swagger 2.0 supports inline definitions for "all" Schema types, the swagger-ui tool does not. 123 | // It expects "complex" Schemas to be defined separately and referenced. For this reason, you should only 124 | // use the "MapType" option when the resulting Schema is a primitive or array type. If you need to alter a 125 | // complex Schema, use a Schema filter. 126 | // 127 | //c.MapType(() => new Schema { type = "integer", format = "int32" }); 128 | 129 | // If you want to post-modify "complex" Schemas once they've been generated, across the board or for a 130 | // specific type, you can wire up one or more Schema filters. 131 | // 132 | //c.SchemaFilter(); 133 | 134 | // In a Swagger 2.0 document, complex types are typically declared globally and referenced by unique 135 | // Schema Id. By default, Swashbuckle does NOT use the full type name in Schema Ids. In most cases, this 136 | // works well because it prevents the "implementation detail" of type namespaces from leaking into your 137 | // Swagger docs and UI. However, if you have multiple types in your API with the same class name, you'll 138 | // need to opt out of this behavior to avoid Schema Id conflicts. 139 | // 140 | //c.UseFullTypeNameInSchemaIds(); 141 | 142 | // Alternatively, you can provide your own custom strategy for inferring SchemaId's for 143 | // describing "complex" types in your API. 144 | // 145 | //c.SchemaId(t => t.FullName.Contains('`') ? t.FullName.Substring(0, t.FullName.IndexOf('`')) : t.FullName); 146 | 147 | // Set this flag to omit schema property descriptions for any type properties decorated with the 148 | // Obsolete attribute 149 | //c.IgnoreObsoleteProperties(); 150 | 151 | // In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers. 152 | // You can change the serializer behavior by configuring the StringToEnumConverter globally or for a given 153 | // enum type. Swashbuckle will honor this change out-of-the-box. However, if you use a different 154 | // approach to serialize enums as strings, you can also force Swashbuckle to describe them as strings. 155 | // 156 | //c.DescribeAllEnumsAsStrings(); 157 | 158 | // Similar to Schema filters, Swashbuckle also supports Operation and Document filters: 159 | // 160 | // Post-modify Operation descriptions once they've been generated by wiring up one or more 161 | // Operation filters. 162 | // 163 | //c.OperationFilter(); 164 | // 165 | // If you've defined an OAuth2 flow as described above, you could use a custom filter 166 | // to inspect some attribute on each action and infer which (if any) OAuth2 scopes are required 167 | // to execute the operation 168 | // 169 | //c.OperationFilter(); 170 | // 171 | // Set filter to eliminate duplicate operation ids from being generated 172 | // when there are multiple operations with the same verb in the API. 173 | // 174 | //c.OperationFilter(); 175 | 176 | // Post-modify the entire Swagger document by wiring up one or more Document filters. 177 | // This gives full control to modify the final SwaggerDocument. You should have a good understanding of 178 | // the Swagger 2.0 spec. - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md 179 | // before using this option. 180 | // 181 | //c.DocumentFilter(); 182 | 183 | // In contrast to WebApi, Swagger 2.0 does not include the query string component when mapping a URL 184 | // to an action. As a result, Swashbuckle will raise an exception if it encounters multiple actions 185 | // with the same path (sans query string) and HTTP method. You can workaround this by providing a 186 | // custom strategy to pick a winner or merge the descriptions for the purposes of the Swagger docs 187 | // 188 | //c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); 189 | 190 | // Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an 191 | // alternative implementation for ISwaggerProvider with the CustomProvider option. 192 | // 193 | //c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider)); 194 | }) 195 | .EnableSwaggerUi(c => 196 | { 197 | // Use the "DocumentTitle" option to change the Document title. 198 | // Very helpful when you have multiple Swagger pages open, to tell them apart. 199 | // 200 | //c.DocumentTitle("My Swagger UI"); 201 | 202 | // Use the "InjectStylesheet" option to enrich the UI with one or more additional CSS stylesheets. 203 | // The file must be included in your project as an "Embedded Resource", and then the resource's 204 | // "Logical Name" is passed to the method as shown below. 205 | // 206 | //c.InjectStylesheet(containingAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testStyles1.css"); 207 | 208 | // Use the "InjectJavaScript" option to invoke one or more custom JavaScripts after the swagger-ui 209 | // has loaded. The file must be included in your project as an "Embedded Resource", and then the resource's 210 | // "Logical Name" is passed to the method as shown above. 211 | // 212 | //c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js"); 213 | 214 | // The swagger-ui renders boolean data types as a dropdown. By default, it provides "true" and "false" 215 | // strings as the possible choices. You can use this option to change these to something else, 216 | // for example 0 and 1. 217 | // 218 | //c.BooleanValues(new[] { "0", "1" }); 219 | 220 | // By default, swagger-ui will validate specs against swagger.io's online validator and display the result 221 | // in a badge at the bottom of the page. Use these options to set a different validator URL or to disable the 222 | // feature entirely. 223 | //c.SetValidatorUrl("http://localhost/validator"); 224 | //c.DisableValidator(); 225 | 226 | // Use this option to control how the Operation listing is displayed. 227 | // It can be set to "None" (default), "List" (shows operations for each resource), 228 | // or "Full" (fully expanded: shows operations and their details). 229 | // 230 | //c.DocExpansion(DocExpansion.List); 231 | 232 | // Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables 233 | // it for all operations. 234 | // 235 | //c.SupportedSubmitMethods("GET", "HEAD"); 236 | 237 | // Use the CustomAsset option to provide your own version of assets used in the swagger-ui. 238 | // It's typically used to instruct Swashbuckle to return your version instead of the default 239 | // when a request is made for "index.html". As with all custom content, the file must be included 240 | // in your project as an "Embedded Resource", and then the resource's "Logical Name" is passed to 241 | // the method as shown below. 242 | // 243 | //c.CustomAsset("index", containingAssembly, "YourWebApiProject.SwaggerExtensions.index.html"); 244 | 245 | // If your API has multiple versions and you've applied the MultipleApiVersions setting 246 | // as described above, you can also enable a select box in the swagger-ui, that displays 247 | // a discovery URL for each version. This provides a convenient way for users to browse documentation 248 | // for different API versions. 249 | // 250 | //c.EnableDiscoveryUrlSelector(); 251 | 252 | // If your API supports the OAuth2 Implicit flow, and you've described it correctly, according to 253 | // the Swagger 2.0 specification, you can enable UI support as shown below. 254 | // 255 | //c.EnableOAuth2Support( 256 | // clientId: "test-client-id", 257 | // clientSecret: null, 258 | // realm: "test-realm", 259 | // appName: "Swagger UI" 260 | // //additionalQueryStringParams: new Dictionary() { { "foo", "bar" } } 261 | //); 262 | 263 | // If your API supports ApiKey, you can override the default values. 264 | // "apiKeyIn" can either be "query" or "header" 265 | // 266 | //c.EnableApiKeySupport("apiKey", "header"); 267 | }); 268 | } 269 | 270 | /// 271 | /// Returns the path to the XMLcomments 272 | /// 273 | /// 274 | private static string GetXmlCommentsPath() 275 | { 276 | var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; 277 | var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".xml"; 278 | var commentsFile = Path.Combine(baseDirectory, "bin/", commentsFileName); 279 | return commentsFile; 280 | 281 | } 282 | } 283 | 284 | internal class IncludeParameterNamesInOperationIdFilter : IOperationFilter 285 | { 286 | public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) 287 | { 288 | if (operation.parameters != null) 289 | { 290 | // Select the capitalized parameter names 291 | var parameters = operation.parameters.Select( 292 | p => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(p.name)); 293 | 294 | // Set the operation id to match the format "OperationByParam1AndParam2" 295 | operation.operationId = string.Format( 296 | "{0}By{1}", 297 | operation.operationId, 298 | string.Join("And", parameters)); 299 | } 300 | } 301 | } 302 | 303 | 304 | } -------------------------------------------------------------------------------- /src/ProductListAPI/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace ProductListAPI 7 | { 8 | /// 9 | /// WebApiConfig 10 | /// 11 | public static class WebApiConfig 12 | { 13 | /// 14 | /// Register 15 | /// 16 | /// 17 | public static void Register(HttpConfiguration config) 18 | { 19 | // Web API configuration and services 20 | 21 | // Web API routes 22 | config.MapHttpAttributeRoutes(); 23 | 24 | config.Routes.MapHttpRoute( 25 | name: "DefaultApi", 26 | routeTemplate: "api/{controller}/{id}", 27 | defaults: new { id = RouteParameter.Optional } 28 | ); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ProductListAPI/Controllers/ProductsController.cs: -------------------------------------------------------------------------------- 1 | using ProductListAPI.Models; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using System.Web.Http; 5 | using System.Linq; 6 | using Swashbuckle.Swagger.Annotations; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System; 10 | using System.Collections; 11 | using System.Diagnostics; 12 | using Microsoft.SqlServer.Server; 13 | 14 | namespace ProductListAPI.Controllers 15 | { 16 | /// 17 | /// Products Controller 18 | /// 19 | public class ProductsController : ApiController 20 | { 21 | private const string FILENAME = "products.json"; 22 | private GenericStorage _storage; 23 | 24 | /// 25 | /// Constructor 26 | /// 27 | public ProductsController() 28 | { 29 | _storage = new GenericStorage(); 30 | } 31 | 32 | private IEnumerable GetInventory() 33 | { 34 | var inventory = _storage.Get(FILENAME); 35 | 36 | if (inventory == null) 37 | { 38 | //Populate with some dummy data to begin with 39 | inventory = GetDefaultProducts(); 40 | _storage.Save( 41 | inventory, 42 | FILENAME); 43 | } 44 | 45 | return inventory; 46 | } 47 | 48 | private IEnumerable GetDefaultProducts() 49 | { 50 | var numProductsToInitialize = 10; 51 | Random rand = new Random(); 52 | Product[] products = new Product[numProductsToInitialize]; 53 | for (var i = 0; i < numProductsToInitialize; i++) 54 | { 55 | products[i] = new Product 56 | { 57 | Id = i, 58 | Name = String.Format("Widget {0}", i.ToString()), 59 | CurrentInventory = rand.Next(0, 300), 60 | Unit = "Units" 61 | }; 62 | } 63 | 64 | return products; 65 | 66 | } 67 | /// 68 | /// Gets the list of products 69 | /// 70 | /// The Product inventory 71 | /// 72 | /// This operation returns the list of products along with their current stock 73 | /// 74 | [HttpGet] 75 | [SwaggerResponse(HttpStatusCode.OK, 76 | Type = typeof(IEnumerable))] 77 | [Route("~/products")] 78 | [SwaggerOperation("GetAllProducts")] 79 | public IEnumerable Get() 80 | { 81 | return GetInventory(); 82 | } 83 | 84 | /// 85 | /// Gets a specific product 86 | /// 87 | /// Identifier for the product 88 | /// The requested product 89 | /// 90 | /// This operation returns the specific product based on the ID along with it's current stock 91 | /// 92 | [HttpGet] 93 | [SwaggerResponse(HttpStatusCode.OK, 94 | Description = "OK", 95 | Type = typeof(Product))] 96 | [SwaggerResponse(HttpStatusCode.NotFound, 97 | Description = "Product not found", 98 | Type = typeof(Product))] 99 | [SwaggerOperation("GetProductById")] 100 | [Route("~/products/{id}")] 101 | public Product Get([FromUri] int id) 102 | { 103 | var inventory = GetInventory(); 104 | return inventory.FirstOrDefault(x => x.Id == id); 105 | } 106 | 107 | /// 108 | /// Update a specific product 109 | /// 110 | /// Product to update inluding ID 111 | /// Product Id to update 112 | /// True if update successful 113 | /// 114 | /// This operation updates the specific product based on the ID along with it's current stock 115 | /// 116 | [HttpPost] 117 | [SwaggerResponse(HttpStatusCode.OK, 118 | Description = "OK", 119 | Type = typeof(bool))] 120 | [SwaggerResponse(HttpStatusCode.NotFound, 121 | Description = "Product not found", 122 | Type = typeof(bool))] 123 | [SwaggerOperation("UpdateProduct")] 124 | [Route("~/products/{ProductId}")] 125 | public HttpResponseMessage Update([FromBody] Product product, [FromUri] int ProductId) 126 | { 127 | var inventory = GetInventory(); 128 | 129 | //var productList = inventory.ToList(); 130 | var curProduct = inventory.FirstOrDefault(x => x.Id == ProductId); 131 | if (curProduct == null || curProduct.Id != ProductId) 132 | { 133 | return Request.CreateResponse(HttpStatusCode.NotFound, false); 134 | } 135 | else 136 | { 137 | Delete(ProductId); 138 | Post(product); 139 | return Request.CreateResponse(HttpStatusCode.OK, true); 140 | } 141 | 142 | 143 | } 144 | 145 | /// 146 | /// Creates a new product 147 | /// 148 | /// The new product 149 | /// The saved product 150 | /// 151 | /// This operation creates a new product along with it's current stock 152 | /// 153 | [HttpPost] 154 | [SwaggerResponse(HttpStatusCode.Created, 155 | Description = "Created", 156 | Type = typeof(Product))] 157 | [Route("~/products")] 158 | [SwaggerOperation("CreateProduct")] 159 | public Product Post([FromBody] Product product) 160 | { 161 | var products = GetInventory(); 162 | var productList = products.ToList(); 163 | productList.Add(product); 164 | _storage.Save(productList, FILENAME); 165 | return product; 166 | } 167 | 168 | /// 169 | /// Deletes a product 170 | /// 171 | /// Identifier of the product to be deleted 172 | /// True if the product was deleted 173 | /// 174 | /// This operation deletes the product from the inventory 175 | /// 176 | [HttpDelete] 177 | [SwaggerResponse(HttpStatusCode.OK, 178 | Description = "OK", 179 | Type = typeof(bool))] 180 | [SwaggerResponse(HttpStatusCode.NotFound, 181 | Description = "Product not found", 182 | Type = typeof(bool))] 183 | [Route("~/products/{id}")] 184 | [SwaggerOperation("DeleteProductById")] 185 | public HttpResponseMessage Delete([FromUri] int id) 186 | { 187 | var products = GetInventory(); 188 | var productList = products.ToList(); 189 | 190 | if (!productList.Any(x => x.Id == id)) 191 | { 192 | return Request.CreateResponse(HttpStatusCode.NotFound, false); 193 | } 194 | else 195 | { 196 | productList.RemoveAll(x => x.Id == id); 197 | _storage.Save(productList, FILENAME); 198 | return Request.CreateResponse(HttpStatusCode.OK, true); 199 | } 200 | } 201 | 202 | /// 203 | /// Deletes all products 204 | /// 205 | /// True if the product was deleted 206 | /// 207 | /// This operation deletes all the products from the inventory 208 | /// 209 | [HttpDelete] 210 | [SwaggerResponse(HttpStatusCode.OK, 211 | Description = "OK", 212 | Type = typeof(bool))] 213 | [Route("~/products")] 214 | [SwaggerOperation("DeleteAllProducts")] 215 | public HttpResponseMessage Delete() 216 | { 217 | 218 | _storage.Delete(FILENAME); 219 | return Request.CreateResponse(HttpStatusCode.OK, true); 220 | 221 | } 222 | 223 | } 224 | } -------------------------------------------------------------------------------- /src/ProductListAPI/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="ProductListAPI.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /src/ProductListAPI/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Routing; 7 | 8 | namespace ProductListAPI 9 | { 10 | /// 11 | /// 12 | /// 13 | public class WebApiApplication : System.Web.HttpApplication 14 | { 15 | /// 16 | /// 17 | /// 18 | protected void Application_Start() 19 | { 20 | GlobalConfiguration.Configure(WebApiConfig.Register); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ProductListAPI/Models/Product.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace ProductListAPI.Models 3 | { 4 | /// 5 | /// Product 6 | /// 7 | public class Product 8 | { 9 | /// 10 | /// The ID of the product. 11 | /// 12 | public int Id { get; set; } 13 | 14 | /// 15 | /// Product name. 16 | /// 17 | public string Name { get; set; } 18 | 19 | 20 | /// 21 | /// Current Inventory 22 | /// 23 | public int CurrentInventory{ get; set; } 24 | 25 | /// 26 | /// The Product's unit. 27 | /// 28 | public string Unit { get; set; } 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/ProductListAPI/ProductListAPI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 2.0 9 | {12B6DD58-3A99-4DDE-9013-3720DEC683F4} 10 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 11 | Library 12 | Properties 13 | ProductListAPI 14 | ProductListAPI 15 | v4.6.1 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | bin\ProductListAPI.xml 34 | 35 | 36 | pdbonly 37 | true 38 | bin\ 39 | TRACE 40 | prompt 41 | 4 42 | bin\ProductListAPI.xml 43 | 44 | 45 | 46 | ..\packages\Microsoft.Azure.AppService.ApiApps.Service.0.9.64\lib\net45\Microsoft.Azure.AppService.ApiApps.Service.dll 47 | 48 | 49 | 50 | ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.6.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll 51 | 52 | 53 | ..\packages\Microsoft.IdentityModel.Logging.5.6.0\lib\net461\Microsoft.IdentityModel.Logging.dll 54 | 55 | 56 | ..\packages\Microsoft.IdentityModel.Tokens.5.6.0\lib\net461\Microsoft.IdentityModel.Tokens.dll 57 | 58 | 59 | True 60 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 61 | 62 | 63 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll 64 | 65 | 66 | ..\packages\Swashbuckle.Core.5.6.0\lib\net40\Swashbuckle.Core.dll 67 | 68 | 69 | 70 | ..\packages\System.IdentityModel.Tokens.Jwt.5.6.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll 71 | 72 | 73 | 74 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.7\lib\net45\System.Web.Http.dll 87 | 88 | 89 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.7\lib\net45\System.Web.Http.WebHost.dll 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | ..\packages\WebActivatorEx.2.2.0\lib\net40\WebActivatorEx.dll 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Global.asax 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | Web.config 128 | 129 | 130 | Web.config 131 | 132 | 133 | 134 | 135 | 10.0 136 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | True 146 | True 147 | 64279 148 | / 149 | http://localhost:64279/ 150 | False 151 | False 152 | 153 | 154 | False 155 | 156 | 157 | 158 | 159 | 166 | -------------------------------------------------------------------------------- /src/ProductListAPI/ProductListAPI.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug|Any CPU 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | plistapi - Web Deploy 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | CurrentPage 21 | True 22 | False 23 | False 24 | False 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | True 34 | False 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/ProductListAPI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProductListAPI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProductListAPI")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("889bdb3a-f9b6-428e-9ddd-96f4fcc5701f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/ProductListAPI/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /src/ProductListAPI/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /src/ProductListAPI/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/ProductListAPI/apiapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schemas/2014-11-01/apiapp.json#", 3 | "id": "ProductListAPI", 4 | "namespace": "microsoft.com", 5 | "gateway": "2015-01-14", 6 | "version": "1.0.0", 7 | "title": "ProductListAPI", 8 | "summary": "", 9 | "author": "", 10 | "endpoints": { 11 | "apiDefinition": "/swagger/docs/v1", 12 | "status": null 13 | } 14 | } -------------------------------------------------------------------------------- /src/ProductListAPI/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------