├── FMLab ├── $tf │ ├── 0 │ │ ├── b37048b0-ce4e-4e7e-9902-ecedff8777d9.gz │ │ └── fe7cf740-4011-43e2-ab3b-e0eb36b1ae39.gz │ ├── 1 │ │ ├── 383bb791-f417-4dd9-9d9f-83221d18622a.gz │ │ ├── 77ea3d91-eeed-44c8-83ed-5094142ca005.gz │ │ ├── 991e67b1-81cc-433e-9b30-595eb688292e.gz │ │ ├── a337a441-a48d-450a-a546-d5bb8c48e136.gz │ │ └── f5a22731-c770-4623-9e5d-83a7f66340f9.gz │ ├── 2 │ │ ├── 06110bd2-084d-4c8b-964d-aac630227768.gz │ │ ├── 4b3dc482-1ed7-421a-ba8d-d0a76d2fbad5.gz │ │ ├── 5108e4d2-8aca-41f8-b85d-aebdf3f90f98.gz │ │ ├── 514f6032-005e-49d9-8867-c28c093103ec.gz │ │ ├── 54e0e862-b17f-45ef-8540-d29b95c7984b.gz │ │ ├── ae6f73b2-b985-4edf-aa93-76eef3127ebd.gz │ │ └── e0a94a22-e548-440a-ba72-5ffb7dfb2005.gz │ ├── 3 │ │ ├── dec4f863-7c2a-44e1-844d-407675224f03.gz │ │ └── f4875a63-c933-4612-b8b5-046164d181a7.gz │ ├── 4 │ │ ├── 418e4ee4-9ef6-47c6-8d1a-675cfd9b077e.gz │ │ ├── 6e13a834-578e-4360-a6d6-42ce671ce661.gz │ │ └── baea85a4-6569-4641-8161-00d21d5fcc1d.gz │ ├── 5 │ │ ├── 99ffa485-a5e8-4d73-a22e-defc18d14662.gz │ │ └── dca24a05-c05d-46ba-bc00-87e1bfd6135c.gz │ ├── 6 │ │ ├── 17432966-7fb7-4c4b-a1c0-4de1b774b98e.gz │ │ ├── 777f1156-94cb-40b1-a9e8-87f2f10042d1.gz │ │ ├── dd7ddea6-4367-4298-a4fd-f347aeb7dd5f.gz │ │ └── fca62e46-c2a4-4434-a5bc-566b8c4aae95.gz │ ├── 7 │ │ ├── 1b53f527-af30-42c1-953b-bfb50c2b6b83.gz │ │ └── ae332fc7-c75c-41b4-9d46-926279288b2b.gz │ ├── 8 │ │ ├── 09bb0848-94bd-4942-a276-f55ac614053e.gz │ │ ├── 220bdbb8-4f22-425b-a94e-5749d2603d03.gz │ │ ├── 813b2f98-3983-48ea-ab18-40cde25b7614.gz │ │ ├── ca3997d8-e6d1-4689-82ce-0aeaa58b077f.gz │ │ └── cd6dd508-4613-4cd4-9949-48f97414f590.gz │ ├── 9 │ │ ├── 0279f1a9-f7b3-4b22-8085-bd9b8244f52e.gz │ │ ├── 25ddbd39-e3fa-4fe6-beb7-e7c9b2034b43.gz │ │ ├── 39be00b9-89b0-4fcd-b2a2-8107af1e968c.gz │ │ ├── 8b281bd9-cec6-42d1-a75c-f29bb9becda2.gz │ │ └── bdb72cd9-30b6-4eb9-9d4a-d8c4f816f79e.gz │ ├── 10 │ │ ├── 05ea4a4a-1c13-4525-aab4-3658155529d2.gz │ │ ├── 4275258a-e231-4b67-a08c-f16733c3c8fe.gz │ │ ├── 6920d30a-7a73-45a8-bf2e-90aabe0aad10.gz │ │ ├── c890a4fa-b780-4bc4-8546-08eb226f28d4.gz │ │ ├── e239beca-1906-4031-86e2-9709ad38c44e.gz │ │ └── f045ba2a-a7b3-453c-a9cf-ebc68b80d3c6.gz │ ├── 12 │ │ ├── 338bcb7c-64b4-4274-879e-9a0716b597d5.gz │ │ ├── cffcb19c-9be5-4281-bbc3-77da08d926dc.gz │ │ ├── d183ad7c-b15a-4c01-b586-9304f788c006.rw │ │ └── fe6345fc-522e-42c6-bfff-ef57c74676a6.gz │ ├── 13 │ │ ├── 6df4da5d-44d1-49e7-9406-98caa32b7f48.gz │ │ ├── 7fa2e96d-8f32-458f-b2f7-7243631c9140.gz │ │ ├── 7fa577fd-4f37-4da5-86a3-88c47cd54d66.gz │ │ ├── 88b41f3d-38fb-4aa4-a0a0-7640b8038c57.gz │ │ └── cab05a9d-8fa0-41da-a68d-86b5bba87a1f.gz │ ├── 14 │ │ ├── 230b847e-80cf-4895-979d-a63fda389f69.gz │ │ ├── 2f08363e-e558-4043-8cd7-f9668d570513.gz │ │ ├── 991e6c0e-64e3-4957-9863-77840f7ef29c.gz │ │ └── c1c2c75e-35c1-4672-9598-908b89dc96d4.gz │ ├── 15 │ │ ├── 4769b42f-2897-4084-8645-58a2ca2c1cf8.gz │ │ ├── 576cdcbf-9d40-4fb8-803b-abe8f5deb00f.gz │ │ ├── bb4aac3f-7dd9-4084-a47f-04f530a89e69.gz │ │ ├── bf0cc88f-766e-4ee4-953f-42e752258501.gz │ │ ├── caeb9e5f-4233-46ab-99c1-094cdfbb3e46.gz │ │ ├── ccbcdb2f-8710-4dd0-90e5-19fe171147d2.gz │ │ ├── f57743cf-99c9-4ef6-8d8c-b9c53e9e1c4f.gz │ │ └── fc3ce97f-a9ca-4939-879e-7b047c44f23a.gz │ ├── localversion.tf1 │ ├── localversion.tfb │ ├── pendingchanges.tf1 │ ├── pendingchanges.tfb │ └── properties.tf1 ├── AxForm_FmtChargeType.xml ├── AxForm_FmtCustomer.xml ├── AxForm_FmtCustomerWorkflow.CTP3.xml ├── AxMenuItemDisplay_FMTCustomerWorkflow.CTP3.xml ├── AxQuery_FMTCustomerWorkflowQuery.CTP3.xml ├── AxWorkflowCategory_FMTWorkflowCategory.CTP3.xml ├── ConnectorClientApplication │ ├── ActivityMessage.cs │ ├── App.config │ ├── ConnectorServiceApplication.csproj │ ├── FleetCustomerPlainText.xslt │ ├── Helper.cs │ ├── Program.cs │ ├── mainForm.Designer.cs │ ├── mainForm.cs │ ├── mainForm.resx │ └── uploadFMCustomer.xml ├── CreateAADApplication │ └── Microsoft.IdentityModel.Clients.ActiveDirectory.xml ├── DemoBP.zip ├── DriversLicenseChecker.cs ├── DynamicsAX.ExcelManifest.xml ├── EDT │ ├── AxEdt_FMTCCExpiryDate.xml │ ├── AxEdt_FMTChargeTypeId.xml │ ├── AxEdt_FMTCreditCardNum.xml │ ├── AxEdt_FMTCustomerRecId.xml │ ├── AxEdt_FMTDescription.xml │ ├── AxEdt_FMTDriversLicense.xml │ └── AxEdt_FMTName.xml ├── FMTutorialDataModel.axpp ├── Lab10-1 │ └── Adding BI to workspaces.axpp ├── Lab10-2 │ ├── Add contextual BI to a form - After Lab.axpp │ ├── Add contextual BI to a form - Before Lab.axpp │ ├── Add contextual BI to a form.axpp │ ├── FMBILabHelper.xml │ ├── FMBIRevenueByVehicleModel.xml │ └── TmpDBBIFMRevenueByVehicleModelByMonth.xml ├── Lab10-3 │ └── FMRentalDetailsReport.axpp ├── ODataConsoleApplication │ ├── App.config │ ├── AuthenticationHelper.cs │ ├── BrowserForm.cs │ ├── BrowserForm.designer.cs │ ├── BrowserForm.resx │ ├── CloudEnvironment.Config │ ├── ODataConsoleApplication.csproj │ ├── ODataConsoleApplication.sln │ ├── ODataProxies.odata.config │ ├── ODataProxies.tt │ ├── Program.cs │ └── packages.config ├── Odata4ConsoleApplication │ ├── App.config │ ├── AuthenticationHelper.cs │ ├── BrowserForm.cs │ ├── BrowserForm.designer.cs │ ├── BrowserForm.resx │ ├── ODataProxyGenerator.tt │ ├── ODataProxyGenerator.ttinclude │ ├── Odata4ConsoleApplication.csproj │ └── Program.cs ├── TaskRecorderScreenshot │ ├── background.js │ ├── manifest.json │ └── screenshot.js ├── TestFiles │ ├── AxClass_FMUnitTestSample.xml │ ├── CodeCoverage.config │ └── Default.RunSettings └── json-ie.reg ├── README.md └── SECURITY.md /FMLab/$tf/0/b37048b0-ce4e-4e7e-9902-ecedff8777d9.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/0/b37048b0-ce4e-4e7e-9902-ecedff8777d9.gz -------------------------------------------------------------------------------- /FMLab/$tf/0/fe7cf740-4011-43e2-ab3b-e0eb36b1ae39.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/0/fe7cf740-4011-43e2-ab3b-e0eb36b1ae39.gz -------------------------------------------------------------------------------- /FMLab/$tf/1/383bb791-f417-4dd9-9d9f-83221d18622a.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/1/383bb791-f417-4dd9-9d9f-83221d18622a.gz -------------------------------------------------------------------------------- /FMLab/$tf/1/77ea3d91-eeed-44c8-83ed-5094142ca005.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/1/77ea3d91-eeed-44c8-83ed-5094142ca005.gz -------------------------------------------------------------------------------- /FMLab/$tf/1/991e67b1-81cc-433e-9b30-595eb688292e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/1/991e67b1-81cc-433e-9b30-595eb688292e.gz -------------------------------------------------------------------------------- /FMLab/$tf/1/a337a441-a48d-450a-a546-d5bb8c48e136.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/1/a337a441-a48d-450a-a546-d5bb8c48e136.gz -------------------------------------------------------------------------------- /FMLab/$tf/1/f5a22731-c770-4623-9e5d-83a7f66340f9.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/1/f5a22731-c770-4623-9e5d-83a7f66340f9.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/05ea4a4a-1c13-4525-aab4-3658155529d2.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/05ea4a4a-1c13-4525-aab4-3658155529d2.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/4275258a-e231-4b67-a08c-f16733c3c8fe.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/4275258a-e231-4b67-a08c-f16733c3c8fe.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/6920d30a-7a73-45a8-bf2e-90aabe0aad10.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/6920d30a-7a73-45a8-bf2e-90aabe0aad10.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/c890a4fa-b780-4bc4-8546-08eb226f28d4.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/c890a4fa-b780-4bc4-8546-08eb226f28d4.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/e239beca-1906-4031-86e2-9709ad38c44e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/e239beca-1906-4031-86e2-9709ad38c44e.gz -------------------------------------------------------------------------------- /FMLab/$tf/10/f045ba2a-a7b3-453c-a9cf-ebc68b80d3c6.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/10/f045ba2a-a7b3-453c-a9cf-ebc68b80d3c6.gz -------------------------------------------------------------------------------- /FMLab/$tf/12/338bcb7c-64b4-4274-879e-9a0716b597d5.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/12/338bcb7c-64b4-4274-879e-9a0716b597d5.gz -------------------------------------------------------------------------------- /FMLab/$tf/12/cffcb19c-9be5-4281-bbc3-77da08d926dc.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/12/cffcb19c-9be5-4281-bbc3-77da08d926dc.gz -------------------------------------------------------------------------------- /FMLab/$tf/12/d183ad7c-b15a-4c01-b586-9304f788c006.rw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/12/d183ad7c-b15a-4c01-b586-9304f788c006.rw -------------------------------------------------------------------------------- /FMLab/$tf/12/fe6345fc-522e-42c6-bfff-ef57c74676a6.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/12/fe6345fc-522e-42c6-bfff-ef57c74676a6.gz -------------------------------------------------------------------------------- /FMLab/$tf/13/6df4da5d-44d1-49e7-9406-98caa32b7f48.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/13/6df4da5d-44d1-49e7-9406-98caa32b7f48.gz -------------------------------------------------------------------------------- /FMLab/$tf/13/7fa2e96d-8f32-458f-b2f7-7243631c9140.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/13/7fa2e96d-8f32-458f-b2f7-7243631c9140.gz -------------------------------------------------------------------------------- /FMLab/$tf/13/7fa577fd-4f37-4da5-86a3-88c47cd54d66.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/13/7fa577fd-4f37-4da5-86a3-88c47cd54d66.gz -------------------------------------------------------------------------------- /FMLab/$tf/13/88b41f3d-38fb-4aa4-a0a0-7640b8038c57.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/13/88b41f3d-38fb-4aa4-a0a0-7640b8038c57.gz -------------------------------------------------------------------------------- /FMLab/$tf/13/cab05a9d-8fa0-41da-a68d-86b5bba87a1f.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/13/cab05a9d-8fa0-41da-a68d-86b5bba87a1f.gz -------------------------------------------------------------------------------- /FMLab/$tf/14/230b847e-80cf-4895-979d-a63fda389f69.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/14/230b847e-80cf-4895-979d-a63fda389f69.gz -------------------------------------------------------------------------------- /FMLab/$tf/14/2f08363e-e558-4043-8cd7-f9668d570513.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/14/2f08363e-e558-4043-8cd7-f9668d570513.gz -------------------------------------------------------------------------------- /FMLab/$tf/14/991e6c0e-64e3-4957-9863-77840f7ef29c.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/14/991e6c0e-64e3-4957-9863-77840f7ef29c.gz -------------------------------------------------------------------------------- /FMLab/$tf/14/c1c2c75e-35c1-4672-9598-908b89dc96d4.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/14/c1c2c75e-35c1-4672-9598-908b89dc96d4.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/4769b42f-2897-4084-8645-58a2ca2c1cf8.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/4769b42f-2897-4084-8645-58a2ca2c1cf8.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/576cdcbf-9d40-4fb8-803b-abe8f5deb00f.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/576cdcbf-9d40-4fb8-803b-abe8f5deb00f.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/bb4aac3f-7dd9-4084-a47f-04f530a89e69.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/bb4aac3f-7dd9-4084-a47f-04f530a89e69.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/bf0cc88f-766e-4ee4-953f-42e752258501.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/bf0cc88f-766e-4ee4-953f-42e752258501.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/caeb9e5f-4233-46ab-99c1-094cdfbb3e46.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/caeb9e5f-4233-46ab-99c1-094cdfbb3e46.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/ccbcdb2f-8710-4dd0-90e5-19fe171147d2.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/ccbcdb2f-8710-4dd0-90e5-19fe171147d2.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/f57743cf-99c9-4ef6-8d8c-b9c53e9e1c4f.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/f57743cf-99c9-4ef6-8d8c-b9c53e9e1c4f.gz -------------------------------------------------------------------------------- /FMLab/$tf/15/fc3ce97f-a9ca-4939-879e-7b047c44f23a.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/15/fc3ce97f-a9ca-4939-879e-7b047c44f23a.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/06110bd2-084d-4c8b-964d-aac630227768.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/06110bd2-084d-4c8b-964d-aac630227768.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/4b3dc482-1ed7-421a-ba8d-d0a76d2fbad5.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/4b3dc482-1ed7-421a-ba8d-d0a76d2fbad5.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/5108e4d2-8aca-41f8-b85d-aebdf3f90f98.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/5108e4d2-8aca-41f8-b85d-aebdf3f90f98.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/514f6032-005e-49d9-8867-c28c093103ec.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/514f6032-005e-49d9-8867-c28c093103ec.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/54e0e862-b17f-45ef-8540-d29b95c7984b.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/54e0e862-b17f-45ef-8540-d29b95c7984b.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/ae6f73b2-b985-4edf-aa93-76eef3127ebd.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/ae6f73b2-b985-4edf-aa93-76eef3127ebd.gz -------------------------------------------------------------------------------- /FMLab/$tf/2/e0a94a22-e548-440a-ba72-5ffb7dfb2005.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/2/e0a94a22-e548-440a-ba72-5ffb7dfb2005.gz -------------------------------------------------------------------------------- /FMLab/$tf/3/dec4f863-7c2a-44e1-844d-407675224f03.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/3/dec4f863-7c2a-44e1-844d-407675224f03.gz -------------------------------------------------------------------------------- /FMLab/$tf/3/f4875a63-c933-4612-b8b5-046164d181a7.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/3/f4875a63-c933-4612-b8b5-046164d181a7.gz -------------------------------------------------------------------------------- /FMLab/$tf/4/418e4ee4-9ef6-47c6-8d1a-675cfd9b077e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/4/418e4ee4-9ef6-47c6-8d1a-675cfd9b077e.gz -------------------------------------------------------------------------------- /FMLab/$tf/4/6e13a834-578e-4360-a6d6-42ce671ce661.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/4/6e13a834-578e-4360-a6d6-42ce671ce661.gz -------------------------------------------------------------------------------- /FMLab/$tf/4/baea85a4-6569-4641-8161-00d21d5fcc1d.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/4/baea85a4-6569-4641-8161-00d21d5fcc1d.gz -------------------------------------------------------------------------------- /FMLab/$tf/5/99ffa485-a5e8-4d73-a22e-defc18d14662.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/5/99ffa485-a5e8-4d73-a22e-defc18d14662.gz -------------------------------------------------------------------------------- /FMLab/$tf/5/dca24a05-c05d-46ba-bc00-87e1bfd6135c.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/5/dca24a05-c05d-46ba-bc00-87e1bfd6135c.gz -------------------------------------------------------------------------------- /FMLab/$tf/6/17432966-7fb7-4c4b-a1c0-4de1b774b98e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/6/17432966-7fb7-4c4b-a1c0-4de1b774b98e.gz -------------------------------------------------------------------------------- /FMLab/$tf/6/777f1156-94cb-40b1-a9e8-87f2f10042d1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/6/777f1156-94cb-40b1-a9e8-87f2f10042d1.gz -------------------------------------------------------------------------------- /FMLab/$tf/6/dd7ddea6-4367-4298-a4fd-f347aeb7dd5f.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/6/dd7ddea6-4367-4298-a4fd-f347aeb7dd5f.gz -------------------------------------------------------------------------------- /FMLab/$tf/6/fca62e46-c2a4-4434-a5bc-566b8c4aae95.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/6/fca62e46-c2a4-4434-a5bc-566b8c4aae95.gz -------------------------------------------------------------------------------- /FMLab/$tf/7/1b53f527-af30-42c1-953b-bfb50c2b6b83.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/7/1b53f527-af30-42c1-953b-bfb50c2b6b83.gz -------------------------------------------------------------------------------- /FMLab/$tf/7/ae332fc7-c75c-41b4-9d46-926279288b2b.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/7/ae332fc7-c75c-41b4-9d46-926279288b2b.gz -------------------------------------------------------------------------------- /FMLab/$tf/8/09bb0848-94bd-4942-a276-f55ac614053e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/8/09bb0848-94bd-4942-a276-f55ac614053e.gz -------------------------------------------------------------------------------- /FMLab/$tf/8/220bdbb8-4f22-425b-a94e-5749d2603d03.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/8/220bdbb8-4f22-425b-a94e-5749d2603d03.gz -------------------------------------------------------------------------------- /FMLab/$tf/8/813b2f98-3983-48ea-ab18-40cde25b7614.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/8/813b2f98-3983-48ea-ab18-40cde25b7614.gz -------------------------------------------------------------------------------- /FMLab/$tf/8/ca3997d8-e6d1-4689-82ce-0aeaa58b077f.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/8/ca3997d8-e6d1-4689-82ce-0aeaa58b077f.gz -------------------------------------------------------------------------------- /FMLab/$tf/8/cd6dd508-4613-4cd4-9949-48f97414f590.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/8/cd6dd508-4613-4cd4-9949-48f97414f590.gz -------------------------------------------------------------------------------- /FMLab/$tf/9/0279f1a9-f7b3-4b22-8085-bd9b8244f52e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/9/0279f1a9-f7b3-4b22-8085-bd9b8244f52e.gz -------------------------------------------------------------------------------- /FMLab/$tf/9/25ddbd39-e3fa-4fe6-beb7-e7c9b2034b43.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/9/25ddbd39-e3fa-4fe6-beb7-e7c9b2034b43.gz -------------------------------------------------------------------------------- /FMLab/$tf/9/39be00b9-89b0-4fcd-b2a2-8107af1e968c.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/9/39be00b9-89b0-4fcd-b2a2-8107af1e968c.gz -------------------------------------------------------------------------------- /FMLab/$tf/9/8b281bd9-cec6-42d1-a75c-f29bb9becda2.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/9/8b281bd9-cec6-42d1-a75c-f29bb9becda2.gz -------------------------------------------------------------------------------- /FMLab/$tf/9/bdb72cd9-30b6-4eb9-9d4a-d8c4f816f79e.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/9/bdb72cd9-30b6-4eb9-9d4a-d8c4f816f79e.gz -------------------------------------------------------------------------------- /FMLab/$tf/localversion.tf1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/localversion.tf1 -------------------------------------------------------------------------------- /FMLab/$tf/localversion.tfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/localversion.tfb -------------------------------------------------------------------------------- /FMLab/$tf/pendingchanges.tf1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/pendingchanges.tf1 -------------------------------------------------------------------------------- /FMLab/$tf/pendingchanges.tfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/$tf/pendingchanges.tfb -------------------------------------------------------------------------------- /FMLab/$tf/properties.tf1: -------------------------------------------------------------------------------- 1 | <~C:\C:\FMLab\$tflocalversionpendingchangesH$/Dynamics ERP Labs/FMTutorial/FMLabC:\FMLab -------------------------------------------------------------------------------- /FMLab/AxForm_FmtChargeType.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FmtChargeType 4 | 5 | 6 | 7 | classDeclaration 8 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | SimpleList 25 | 1.1 26 | 27 | 28 | 30 | ApplicationBar 31 | 429496729 32 | %1 33 | Yes 34 | ActionPane 35 | -1 36 | 38 | 39 | No 40 | No 41 | 42 | 44 | CustomFilterGroup 45 | CustomAndQuickFilters 46 | 1.1 47 | Group 48 | SizeToAvailable 49 | 51 | 52 | 53 | QuickFilter 54 | 55 | QuickFilterControl 56 | 57 | 58 | 59 | targetControlName 60 | String 61 | 62 | 63 | defaultColumnName 64 | String 65 | 66 | 67 | 68 | 69 | 70 | HorizontalLeft 71 | None 72 | 73 | Edit 74 | 75 | 77 | Grid 78 | 1431655764 79 | %1 80 | Grid 81 | -1 82 | 84 | 85 | No 86 | No 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /FMLab/AxForm_FmtCustomer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FmtCustomer 4 | 5 | 6 | 7 | classDeclaration 8 | 16 | 17 | 18 | 19 | 20 | FmtCustomer 21 | 22 | 23 | research 24 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | FmtCustomer 42 | FmtCustomer
43 | 44 | 45 | Address 46 | 47 | 48 | AddressID 49 | 50 | 51 | AuditStatus 52 | 53 | 54 | CCExpiryDate 55 | 56 | 57 | CellPhone 58 | 59 | 60 | CreditCardNum 61 | 62 | 63 | CustGroup 64 | 65 | 66 | DriverLicense 67 | 68 | 69 | Email 70 | 71 | 72 | FirstName 73 | 74 | 75 | Image 76 | 77 | 78 | LastName 79 | 80 | 81 | LicenseImage 82 | 83 | 84 | Partition 85 | 86 | 87 | RecId 88 | 89 | 90 | TableId 91 | 92 | 93 | 94 | 95 | 96 |
97 |
98 | 99 | 100 | 101 | 103 | ApplicationBar 104 | 715827882 105 | %1 106 | Yes 107 | ActionPane 108 | -1 109 | 0 110 | 112 | 113 | No 114 | No 115 | 116 | 118 | GridDetailsTab 119 | No 120 | 1431655764 121 | %1 122 | 0 123 | Tab 124 | -1 125 | 0 126 | 128 | 129 | 131 | TabPageGrid 132 | 1610612733 133 | %1 134 | Auto 135 | TabPage 136 | -1 137 | Auto 138 | 140 | 141 | 143 | MainGrid 144 | 1431655764 145 | %1 146 | Grid 147 | -1 148 | 150 | 151 | GridDefaultActionButton 152 | 153 | 155 | GridDefaultActionButton 156 | Yes 157 | CommandButton 158 | No 159 | 161 | DetailsView 162 | 163 | 164 | Grid 165 | Auto 166 | 167 | 168 | 170 | TabPageDetails 171 | 1073741822 172 | %1 173 | Auto 174 | TabPage 175 | -1 176 | Auto 177 | 179 | 180 | 182 | TitleGroup 183 | 1073741822 184 | %1 185 | Group 186 | -1 187 | 189 | 190 | 192 | HeaderTitle 193 | 1431655764 194 | %1 195 | Yes 196 | String 197 | -1 198 | 200 | 201 | 202 | 203 | Auto 204 | 205 | 206 | 208 | DetailsBodyTab 209 | 1610612733 210 | %1 211 | Tab 212 | -1 213 | 215 | 216 | 218 | General 219 | 1431655764 220 | %1 221 | Auto 222 | TabPage 223 | -1 224 | Auto 225 | 227 | 228 | Auto 229 | @SYS2952 230 | Auto 231 | 232 | 233 | No 234 | 235 | 236 | 237 | Details 238 | Auto 239 | 240 | 241 | 242 | No 243 | No 244 | 245 | 246 | 247 | 248 |
-------------------------------------------------------------------------------- /FMLab/AxMenuItemDisplay_FMTCustomerWorkflow.CTP3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FMTCustomerWorkflow 4 | FMTCustomerWorkflow 5 | -------------------------------------------------------------------------------- /FMLab/AxQuery_FMTCustomerWorkflowQuery.CTP3.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTCustomerWorkflowQuery 5 | 6 | 7 | 8 | classDeclaration 9 | 14 | 15 | 16 | 17 | 18 | 19 | FMTCustomer 20 | Yes 21 | FMTCustomer
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | classDeclaration 34 | 35 | 36 | 37 | 38 |
-------------------------------------------------------------------------------- /FMLab/AxWorkflowCategory_FMTWorkflowCategory.CTP3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FMTWorkflowCategory 4 | 5 | Basic 6 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/ActivityMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ConnectorServiceApplication 8 | { 9 | public class ActivityMessage 10 | { 11 | /// 12 | /// Correlation-Id. 13 | /// 14 | 15 | public string CorrelationId { get; set; } 16 | 17 | /// 18 | /// Pop-Receipt. 19 | /// 20 | 21 | public string PopReceipt { get; set; } 22 | 23 | /// 24 | /// The content, if the content is completely contained within the queue message. 25 | /// 26 | 27 | public string Content { get; set; } 28 | 29 | /// 30 | /// The location to download, if the content is outside of the queue message. 31 | /// 32 | 33 | public Uri DownloadLocation { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/ConnectorServiceApplication.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {78BE1A6C-63E2-4F41-A6E5-CA8D1DEDF12C} 8 | WinExe 9 | Properties 10 | ConnectorServiceApplication 11 | ConnectorServiceApplication 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | .\Microsoft.IdentityModel.Clients.ActiveDirectory.dll 37 | 38 | 39 | .\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Form 60 | 61 | 62 | mainForm.cs 63 | 64 | 65 | 66 | mainForm.cs 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/FleetCustomerPlainText.xslt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | FirstName: LastName 6 | 7 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.IdentityModel.Clients.ActiveDirectory; 7 | using System.Net.Http; 8 | using System.Net.Http.Headers; 9 | using System.IO; 10 | using System.Net.Http.Formatting; 11 | using System.Configuration; 12 | 13 | namespace ConnectorServiceApplication 14 | { 15 | class Helper 16 | { 17 | string authenticationHeader = ""; 18 | public string AuthenticationHeader 19 | { 20 | get 21 | { 22 | return authenticationHeader; 23 | } 24 | } 25 | 26 | 27 | public Helper(string clientId, string clientSecret) 28 | { 29 | //authentication string details 30 | UriBuilder uri = new UriBuilder(ConfigurationManager.AppSettings["Azure auth Uri"]); 31 | uri.Path = ConfigurationManager.AppSettings["Aad Tenant"]; 32 | 33 | AuthenticationContext authenticationContext = new AuthenticationContext(uri.ToString()); 34 | ClientCredential clientCred = new ClientCredential(clientId, clientSecret); 35 | AuthenticationResult authenticationResult = authenticationContext.AcquireToken(ConfigurationManager.AppSettings["Rainier Service Prinicipal"], clientCred); 36 | 37 | authenticationHeader = authenticationResult.CreateAuthorizationHeader(); 38 | } 39 | 40 | 41 | public HttpResponseMessage SendPostRequest(Uri uri, string authenticationHeader, string body, ActivityMessage message) 42 | { 43 | 44 | using (HttpClientHandler handler = new HttpClientHandler() { UseCookies = false }) 45 | { 46 | using (HttpClient webClient = new HttpClient(handler)) 47 | { 48 | webClient.DefaultRequestHeaders.Authorization = ParseAuthenticationHeader(authenticationHeader); 49 | 50 | HttpResponseMessage response; 51 | 52 | if (body != null) 53 | { 54 | //convert string into memorystream to be passed in the post request 55 | byte[] bytes = Encoding.ASCII.GetBytes(body); 56 | MemoryStream memStream = new MemoryStream(bytes); 57 | 58 | using (StreamContent content = new StreamContent(memStream)) 59 | { 60 | response = webClient.PostAsync(uri, content).Result; 61 | } 62 | } 63 | else 64 | { 65 | response = webClient.PostAsJsonAsync(uri.ToString(), message).Result; 66 | } 67 | 68 | return response; 69 | } 70 | } 71 | } 72 | 73 | public HttpResponseMessage SendRequest(HttpRequestMessage request) 74 | { 75 | using (HttpClientHandler handler = new HttpClientHandler() { UseCookies = false }) 76 | { 77 | using (HttpClient webClient = new HttpClient(handler)) 78 | { 79 | HttpResponseMessage response = webClient.SendAsync(request).Result; 80 | return response; 81 | } 82 | } 83 | } 84 | 85 | 86 | 87 | private static AuthenticationHeaderValue ParseAuthenticationHeader(string authenticationHeader) 88 | { 89 | string[] split = authenticationHeader.Split(' '); 90 | string scheme = split[0]; 91 | string parameter = split[1]; 92 | return new AuthenticationHeaderValue(scheme, parameter); 93 | } 94 | 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace ConnectorServiceApplication 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new mainForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/mainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ConnectorServiceApplication 2 | { 3 | partial class mainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 32 | this.txtBoxTenant = new System.Windows.Forms.TextBox(); 33 | this.label8 = new System.Windows.Forms.Label(); 34 | this.txtBoxSecret = new System.Windows.Forms.TextBox(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.txtBoxClientId = new System.Windows.Forms.TextBox(); 37 | this.label1 = new System.Windows.Forms.Label(); 38 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 39 | this.btnEnqueue = new System.Windows.Forms.Button(); 40 | this.label4 = new System.Windows.Forms.Label(); 41 | this.richTextEnqueue = new System.Windows.Forms.RichTextBox(); 42 | this.txtBoxInActivity = new System.Windows.Forms.TextBox(); 43 | this.label3 = new System.Windows.Forms.Label(); 44 | this.groupBox3 = new System.Windows.Forms.GroupBox(); 45 | this.btnDequeue = new System.Windows.Forms.Button(); 46 | this.label5 = new System.Windows.Forms.Label(); 47 | this.richTxtDequeue = new System.Windows.Forms.RichTextBox(); 48 | this.txtBoxOutActivity = new System.Windows.Forms.TextBox(); 49 | this.label6 = new System.Windows.Forms.Label(); 50 | this.txtBoxBaseUri = new System.Windows.Forms.TextBox(); 51 | this.label7 = new System.Windows.Forms.Label(); 52 | this.richTxtLog = new System.Windows.Forms.RichTextBox(); 53 | this.groupBox1.SuspendLayout(); 54 | this.groupBox2.SuspendLayout(); 55 | this.groupBox3.SuspendLayout(); 56 | this.SuspendLayout(); 57 | // 58 | // groupBox1 59 | // 60 | this.groupBox1.Controls.Add(this.txtBoxTenant); 61 | this.groupBox1.Controls.Add(this.label8); 62 | this.groupBox1.Controls.Add(this.txtBoxSecret); 63 | this.groupBox1.Controls.Add(this.label2); 64 | this.groupBox1.Controls.Add(this.txtBoxClientId); 65 | this.groupBox1.Controls.Add(this.label1); 66 | this.groupBox1.ForeColor = System.Drawing.Color.White; 67 | this.groupBox1.Location = new System.Drawing.Point(12, 18); 68 | this.groupBox1.Name = "groupBox1"; 69 | this.groupBox1.Size = new System.Drawing.Size(912, 81); 70 | this.groupBox1.TabIndex = 0; 71 | this.groupBox1.TabStop = false; 72 | this.groupBox1.Text = "Azure Client Registration Details "; 73 | // 74 | // txtBoxTenant 75 | // 76 | this.txtBoxTenant.Location = new System.Drawing.Point(96, 48); 77 | this.txtBoxTenant.Name = "txtBoxTenant"; 78 | this.txtBoxTenant.ReadOnly = true; 79 | this.txtBoxTenant.Size = new System.Drawing.Size(277, 20); 80 | this.txtBoxTenant.TabIndex = 5; 81 | // 82 | // label8 83 | // 84 | this.label8.AutoSize = true; 85 | this.label8.Location = new System.Drawing.Point(10, 48); 86 | this.label8.Name = "label8"; 87 | this.label8.Size = new System.Drawing.Size(71, 15); 88 | this.label8.TabIndex = 4; 89 | this.label8.Text = "AAD Tenant"; 90 | // 91 | // txtBoxSecret 92 | // 93 | this.txtBoxSecret.Location = new System.Drawing.Point(622, 19); 94 | this.txtBoxSecret.Name = "txtBoxSecret"; 95 | this.txtBoxSecret.ReadOnly = true; 96 | this.txtBoxSecret.Size = new System.Drawing.Size(277, 20); 97 | this.txtBoxSecret.TabIndex = 3; 98 | this.txtBoxSecret.Text = "Client Secret key"; 99 | // 100 | // label2 101 | // 102 | this.label2.AutoSize = true; 103 | this.label2.Location = new System.Drawing.Point(519, 22); 104 | this.label2.Name = "label2"; 105 | this.label2.Size = new System.Drawing.Size(97, 15); 106 | this.label2.TabIndex = 2; 107 | this.label2.Text = "Client Secret key"; 108 | // 109 | // txtBoxClientId 110 | // 111 | this.txtBoxClientId.Location = new System.Drawing.Point(235, 19); 112 | this.txtBoxClientId.Name = "txtBoxClientId"; 113 | this.txtBoxClientId.ReadOnly = true; 114 | this.txtBoxClientId.Size = new System.Drawing.Size(277, 20); 115 | this.txtBoxClientId.TabIndex = 1; 116 | // 117 | // label1 118 | // 119 | this.label1.AutoSize = true; 120 | this.label1.Location = new System.Drawing.Point(10, 22); 121 | this.label1.Name = "label1"; 122 | this.label1.Size = new System.Drawing.Size(219, 15); 123 | this.label1.TabIndex = 0; 124 | this.label1.Text = "Registered Client Id (from Azure Portal)"; 125 | // 126 | // groupBox2 127 | // 128 | this.groupBox2.Controls.Add(this.btnEnqueue); 129 | this.groupBox2.Controls.Add(this.label4); 130 | this.groupBox2.Controls.Add(this.richTextEnqueue); 131 | this.groupBox2.Controls.Add(this.txtBoxInActivity); 132 | this.groupBox2.Controls.Add(this.label3); 133 | this.groupBox2.ForeColor = System.Drawing.Color.White; 134 | this.groupBox2.Location = new System.Drawing.Point(12, 134); 135 | this.groupBox2.Name = "groupBox2"; 136 | this.groupBox2.Size = new System.Drawing.Size(912, 275); 137 | this.groupBox2.TabIndex = 1; 138 | this.groupBox2.TabStop = false; 139 | this.groupBox2.Text = "Enqueue a message"; 140 | // 141 | // btnEnqueue 142 | // 143 | this.btnEnqueue.ForeColor = System.Drawing.Color.Black; 144 | this.btnEnqueue.Location = new System.Drawing.Point(712, 28); 145 | this.btnEnqueue.Name = "btnEnqueue"; 146 | this.btnEnqueue.Size = new System.Drawing.Size(150, 23); 147 | this.btnEnqueue.TabIndex = 6; 148 | this.btnEnqueue.Text = "Enqueue Message"; 149 | this.btnEnqueue.UseVisualStyleBackColor = true; 150 | this.btnEnqueue.Click += new System.EventHandler(this.btnEnqueue_Click); 151 | // 152 | // label4 153 | // 154 | this.label4.AutoSize = true; 155 | this.label4.Location = new System.Drawing.Point(10, 68); 156 | this.label4.Name = "label4"; 157 | this.label4.Size = new System.Drawing.Size(58, 15); 158 | this.label4.TabIndex = 5; 159 | this.label4.Text = "Message"; 160 | // 161 | // richTextEnqueue 162 | // 163 | this.richTextEnqueue.BackColor = System.Drawing.SystemColors.Info; 164 | this.richTextEnqueue.Font = new System.Drawing.Font("Segoe UI", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 165 | this.richTextEnqueue.Location = new System.Drawing.Point(83, 65); 166 | this.richTextEnqueue.Name = "richTextEnqueue"; 167 | this.richTextEnqueue.Size = new System.Drawing.Size(816, 199); 168 | this.richTextEnqueue.TabIndex = 4; 169 | this.richTextEnqueue.Text = ""; 170 | // 171 | // txtBoxInActivity 172 | // 173 | this.txtBoxInActivity.Location = new System.Drawing.Point(83, 30); 174 | this.txtBoxInActivity.Name = "txtBoxInActivity"; 175 | this.txtBoxInActivity.Size = new System.Drawing.Size(277, 20); 176 | this.txtBoxInActivity.TabIndex = 3; 177 | // 178 | // label3 179 | // 180 | this.label3.AutoSize = true; 181 | this.label3.Location = new System.Drawing.Point(10, 33); 182 | this.label3.Name = "label3"; 183 | this.label3.Size = new System.Drawing.Size(55, 15); 184 | this.label3.TabIndex = 2; 185 | this.label3.Text = "Activity Id"; 186 | // 187 | // groupBox3 188 | // 189 | this.groupBox3.Controls.Add(this.btnDequeue); 190 | this.groupBox3.Controls.Add(this.label5); 191 | this.groupBox3.Controls.Add(this.richTxtDequeue); 192 | this.groupBox3.Controls.Add(this.txtBoxOutActivity); 193 | this.groupBox3.Controls.Add(this.label6); 194 | this.groupBox3.ForeColor = System.Drawing.Color.White; 195 | this.groupBox3.Location = new System.Drawing.Point(12, 415); 196 | this.groupBox3.Name = "groupBox3"; 197 | this.groupBox3.Size = new System.Drawing.Size(912, 275); 198 | this.groupBox3.TabIndex = 2; 199 | this.groupBox3.TabStop = false; 200 | this.groupBox3.Text = "Dequeue message"; 201 | // 202 | // btnDequeue 203 | // 204 | this.btnDequeue.ForeColor = System.Drawing.Color.Black; 205 | this.btnDequeue.Location = new System.Drawing.Point(728, 28); 206 | this.btnDequeue.Name = "btnDequeue"; 207 | this.btnDequeue.Size = new System.Drawing.Size(150, 23); 208 | this.btnDequeue.TabIndex = 6; 209 | this.btnDequeue.Text = "Dequeue Message"; 210 | this.btnDequeue.UseVisualStyleBackColor = true; 211 | this.btnDequeue.Click += new System.EventHandler(this.btnDequeue_Click); 212 | // 213 | // label5 214 | // 215 | this.label5.AutoSize = true; 216 | this.label5.Location = new System.Drawing.Point(10, 68); 217 | this.label5.Name = "label5"; 218 | this.label5.Size = new System.Drawing.Size(58, 15); 219 | this.label5.TabIndex = 5; 220 | this.label5.Text = "Message"; 221 | // 222 | // richTxtDequeue 223 | // 224 | this.richTxtDequeue.BackColor = System.Drawing.SystemColors.Info; 225 | this.richTxtDequeue.Location = new System.Drawing.Point(83, 65); 226 | this.richTxtDequeue.Name = "richTxtDequeue"; 227 | this.richTxtDequeue.Size = new System.Drawing.Size(816, 199); 228 | this.richTxtDequeue.TabIndex = 4; 229 | this.richTxtDequeue.Text = ""; 230 | // 231 | // txtBoxOutActivity 232 | // 233 | this.txtBoxOutActivity.Location = new System.Drawing.Point(83, 30); 234 | this.txtBoxOutActivity.Name = "txtBoxOutActivity"; 235 | this.txtBoxOutActivity.Size = new System.Drawing.Size(277, 20); 236 | this.txtBoxOutActivity.TabIndex = 3; 237 | // 238 | // label6 239 | // 240 | this.label6.AutoSize = true; 241 | this.label6.Location = new System.Drawing.Point(10, 33); 242 | this.label6.Name = "label6"; 243 | this.label6.Size = new System.Drawing.Size(55, 15); 244 | this.label6.TabIndex = 2; 245 | this.label6.Text = "Activity Id"; 246 | // 247 | // txtBoxBaseUri 248 | // 249 | this.txtBoxBaseUri.Location = new System.Drawing.Point(200, 108); 250 | this.txtBoxBaseUri.Name = "txtBoxBaseUri"; 251 | this.txtBoxBaseUri.Size = new System.Drawing.Size(479, 20); 252 | this.txtBoxBaseUri.TabIndex = 5; 253 | this.txtBoxBaseUri.Text = "Dynamics base URL for your org"; 254 | // 255 | // label7 256 | // 257 | this.label7.AutoSize = true; 258 | this.label7.Location = new System.Drawing.Point(11, 108); 259 | this.label7.Name = "label7"; 260 | this.label7.Size = new System.Drawing.Size(183, 15); 261 | this.label7.TabIndex = 4; 262 | this.label7.Text = "Dynamics base URL for your org"; 263 | // 264 | // richTxtLog 265 | // 266 | this.richTxtLog.BackColor = System.Drawing.SystemColors.ControlLight; 267 | this.richTxtLog.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 268 | this.richTxtLog.Location = new System.Drawing.Point(930, 60); 269 | this.richTxtLog.Name = "richTxtLog"; 270 | this.richTxtLog.Size = new System.Drawing.Size(528, 619); 271 | this.richTxtLog.TabIndex = 6; 272 | this.richTxtLog.Text = ""; 273 | // 274 | // mainForm 275 | // 276 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 277 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 278 | this.BackColor = System.Drawing.Color.Black; 279 | this.ClientSize = new System.Drawing.Size(1470, 701); 280 | this.Controls.Add(this.richTxtLog); 281 | this.Controls.Add(this.txtBoxBaseUri); 282 | this.Controls.Add(this.label7); 283 | this.Controls.Add(this.groupBox3); 284 | this.Controls.Add(this.groupBox2); 285 | this.Controls.Add(this.groupBox1); 286 | this.ForeColor = System.Drawing.Color.White; 287 | this.Name = "mainForm"; 288 | this.Text = "Connector Service - Client Application"; 289 | this.groupBox1.ResumeLayout(false); 290 | this.groupBox1.PerformLayout(); 291 | this.groupBox2.ResumeLayout(false); 292 | this.groupBox2.PerformLayout(); 293 | this.groupBox3.ResumeLayout(false); 294 | this.groupBox3.PerformLayout(); 295 | this.ResumeLayout(false); 296 | this.PerformLayout(); 297 | 298 | } 299 | 300 | #endregion 301 | 302 | private System.Windows.Forms.GroupBox groupBox1; 303 | private System.Windows.Forms.Label label1; 304 | private System.Windows.Forms.TextBox txtBoxSecret; 305 | private System.Windows.Forms.Label label2; 306 | private System.Windows.Forms.TextBox txtBoxClientId; 307 | private System.Windows.Forms.GroupBox groupBox2; 308 | private System.Windows.Forms.TextBox txtBoxInActivity; 309 | private System.Windows.Forms.Label label3; 310 | private System.Windows.Forms.RichTextBox richTextEnqueue; 311 | private System.Windows.Forms.Button btnEnqueue; 312 | private System.Windows.Forms.Label label4; 313 | private System.Windows.Forms.GroupBox groupBox3; 314 | private System.Windows.Forms.Button btnDequeue; 315 | private System.Windows.Forms.Label label5; 316 | private System.Windows.Forms.RichTextBox richTxtDequeue; 317 | private System.Windows.Forms.TextBox txtBoxOutActivity; 318 | private System.Windows.Forms.Label label6; 319 | private System.Windows.Forms.TextBox txtBoxBaseUri; 320 | private System.Windows.Forms.Label label7; 321 | private System.Windows.Forms.RichTextBox richTxtLog; 322 | private System.Windows.Forms.Label label8; 323 | private System.Windows.Forms.TextBox txtBoxTenant; 324 | } 325 | } 326 | 327 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/mainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using System.Net.Http; 11 | using System.Configuration; 12 | 13 | namespace ConnectorServiceApplication 14 | { 15 | public partial class mainForm : Form 16 | { 17 | 18 | public mainForm() 19 | { 20 | InitializeComponent(); 21 | 22 | txtBoxBaseUri.Text = ConfigurationManager.AppSettings["Rainier Uri"]; 23 | txtBoxClientId.Text = ConfigurationManager.AppSettings["Azure Client Id"]; 24 | txtBoxSecret.Text = ConfigurationManager.AppSettings[ "Azure Client Secret"]; 25 | txtBoxTenant.Text = ConfigurationManager.AppSettings["Aad Tenant"]; 26 | } 27 | 28 | private void btnEnqueue_Click(object sender, EventArgs e) 29 | { 30 | if (richTextEnqueue.Text.Length == 0) 31 | return; 32 | 33 | Cursor.Current = Cursors.WaitCursor; 34 | 35 | //authenticate 36 | Helper helper = new Helper(txtBoxClientId.Text, txtBoxSecret.Text); 37 | 38 | //remove the unwanted curly braces 39 | txtBoxInActivity.Text = txtBoxInActivity.Text.Replace("{", ""); 40 | txtBoxInActivity.Text = txtBoxInActivity.Text.Replace("}", ""); 41 | 42 | //access the Connector API 43 | UriBuilder enqueueUri = new UriBuilder(txtBoxBaseUri.Text); 44 | enqueueUri.Path = "api/connector/Enqueue/" + txtBoxInActivity.Text; 45 | 46 | helper.SendPostRequest(enqueueUri.Uri, helper.AuthenticationHeader, richTextEnqueue.Text, null); 47 | richTxtLog.AppendText ("Message Enqueued: " + enqueueUri.Uri + "\u2028"); 48 | 49 | Cursor.Current = Cursors.Default; 50 | } 51 | 52 | 53 | private void btnDequeue_Click(object sender, EventArgs e) 54 | { 55 | if (txtBoxOutActivity.Text.Length == 0) 56 | return; 57 | 58 | Cursor.Current = Cursors.WaitCursor; 59 | 60 | //authenticate 61 | Helper helper = new Helper(txtBoxClientId.Text, txtBoxSecret.Text); 62 | 63 | //remove the unwanted curly braces 64 | txtBoxOutActivity.Text = txtBoxOutActivity.Text.Replace("{", ""); 65 | txtBoxOutActivity.Text = txtBoxOutActivity.Text.Replace("}", ""); 66 | 67 | //access the Connector API 68 | UriBuilder dequeueUri = new UriBuilder(txtBoxBaseUri.Text); 69 | dequeueUri.Path = "api/connector/dequeue/" + txtBoxOutActivity.Text; 70 | 71 | 72 | //send a request to get the next queue message 73 | HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, dequeueUri.Uri); 74 | request.Headers.Add("Authorization", helper.AuthenticationHeader); 75 | HttpResponseMessage response = helper.SendRequest(request); 76 | 77 | //read the response 78 | ActivityMessage responseMessage = response.Content.ReadAsAsync().Result; 79 | if (responseMessage == null) 80 | { 81 | MessageBox.Show("No more messages in the queue"); 82 | return; 83 | } 84 | 85 | 86 | //read the downloadlocation and make a blob request 87 | request = new HttpRequestMessage(HttpMethod.Get, responseMessage.DownloadLocation.ToString()); 88 | request.Headers.Add("Authorization", helper.AuthenticationHeader); 89 | 90 | //send a request to get the actual content from the blob storage 91 | HttpResponseMessage blobResponse = helper.SendRequest(request); 92 | richTxtDequeue.Text = blobResponse.Content.ReadAsStringAsync().Result; 93 | 94 | //ack the message 95 | UriBuilder ackUri= new UriBuilder(txtBoxBaseUri.Text); 96 | ackUri.Path = "api/connector/ack/" + txtBoxOutActivity.Text; 97 | helper.SendPostRequest(ackUri.Uri, helper.AuthenticationHeader, null, responseMessage); 98 | 99 | richTxtLog.AppendText ("Message dequeued and acked. MessageId: " + responseMessage.CorrelationId + "\u2028"); 100 | 101 | Cursor.Current = Cursors.Default; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/mainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /FMLab/ConnectorClientApplication/uploadFMCustomer.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FMLab/DemoBP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/DemoBP.zip -------------------------------------------------------------------------------- /FMLab/DriversLicenseChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DriversLicenseEvaluator 8 | { 9 | using Dynamics.AX.Application; 10 | using Microsoft.Dynamics.AX.Framework.Linq.Data; 11 | using Microsoft.Dynamics.Ax.Xpp; 12 | 13 | public class DriversLicenseChecker 14 | { 15 | public static bool CheckDriversLicense(long customerId) 16 | { 17 | // Use LINQ to get back to the information about the 18 | // license number 19 | FMCustomer customer; 20 | QueryProvider provider = new AXQueryProvider(null); 21 | var customers = new QueryCollection(provider); 22 | 23 | // Build the query (but do not execute it) 24 | var query = from c in customers 25 | where c.RecId == customerId 26 | select c; 27 | 28 | // Execute the query: 29 | customer = query.FirstOrDefault(); 30 | if (customer == null) 31 | { 32 | throw new ArgumentException 33 | ("The customerId does not designate a customer"); 34 | } 35 | 36 | // or, much more succinctly: 37 | // customer = customers.Single(c => c.RecId == customerId); 38 | 39 | if (string.IsNullOrEmpty(customer.DriverLicense)) 40 | { 41 | // No driver's license was recorded. Veto the rental. 42 | return false; 43 | } 44 | 45 | // Call the DOT web service to validate the license number. 46 | // This is not practical for this lab, because all the service providers 47 | // charge for this service. Instead, just assume that any license number 48 | // that contains the sequence "89" is valid. 49 | // In the demo data, this is true for Adrian Lannin, 50 | // but not for Phil Spencer. 51 | return customer.DriverLicense.Contains("89"); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FMLab/DynamicsAX.ExcelManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 61bcc63f-b860-4280-8280-3e4fb5ea7726 6 | 1.0.0.0 7 | Microsoft Corporation 8 | en-US 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ReadWriteDocument 29 | 30 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTCCExpiryDate.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTCCExpiryDate 5 | Calendar 6 | @SYS78674 7 | 8 | FMTCustomer 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTChargeTypeId.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTChargeTypeId 5 | @SYS78674 6 | 7 | 8 | 9 | 10 | 20 11 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTCreditCardNum.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTCreditCardNum 5 | 6 | 7 | 8 | 20 9 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTCustomerRecId.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTCustomerRecId 5 | RefRecId 6 | @SYS78674 7 | 8 | FMTCustomer 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTDescription.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTDescription 5 | @SYS78674 6 | 7 | 8 | 9 | 10 | 255 11 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTDriversLicense.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTDriversLicense 5 | @SYS78674 6 | 7 | 8 | 9 | 10 | 20 11 | -------------------------------------------------------------------------------- /FMLab/EDT/AxEdt_FMTName.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | FMTName 5 | @SYS78674 6 | 7 | FMTCustomer 8 | 9 | 10 | 11 | 50 12 | -------------------------------------------------------------------------------- /FMLab/FMTutorialDataModel.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/FMTutorialDataModel.axpp -------------------------------------------------------------------------------- /FMLab/Lab10-1/Adding BI to workspaces.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/Lab10-1/Adding BI to workspaces.axpp -------------------------------------------------------------------------------- /FMLab/Lab10-2/Add contextual BI to a form - After Lab.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/Lab10-2/Add contextual BI to a form - After Lab.axpp -------------------------------------------------------------------------------- /FMLab/Lab10-2/Add contextual BI to a form - Before Lab.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/Lab10-2/Add contextual BI to a form - Before Lab.axpp -------------------------------------------------------------------------------- /FMLab/Lab10-2/Add contextual BI to a form.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/Lab10-2/Add contextual BI to a form.axpp -------------------------------------------------------------------------------- /FMLab/Lab10-2/FMBILabHelper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FMBILabHelper 4 | 5 | 16 | 17 | 18 | FMBILab_ExecuteQuery 19 | 21 | /// Helper method to Read data from an Aggregate Data entity and move to the Temp table required by Lab 10.2 22 | /// 23 | /// 24 | 25 | public static void FMBILab_ExecuteQuery(str vehicleMakeParameter, TmpDBBIFMRevenueByVehicleModelByMonth tempTable) 26 | { 27 | try 28 | { 29 | 30 | // Get the aggregate query behind the existing Aggregate data entity FMBIRevenueByVehicleModel 31 | AggregateQuery aq = AggregateQueryRun::QueryFromAggregateDataEntity(tablestr(FMBIRevenueByVehicleModel)); 32 | 33 | if (aq != null) 34 | { 35 | 36 | // Defne the filter expression using the Vehicle make 37 | LevelExpression allMakes = new LevelExpression(dimensionhierarchylevelstr("FMAggregateMeasurements/FMVehicle/VehicleMake/VehicleMake")); 38 | LogicalExpression currentMakeFilter = new Microsoft.Dynamics.AX.Framework.Analytics.AggregateQuery.QueryModel.Core.Exists(new MemberExpression(allMakes, vehicleMakeParameter)); 39 | 40 | // Add the filter condition to the orignal query 41 | aq.AddSelect(new FilterExpression(SetExpression::ALL, currentMakeFilter)); 42 | 43 | // Since the Aggregate Data entity does not have a month column, We need to add months to the existing query 44 | // we can add additional dimension attributes and measures. But we can't remove existing ones at present 45 | SetExpression allMonths = new LevelExpression(dimensionhierarchylevelstr("FMAggregateMeasurements/RentalStartDate/Quarter/Quarter")); 46 | 47 | /// Add the new Set to the orignal query as another column. "As" is an alias that we will provide to this column 48 | /// We don't need to provide Aliases for fields sourced from an Aggregate Data entity 49 | aq.AddSelect(allMonths.As("Quarter")); 50 | 51 | /// Create a QueryRun object using the query we have constructed. QueryRun objet enables us to retrieve data 52 | AggregateQueryRun queryRun = new AggregateQueryRun(aq); 53 | 54 | /// Instead of iterating in a loop and reading data from the QueryRun object, we can Bulk move data into the destination Table 55 | /// define the mappins between the dataset of the query result and our target table that we want to populate 56 | QueryResultToDatasourceColumnMappings mappings = new QueryResultToDatasourceColumnMappings(); 57 | mappings.AddMapping("TotalRevenue", fieldstr(TmpDBBIFMRevenueByVehicleModelByMonth, TotalRevenue)); 58 | mappings.AddMapping("NumRentals", fieldstr(TmpDBBIFMRevenueByVehicleModelByMonth, NumRentals)); 59 | mappings.AddMapping("VehicleModel", fieldstr(TmpDBBIFMRevenueByVehicleModelByMonth, VehicleModel)); 60 | mappings.AddMapping("Quarter", fieldstr(TmpDBBIFMRevenueByVehicleModelByMonth, RentalMonth)); 61 | 62 | // execute the query and populate the target table as a bulk move 63 | queryRun.RunAndPopulate(tempTable, mappings); 64 | } 65 | } 66 | catch (Exception::CLRError) 67 | { 68 | SRSProxy::handleClrException(Exception::Error); 69 | } 70 | } 71 | 72 | ]]> 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /FMLab/Lab10-2/FMBIRevenueByVehicleModel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FMBIRevenueByVehicleModel 4 | 5 | 10 | 11 | 12 | 13 | DataSource 14 | FMAggregateMeasurements 15 | 16 | 17 | 18 | 19 | AutoReport 20 | 21 | 22 | 23 | AutoLookup 24 | 25 | 26 | 27 | AutoIdentification 28 | Yes 29 | 30 | 31 | 32 | AutoSummary 33 | 34 | 35 | 36 | AutoBrowse 37 | 38 | 39 | 40 | 41 | 43 | NumRentals 44 | BIRCount 45 | NoRentals 46 | FMRentalCharges 47 | 48 | 50 | TotalRevenue 51 | FMExtendedAmount 52 | TotalRevenue 53 | FMRentalCharges 54 | 55 | 57 | VehicleModel 58 | VehicleModel 59 | FMVehicle 60 | FMVehicleModelId 61 | FMRentalCharges 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /FMLab/Lab10-2/TmpDBBIFMRevenueByVehicleModelByMonth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | TmpDBBIFMRevenueByVehicleModelByMonth 4 | 5 | 10 | 11 | 12 | No 13 | TempDB 14 | 15 | 16 | 17 | AutoReport 18 | 19 | 20 | 21 | AutoLookup 22 | 23 | 24 | 25 | AutoIdentification 26 | Yes 27 | 28 | 29 | 30 | AutoSummary 31 | 32 | 33 | 34 | AutoBrowse 35 | 36 | 37 | 38 | 39 | 41 | TotalRevenue 42 | FMExtendedAmount 43 | 44 | 46 | NumRentals 47 | FMQuantity 48 | 49 | 51 | VehicleModel 52 | FMVehicleModelId 53 | 20 54 | 55 | 57 | RentalMonth 58 | 30 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | Relation1 67 | FMVehicleModel 68 | ExactlyOne 69 | 70 | 72 | VehicleModel 73 | VehicleModel 74 | Model 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /FMLab/Lab10-3/FMRentalDetailsReport.axpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/FMLab/01130ec5ff2c0c5ff26aaba52743b4e4ec0d1174/FMLab/Lab10-3/FMRentalDetailsReport.axpp -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/AuthenticationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | using Microsoft.IdentityModel.Protocols.WSTrust; 7 | using System.IdentityModel.Tokens; 8 | using WindowsForms = System.Windows.Forms; 9 | using Microsoft.IdentityModel.Tokens.Saml2; 10 | using Microsoft.IdentityModel.Tokens.Saml11; 11 | using System.IO; 12 | using System.Xml; 13 | using System.Net; 14 | using System.Net.Security; 15 | using System.Security.Cryptography.X509Certificates; 16 | using System.Globalization; 17 | using System.Configuration; 18 | using System.Diagnostics; 19 | using ODataConsoleApplication.ServiceReference1; 20 | using System.Data.Services.Client; 21 | 22 | namespace ODataConsoleApplication 23 | { 24 | internal class AuthenticationHelper 25 | { 26 | const string aosUrl = "https://usncax1aos.cloud.onebox.dynamics.com/"; 27 | private static String cookies; 28 | 29 | internal static string PerformAuthentication(Resources context) 30 | { 31 | 32 | AcsResponse param = new AcsResponse(); 33 | BrowserForm browserForm = new BrowserForm(aosUrl, param); 34 | WindowsForms.Application.Run(browserForm); 35 | // Debug.Assert(!browserForm.NavigationCanceled, "Unable to perform authentication to AOS"); 36 | 37 | HttpWebRequest httpRequest; 38 | HttpWebResponse httpResponse; 39 | CookieContainer cookieContainer = new CookieContainer(); 40 | 41 | httpRequest = (HttpWebRequest)WebRequest.Create(aosUrl); 42 | httpRequest.Method = "POST"; 43 | httpRequest.ContentType = "application/x-www-form-urlencoded"; 44 | 45 | // 46 | // Authentication was done by using the hostname URI and not 47 | // full request URI. Hence, we should not let autoredirect 48 | // happen. 49 | // 50 | 51 | httpRequest.AllowAutoRedirect = false; 52 | httpRequest.CookieContainer = cookieContainer; 53 | 54 | StreamWriter writer = new StreamWriter(httpRequest.GetRequestStream(), Encoding.ASCII); 55 | writer.Write(param.GetAcsResponseString()); 56 | writer.Flush(); 57 | writer.Close(); 58 | 59 | httpResponse = (HttpWebResponse)httpRequest.GetResponse(); 60 | httpResponse.Close(); 61 | 62 | StringBuilder retval = new StringBuilder(); 63 | 64 | CookieCollection cookiesCollection = cookieContainer.GetCookies(new Uri(aosUrl)); 65 | 66 | if (cookiesCollection.Count > 0) 67 | { 68 | foreach (Cookie c in cookiesCollection) 69 | { 70 | retval.AppendFormat("{0}={1}; ", c.Name, c.Value); 71 | } 72 | 73 | //Remove the trailing "; " 74 | retval.Remove(retval.Length - 2, 2); 75 | } 76 | 77 | cookies = retval.ToString(); 78 | 79 | context.SendingRequest += new EventHandler(OnSendingRequest); 80 | 81 | return cookies; 82 | } 83 | 84 | public static void OnSendingRequest(object sender, SendingRequestEventArgs e) 85 | { 86 | // Add the cookie to the cookie header to authenticate call to service 87 | e.RequestHeaders.Add(HttpRequestHeader.Cookie, cookies); 88 | } 89 | 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/BrowserForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.Xml; 10 | using System.Web; 11 | using System.Diagnostics; 12 | using System.Globalization; 13 | using System.Text.RegularExpressions; 14 | 15 | namespace ODataConsoleApplication 16 | { 17 | public partial class BrowserForm : Form 18 | { 19 | public BrowserForm(String url, AcsResponse param) 20 | { 21 | SetUrl(url); 22 | SetAcsResponseParam(param); 23 | InitializeComponent(); 24 | } 25 | 26 | private String GetUrl() 27 | { 28 | return m_url; 29 | } 30 | 31 | private void SetUrl(String url) 32 | { 33 | m_url = url; 34 | } 35 | 36 | private void SetAcsResponseParam(AcsResponse param) 37 | { 38 | m_acsResponseParam = param; 39 | } 40 | 41 | private void ReturnAcsResponse(String acsResponseString) 42 | { 43 | m_acsResponseParam.SetAcsResponseString(acsResponseString); 44 | } 45 | 46 | private String m_url; 47 | private AcsResponse m_acsResponseParam; // Ref to caller provided. 48 | 49 | private void BrowserForm_Load(object sender, EventArgs e) 50 | { 51 | this.Browser.Navigate(GetUrl()); 52 | } 53 | 54 | private void WebBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e) 55 | { 56 | try 57 | { 58 | // Check if we are about to submit the SAML token returned by ACS. 59 | if (String.Compare(e.Url.AbsoluteUri, GetUrl(), true) == 0) 60 | { 61 | // Extract ACS response. 62 | if (this.Browser.Document.All["wresult"] != null) 63 | { 64 | // Cancel the request so that the POST doesn't actually happen. 65 | e.Cancel = true; 66 | 67 | try 68 | { 69 | String acsResponse; 70 | 71 | // 72 | // The ACS response that needs to be posted back has to be in a very 73 | // specific format. 74 | // 75 | 76 | dynamic wa = this.Browser.Document.All["wa"].DomElement; 77 | String waString = System.Web.HttpUtility.HtmlDecode(wa.value); 78 | #if false 79 | Console.WriteLine("wa={0}", waString); 80 | #endif 81 | 82 | dynamic wresult = this.Browser.Document.All["wresult"].DomElement; 83 | String wresultString = System.Web.HttpUtility.HtmlDecode(wresult.value); 84 | wresultString = wresultString.Replace("&", "&"); 85 | #if false 86 | Console.WriteLine("wresult={0}", wresultString); 87 | #endif 88 | 89 | dynamic wctx = this.Browser.Document.All["wctx"].DomElement; 90 | String wctxString = System.Web.HttpUtility.HtmlDecode(wctx.value); 91 | #if false 92 | Console.WriteLine("wctx={0}", wctxString); 93 | #endif 94 | 95 | acsResponse = "wa=" + System.Web.HttpUtility.UrlEncode(waString, Encoding.ASCII) + "&" + 96 | "wresult=" + System.Web.HttpUtility.UrlEncode(wresultString, Encoding.ASCII) + "&" + 97 | "wctx=" + System.Web.HttpUtility.UrlEncode(wctxString, Encoding.ASCII); 98 | 99 | #if false 100 | Console.WriteLine("URL encoded ACS response:"); 101 | Console.WriteLine(acsResponse); 102 | #endif 103 | 104 | ReturnAcsResponse(acsResponse); 105 | } 106 | catch (Exception exception) 107 | { 108 | Console.WriteLine(exception.ToString()); 109 | } 110 | 111 | // Close the browser form. 112 | this.Dispose(); 113 | } 114 | } 115 | } 116 | catch (Exception ) 117 | { 118 | 119 | } 120 | } 121 | 122 | private void BrowserForm_Closing(object sender, CancelEventArgs e) 123 | { 124 | //this.navigationCanceled = true; 125 | } 126 | 127 | } 128 | 129 | public class AcsResponse 130 | { 131 | public AcsResponse() 132 | { 133 | m_acsResponseString = String.Empty; 134 | } 135 | 136 | public void SetAcsResponseString(String acsResponseString) 137 | { 138 | m_acsResponseString = acsResponseString; 139 | } 140 | 141 | public String GetAcsResponseString() 142 | { 143 | return m_acsResponseString; 144 | } 145 | 146 | private String m_acsResponseString; 147 | } 148 | 149 | } -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/BrowserForm.designer.cs: -------------------------------------------------------------------------------- 1 | namespace ODataConsoleApplication 2 | { 3 | partial class BrowserForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.Browser = new System.Windows.Forms.WebBrowser(); 32 | this.SuspendLayout(); 33 | // 34 | // Browser 35 | // 36 | this.Browser.Dock = System.Windows.Forms.DockStyle.Fill; 37 | this.Browser.Location = new System.Drawing.Point(0, 0); 38 | this.Browser.MinimumSize = new System.Drawing.Size(20, 20); 39 | this.Browser.Name = "Browser"; 40 | //this.Browser.ScrollBarsEnabled = false; 41 | this.Browser.Size = new System.Drawing.Size(903, 403); 42 | this.Browser.TabIndex = 0; 43 | this.Browser.Navigating += new System.Windows.Forms.WebBrowserNavigatingEventHandler(this.WebBrowser_Navigating); 44 | // 45 | // BrowserForm 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.ClientSize = new System.Drawing.Size(903, 403); 50 | this.Controls.Add(this.Browser); 51 | this.Name = "BrowserForm"; 52 | this.Text = "BrowserForm"; 53 | this.Load += new System.EventHandler(this.BrowserForm_Load); 54 | this.Closing += new System.ComponentModel.CancelEventHandler(BrowserForm_Closing); 55 | this.ResumeLayout(false); 56 | } 57 | 58 | #endregion 59 | 60 | private System.Windows.Forms.WebBrowser Browser; 61 | } 62 | } -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/BrowserForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/CloudEnvironment.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 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 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/ODataConsoleApplication.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {621892ED-222F-4FA6-BCD8-61C82CEAFCA3} 8 | Exe 9 | Properties 10 | ODataConsoleApplication 11 | ODataConsoleApplication 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | False 40 | ..\..\..\..\..\..\Program Files\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\Microsoft.IdentityModel.dll 41 | 42 | 43 | .\Microsoft.OData.Client.dll 44 | 45 | 46 | .\Microsoft.OData.Core.dll 47 | 48 | 49 | .\Microsoft.OData.Edm.dll 50 | 51 | 52 | .\Microsoft.Spatial.dll 53 | 54 | 55 | .\MS.Dynamics.TestTools.CloudCommonTestUtilities.dll 56 | 57 | 58 | .\MS.Dynamics.TestTools.Common.dll 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | True 78 | True 79 | ODataProxies.tt 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | TextTemplatingFileGenerator 88 | ODataProxies.cs 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/ODataConsoleApplication.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ODataConsoleApplication", "ODataConsoleApplication.csproj", "{621892ED-222F-4FA6-BCD8-61C82CEAFCA3}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {621892ED-222F-4FA6-BCD8-61C82CEAFCA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {621892ED-222F-4FA6-BCD8-61C82CEAFCA3}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {621892ED-222F-4FA6-BCD8-61C82CEAFCA3}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {621892ED-222F-4FA6-BCD8-61C82CEAFCA3}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/ODataProxies.odata.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | //using System.Data.Services.Client; 7 | //using ODataConsoleClient; 8 | using System.IO; 9 | using MS.Dynamics.TestTools.CloudCommonTestUtilities.Authentication; 10 | using Microsoft.OData.Client; 11 | using System.Net; 12 | 13 | 14 | namespace ODataConsoleClient 15 | { 16 | class Program 17 | { 18 | 19 | private static EventHandler _ODataResource_SendingRequest = new EventHandler(OnSendingRequest); 20 | 21 | /// 22 | /// Does all needed initialization to the context object 23 | /// 24 | /// the data context object to initialize 25 | public static void InitializeContextObject(DataServiceContext contextObject) 26 | { 27 | // Make sure it is not null 28 | if (contextObject == null) 29 | { 30 | throw new ArgumentNullException("contextObject"); 31 | } 32 | 33 | // Register to the send request event in order to add the request header 34 | contextObject.SendingRequest2 += new EventHandler(_ODataResource_SendingRequest); 35 | } 36 | 37 | 38 | /// 39 | /// Adds to the request the cookie header for the security token 40 | /// 41 | /// the sender of the event 42 | /// the args for adding the cookie to 43 | public static void OnSendingRequest(object sender, SendingRequest2EventArgs e) 44 | { 45 | // Add the cookie in the commonUtil to the cookie header to authenticate call to service 46 | e.RequestMessage.SetHeader(HttpRequestHeader.Cookie.ToString(), AuthenticationUtils.GetCookie(AuthenticatorFactory.AdminAuthenticator)); 47 | } 48 | 49 | 50 | public static Resources context; 51 | 52 | [STAThread] 53 | static void Main(string[] args) 54 | { 55 | string ODataServiceEndpoint = "https://usncax1aos.cloud.onebox.dynamics.com/data"; 56 | 57 | Uri dynODataURI = new Uri(ODataServiceEndpoint, UriKind.Absolute); 58 | //Creates a DataServiceContext class which encapsulates operations that are supported by the OData endpoint 59 | context = new Resources(dynODataURI); 60 | 61 | //Authenticate the user 62 | //AuthenticationHelper.PerformAuthentication(context); 63 | Program.InitializeContextObject(context); 64 | 65 | CreateExchange(); 66 | 67 | Console.WriteLine("-------------------------------------------------------------------"); 68 | Console.WriteLine("Query all the customers in Fleet Management. Enter to start ..."); 69 | Console.WriteLine("-------------------------------------------------------------------"); 70 | Console.ReadLine(); 71 | 72 | GetAllCustomers(); 73 | 74 | Console.WriteLine(); 75 | Console.WriteLine("-------------------------------------"); 76 | Console.WriteLine("Create a new customer. Enter to start"); 77 | Console.WriteLine("-------------------------------------"); 78 | Console.ReadLine(); 79 | 80 | 81 | Customer newCustomer = CreateCustomer(); 82 | 83 | 84 | Console.WriteLine(); 85 | Console.WriteLine("--------------------------------------------------------------------"); 86 | Console.WriteLine("Create a new reservation for the customer. Enter to start ..."); 87 | Console.WriteLine("--------------------------------------------------------------------"); 88 | Console.ReadLine(); 89 | 90 | CreateReservation(newCustomer); 91 | 92 | 93 | Console.ForegroundColor = ConsoleColor.White; 94 | Console.BackgroundColor = ConsoleColor.Black; 95 | 96 | Console.WriteLine(); 97 | 98 | Console.WriteLine("***************************************************"); 99 | Console.WriteLine("* *"); 100 | Console.WriteLine("You have successfully completed, \t\t\n 1. Creating a new customer \t\t\t\n 2. Creating a new reservation for that customer. \n " + 101 | "Please refer back to Hands on Lab documentation to continue \n Press Enter to close this application \t"); 102 | Console.WriteLine("* *"); 103 | Console.WriteLine("***************************************************"); 104 | 105 | Console.ReadLine(); 106 | 107 | } 108 | 109 | /// 110 | /// This method issues a query URI to retrieve all the Customers from the Customer OData Entity 111 | /// 112 | private static void GetAllCustomers() 113 | { 114 | //Using the DataServiceContext class, we can simply perform a LINQ query to retrieve all Customers from the Customer entity. 115 | //This internally will issue web request by using the URI that represents OData protocol 116 | var query = from customer in context.Customers 117 | select customer; 118 | 119 | 120 | Console.ForegroundColor = ConsoleColor.Cyan; 121 | //Display the http request Uri that was sent to fetch all customers 122 | Console.WriteLine("Request Uri: " + query.ToString()); 123 | Console.ForegroundColor = ConsoleColor.White; 124 | 125 | Console.WriteLine(); 126 | 127 | //After retrieving all the customers, iterate through the collection and print each one. 128 | foreach (Customer c in query) 129 | { 130 | Console.WriteLine("Customer.RecId: " + c.RecId); 131 | Console.WriteLine("First Name: " + c.FirstName); 132 | Console.WriteLine("Last Name: " + c.LastName); 133 | 134 | Console.WriteLine("++++++++"); 135 | } 136 | } 137 | 138 | 139 | /// 140 | /// This method prompts the user for first name and last name and then uses that to create a new customer by calling the Customer OData entity 141 | /// 142 | /// 143 | private static Customer CreateCustomer() 144 | { 145 | 146 | Console.WriteLine("Enter First Name, and then press Enter"); 147 | string firstName = Console.ReadLine(); 148 | 149 | Console.WriteLine("Enter Last Name, and then press Enter "); 150 | string lastName = Console.ReadLine(); 151 | 152 | //Create the Customer object with the first and last names provided by the user 153 | Customer newCustomer = new Customer() 154 | { 155 | FirstName = firstName, 156 | LastName = lastName, 157 | CellPhone = "0123456789", 158 | Email = "test@contoso.com" 159 | }; 160 | 161 | //Add the new customer object to the DataServiceContext object 162 | context.AddToCustomers(newCustomer); 163 | 164 | //Save the DataServiceContext object and an internally a POST call is made to the OData Customer entity. 165 | //Record is created in Rainier Database 166 | OperationResponse response = context.SaveChanges().First(); 167 | 168 | Console.ForegroundColor = ConsoleColor.Cyan; 169 | if (response.Error == null) 170 | { 171 | Console.WriteLine("New customer created: "); 172 | //Display the URI of the new customer 173 | Console.WriteLine(response.Headers["Location"]); 174 | } 175 | Console.ForegroundColor = ConsoleColor.White; 176 | 177 | return newCustomer ; 178 | } 179 | 180 | private static SVC_ODataPersonView_DE CreateExchange() 181 | { 182 | DataServiceCollection svcOdata = new DataServiceCollection(context); 183 | 184 | var newExchange = new SVC_ODataPersonView_DE(); 185 | svcOdata.Add(newExchange); 186 | 187 | newExchange.Name = "foo bar"; 188 | newExchange.Email = "kuntal-test"; 189 | 190 | context.SaveChanges(SaveChangesOptions.PostOnlySetProperties); 191 | 192 | //context.SaveChanges(); 193 | 194 | return newExchange; 195 | 196 | } 197 | 198 | /// 199 | /// This method creates a new reservation record for the customer, created by the CreateCustomer method. 200 | /// 201 | /// 202 | /// 203 | private static Reservation CreateReservation(Customer customer) 204 | { 205 | Random rnd = new Random (); 206 | 207 | //Create a new Reservation object with the details for new customer. 208 | Reservation reservation = new Reservation() 209 | { 210 | Customer = customer, 211 | PickupDate = DateTime.Today, 212 | ReturnDate = DateTime.Today.AddDays (5.0), 213 | State =0, //Limitation of OData, no client-side Enum support 214 | ReservationId = "OData_" + rnd.Next (500).ToString () 215 | }; 216 | 217 | //Query the vehicle Odata Entity to retrieve the first vehicle from the list 218 | var vehicle = (from v in context.Vehicles 219 | select v).First(); 220 | 221 | 222 | // Set up the relationship between (a) reservation and vehicle and (b) reservation and customer. 223 | 224 | //Add a link to the customer from the reservation 225 | reservation.Customer = customer; 226 | reservation.CustomerId = customer.RecId; 227 | customer.Reservations.Add(reservation); 228 | 229 | context.AddToReservations(reservation); 230 | context.AddLink(customer, "Reservations", reservation); 231 | 232 | //add link to the vehicle from the reservation 233 | reservation.Vehicle = vehicle; 234 | reservation.VehicleId = vehicle.RecId; 235 | vehicle.Reservations.Add(reservation); 236 | context.SetLink(reservation, "Vehicle", vehicle); 237 | 238 | // Now that we have created a new reservation and set the required relationship with customer and vehicle, 239 | // we will save these changes. Internally, this will also 240 | // perform a POST to the Reservation OData Entity. 241 | OperationResponse response = context.SaveChanges().First(); 242 | 243 | Console.ForegroundColor = ConsoleColor.Cyan; 244 | if (response.Error == null) 245 | { 246 | Console.WriteLine("New Reservation created"); 247 | //Display the URI of the newly created reservation 248 | Console.WriteLine(response.Headers["Location"]); 249 | } 250 | Console.ForegroundColor = ConsoleColor.White; 251 | 252 | return reservation; 253 | 254 | } 255 | 256 | 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /FMLab/ODataConsoleApplication/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/AuthenticationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | using Microsoft.IdentityModel.Protocols.WSTrust; 7 | using System.IdentityModel.Tokens; 8 | using WindowsForms = System.Windows.Forms; 9 | using Microsoft.IdentityModel.Tokens.Saml2; 10 | using Microsoft.IdentityModel.Tokens.Saml11; 11 | using System.IO; 12 | using System.Xml; 13 | using System.Net; 14 | using System.Net.Security; 15 | using System.Security.Cryptography.X509Certificates; 16 | using System.Globalization; 17 | using System.Configuration; 18 | using System.Diagnostics; 19 | using ODataClient.Microsoft.Dynamics.DataEntities; 20 | using System.Data.Services.Client; 21 | using Microsoft.OData.Client; 22 | 23 | namespace Odata4ConsoleApplication 24 | { 25 | internal class AuthenticationHelper 26 | { 27 | //const string aosUrl = "https://usnconeboxax1aos.cloud.onebox.dynamics.com/"; 28 | private static String cookies; 29 | 30 | internal static string PerformAuthentication(Resources context, string aosUrl) 31 | { 32 | 33 | AcsResponse param = new AcsResponse(); 34 | BrowserForm browserForm = new BrowserForm(aosUrl, param); 35 | WindowsForms.Application.Run(browserForm); 36 | 37 | HttpWebRequest httpRequest; 38 | HttpWebResponse httpResponse; 39 | CookieContainer cookieContainer = new CookieContainer(); 40 | 41 | httpRequest = (HttpWebRequest)WebRequest.Create(aosUrl); 42 | httpRequest.Method = "POST"; 43 | httpRequest.ContentType = "application/x-www-form-urlencoded"; 44 | 45 | httpRequest.AllowAutoRedirect = true; 46 | httpRequest.CookieContainer = cookieContainer; 47 | 48 | StreamWriter writer = new StreamWriter(httpRequest.GetRequestStream(), Encoding.ASCII); 49 | writer.Write(param.GetAcsResponseString()); 50 | writer.Flush(); 51 | writer.Close(); 52 | 53 | httpResponse = (HttpWebResponse)httpRequest.GetResponse(); 54 | httpResponse.Close(); 55 | 56 | StringBuilder retval = new StringBuilder(); 57 | 58 | CookieCollection cookiesCollection = cookieContainer.GetCookies(new Uri(aosUrl)); 59 | 60 | if (cookiesCollection.Count > 0) 61 | { 62 | foreach (Cookie c in cookiesCollection) 63 | { 64 | retval.AppendFormat("{0}={1}; ", c.Name, c.Value); 65 | } 66 | 67 | //Remove the trailing "; " 68 | retval.Remove(retval.Length - 2, 2); 69 | } 70 | 71 | cookies = retval.ToString(); 72 | 73 | context.SendingRequest2 += new EventHandler(OnSendingRequest); 74 | 75 | return cookies; 76 | } 77 | 78 | public static void OnSendingRequest(object sender, SendingRequest2EventArgs e) 79 | { 80 | // Add the cookie to the cookie header to all requests 81 | e.RequestMessage.SetHeader(HttpRequestHeader.Cookie.ToString(), cookies); 82 | } 83 | 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/BrowserForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.Xml; 10 | using System.Web; 11 | using System.Diagnostics; 12 | using System.Globalization; 13 | using System.Text.RegularExpressions; 14 | 15 | namespace Odata4ConsoleApplication 16 | { 17 | public partial class BrowserForm : Form 18 | { 19 | public BrowserForm(String url, AcsResponse param) 20 | { 21 | SetUrl(url); 22 | SetAcsResponseParam(param); 23 | InitializeComponent(); 24 | } 25 | 26 | private String GetUrl() 27 | { 28 | return m_url; 29 | } 30 | 31 | private void SetUrl(String url) 32 | { 33 | m_url = url; 34 | } 35 | 36 | private void SetAcsResponseParam(AcsResponse param) 37 | { 38 | m_acsResponseParam = param; 39 | } 40 | 41 | private void ReturnAcsResponse(String acsResponseString) 42 | { 43 | m_acsResponseParam.SetAcsResponseString(acsResponseString); 44 | } 45 | 46 | private String m_url; 47 | private AcsResponse m_acsResponseParam; // Ref to caller provided. 48 | 49 | private void BrowserForm_Load(object sender, EventArgs e) 50 | { 51 | this.Browser.Navigate(GetUrl()); 52 | } 53 | 54 | private void WebBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e) 55 | { 56 | try 57 | { 58 | // Check if we are about to submit the SAML token returned by ACS. 59 | if (String.Compare(e.Url.AbsoluteUri, GetUrl(), true) == 0) 60 | { 61 | // Extract ACS response. 62 | if (this.Browser.Document != null && this.Browser.Document.All["wresult"] != null) 63 | { 64 | // Cancel the request so that the POST doesn't actually happen. 65 | e.Cancel = true; 66 | 67 | try 68 | { 69 | String acsResponse; 70 | 71 | // 72 | // The ACS response that needs to be posted back has to be in a very 73 | // specific format. 74 | // 75 | 76 | dynamic wa = this.Browser.Document.All["wa"].DomElement; 77 | String waString = System.Web.HttpUtility.HtmlDecode(wa.value); 78 | #if false 79 | Console.WriteLine("wa={0}", waString); 80 | #endif 81 | 82 | dynamic wresult = this.Browser.Document.All["wresult"].DomElement; 83 | String wresultString = System.Web.HttpUtility.HtmlDecode(wresult.value); 84 | wresultString = wresultString.Replace("&", "&"); 85 | #if false 86 | Console.WriteLine("wresult={0}", wresultString); 87 | #endif 88 | 89 | dynamic wctx = this.Browser.Document.All["wctx"].DomElement; 90 | String wctxString = System.Web.HttpUtility.HtmlDecode(wctx.value); 91 | #if false 92 | Console.WriteLine("wctx={0}", wctxString); 93 | #endif 94 | 95 | acsResponse = "wa=" + System.Web.HttpUtility.UrlEncode(waString, Encoding.ASCII) + "&" + 96 | "wresult=" + System.Web.HttpUtility.UrlEncode(wresultString, Encoding.ASCII) + "&" + 97 | "wctx=" + System.Web.HttpUtility.UrlEncode(wctxString, Encoding.ASCII); 98 | 99 | #if false 100 | Console.WriteLine("URL encoded ACS response:"); 101 | Console.WriteLine(acsResponse); 102 | #endif 103 | 104 | ReturnAcsResponse(acsResponse); 105 | } 106 | catch (Exception exception) 107 | { 108 | Console.WriteLine(exception.ToString()); 109 | } 110 | 111 | // Close the browser form. 112 | this.Dispose(); 113 | } 114 | } 115 | } 116 | catch (Exception ) 117 | { 118 | 119 | } 120 | } 121 | 122 | private void BrowserForm_Closing(object sender, CancelEventArgs e) 123 | { 124 | //this.navigationCanceled = true; 125 | } 126 | 127 | } 128 | 129 | public class AcsResponse 130 | { 131 | public AcsResponse() 132 | { 133 | m_acsResponseString = String.Empty; 134 | } 135 | 136 | public void SetAcsResponseString(String acsResponseString) 137 | { 138 | m_acsResponseString = acsResponseString; 139 | } 140 | 141 | public String GetAcsResponseString() 142 | { 143 | return m_acsResponseString; 144 | } 145 | 146 | private String m_acsResponseString; 147 | } 148 | 149 | } -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/BrowserForm.designer.cs: -------------------------------------------------------------------------------- 1 | namespace Odata4ConsoleApplication 2 | { 3 | partial class BrowserForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.Browser = new System.Windows.Forms.WebBrowser(); 32 | this.SuspendLayout(); 33 | // 34 | // Browser 35 | // 36 | this.Browser.Dock = System.Windows.Forms.DockStyle.Fill; 37 | this.Browser.Location = new System.Drawing.Point(0, 0); 38 | this.Browser.MinimumSize = new System.Drawing.Size(20, 20); 39 | this.Browser.Name = "Browser"; 40 | //this.Browser.ScrollBarsEnabled = false; 41 | this.Browser.Size = new System.Drawing.Size(903, 403); 42 | this.Browser.TabIndex = 0; 43 | this.Browser.Navigating += new System.Windows.Forms.WebBrowserNavigatingEventHandler(this.WebBrowser_Navigating); 44 | // 45 | // BrowserForm 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.ClientSize = new System.Drawing.Size(903, 403); 50 | this.Controls.Add(this.Browser); 51 | this.Name = "BrowserForm"; 52 | this.Text = "BrowserForm"; 53 | this.Load += new System.EventHandler(this.BrowserForm_Load); 54 | this.Closing += new System.ComponentModel.CancelEventHandler(BrowserForm_Closing); 55 | this.ResumeLayout(false); 56 | } 57 | 58 | #endregion 59 | 60 | private System.Windows.Forms.WebBrowser Browser; 61 | } 62 | } -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/BrowserForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/ODataProxyGenerator.tt: -------------------------------------------------------------------------------- 1 | <#@ include file="ODataProxyGenerator.ttinclude" #> 2 | <#+ 3 | public static class Configuration 4 | { 5 | // The URI of the metadata document. The value must be set to a valid service document URI or a local file path 6 | // eg : "http://services.odata.org/V4/OData/OData.svc/", "File:///C:/Odata.edmx", or @"C:\Odata.edmx" 7 | // ### Notice ### If the OData service requires authentication for accessing the metadata document, the value of 8 | // MetadataDocumentUri has to be set to a local file path, or the client code generation process will fail. 9 | 10 | public const string MetadataDocumentUri = "/data/"; 11 | 12 | // The use of DataServiceCollection enables entity and property tracking. The value must be set to true or false. 13 | public const bool UseDataServiceCollection = true; 14 | 15 | // The namespace of the client code generated. It replaces the original namspace in the metadata document, 16 | // unless the model has several namespaces. 17 | public const string NamespacePrefix = "ODataClient"; 18 | 19 | // The target language of the generated client code. The value must be set to "CSharp" or "VB". 20 | public const string TargetLanguage = "CSharp"; 21 | 22 | // This flag indicates whether to enable naming alias. The value must be set to true or false. 23 | public const bool EnableNamingAlias = true; 24 | 25 | // This flag indicates whether to ignore unexpected elements and attributes in the metadata document and generate 26 | // the client code if any. The value must be set to true or false. 27 | public const bool IgnoreUnexpectedElementsAndAttributes = true; 28 | } 29 | 30 | public static class Customization 31 | { 32 | /// 33 | /// Changes the text to use upper camel case, which upper case for the first character. 34 | /// 35 | /// Text to convert. 36 | /// The converted text in upper camel case 37 | internal static string CustomizeNaming(string text) 38 | { 39 | if (string.IsNullOrEmpty(text)) 40 | { 41 | return text; 42 | } 43 | 44 | if (text.Length == 1) 45 | { 46 | return Char.ToUpperInvariant(text[0]).ToString(CultureInfo.InvariantCulture); 47 | } 48 | 49 | return Char.ToUpperInvariant(text[0]) + text.Substring(1); 50 | } 51 | 52 | /// 53 | /// Changes the namespace to use upper camel case, which upper case for the first character of all segments. 54 | /// 55 | /// Namespace to convert. 56 | /// The converted namespace in upper camel case 57 | internal static string CustomizeNamespace(string fullNamespace) 58 | { 59 | if (string.IsNullOrEmpty(fullNamespace)) 60 | { 61 | return fullNamespace; 62 | } 63 | 64 | string[] segs = fullNamespace.Split('.'); 65 | string upperNamespace = string.Empty; 66 | int n = segs.Length; 67 | for (int i = 0; i < n; ++i) 68 | { 69 | upperNamespace += Customization.CustomizeNaming(segs[i]); 70 | upperNamespace += (i == n - 1 ? string.Empty : "."); 71 | } 72 | 73 | return upperNamespace; 74 | } 75 | } 76 | #> 77 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/Odata4ConsoleApplication.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {86E584DD-9A75-4DA3-973E-B5AF5CEE23A9} 8 | Exe 9 | Properties 10 | Odata4ConsoleApplication 11 | Odata4ConsoleApplication 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | False 37 | .\Microsoft.IdentityModel.dll 38 | 39 | 40 | .\Microsoft.OData.Client.dll 41 | 42 | 43 | .\Microsoft.OData.Core.dll 44 | 45 | 46 | .\Microsoft.OData.Edm.dll 47 | 48 | 49 | .\Microsoft.Spatial.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Form 70 | 71 | 72 | 73 | True 74 | True 75 | ODataProxyGenerator.tt 76 | 77 | 78 | 79 | 80 | 81 | 82 | TextTemplatingFileGenerator 83 | ODataProxyGenerator.cs 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 104 | -------------------------------------------------------------------------------- /FMLab/Odata4ConsoleApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ODataClient.Microsoft.Dynamics.DataEntities; 7 | using Microsoft.OData.Client; 8 | using System.Net.Http; 9 | 10 | 11 | namespace Odata4ConsoleApplication 12 | { 13 | class Program 14 | { 15 | 16 | public static Resources context; 17 | 18 | [STAThread] 19 | static void Main(string[] args) 20 | { 21 | //the following BaseUri needs to be updated to your org 22 | string dynamicsBaseUri = "https://usnconeboxax1aos.cloud.onebox.dynamics.com/"; 23 | string ODataServiceEndpoint = dynamicsBaseUri + "data"; 24 | 25 | Uri dynODataURI = new Uri(ODataServiceEndpoint, UriKind.Absolute); 26 | 27 | //Creates a DataServiceContext class which encapsulates operations that are supported by the OData endpoint 28 | context = new Resources(dynODataURI); 29 | 30 | //Authenticate the user 31 | AuthenticationHelper.PerformAuthentication(context,dynamicsBaseUri); 32 | 33 | Console.WriteLine("-------------------------------------------------------------------"); 34 | Console.WriteLine("Query all the customers in Fleet Management. Enter to start ..."); 35 | Console.WriteLine("-------------------------------------------------------------------"); 36 | Console.ReadLine(); 37 | 38 | GetAllCustomers(); 39 | 40 | Console.WriteLine(); 41 | Console.WriteLine("-------------------------------------"); 42 | Console.WriteLine("Create a new customer. Enter to start"); 43 | Console.WriteLine("-------------------------------------"); 44 | Console.ReadLine(); 45 | 46 | 47 | FleetCustomer newCustomer = CreateCustomer(); 48 | 49 | Console.WriteLine(); 50 | Console.WriteLine("--------------------------------------------------------------------"); 51 | Console.WriteLine("Create a new reservation for the customer. Enter to start ..."); 52 | Console.WriteLine("--------------------------------------------------------------------"); 53 | Console.ReadLine(); 54 | 55 | FleetRental newRental = CreateReservation(newCustomer); 56 | 57 | Console.WriteLine(); 58 | Console.WriteLine("--------------------------------------------------------------------"); 59 | Console.WriteLine("Call action on the reservation ..."); 60 | Console.WriteLine("--------------------------------------------------------------------"); 61 | Console.ReadLine(); 62 | 63 | UriBuilder buildUri = new UriBuilder(ODataServiceEndpoint); 64 | buildUri.Path = String.Format("data/FleetRentals('{0}')/Microsoft.Dynamics.DataEntities.ReturnRental", newRental.RentalId); 65 | 66 | //following code invokes the action by sending an HTTPPost request for the buildUri 67 | var returnValue = context.Execute(new Uri(buildUri.ToString()), "POST", true); 68 | 69 | Console.ForegroundColor = ConsoleColor.Cyan; 70 | Console.WriteLine("Invoked ReturnRental action, response is: \n" + returnValue.Single()); 71 | 72 | Console.ForegroundColor = ConsoleColor.White; 73 | Console.BackgroundColor = ConsoleColor.Black; 74 | 75 | Console.WriteLine(); 76 | 77 | Console.WriteLine("***************************************************"); 78 | Console.WriteLine("* *"); 79 | Console.WriteLine("You have successfully completed, \t\t\n 1. Creating a new customer \t\t\t\n 2. Creating a new reservation for that customer. \n " + 80 | "Please refer back to Hands on Lab documentation to continue \n Press Enter to close this application \t"); 81 | Console.WriteLine("* *"); 82 | Console.WriteLine("***************************************************"); 83 | 84 | Console.ReadLine(); 85 | 86 | } 87 | 88 | /// 89 | /// This method issues a query URI to retrieve all the Customers from the Customer OData Entity 90 | /// 91 | private static void GetAllCustomers() 92 | { 93 | //Using the DataServiceContext class, we can simply perform a LINQ query to retrieve all Customers from the Customer entity. 94 | //This internally will issue web request by using the URI that represents OData protocol 95 | //get all customers 96 | var query = from customer in context.FleetCustomers 97 | select customer; 98 | 99 | Console.ForegroundColor = ConsoleColor.Cyan; 100 | //Display the http request Uri that was sent to fetch all customers 101 | Console.WriteLine("Request Uri: " + query.ToString()); 102 | Console.ForegroundColor = ConsoleColor.White; 103 | 104 | Console.WriteLine(); 105 | 106 | //After retrieving all the customers, iterate through the collection and print each one. 107 | foreach (FleetCustomer c in query) 108 | { 109 | Console.WriteLine("Customer.Driver License: " + c.DriverLicense); 110 | Console.WriteLine("First Name: " + c.FirstName); 111 | Console.WriteLine("Last Name: " + c.LastName); 112 | 113 | Console.WriteLine("++++++++"); 114 | } 115 | } 116 | 117 | /// 118 | /// This method prompts the user for first name and last name and then uses that to create a new customer by calling the Customer OData entity 119 | /// 120 | /// 121 | private static FleetCustomer CreateCustomer() 122 | { 123 | 124 | Console.WriteLine("Enter First Name, and then press Enter"); 125 | string firstName = Console.ReadLine(); 126 | 127 | Console.WriteLine("Enter Last Name, and then press Enter "); 128 | string lastName = Console.ReadLine(); 129 | 130 | Random rnd = new Random(); 131 | 132 | //Create the Customer object with the first and last names provided by the user 133 | FleetCustomer newCustomer = new FleetCustomer() 134 | { 135 | FirstName = firstName, 136 | LastName = lastName, 137 | DriverLicense = "B923-2381-" + rnd.Next(1000,7000).ToString(), 138 | CellPhone = "0123456789", 139 | Email = "test@contoso.com", 140 | }; 141 | 142 | //Add the new customer object to the DataServiceContext object 143 | context.AddToFleetCustomers(newCustomer); 144 | 145 | //Save the DataServiceContext object and an internally a POST call is made to the OData Customer entity. 146 | //Record is created in Rainier Database 147 | Microsoft.OData.Client.DataServiceResponse response = null; 148 | try 149 | { 150 | response = context.SaveChanges(); 151 | } 152 | catch (DataServiceRequestException e) 153 | { 154 | Console.WriteLine("Error occured while saving. Error Details: " + e.InnerException.Message); 155 | } 156 | 157 | //the following code retrieves the location header which represents the newly created entity 158 | foreach (ChangeOperationResponse r in response) 159 | { 160 | if (r.Headers.ContainsKey("Location")) 161 | { 162 | Console.ForegroundColor = ConsoleColor.Cyan; 163 | Console.WriteLine("New customer created: "); 164 | Console.WriteLine(r.Headers["Location"]); 165 | } 166 | } 167 | 168 | Console.ForegroundColor = ConsoleColor.White; 169 | 170 | return newCustomer; 171 | } 172 | 173 | 174 | /// 175 | /// This method creates a new reservation record for the customer, created by the CreateCustomer method. 176 | /// 177 | /// 178 | /// 179 | private static FleetRental CreateReservation(FleetCustomer customer) 180 | { 181 | Random rnd = new Random(); 182 | 183 | DataServiceCollection reservations = new DataServiceCollection(context); 184 | 185 | FleetRental reservation = new FleetRental(); 186 | 187 | reservations.Add(reservation); 188 | //Create a new Reservation object with the details for new customer. 189 | 190 | 191 | reservation.CustomerFirstName = customer.FirstName; 192 | reservation.CustomerLastName = customer.LastName; 193 | reservation.CustomerDriverLicense = customer.DriverLicense; 194 | reservation.State = 0; //Limitation of OData, no client-side Enum support 195 | reservation.RentalId = "OData_" + rnd.Next(500).ToString(); 196 | reservation.Comments = "New customer"; 197 | reservation.VehicleId = "Adatum_Four_2"; 198 | reservation.VehicleVIN = "WAUXL58E15A104563"; 199 | reservation.EndDate = DateTime.Today.AddDays (5); 200 | reservation.StartDate = DateTime.Today; 201 | 202 | 203 | Microsoft.OData.Client.DataServiceResponse response = null; 204 | try 205 | { 206 | response = context.SaveChanges(SaveChangesOptions.PostOnlySetProperties); 207 | } 208 | catch (DataServiceRequestException e) 209 | { 210 | Console.WriteLine("Error occured while saving. Error Details: " + e.InnerException.Message); 211 | } 212 | 213 | 214 | //the following code retrieves the location header which represents the newly created entity 215 | Console.ForegroundColor = ConsoleColor.Cyan; 216 | foreach (ChangeOperationResponse r in response) 217 | { 218 | if (r.Headers.ContainsKey("Location")) 219 | { 220 | Console.ForegroundColor = ConsoleColor.Cyan; 221 | Console.WriteLine("New reservation created: "); 222 | Console.WriteLine(r.Headers["Location"]); 223 | } 224 | } 225 | Console.ForegroundColor = ConsoleColor.White; 226 | 227 | return reservation; 228 | 229 | } 230 | 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /FMLab/TaskRecorderScreenshot/background.js: -------------------------------------------------------------------------------- 1 | chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { 2 | if (request.name == 'screenshot') { 3 | chrome.tabs.captureVisibleTab(null, null, function(dataUrl) { 4 | sendResponse({ screenshotUrl: dataUrl }); 5 | }); 6 | } 7 | return true; 8 | }); 9 | -------------------------------------------------------------------------------- /FMLab/TaskRecorderScreenshot/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dynamics 365 for Finance and Operations Task Recorder Screenshot Extension", 3 | "version": "1.0.0.2", 4 | "description": "Screenshot capture used for Dynamics 365 for Finance and Operations task recorder.", 5 | "background": { 6 | "scripts": ["background.js"] 7 | }, 8 | "content_scripts": [ 9 | { 10 | "matches": ["https://*.dynamics.com/*"], 11 | "js": ["screenshot.js"] 12 | } 13 | ], 14 | "permissions": [ 15 | "tabs", "" 16 | ], 17 | "manifest_version": 2 18 | } 19 | -------------------------------------------------------------------------------- /FMLab/TaskRecorderScreenshot/screenshot.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("screenshot", function() { 2 | chrome.extension.sendMessage({name: 'screenshot'}, function(response) { 3 | var dataURL = response.screenshotUrl; 4 | var image = new Image(); 5 | 6 | image.onload = function() { 7 | // Cut the task recorder pane from the screenshot. 8 | var ratio = window.devicePixelRatio; 9 | var canvas = document.createElement("canvas"); 10 | var context = canvas.getContext('2d'); 11 | canvas.width = window.innerWidth * ratio; 12 | canvas.height = window.innerHeight * ratio; 13 | var taskRecorderPaneWidth = document.getElementById('asidePane').clientWidth * ratio; 14 | context.drawImage(image, 0, 0, (canvas.width - taskRecorderPaneWidth), canvas.height, 0, 0, canvas.width, canvas.height); 15 | var croppedImage = canvas.toDataURL('image/png'); 16 | 17 | var origin = window.location.protocol + "//" + window.location.host; 18 | window.postMessage(croppedImage, origin); 19 | }; 20 | image.src = dataURL; 21 | 22 | 23 | }); 24 | }); 25 | 26 | var isInstalledNode = document.createElement('div'); 27 | isInstalledNode.id = 'screenshotExtensionIsInstalled'; 28 | document.body.appendChild(isInstalledNode); -------------------------------------------------------------------------------- /FMLab/TestFiles/AxClass_FMUnitTestSample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FMUnitTestSample 4 | 5 | 10 | 11 | 12 | setup 13 | 20 | 21 | 22 | testFMTotalsEngine 23 | 51 | 52 | 53 | testFMCarValidateField 54 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /FMLab/TestFiles/CodeCoverage.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | .*Dynamics\.AX\.ApplicationPlatform\.* 10 | .*Dynamics\.AX\.FleetManagement\.* 11 | 12 | 13 | 14 | .*CPPUnitTestFramework.* 15 | .*AOSKernel.* 16 | 17 | 18 | 19 | 22 | 30000 23 | true 24 | 25 | 29 | true 30 | 31 | 37 | true 38 | 39 | 43 | true 44 | 45 | 48 | 49 | Network Service 50 | Everyone 51 | 52 | 53 | 56 | 57 | T:\Bin 58 | T:\modules\ApplicationSuite\bin 59 | T:\modules\ApplicationPlatform\bin 60 | T:\modules\ApplicationFoundation\bin 61 | 62 | 63 | 71 | 72 | 76 | 77 | 78 | 79 | .*test.* 80 | 81 | 82 | 83 | 88 | 89 | 90 | 91 | ^B77A5C561934E089$ 92 | ^B03F5F7F11D50A3A$ 93 | ^31BF3856AD364E35$ 94 | ^89845DCD8080CC91$ 95 | ^71E9BCE111E9429C$ 96 | ^8F50407C4E9E73B6$ 97 | ^E361AF139669C375$ 98 | 99 | 100 | 101 | 105 | 106 | 107 | 108 | .*\\atlmfc\\.* 109 | 110 | .*\\vctools\\.* 111 | 112 | .*\\public\\sdk\\.* 113 | .*\\microsoft sdks\\.* 114 | 115 | .*\\vc\\include\\.* 116 | 117 | 118 | 119 | 124 | 125 | 126 | ^System.Diagnostics.DebuggerHiddenAttribute$ 127 | ^System.Diagnostics.DebuggerNonUserCodeAttribute$ 128 | ^System.Runtime.CompilerServices.CompilerGeneratedAttribute$ 129 | ^System.CodeDom.Compiler.GeneratedCodeAttribute$ 130 | ^System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute$ 131 | 132 | 133 | 134 | 138 | 139 | 140 | 141 | ^std::.* 142 | 143 | ^ATL::.* 144 | 145 | .*::__GetTestMethodInfo.* 146 | 147 | .*__CxxPureMSILEntry.* 148 | 149 | ^Microsoft::VisualStudio::CppCodeCoverageFramework::.* 150 | 151 | ^Microsoft::VisualStudio::CppUnitTestFramework::.* 152 | 153 | .*::YOU_CAN_ONLY_DESIGNATE_ONE_.* 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /FMLab/TestFiles/Default.RunSettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | .\TestResults 7 | 8 | 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | initial 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /FMLab/json-ie.reg: -------------------------------------------------------------------------------- 1 | Windows Registry Editor Version 5.00 2 | ; 3 | ; Tell IE to open JSON documents in the browser. 4 | ; 25336920-03F9-11cf-8FD0-00AA00686F13 is the CLSID for the "Browse in place" . 5 | ; 6 | 7 | [HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/json] 8 | "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" 9 | "Encoding"=hex:08,00,00,00 10 | 11 | [HKEY_CLASSES_ROOT\MIME\Database\Content Type\text/json] 12 | "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" 13 | "Encoding"=hex:08,00,00,00 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FMLab 2 | FMLab is the sample code you need for several of the Dynamics AX tutorials on http://ax.help.dynamics.com. These tutorials use a model named Fleet Management Tutorial. 3 | -------------------------------------------------------------------------------- /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 definition of a security vulnerability](https://aka.ms/opensource/security/definition), 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://aka.ms/opensource/security/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 [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 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://aka.ms/opensource/security/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://aka.ms/opensource/security/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://aka.ms/opensource/security/cvd). 40 | 41 | 42 | --------------------------------------------------------------------------------