├── .gitignore ├── LICENSE ├── LICENSE.Argotic ├── LICENSE.LINQBridge ├── LICENSE.Moq ├── LICENSE.NUnit ├── README.mdown ├── SDataCSharpClientLib.sln ├── SDataCSharpClientLib2008.sln ├── Sage.SData.Client.Test ├── Core │ ├── AtomFeedReaderTests.cs │ ├── BatchProcessTests.cs │ ├── IntermediateApplicationsRequestTests.cs │ ├── IntermediateContractsRequestTests.cs │ ├── IntermediateDataSetsRequestTests.cs │ ├── IntermediateResourceCollectionsRequestTests.cs │ ├── IntermediateServicesRequestTests.cs │ ├── SDataEndPointCollectionRequestTests.cs │ ├── SDataResourceCollectionRequestTests.cs │ ├── SDataResourcePropertyRequestTests.cs │ ├── SDataResourceSchemaRequestTests.cs │ ├── SDataServiceOperationRequestTests.cs │ ├── SDataServiceTests.cs │ ├── SDataSingleResourceRequestTests.cs │ └── SDataTemplateResourceRequestTests.cs ├── Extensions │ ├── SDataExtensionContextTests.cs │ ├── SDataPayloadTests.cs │ ├── SDataSimpleCollectionTests.cs │ ├── SDataSyncExtensionContextTests.cs │ ├── SyndicationExtensionTests.cs │ └── Utility.cs ├── Framework │ ├── DiagnosisTests.cs │ ├── MediaTypeNamesTests.cs │ ├── SDataUriTests.cs │ ├── UriFormatterTests.cs │ ├── UriPathParserTests.cs │ └── W3CDateTimeTests.cs ├── Metadata │ └── SDataSchemaTests.cs ├── Mime │ └── MimeMessageTests.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Sage.SData.Client.Test.csproj ├── TestData.cs ├── TestEntry.xml ├── TestFeed.xml └── TestSchema.xsd ├── Sage.SData.Client ├── Adapters │ ├── Atom10SyndicationResourceAdapter.cs │ └── SyndicationResourceAdapter.cs ├── Atom │ ├── AtomCategory.cs │ ├── AtomContent.cs │ ├── AtomEntry.cs │ ├── AtomFeed.cs │ ├── AtomGenerator.cs │ ├── AtomIcon.cs │ ├── AtomId.cs │ ├── AtomLink.cs │ ├── AtomLogo.cs │ ├── AtomPersonConstruct.cs │ ├── AtomSource.cs │ ├── AtomTextConstruct.cs │ ├── AtomTextConstructType.cs │ ├── AtomUtility.cs │ └── IAtomCommonObjectAttributes.cs ├── Common │ ├── ComparisonUtility.cs │ ├── DiscoverableSyndicationEndpoint.cs │ ├── EnumerationMetadataAttribute.cs │ ├── Guard.cs │ ├── ISyndicationResource.cs │ ├── MimeMediaTypeAttribute.cs │ ├── SyndicationContentFormat.cs │ ├── SyndicationDateTimeUtility.cs │ ├── SyndicationDiscoveryUtility.cs │ ├── SyndicationEncodingUtility.cs │ ├── SyndicationResourceLoadSettings.cs │ ├── SyndicationResourceLoadedEventArgs.cs │ ├── SyndicationResourceMetadata.cs │ ├── SyndicationResourceSaveSettings.cs │ ├── TrackbackDiscoveryMetadata.cs │ └── WebRequestOptions.cs ├── Core │ ├── AsyncRequest.cs │ ├── AtomFeedReader.cs │ ├── BatchProcess.cs │ ├── ISDataRequestSettings.cs │ ├── ISDataService.cs │ ├── IntermediateApplicationsRequest.cs │ ├── IntermediateContractsRequest.cs │ ├── IntermediateDataSetsRequest.cs │ ├── IntermediateResourceCollectionsRequest.cs │ ├── IntermediateServicesRequest.cs │ ├── ReadCompletedEventArgs.cs │ ├── SDataApplicationRequest.cs │ ├── SDataBaseRequest.cs │ ├── SDataBatchRequest.cs │ ├── SDataClientException.cs │ ├── SDataEndPointCollectionRequest.cs │ ├── SDataOperationalRequest.cs │ ├── SDataResourceCollectionRequest.cs │ ├── SDataResourcePropertyRequest.cs │ ├── SDataResourceSchemaRequest.cs │ ├── SDataService.cs │ ├── SDataServiceOperationRequest.cs │ ├── SDataSingleResourceRequest.cs │ ├── SDataSystemRequest.cs │ └── SDataTemplateResourceRequest.cs ├── Examplecs.cs ├── Extensions │ ├── IExtensibleSyndicationObject.cs │ ├── ISyndicationExtension.cs │ ├── OpenSearch │ │ ├── OpenSearchExtension.cs │ │ ├── OpenSearchExtensionContext.cs │ │ └── OpenSearchExtensionHelper.cs │ ├── SData │ │ ├── SDataExtension.cs │ │ ├── SDataExtensionContext.cs │ │ ├── SDataExtensionHelper.cs │ │ ├── SDataPayload.cs │ │ ├── SDataPayloadCollection.cs │ │ ├── SDataPayloadTypeDescriptionProvider.cs │ │ ├── SDataSimpleCollection.cs │ │ └── XPathNavigatorExtensions.cs │ ├── SDataHttp │ │ ├── SDataHttpExtension.cs │ │ ├── SDataHttpExtensionContext.cs │ │ └── SDataHttpExtensionHelper.cs │ ├── SDataSync │ │ ├── SDataSyncExtension.cs │ │ ├── SDataSyncExtensionContext.cs │ │ └── SDataSyncExtensionHelper.cs │ ├── SimpleList │ │ ├── SimpleListDataType.cs │ │ ├── SimpleListGroup.cs │ │ ├── SimpleListSort.cs │ │ ├── SimpleListSyndicationExtension.cs │ │ ├── SimpleListSyndicationExtensionContext.cs │ │ └── SimpleListSyndicationExtensionHelper.cs │ ├── SyndicationExtension.cs │ ├── SyndicationExtensionAdapter.cs │ └── SyndicationExtensionLoadedEventArgs.cs ├── Framework │ ├── AttachedFile.cs │ ├── Common.cs │ ├── Diagnosis.cs │ ├── Digest.cs │ ├── DigestEntry.cs │ ├── HttpMethod.cs │ ├── MediaType.cs │ ├── MediaTypeNames.cs │ ├── RequestOperation.cs │ ├── SDataException.cs │ ├── SDataRequest.cs │ ├── SDataResponse.cs │ ├── SDataUri.cs │ ├── Severity.cs │ ├── StreamExtensions.cs │ ├── SyncMode.cs │ ├── SyncState.cs │ ├── Tracking.cs │ ├── UriFormatter.cs │ ├── UriPathParser.cs │ ├── UriPathSegment.cs │ ├── UriQueryParser.cs │ └── W3CDateTime.cs ├── LinqBridge │ ├── Action.cs │ ├── Enumerable.cs │ ├── Enumerable.g.cs │ ├── Enumerable.g.tt │ ├── ExtensionAttribute.cs │ ├── Func.cs │ ├── IGrouping.cs │ ├── ILookup.cs │ ├── IOrderedEnumerable.cs │ ├── Lookup.cs │ ├── OrderedEnumerable.cs │ ├── Public.cs │ └── Tuple.cs ├── Metadata │ ├── BatchingMode.cs │ ├── CollectionDebugView.cs │ ├── ComplianceLevel.cs │ ├── EnumEx.cs │ ├── InvocationMode.cs │ ├── KeyedCollection.cs │ ├── KeyedEnumerable.cs │ ├── KeyedObjectCollection.cs │ ├── RelationshipType.cs │ ├── SDataSchema.cs │ ├── SDataSchemaChoiceItem.cs │ ├── SDataSchemaChoiceType.cs │ ├── SDataSchemaComplexType.cs │ ├── SDataSchemaDocumentation.cs │ ├── SDataSchemaEnumItem.cs │ ├── SDataSchemaEnumType.cs │ ├── SDataSchemaItem.cs │ ├── SDataSchemaNamedQueryType.cs │ ├── SDataSchemaObject.cs │ ├── SDataSchemaProperty.cs │ ├── SDataSchemaRelationshipProperty.cs │ ├── SDataSchemaResourceType.cs │ ├── SDataSchemaServiceOperationType.cs │ ├── SDataSchemaSet.cs │ ├── SDataSchemaSimpleType.cs │ ├── SDataSchemaTopLevelType.cs │ ├── SDataSchemaType.cs │ ├── SDataSchemaTypeReference.cs │ ├── SDataSchemaValueProperty.cs │ └── SDataSchemaValueType.cs ├── Mime │ ├── MimeHelper.cs │ ├── MimeMessage.cs │ └── MimePart.cs ├── Properties │ └── AssemblyInfo.cs ├── Sage.SData.Client_2_0.csproj └── Sage.SData.Client_3_5.csproj ├── demos └── SDataClientApp │ ├── BaseControl.cs │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── Program.cs │ ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings │ ├── ResourceCollection.Designer.cs │ ├── ResourceCollection.cs │ ├── ResourceCollection.resx │ ├── ResourceProperties.Designer.cs │ ├── ResourceProperties.cs │ ├── ResourceProperties.resx │ ├── ResourceSchema.Designer.cs │ ├── ResourceSchema.cs │ ├── ResourceSchema.resx │ ├── ResourceTemplate.Designer.cs │ ├── ResourceTemplate.cs │ ├── ResourceTemplate.resx │ ├── SDataClientApp.csproj │ ├── ServiceConfig.Designer.cs │ ├── ServiceConfig.cs │ ├── ServiceConfig.resx │ ├── SingleResource.Designer.cs │ ├── SingleResource.cs │ ├── SingleResource.resx │ └── app.config ├── dependencies ├── Moq │ ├── Moq.dll │ └── Moq.xml └── NUnit │ ├── nunit.framework.dll │ └── nunit.framework.xml └── docs ├── Intro to SData CSharp Client Lib.doc └── SDataClientAPI.chm /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2 | *.obj 3 | *.exe 4 | *.pdb 5 | *.user 6 | *.aps 7 | *.pch 8 | *.vspscc 9 | *.vssscc 10 | *_i.c 11 | *_p.c 12 | *.ncb 13 | *.suo 14 | *.tlb 15 | *.tlh 16 | *.bak 17 | *.cache 18 | *.ilk 19 | *.log 20 | *.lib 21 | *.sbr 22 | *.sdf 23 | ipch/ 24 | obj/ 25 | [Bb]in 26 | [Dd]ebug*/ 27 | [Rr]elease*/ 28 | 29 | #Tooling 30 | _ReSharper*/ 31 | *.resharper.user 32 | [Tt]est[Rr]esult* 33 | *.ReSharper 34 | 35 | #OS junk files 36 | Thumbs.db 37 | *.DS_Store 38 | 39 | #VIM junk 40 | *.swp 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Sage Software, Inc. All rights reserved. Sage does not charge for use of the Software licensed herein. Charges for any other software or services will be set forth in a separate written agreement between the parties. Software license granted to you herein is contingent upon your acknowledgement and agreement to the terms herein. If you do not agree to these terms, you do not have the permission to use the Software in any manner. You acknowledge and agree to the following: (i) Sage provides the Software free of charge and without any obligation of technical support or maintenance; (ii) Sage does not guarantee the accuracy, completeness, and reliability of the Software or whether the Software is virus-free; (iii) Sage makes no representation about whether the Software has been tested (either internally or via beta test) for quality assurance or quality control, (iv) Sage does not guarantee that the Software does not infringe any third party rights; (v) you may experience bugs, errors, loss or corruption of data, and difficulty in use, and (vi) you shall have sole responsibility for protection and preservation of your data and files. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this sentence and the following Disclaimer. Redistributions in binary form must reproduce the above copyright notice, this sentence and the following Disclaimer in the documentation and/or other materials provided with the distribution. Neither the names of ACT!, Sage, Sage Group plc, any of Sage�s product/service names, nor the names of the contributors to the Software may be used to endorse or promote products/services derived from this Software without specific prior written permission of Sage. Disclaimer: THE SOFTWARE IS ACCEPTED BY YOU "AS IS" AND "WITH ALL FAULTS". ALL WARRANTIES CONCERNING THE SOFTWARE, EXPRESS OR IMPLIED, STATUTORY, OR IN ANY OTHER PROVISION OF THIS AGREEMENT INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE, ARE HEREBY EXPRESSLY DISCLAIMED AND EXCLUDED. WHETHER OR NOT ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, SAGE SHALL NOT UNDER ANY CIRCUMSTANCE BE LIABLE TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF GOODWILL, LOST PROFITS, LOST DATA, WORK STOPPAGE OR COMPUTER HARDWARE OR SOFTWARE DAMAGE, FAILURE OR MALFUNCTION, EVEN IF SAGE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. 4 | 5 | You acknowledge that Sage retains and is not transferring to you any title to or ownership rights in or to any intellectual property in the Software, any modifications thereto, or copies thereof. Sage may terminate this Agreement, in its sole discretion. Upon termination of this Agreement, you shall return to Sage, or destroy, all originals and copies of all Software (including any support materials furnished by Sage), permanently purge all machine-readable copies of the Software from all computers and storage devices, and to certify to Sage in writing that the foregoing duties have been performed and that you will not in any way use or permit the use of the Software. This Agreement shall be governed by the laws of the State of California. 6 | -------------------------------------------------------------------------------- /LICENSE.Argotic: -------------------------------------------------------------------------------- 1 | See http://argotic.codeplex.com/ 2 | 3 | Copyright (c) 2008 Brian William Kuhn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.LINQBridge: -------------------------------------------------------------------------------- 1 | See http://code.google.com/p/linqbridge/ 2 | 3 | LINQBridge Copyright (c) 2007-2009, Atif Aziz, Joseph Albahari 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | - Neither the name of the original authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /LICENSE.Moq: -------------------------------------------------------------------------------- 1 | See http://code.google.com/p/moq/ 2 | 3 | Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD 4 | http://code.google.com/p/moq/ 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, 8 | with or without modification, are permitted provided 9 | that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the 12 | above copyright notice, this list of conditions and 13 | the following disclaimer. 14 | 15 | * Redistributions in binary form must reproduce 16 | the above copyright notice, this list of conditions 17 | and the following disclaimer in the documentation 18 | and/or other materials provided with the distribution. 19 | 20 | * Neither the name of Clarius Consulting, Manas Technology Solutions or InSTEDD nor the 21 | names of its contributors may be used to endorse 22 | or promote products derived from this software 23 | without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 26 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 27 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 30 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 35 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 36 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 | SUCH DAMAGE. 39 | 40 | [This is the BSD license, see 41 | http://www.opensource.org/licenses/bsd-license.php] -------------------------------------------------------------------------------- /LICENSE.NUnit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/LICENSE.NUnit -------------------------------------------------------------------------------- /README.mdown: -------------------------------------------------------------------------------- 1 | Sage SData Client Libraries for .NET 2 | ==================================== 3 | 4 | This repository contains the following 5 | 6 | * A .NET 3.5 library for consuming [SData](http://sdata.sage.com). 7 | * A set of unit tests 8 | * A WinForms application, which demonstrates various features of the API 9 | 10 | For information about the client library and examples on how to use it, check out "Intro to SData CSharp Client Lib.doc" in the [docs](https://github.com/SageScottsdalePlatform/SDataCSharpClientLib/tree/master/docs/) subfolder. 11 | 12 | Also, keep an eye on the [Wiki](https://github.com/SageScottsdalePlatform/SDataCSharpClientLib/wikis) for up-to-date information. -------------------------------------------------------------------------------- /SDataCSharpClientLib.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDataClientApp", "demos\SDataClientApp\SDataClientApp.csproj", "{908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client_3_5", "Sage.SData.Client\Sage.SData.Client_3_5.csproj", "{590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client_2_0", "Sage.SData.Client\Sage.SData.Client_2_0.csproj", "{CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client.Test", "Sage.SData.Client.Test\Sage.SData.Client.Test.csproj", "{92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /SDataCSharpClientLib2008.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDataClientApp", "demos\SDataClientApp\SDataClientApp.csproj", "{908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client_3_5", "Sage.SData.Client\Sage.SData.Client_3_5.csproj", "{590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client_2_0", "Sage.SData.Client\Sage.SData.Client_2_0.csproj", "{CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sage.SData.Client.Test", "Sage.SData.Client.Test\Sage.SData.Client.Test.csproj", "{92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {590B03D1-FC26-4AFD-98F8-421E6E8DDBA8}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {CAD51DA5-A6D2-4BFC-9D81-23F4F474615B}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {908FFE7B-070B-41FC-8D3E-B0FEAE1AB972}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {92C27580-82D9-46FC-8E4A-9B75E6FF6C2B}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/AtomFeedReaderTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | using Moq; 6 | using NUnit.Framework; 7 | using Sage.SData.Client.Atom; 8 | using Sage.SData.Client.Core; 9 | using Sage.SData.Client.Extensions; 10 | using Sage.SData.Client.Test.Properties; 11 | 12 | namespace Sage.SData.Client.Test.Core 13 | { 14 | [TestFixture] 15 | public class AtomFeedReaderTests : AssertionHelper 16 | { 17 | private Mock _mock; 18 | private ISDataService _service; 19 | 20 | [TestFixtureSetUp] 21 | public void Setup() 22 | { 23 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 24 | _service = _mock.Object; 25 | } 26 | 27 | [Test] 28 | public void AtomFeedReader_Verify_CanRead() 29 | { 30 | var request = new SDataResourceCollectionRequest(_service); 31 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 32 | 33 | var reader = request.ExecuteReader(); 34 | Expect(reader, Is.Not.Null); 35 | } 36 | 37 | [Test] 38 | public void AtomFeedReader_EnumeratorMatchesIndexer() 39 | { 40 | var request = new SDataResourceCollectionRequest(_service); 41 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 42 | 43 | var reader = request.ExecuteReader(); 44 | var i = 0; 45 | 46 | foreach (var entry in reader) 47 | { 48 | Expect(entry, Is.EqualTo(reader[i])); 49 | i++; 50 | } 51 | } 52 | 53 | [Test] 54 | public void AtomFeedReader_IndexerMatchesCurrent() 55 | { 56 | var request = new SDataResourceCollectionRequest(_service); 57 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 58 | 59 | var reader = request.ExecuteReader(); 60 | 61 | for (var i = 0; i < reader.Count; i++) 62 | { 63 | Expect(i, Is.EqualTo(reader.CurrentIndex)); 64 | Expect(reader[i], Is.EqualTo(reader.Current)); 65 | reader.MoveNext(); 66 | } 67 | 68 | Expect(!reader.MoveNext()); 69 | } 70 | 71 | [Test] 72 | public void AtomFeedReader_CurrentMatchesEnumerator() 73 | { 74 | var request = new SDataResourceCollectionRequest(_service); 75 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 76 | 77 | var reader = request.ExecuteReader(); 78 | var enumerator = reader.GetEnumerator(); 79 | 80 | do 81 | { 82 | enumerator.MoveNext(); 83 | Expect(reader.Current, Is.EqualTo(enumerator.Current)); 84 | } while (reader.MoveNext()); 85 | 86 | Expect(!enumerator.MoveNext()); 87 | } 88 | 89 | [Test] 90 | public void AtomFeedReader_MultiPageEnumerator() 91 | { 92 | var page1 = new AtomFeed(); 93 | var page2 = new AtomFeed(); 94 | 95 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Resources.TestFeed))) 96 | { 97 | page1.Load(stream); 98 | stream.Seek(0, SeekOrigin.Begin); 99 | page2.Load(stream); 100 | } 101 | 102 | page1.SetOpenSearchStartIndex(1); 103 | page1.SetOpenSearchItemsPerPage(1); 104 | ((IList) page1.Entries).RemoveAt(1); 105 | 106 | page2.SetOpenSearchStartIndex(2); 107 | page2.SetOpenSearchItemsPerPage(1); 108 | ((IList) page2.Entries).RemoveAt(0); 109 | 110 | var pages = new Stack(new[] {page2, page1}); 111 | 112 | var request = new SDataResourceCollectionRequest(_service); 113 | _mock.Setup(s => s.ReadFeed(request)).Returns(pages.Pop).AtMost(2); 114 | 115 | var reader = request.ExecuteReader(); 116 | reader.ToList(); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/BatchProcessTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Sage.SData.Client.Core; 3 | 4 | namespace Sage.SData.Client.Test.Core 5 | { 6 | [TestFixture] 7 | public class BatchProcessTests 8 | { 9 | [Test] 10 | public void BatchProcess_AddItemWithoutRequest() 11 | { 12 | var item = new SDataBatchRequestItem(); 13 | var added = BatchProcess.Instance.AddToBatch(item); 14 | Assert.That(added, Is.False); 15 | } 16 | 17 | [Test] 18 | public void BatchProcess_RequestRemovedOnDispose() 19 | { 20 | var service = new SDataService("http://localhost:59213/sdata/aw/dynamic/-/"); 21 | 22 | using (var request = new SDataBatchRequest(service)) 23 | { 24 | Assert.That(BatchProcess.Instance.Requests, Contains.Item(request)); 25 | } 26 | 27 | Assert.That(BatchProcess.Instance.Requests, Is.Empty); 28 | } 29 | 30 | [Test] 31 | public void BatchProcess_AddItemWithRequest() 32 | { 33 | var service = new SDataService("http://localhost:59213/sdata/aw/dynamic/-/"); 34 | 35 | using (var request = new SDataBatchRequest(service) {ResourceKind = "employees"}) 36 | { 37 | var item = new SDataBatchRequestItem 38 | { 39 | Url = "http://localhost:59213/sdata/aw/dynamic/-/employees" 40 | }; 41 | var added = BatchProcess.Instance.AddToBatch(item); 42 | Assert.That(added, Is.True); 43 | Assert.That(request.Items, Contains.Item(item)); 44 | } 45 | } 46 | 47 | [Test] 48 | public void BatchProcess_AddItemWithUnsuitableRequest() 49 | { 50 | var service = new SDataService("http://localhost:59213/sdata/aw/dynamic/-/"); 51 | 52 | using (var request = new SDataBatchRequest(service) {ResourceKind = "employees"}) 53 | { 54 | var item = new SDataBatchRequestItem 55 | { 56 | Url = "http://localhost:59213/sdata/aw/dynamic/-/contacts" 57 | }; 58 | var added = BatchProcess.Instance.AddToBatch(item); 59 | Assert.That(added, Is.False); 60 | Assert.That(request.Items, Is.Empty); 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/IntermediateApplicationsRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class IntermediateApplicationsRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void IntermediateApplications_Verify_CanContruct() 22 | { 23 | var request = new IntermediateApplicationsRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void IntermediateApplications_Verify_ToString() 29 | { 30 | var request = new IntermediateApplicationsRequest(_service); 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata")); 33 | } 34 | 35 | [Test] 36 | public void IntermediateApplications_Verify_CanRead() 37 | { 38 | var request = new IntermediateApplicationsRequest(_service); 39 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 40 | 41 | var feed = request.Read(); 42 | Expect(feed, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/IntermediateContractsRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class IntermediateContractsRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void IntermediateContracts_Verify_CanConstruct() 22 | { 23 | var request = new IntermediateContractsRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void IntermediateContracts_Verify_ToString() 29 | { 30 | var request = new IntermediateContractsRequest(_service); 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw")); 33 | } 34 | 35 | [Test] 36 | public void IntermediateContracts_Verify_CanRead() 37 | { 38 | var request = new IntermediateContractsRequest(_service); 39 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 40 | 41 | var feed = request.Read(); 42 | Expect(feed, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/IntermediateDataSetsRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class IntermediateDataSetsRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void IntermediateDataSets_Verify_CanContruct() 22 | { 23 | var request = new IntermediateDataSetsRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void IntermediateDataSets_Verify_ToString() 29 | { 30 | var request = new IntermediateDataSetsRequest(_service); 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic")); 33 | } 34 | 35 | [Test] 36 | public void IntermediateDataSets_Verify_CanRead() 37 | { 38 | var request = new IntermediateDataSetsRequest(_service); 39 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 40 | 41 | var feed = request.Read(); 42 | Expect(feed, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/IntermediateResourceCollectionsRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class IntermediateResourceCollectionsRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void IntermediateResourceCollections_Verify_CanContruct() 22 | { 23 | var request = new IntermediateResourceCollectionsRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void IntermediateResourceCollections_Verify_ToString() 29 | { 30 | var request = new IntermediateResourceCollectionsRequest(_service); 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-")); 33 | } 34 | 35 | [Test] 36 | public void IntermediateResourceCollections_Verify_CanRead() 37 | { 38 | var request = new IntermediateResourceCollectionsRequest(_service); 39 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 40 | 41 | var feed = request.Read(); 42 | Expect(feed, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/IntermediateServicesRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class IntermediateServicesRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void IntermediateServices_Verify_CanContruct() 22 | { 23 | var request = new IntermediateServicesRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void IntermediateServices_Verify_ToString() 29 | { 30 | var request = new IntermediateServicesRequest(_service) {ResourceKind = "employees"}; 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees/$service")); 33 | } 34 | 35 | [Test] 36 | public void IntermediateServices_Verify_CanRead() 37 | { 38 | var request = new IntermediateServicesRequest(_service) {ResourceKind = "employees"}; 39 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 40 | 41 | var feed = request.Read(); 42 | Expect(feed, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataEndPointCollectionRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class SDataEndPointCollectionRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void EndPointCollection_Verify_Url() 22 | { 23 | var request = new SDataEndPointCollectionRequest(_service); 24 | var url = request.ToString(); 25 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/$system/registry/endpoints")); 26 | } 27 | 28 | [Test] 29 | public void EndPointCollection_Verify_CanRead() 30 | { 31 | var request = new SDataEndPointCollectionRequest(_service); 32 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 33 | 34 | var feed = request.Read(); 35 | Expect(feed, Is.Not.Null); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataResourceCollectionRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class SDataResourceCollectionRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void ResourceCollection_Verify_CanConstruct() 22 | { 23 | var request = new SDataResourceCollectionRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void ResourceCollection_Verify_ToStringWithPaging() 29 | { 30 | var request = new SDataResourceCollectionRequest(_service) 31 | { 32 | ResourceKind = "employees", 33 | StartIndex = 1, 34 | Count = 100 35 | }; 36 | var url = request.ToString(); 37 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees?startIndex=1&count=100")); 38 | } 39 | 40 | [Test] 41 | public void ResourceCollection_Verify_ToStringWithQuery() 42 | { 43 | var request = new SDataResourceCollectionRequest(_service) 44 | { 45 | ResourceKind = "employees", 46 | QueryValues = {{"where", "gender eq m"}} 47 | }; 48 | var url = request.ToString(); 49 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees?where=gender eq m")); 50 | } 51 | 52 | [Test] 53 | public void ResourceCollection_Verify_ToStringWithQuery_MultipleValues() 54 | { 55 | var request = new SDataResourceCollectionRequest(_service) 56 | { 57 | ResourceKind = "employees", 58 | QueryValues = 59 | { 60 | {"where", "gender eq m"}, 61 | {"orderBy", "orderDate DESC"} 62 | } 63 | }; 64 | var url = request.ToString(); 65 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees?where=gender eq m&orderBy=orderDate DESC")); 66 | } 67 | 68 | [Test] 69 | public void ResourceCollection_Verify_CanRead() 70 | { 71 | var request = new SDataResourceCollectionRequest(_service) {ResourceKind = "employees"}; 72 | _mock.Setup(s => s.ReadFeed(request)).Returns(TestData.Feed); 73 | 74 | var feed = request.Read(); 75 | Expect(feed, Is.Not.Null); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataResourceSchemaRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class SDataResourceSchemaRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void ResourceSchema_Verify_CanRead() 22 | { 23 | var request = new SDataResourceSchemaRequest(_service) {ResourceKind = "employees"}; 24 | _mock.Setup(s => s.ReadSchema(request)).Returns(TestData.Schema); 25 | 26 | var schema = request.Read(); 27 | Expect(schema, Is.Not.Null); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataServiceOperationRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class SDataServiceOperationRequestTests : AssertionHelper 9 | { 10 | private ISDataService _service; 11 | private Mock _mock; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void ServiceOperation_Verify_ToString() 22 | { 23 | var request = new SDataServiceOperationRequest(_service) 24 | { 25 | ResourceKind = "employees", 26 | OperationName = "getStats" 27 | }; 28 | var url = request.ToString(); 29 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees/$service/getStats")); 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataServiceTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Sage.SData.Client.Core; 3 | 4 | namespace Sage.SData.Client.Test.Core 5 | { 6 | using System; 7 | using Atom; 8 | using Client.Framework; 9 | using Moq; 10 | 11 | [TestFixture] 12 | public class SDataServiceTests : AssertionHelper 13 | { 14 | [Test] 15 | public void Service_Verify_CanConstruct() 16 | { 17 | var service = new SDataService(); 18 | Expect(service, Is.Not.Null); 19 | } 20 | 21 | [Test] 22 | public void Service_Verify_CanConstructWithUrl() 23 | { 24 | var service = new SDataService("http://localhost:59213/sdata/aw/dynamic/-/employees", "lee", "abc123"); 25 | Expect(service, Is.Not.Null); 26 | } 27 | 28 | [Test] 29 | public void Service_Verity_CanInitialize() 30 | { 31 | var service = new SDataService("http://localhost:59213/sdata/aw/dynamic/-/employees", "lee", "abc123"); 32 | 33 | Expect(service.UserName, Is.Not.Null); 34 | Expect(service.UserName, Is.EqualTo("lee")); 35 | 36 | Expect(service.Password, Is.Not.Null); 37 | Expect(service.Password, Is.EqualTo("abc123")); 38 | 39 | Expect(service.Protocol, Is.Not.Null); 40 | Expect(service.Protocol, Is.EqualTo("http")); 41 | 42 | Expect(service.ServerName, Is.Not.Null); 43 | Expect(service.ServerName, Is.EqualTo("localhost")); 44 | 45 | Expect(service.Port, Is.Not.Null); 46 | Expect(service.Port, Is.EqualTo(59213)); 47 | 48 | Expect(service.VirtualDirectory, Is.Not.Null); 49 | Expect(service.VirtualDirectory, Is.EqualTo("sdata")); 50 | 51 | Expect(service.ApplicationName, Is.Not.Null); 52 | Expect(service.ApplicationName, Is.EqualTo("aw")); 53 | 54 | Expect(service.ContractName, Is.Not.Null); 55 | Expect(service.ContractName, Is.EqualTo("dynamic")); 56 | 57 | Expect(service.DataSet, Is.Not.Null); 58 | Expect(service.DataSet, Is.EqualTo("-")); 59 | } 60 | 61 | [Test] 62 | public void verify_can_handle_AtomFeed_response_for_create_entry() 63 | { 64 | var mock = new Mock(MockBehavior.Strict); 65 | var feed = new AtomFeed(); 66 | feed.AddEntry(new AtomEntry()); 67 | 68 | mock.SetupGet(r => r.Content).Returns(feed); 69 | mock.SetupGet(r => r.ETag).Returns(String.Empty); 70 | 71 | var service = new MockService(mock); 72 | var result = service.CreateEntry(new SDataServiceOperationRequest(service) { OperationName = "computePrice" }, new AtomEntry()); 73 | Expect(result, Is.InstanceOf()); 74 | } 75 | 76 | [Test] 77 | public void verify_can_handle_AtomEntry_response_for_create_entry() 78 | { 79 | var mock = new Mock(MockBehavior.Strict); 80 | mock.SetupGet(r => r.Content).Returns(new AtomEntry()); 81 | mock.SetupGet(r => r.ETag).Returns(String.Empty); 82 | 83 | var service = new MockService(mock); 84 | var result = service.CreateEntry(new SDataServiceOperationRequest(service) { OperationName = "computePrice" }, new AtomEntry()); 85 | Expect(result, Is.InstanceOf()); 86 | } 87 | 88 | class MockService : SDataService 89 | { 90 | private readonly Mock _mock; 91 | 92 | public MockService(Mock mock) 93 | { 94 | _mock = mock; 95 | } 96 | 97 | protected override ISDataResponse ExecuteRequest(string url, RequestOperation operation, MediaType[] accept) 98 | { 99 | return _mock.Object; 100 | } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Core/SDataTemplateResourceRequestTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Core; 4 | 5 | namespace Sage.SData.Client.Test.Core 6 | { 7 | [TestFixture] 8 | public class SDataTemplateResourceRequestTests : AssertionHelper 9 | { 10 | private Mock _mock; 11 | private ISDataService _service; 12 | 13 | [TestFixtureSetUp] 14 | public void Setup() 15 | { 16 | _mock = new Mock(MockBehavior.Strict, "http://localhost:59213/sdata/aw/dynamic/-/", "lee", "abc123"); 17 | _service = _mock.Object; 18 | } 19 | 20 | [Test] 21 | public void TemplateResource_Verify_CanConstruct() 22 | { 23 | var request = new SDataTemplateResourceRequest(_service); 24 | Expect(request, Is.Not.Null); 25 | } 26 | 27 | [Test] 28 | public void TemplateResource_Verify_ToString() 29 | { 30 | var request = new SDataTemplateResourceRequest(_service) {ResourceKind = "employees"}; 31 | var url = request.ToString(); 32 | Expect(url, Is.EqualTo("http://localhost:59213/sdata/aw/dynamic/-/employees/$template")); 33 | } 34 | 35 | [Test] 36 | public void TemplateResource_Verify_CanRead() 37 | { 38 | var request = new SDataTemplateResourceRequest(_service) {ResourceKind = "employees"}; 39 | _mock.Setup(s => s.ReadEntry(request)).Returns(TestData.Entry); 40 | 41 | var entry = request.Read(); 42 | Expect(entry, Is.Not.Null); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Extensions/SDataExtensionContextTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Text; 4 | using NUnit.Framework; 5 | using Sage.SData.Client.Atom; 6 | using Sage.SData.Client.Extensions; 7 | 8 | namespace Sage.SData.Client.Test.Extensions 9 | { 10 | [TestFixture] 11 | public class SDataExtensionContextTests 12 | { 13 | [Test] 14 | public void Nested_And_Unnested_Resource_Diagnoses_Test() 15 | { 16 | const string xml = @" 17 | 18 | 19 | 20 | one 21 | 22 | 23 | 24 | two 25 | 26 | 27 | 28 | 29 | three 30 | 31 | 32 | 33 | four 34 | 35 | 36 | "; 37 | var feed = new AtomFeed(); 38 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) 39 | { 40 | feed.Load(stream); 41 | } 42 | 43 | var diagnoses = feed.GetSDataDiagnoses(); 44 | Assert.That(diagnoses.Count, Is.EqualTo(2)); 45 | Assert.That(diagnoses[0].Message, Is.EqualTo("one")); 46 | Assert.That(diagnoses[1].Message, Is.EqualTo("two")); 47 | 48 | Assume.That(feed.Entries.Any()); 49 | diagnoses = feed.Entries.First().GetSDataDiagnoses(); 50 | Assert.That(diagnoses.Count, Is.EqualTo(2)); 51 | Assert.That(diagnoses[0].Message, Is.EqualTo("three")); 52 | Assert.That(diagnoses[1].Message, Is.EqualTo("four")); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Extensions/SDataSyncExtensionContextTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using NUnit.Framework; 5 | using Sage.SData.Client.Atom; 6 | using Sage.SData.Client.Extensions; 7 | using Sage.SData.Client.Framework; 8 | 9 | namespace Sage.SData.Client.Test.Extensions 10 | { 11 | [TestFixture] 12 | public class SDataSyncExtensionContextTests 13 | { 14 | [Test] 15 | public void Typical_Feed() 16 | { 17 | var xml = @" 19 | catchUp 20 | 21 | http://www.example.com/sdata/myApp1/myContract/-/accounts 22 | 23 | http://www.example.com/sdata/myApp1/myContract/-/accounts 24 | 6 25 | 2008-10-30T17:23:08Z 26 | 2 27 | 28 | 29 | http://www.example.com/sdata/myApp2/myContract/-/accounts 30 | 10 31 | 2008-10-30T12:16:51Z 32 | 1 33 | 34 | 35 | "; 36 | var feed = new AtomFeed(); 37 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) 38 | { 39 | feed.Load(stream); 40 | } 41 | 42 | var syncMode = feed.GetSDataSyncMode(); 43 | Assert.That(syncMode, Is.EqualTo(SyncMode.CatchUp)); 44 | 45 | var digest = feed.GetSDataSyncDigest(); 46 | Assert.That(digest, Is.Not.Null); 47 | Assert.That(digest.Origin, Is.EqualTo("http://www.example.com/sdata/myApp1/myContract/-/accounts")); 48 | Assert.That(digest.Entries.Length, Is.EqualTo(2)); 49 | 50 | var entry = digest.Entries[0]; 51 | Assert.That(entry.EndPoint, Is.EqualTo("http://www.example.com/sdata/myApp1/myContract/-/accounts")); 52 | Assert.That(entry.Tick, Is.EqualTo(6L)); 53 | Assert.That(entry.Stamp, Is.EqualTo(new DateTime(2008, 10, 30, 17, 23, 08))); 54 | Assert.That(entry.ConflictPriority, Is.EqualTo(2)); 55 | 56 | entry = digest.Entries[1]; 57 | Assert.That(entry.EndPoint, Is.EqualTo("http://www.example.com/sdata/myApp2/myContract/-/accounts")); 58 | Assert.That(entry.Tick, Is.EqualTo(10L)); 59 | Assert.That(entry.Stamp, Is.EqualTo(new DateTime(2008, 10, 30, 12, 16, 51))); 60 | Assert.That(entry.ConflictPriority, Is.EqualTo(1)); 61 | } 62 | 63 | [Test] 64 | public void Typical_Entry() 65 | { 66 | var xml = @" 68 | 69 | http://www.example.com/sdata/myApp1/myContract/-/accounts 70 | 5 71 | 2008-10-30T14:55:43Z 72 | 73 | "; 74 | var entry = new AtomEntry(); 75 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) 76 | { 77 | entry.Load(stream); 78 | } 79 | 80 | var syncState = entry.GetSDataSyncState(); 81 | Assert.That(syncState.EndPoint, Is.EqualTo("http://www.example.com/sdata/myApp1/myContract/-/accounts")); 82 | Assert.That(syncState.Tick, Is.EqualTo(5L)); 83 | Assert.That(syncState.Stamp, Is.EqualTo(new DateTime(2008, 10, 30, 14, 55, 43))); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Extensions/SyndicationExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Xml; 4 | using NUnit.Framework; 5 | using Sage.SData.Client.Atom; 6 | using Sage.SData.Client.Extensions; 7 | 8 | namespace Sage.SData.Client.Test.Extensions 9 | { 10 | [TestFixture] 11 | public class SyndicationExtensionTests 12 | { 13 | [Test] 14 | public void Extension_Namespace_Declared_On_Root_Element_Test() 15 | { 16 | const string xml = @" 17 | 18 | 33 19 | 20 | "; 21 | var feed = new AtomFeed(); 22 | 23 | using (var reader = new StringReader(xml)) 24 | using (var xmlReader = XmlReader.Create(reader)) 25 | { 26 | feed.Load(xmlReader); 27 | } 28 | 29 | Assume.That(feed.Entries, Is.Not.Empty); 30 | var entry = feed.Entries.First(); 31 | Assert.That(entry.Extensions.OfType().Any()); 32 | } 33 | 34 | [Test] 35 | public void Extension_Namespace_Declared_On_Extension_Element_Test() 36 | { 37 | const string xml = @" 38 | 39 | 33 40 | 41 | "; 42 | var feed = new AtomFeed(); 43 | 44 | using (var reader = new StringReader(xml)) 45 | using (var xmlReader = XmlReader.Create(reader)) 46 | { 47 | feed.Load(xmlReader); 48 | } 49 | 50 | Assume.That(feed.Entries, Is.Not.Empty); 51 | var entry = feed.Entries.First(); 52 | Assert.That(entry.Extensions.OfType().Any()); 53 | } 54 | 55 | [Test] 56 | public void Extension_Namespace_Declared_On_Extension_Element_Without_Prefix_Test() 57 | { 58 | const string xml = @" 59 | 60 | 33 61 | 62 | "; 63 | var feed = new AtomFeed(); 64 | 65 | using (var reader = new StringReader(xml)) 66 | using (var xmlReader = XmlReader.Create(reader)) 67 | { 68 | feed.Load(xmlReader); 69 | } 70 | 71 | Assume.That(feed.Entries, Is.Not.Empty); 72 | var entry = feed.Entries.First(); 73 | Assert.That(entry.Extensions.OfType().Any()); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Extensions/Utility.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Xml; 3 | using System.Xml.XPath; 4 | using Sage.SData.Client.Extensions; 5 | 6 | namespace Sage.SData.Client.Test.Extensions 7 | { 8 | public static class Utility 9 | { 10 | public static SDataPayload LoadPayload(string xml) 11 | { 12 | var payload = new SDataPayload(); 13 | 14 | using (var strReader = new StringReader(xml)) 15 | using (var xmlReader = XmlReader.Create(strReader)) 16 | { 17 | var doc = new XPathDocument(xmlReader); 18 | var source = doc.CreateNavigator(); 19 | var manager = new XmlNamespaceManager(source.NameTable); 20 | source.MoveToFirstChild(); 21 | payload.Load(source, manager); 22 | } 23 | 24 | return payload; 25 | } 26 | 27 | public static XPathNavigator WritePayload(SDataPayload payload) 28 | { 29 | using (var stream = new MemoryStream()) 30 | { 31 | using (var writer = XmlWriter.Create(stream)) 32 | { 33 | payload.WriteTo(writer, Client.Framework.Common.SData.Namespace); 34 | } 35 | 36 | stream.Seek(0, SeekOrigin.Begin); 37 | return new XPathDocument(stream).CreateNavigator(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/DiagnosisTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using System.Xml; 4 | using System.Xml.Serialization; 5 | using System.Xml.XPath; 6 | using NUnit.Framework; 7 | using Sage.SData.Client.Framework; 8 | 9 | namespace Sage.SData.Client.Test.Framework 10 | { 11 | [TestFixture] 12 | public class DiagnosisTests 13 | { 14 | /// 15 | /// According to section 3.10 of the SData spec, the sdataCode and 16 | /// applicationCode elements on the diagnosis type are both strings, 17 | /// not integers. sdataCode should be an enumeration since it has a 18 | /// predefined set of values. 19 | /// 20 | [Test] 21 | public void Diagnosis_SDataCode_Should_Be_An_Enum_Test() 22 | { 23 | var diagnosis = new Diagnosis 24 | { 25 | SDataCode = DiagnosisCode.ApplicationDiagnosis, 26 | ApplicationCode = "Application error" 27 | }; 28 | string xml; 29 | 30 | using (var textWriter = new StringWriter()) 31 | using (var xmlWriter = new XmlTextWriter(textWriter)) 32 | { 33 | diagnosis.WriteTo(xmlWriter, null); 34 | xml = textWriter.ToString(); 35 | } 36 | 37 | XPathNavigator nav; 38 | 39 | using (var textReader = new StringReader(xml)) 40 | using (var xmlReader = new XmlTextReader(textReader)) 41 | { 42 | nav = new XPathDocument(xmlReader).CreateNavigator(); 43 | } 44 | 45 | var node = nav.SelectSingleNode("diagnosis/sdataCode"); 46 | Assert.IsNotNull(node); 47 | Assert.AreEqual("ApplicationDiagnosis", node.Value); 48 | 49 | node = nav.SelectSingleNode("diagnosis/applicationCode"); 50 | Assert.IsNotNull(node); 51 | Assert.AreEqual("Application error", node.Value); 52 | } 53 | 54 | [Test] 55 | public void Enum_Properties_Should_Be_Case_Insensitive_Test() 56 | { 57 | const string xml = 58 | @" 59 | eRrOr 60 | bAdUrLsYnTaX 61 | "; 62 | Diagnosis diagnosis; 63 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) 64 | { 65 | diagnosis = (Diagnosis) new XmlSerializer(typeof (Diagnosis)).Deserialize(stream); 66 | } 67 | 68 | Assert.That(diagnosis.Severity, Is.EqualTo(Severity.Error)); 69 | Assert.That(diagnosis.SDataCode, Is.EqualTo(DiagnosisCode.BadUrlSyntax)); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/MediaTypeNamesTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Sage.SData.Client.Framework; 3 | 4 | namespace Sage.SData.Client.Test.Framework 5 | { 6 | [TestFixture] 7 | public class MediaTypeNamesTests 8 | { 9 | /// 10 | /// Extra spaces shouldn't interfer with media type resolution. 11 | /// 12 | [Test] 13 | public void Content_Type_With_Extra_Spaces_Test() 14 | { 15 | const string contentType = "application/atom+xml; type=entry "; 16 | var result = MediaTypeNames.GetMediaType(contentType); 17 | Assert.AreEqual(MediaType.AtomEntry, result); 18 | } 19 | 20 | /// 21 | /// Character casing shouldn't interfer with media type resolution. 22 | /// 23 | [Test] 24 | public void Content_Type_With_Unusual_Character_Casing_Test() 25 | { 26 | const string contentType = "APPLICATION/ATOM+XML; TYPE=ENTRY"; 27 | var result = MediaTypeNames.GetMediaType(contentType); 28 | Assert.AreEqual(MediaType.AtomEntry, result); 29 | } 30 | 31 | /// 32 | /// Additional content type parameters shouldn't interfer with type resolution. 33 | /// 34 | [Test] 35 | public void Content_Type_With_Additional_Parameters_Test() 36 | { 37 | const string contentType = "application/atom+xml; charset=UTF-8; type=entry"; 38 | var result = MediaTypeNames.GetMediaType(contentType); 39 | Assert.AreEqual(MediaType.AtomEntry, result); 40 | } 41 | 42 | /// 43 | /// The legacy XML content type "text/xml" should resolve to the XML media type. 44 | /// 45 | [Test] 46 | public void Legacy_Xml_Content_Type_Test() 47 | { 48 | const string contentType = "text/xml"; 49 | var result = MediaTypeNames.GetMediaType(contentType); 50 | Assert.AreEqual(MediaType.Xml, result); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/SDataUriTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Sage.SData.Client.Framework; 3 | 4 | namespace Sage.SData.Client.Test.Framework 5 | { 6 | [TestFixture] 7 | public class SDataUriTests 8 | { 9 | /// 10 | /// Appending path segments to specific service urls should append the 11 | /// segment to the end of the url, not in the resource segment position. 12 | /// 13 | [Test] 14 | public void Appending_Segments_To_Specific_Service_Urls_Test() 15 | { 16 | var uri = new SDataUri("http://test.com/sdata/-/-/-/resource/$service/name"); 17 | uri.AppendPath("test"); 18 | Assert.AreEqual("resource", uri.CollectionType); 19 | Assert.AreEqual("name", uri.ServiceMethod); 20 | Assert.AreEqual("-/-/-/resource/$service/name/test", uri.DirectPath); 21 | Assert.AreEqual("http://test.com/sdata/-/-/-/resource/$service/name/test", uri.ToString()); 22 | } 23 | 24 | /// 25 | /// Non-standard query parameters such as IncludeContent should be 26 | /// prefixed with an underscore to prevent potential conflicts with 27 | /// future SData versions. 28 | /// 29 | [Test] 30 | public void Non_Standard_Parameters_Should_Have_Underscore_Prefix_Test() 31 | { 32 | var uri = new SDataUri("http://test.com/sdata/-/-/-/resource?_includeContent=true"); 33 | Assert.IsTrue(uri.IncludeContent ?? false); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/UriFormatterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Framework; 4 | 5 | namespace Sage.SData.Client.Test.Framework 6 | { 7 | [TestFixture] 8 | public class UriFormatterTests : AssertionHelper 9 | { 10 | /// 11 | /// The path segments property should be refreshed when a new uri 12 | /// is assigned to an existing uri formatter. 13 | /// 14 | [Test] 15 | public void Assign_New_Uri_To_Existing_Test() 16 | { 17 | var uri = new UriFormatter("http://m6400/sdata/-/-/-/"); 18 | var expected = new[] {new UriPathSegment("-"), new UriPathSegment("-"), new UriPathSegment("-")}; 19 | CollectionAssert.AreEquivalent(uri.PathSegments, expected); 20 | 21 | uri.Uri = new Uri("http://localhost:3333/sdata/aw/dynamic/-/"); 22 | expected = new[] {new UriPathSegment("aw"), new UriPathSegment("dynamic"), new UriPathSegment("-")}; 23 | CollectionAssert.AreEquivalent(uri.PathSegments, expected); 24 | } 25 | 26 | /// 27 | /// URI fragments should be supported to facilitate working with 28 | /// $schema redirection URIs. 29 | /// 30 | [Test] 31 | public void Support_Uri_Fragments_Test() 32 | { 33 | var uri = new UriFormatter("http://m6400/sdata/-/-/-/#one"); 34 | Assert.That(uri.Fragment, Is.EqualTo("one")); 35 | 36 | uri.Host = "localhost"; 37 | Assert.That(uri.Fragment, Is.EqualTo("one")); 38 | 39 | uri.Fragment = "two"; 40 | StringAssert.EndsWith("#two", uri.ToString()); 41 | } 42 | 43 | [Test] 44 | public void Assign_Ampersand_In_Query_Arg_Test() 45 | { 46 | var uri = new SDataUri("http://localhost:2001/sdata/aw/dynamic/-/accounts"); 47 | uri["a"] = "&"; 48 | uri["b"] = "&"; 49 | 50 | Assert.That(uri["a"], Is.EqualTo("&")); 51 | Assert.That(uri["b"], Is.EqualTo("&")); 52 | Assert.That(uri.Query, Is.EqualTo("a=%26&b=%26")); 53 | } 54 | 55 | [Test] 56 | public void Assign_Ampersand_In_Query_Test() 57 | { 58 | var uri = new SDataUri("http://localhost:2001/sdata/aw/dynamic/-/accounts") {Query = "a=%26&b=%26"}; 59 | 60 | Assert.That(uri.Query, Is.EqualTo("a=%26&b=%26")); 61 | Assert.That(uri["a"], Is.EqualTo("&")); 62 | Assert.That(uri["b"], Is.EqualTo("&")); 63 | } 64 | 65 | /// 66 | /// Modifying the QueryArgs dictionary should cause the Query property 67 | /// and ToString method to update accordingly. 68 | /// 69 | [Test] 70 | public void Modifying_QueryArgs_Should_Update_Query_And_ToString_Test() 71 | { 72 | var uri = new UriFormatter("http://localhost"); 73 | 74 | Assert.That(string.IsNullOrEmpty(uri.Query)); 75 | Assert.That(uri.QueryArgs.Count == 0); 76 | Assert.That(uri.ToString() == "http://localhost/"); 77 | 78 | uri.QueryArgs.Add("orderBy", "name"); 79 | 80 | Assert.That(uri.Query == "orderBy=name"); 81 | Assert.That(uri.QueryArgs.Count == 1); 82 | Assert.That(uri.ToString() == "http://localhost/?orderBy=name"); 83 | 84 | uri.QueryArgs.Clear(); 85 | 86 | Assert.That(string.IsNullOrEmpty(uri.Query)); 87 | Assert.That(uri.QueryArgs.Count == 0); 88 | Assert.That(uri.ToString() == "http://localhost/"); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/UriPathParserTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Sage.SData.Client.Framework; 3 | 4 | namespace Sage.SData.Client.Test.Framework 5 | { 6 | [TestFixture] 7 | public class UriPathParserTests 8 | { 9 | /// 10 | /// The URI path parser should handle open parentheses characters 11 | /// in literal string predicates. 12 | /// 13 | [Test] 14 | public void Literal_String_Predicate_With_Open_Paren_Test() 15 | { 16 | var segments = UriPathParser.Parse("aaa('bbb(ccc')"); 17 | Assert.That(segments, Is.Not.Null); 18 | Assert.That(segments.Length, Is.EqualTo(1)); 19 | 20 | var segment = segments[0]; 21 | Assert.That(segment.Text, Is.EqualTo("aaa")); 22 | Assert.That(segment.HasPredicate); 23 | Assert.That(segment.Predicate, Is.EqualTo("'bbb(ccc'")); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Framework/W3CDateTimeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using Sage.SData.Client.Framework; 4 | 5 | namespace Sage.SData.Client.Test.Framework 6 | { 7 | [TestFixture] 8 | public class W3CDateTimeTests 9 | { 10 | /// 11 | /// W3CDateTime should be capable of parsing dates before 1000 A.D. 12 | /// provided leading zeros are present. 13 | /// 14 | [Test] 15 | public void Able_To_Parse_Dates_Before_1000AD_Test() 16 | { 17 | var date = W3CDateTime.Parse("0001-01-01"); 18 | Assert.AreEqual(new DateTime(1, 1, 1), date.DateTime); 19 | 20 | date = W3CDateTime.Parse("0200-02-02"); 21 | Assert.AreEqual(new DateTime(200, 2, 2), date.DateTime); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Sage.SData.Client.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Sage Software, Inc.")] 12 | [assembly: AssemblyProduct("Sage.SData.Client.Test")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d210cf28-24dc-48e0-887d-9b7c53dc4791")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | [assembly: NeutralResourcesLanguage("en-US")] -------------------------------------------------------------------------------- /Sage.SData.Client.Test/TestData.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using Sage.SData.Client.Atom; 4 | using Sage.SData.Client.Metadata; 5 | using Sage.SData.Client.Test.Properties; 6 | 7 | namespace Sage.SData.Client.Test 8 | { 9 | public static class TestData 10 | { 11 | private static AtomFeed _feed; 12 | private static AtomEntry _entry; 13 | private static SDataSchema _schema; 14 | 15 | public static AtomFeed Feed 16 | { 17 | get 18 | { 19 | if (_feed == null) 20 | { 21 | _feed = new AtomFeed(); 22 | 23 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Resources.TestFeed))) 24 | { 25 | _feed.Load(stream); 26 | } 27 | } 28 | 29 | return _feed; 30 | } 31 | } 32 | 33 | public static AtomEntry Entry 34 | { 35 | get 36 | { 37 | if (_entry == null) 38 | { 39 | _entry = new AtomEntry(); 40 | 41 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Resources.TestEntry))) 42 | { 43 | _entry.Load(stream); 44 | } 45 | } 46 | 47 | return _entry; 48 | } 49 | } 50 | 51 | public static SDataSchema Schema 52 | { 53 | get 54 | { 55 | if (_schema == null) 56 | { 57 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Resources.TestSchema))) 58 | { 59 | _schema = SDataSchema.Read(stream); 60 | } 61 | } 62 | 63 | return _schema; 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Sage.SData.Client.Test/TestEntry.xml: -------------------------------------------------------------------------------- 1 |  2 | 6 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 7 | 8 | 9 | 10 | 11 | 0001-01-01T00:00:00+00:00 12 | 13 | 14 | Production Technician - WC60 15 | 14417807 16 | 1209 17 | adventure-works\guy1 18 | 16 19 | 1972-05-15T00:00:00+00:00 20 | False 21 | False 22 | 1996-07-31T00:00:00+00:00 23 | False 24 | 21 25 | 30 26 | True 27 | aae1d04a-c237-4974-b4d5-935247737718 28 | 2004-07-31T00:00:00+00:00 29 | 30 | 31 | -------------------------------------------------------------------------------- /Sage.SData.Client/Atom/AtomTextConstructType.cs: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | Modification History: 3 | ***************************************************************************** 4 | Date Author Description 5 | ***************************************************************************** 6 | 12/11/2007 brian.kuhn Created AtomTextConstructType Enumeration 7 | ****************************************************************************/ 8 | using System; 9 | 10 | using Sage.SData.Client.Common; 11 | 12 | namespace Sage.SData.Client.Atom 13 | { 14 | /// 15 | /// Represents the entity encoding utilized by human-readable text constructs. 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | [Serializable()] 22 | public enum AtomTextConstructType 23 | { 24 | /// 25 | /// No entity-encoding type specified. 26 | /// 27 | [EnumerationMetadata(DisplayName = "", AlternateValue = "")] 28 | None = 0, 29 | 30 | /// 31 | /// Indicates that the human-readable text is Hyper-Text Markup Language (HTML) encoded. 32 | /// 33 | [EnumerationMetadata(DisplayName = "HTML", AlternateValue = "html")] 34 | Html = 1, 35 | 36 | /// 37 | /// Indicates that the human-readable text is not encoded per a specific entity scheme. 38 | /// 39 | [EnumerationMetadata(DisplayName = "Text", AlternateValue = "text")] 40 | Text = 2, 41 | 42 | /// 43 | /// Indicates that the human-readable text is Extensible Hyper-Text Markup Language (XHTML) encoded. 44 | /// 45 | [EnumerationMetadata(DisplayName = "XHTML", AlternateValue = "xhtml")] 46 | Xhtml = 3 47 | } 48 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Atom/IAtomCommonObjectAttributes.cs: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | Modification History: 3 | ***************************************************************************** 4 | Date Author Description 5 | ***************************************************************************** 6 | 12/06/2007 brian.kuhn Created IAtomCommonObjectAttributes Interface 7 | ****************************************************************************/ 8 | using System; 9 | using System.Globalization; 10 | 11 | namespace Sage.SData.Client.Atom 12 | { 13 | /// 14 | /// Allows an object to implement common Atom entity attributes by representing a set of properties, methods, indexers and events common to Atom syndication resources. 15 | /// 16 | /// 17 | /// 18 | interface IAtomCommonObjectAttributes 19 | { 20 | //============================================================ 21 | // PUBLIC PROPERTIES 22 | //============================================================ 23 | #region BaseUri 24 | /// 25 | /// Gets or sets the base URI other than the base URI of the document or external entity. 26 | /// 27 | /// A that represents a base URI other than the base URI of the document or external entity. The default value is a null reference. 28 | /// 29 | /// 30 | /// The value of this property is interpreted as a URI Reference as defined in RFC 2396: Uniform Resource Identifiers, 31 | /// after processing according to XML Base, Section 3.1 (URI Reference Encoding and Escaping). 32 | /// 33 | Uri BaseUri 34 | { 35 | get; 36 | set; 37 | } 38 | #endregion 39 | 40 | #region Language 41 | /// 42 | /// Gets or sets the natural or formal language in which the content is written. 43 | /// 44 | /// A that represents the natural or formal language in which the content is written. The default value is a null reference. 45 | /// 46 | /// 47 | /// The value of this property is a language identifier as defined by RFC 3066: Tags for the Identification of Languages, or its successor. 48 | /// 49 | /// 50 | CultureInfo Language 51 | { 52 | get; 53 | set; 54 | } 55 | #endregion 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sage.SData.Client/Core/BatchProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Sage.SData.Client.Common; 5 | using Sage.SData.Client.Framework; 6 | 7 | namespace Sage.SData.Client.Core 8 | { 9 | /// 10 | /// Class used to batch process atom entries for Insert, Update, and Delete 11 | /// 12 | public sealed class BatchProcess 13 | { 14 | /// 15 | /// The only instance of the BatchProcess class 16 | /// 17 | public static readonly BatchProcess Instance = new BatchProcess(); 18 | 19 | private readonly IList _requests; 20 | 21 | private BatchProcess() 22 | { 23 | _requests = new List(); 24 | } 25 | 26 | /// 27 | /// Current stack 28 | /// 29 | public IList Requests 30 | { 31 | get { return _requests; } 32 | } 33 | 34 | /// 35 | /// Adds a url to the batch for processing 36 | /// 37 | /// url for batch item 38 | /// True if an appropriate pending batch operation was found 39 | public bool AddToBatch(SDataBatchRequestItem item) 40 | { 41 | Guard.ArgumentNotNull(item, "item"); 42 | 43 | var id = GetBatchKey(item.Url, "$batch"); 44 | var request = _requests.LastOrDefault(x => string.Equals(GetBatchKey(x.ToString()), id, StringComparison.InvariantCultureIgnoreCase)); 45 | 46 | if (request != null) 47 | { 48 | request.Items.Add(item); 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | private static string GetBatchKey(string url, params string[] extraSegments) 56 | { 57 | return new SDataUri(url) 58 | { 59 | CollectionPredicate = null, 60 | Query = null 61 | }.AppendPath(extraSegments).ToString(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/ISDataRequestSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Sage.SData.Client.Core 2 | { 3 | /// 4 | /// Interface which defines the settings common to all 5 | /// SData Requests 6 | /// 7 | public interface ISDataRequestSettings 8 | { 9 | /// 10 | /// Accessor method for protocol 11 | /// 12 | /// HTTP is the default but can be HTTPS 13 | string Protocol { get; set; } 14 | 15 | /// IP address is also allowed (192.168.1.1). 16 | /// Can be followed by port number. For example www.example.com:5493. 17 | /// 5493 is the recommended port number for SData services that are not exposed on the Internet. 18 | /// 19 | string ServerName { get; set; } 20 | 21 | /// 22 | /// Accessor method for port 23 | /// 24 | int? Port { get; set; } 25 | 26 | /// 27 | /// Accessor method for virtual directory 28 | /// 29 | /// 30 | /// Must be sdata, unless the technical framework imposes something different. 31 | /// 32 | string VirtualDirectory { get; set; } 33 | } 34 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/IntermediateApplicationsRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// Intermediate request to retrieve enumeration of applications 7 | /// 8 | /// http://sdata.acme.com/sdata 9 | /// Feed level category = provider Entry level category = application 10 | public class IntermediateApplicationsRequest : SDataBaseRequest 11 | { 12 | /// 13 | /// Constructor 14 | /// 15 | /// ISDataService for this request 16 | public IntermediateApplicationsRequest(ISDataService service) 17 | : base(service) 18 | { 19 | } 20 | 21 | /// 22 | /// Reads the AtomFeed for enumeration of applications 23 | /// 24 | /// AtomFeed 25 | /// 26 | /// 27 | /// 31 | /// 32 | /// 33 | public virtual AtomFeed Read() 34 | { 35 | return Service.ReadFeed(this); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/IntermediateContractsRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sage.SData.Client.Atom; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | /// 7 | /// Intermediate request to retrieve enumeration of contracts 8 | /// from the specified application and dataset 9 | /// 10 | /// http://sdata.acme.com/sdata/sageApp 11 | /// Feed level category = application Entry level category = contract 12 | public class IntermediateContractsRequest : IntermediateApplicationsRequest 13 | { 14 | /// 15 | /// Accessor method for application 16 | /// 17 | /// the application name 18 | public string ApplicationName 19 | { 20 | get { return Uri.Product; } 21 | set { Uri.Product = value; } 22 | } 23 | 24 | /// 25 | /// Accessor method for application 26 | /// 27 | /// the application name 28 | [Obsolete("Use the ApplicationName property instead.")] 29 | public string Application 30 | { 31 | get { return ApplicationName; } 32 | set { ApplicationName = value; } 33 | } 34 | 35 | /// 36 | /// Constructor 37 | /// 38 | /// ISDataService for this request 39 | public IntermediateContractsRequest(ISDataService service) 40 | : base(service) 41 | { 42 | ApplicationName = !string.IsNullOrEmpty(service.ApplicationName) ? service.ApplicationName : "-"; 43 | } 44 | 45 | /// 46 | /// Reads the AtomFeed for enumeration of contracts 47 | /// 48 | /// AtomFeed 49 | /// 50 | /// 51 | /// 55 | /// 56 | /// 57 | public override AtomFeed Read() 58 | { 59 | return Service.ReadFeed(this); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/IntermediateDataSetsRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// Intermediate URL to retrieve enumeration of datasets 7 | /// from the specified application 8 | /// 9 | /// http://sdata.acme.com/sdata/sageApp/test 10 | /// Feed level category = contract Entry level category = dataset 11 | public class IntermediateDataSetsRequest : IntermediateContractsRequest 12 | { 13 | /// 14 | /// Accessor method for contractName 15 | /// 16 | /// An SData service can support several “integration contracts” side-by-side. 17 | /// For example, a typical Sage ERP service will support a crmErp contract which exposes 18 | /// the resources required by CRM integration (with schemas imposed by the CRM/ERP contract) 19 | /// and a native or default contract which exposes all the resources of the ERP in their native format. 20 | /// 21 | public string ContractName 22 | { 23 | get { return Uri.Contract; } 24 | set { Uri.Contract = value; } 25 | } 26 | 27 | /// 28 | /// Constructor 29 | /// 30 | /// ISDataService for this request 31 | public IntermediateDataSetsRequest(ISDataService service) 32 | : base(service) 33 | { 34 | ContractName = !string.IsNullOrEmpty(service.ContractName) ? service.ContractName : "-"; 35 | } 36 | 37 | /// 38 | /// Reads the AtomFeed for enumeration of datasets 39 | /// 40 | /// AtomFeed 41 | /// 42 | /// 43 | /// 47 | /// 48 | /// 49 | public override AtomFeed Read() 50 | { 51 | return Service.ReadFeed(this); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/IntermediateResourceCollectionsRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// Intermediate request to retrieve enumeration of resource collections 7 | /// from the specified by a given contract 8 | /// 9 | /// http://sdata.acme.com/sdata/sageApp/test/prod 10 | /// 11 | /// Feed level category = dataset Entry level category = collection 12 | /// Enumeration of resource collections exposed by the test contract 13 | /// 14 | public class IntermediateResourceCollectionsRequest : IntermediateDataSetsRequest 15 | { 16 | /// 17 | /// Accessor method for dataSet 18 | /// 19 | /// Identifies the dataset when the application gives access to several datasets, such as several companies and production/test datasets. 20 | /// If the application can only handle a single dataset, or if it can be configured with a default dataset, 21 | /// a hyphen can be used as a placeholder for the default dataset. 22 | /// For example, if prod is the default dataset in the example above, the URL could be shortened as: 23 | /// http://www.example.com/sdata/sageApp/test/-/accounts?startIndex=21&count=10 24 | /// If several parameters are required to specify the dataset (for example database name and company id), 25 | /// they should be formatted as a single segment in the URL. For example, sageApp/test/demodb;acme/accounts -- the semicolon separator is application specific, not imposed by SData. 26 | /// 27 | public string DataSet 28 | { 29 | get { return Uri.CompanyDataset; } 30 | set { Uri.CompanyDataset = value; } 31 | } 32 | 33 | /// 34 | /// Constructor 35 | /// 36 | /// ISDataService for this request 37 | public IntermediateResourceCollectionsRequest(ISDataService service) 38 | : base(service) 39 | { 40 | DataSet = !string.IsNullOrEmpty(service.DataSet) ? service.DataSet : "-"; 41 | } 42 | 43 | /// 44 | /// Reads the AtomFeed for enumeration of resource collections 45 | /// 46 | /// AtomFeed 47 | /// 48 | /// 49 | /// 53 | /// 54 | /// 55 | public override AtomFeed Read() 56 | { 57 | return Service.ReadFeed(this); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/IntermediateServicesRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Framework; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// Intermediate URL to retrieve enumeration of services 7 | /// from the specified contract or contract and resource kind 8 | /// 9 | /// 10 | /// http://sdata.acme.com/sdata/sageApp/test/prod/$service 11 | /// http://sdata.acme.com/sdata/sageApp/test/prod/accounts/$service 12 | /// 13 | /// Feed level category = service field level category = operation 14 | public class IntermediateServicesRequest : IntermediateResourceCollectionsRequest 15 | { 16 | private const string ServiceTerm = "$service"; 17 | 18 | /// 19 | /// Accessor method for resourceKind 20 | /// 21 | /// 22 | /// This URL segment identifies the kind of resource that is queried (account, contact, salesOrder, etc.) 23 | /// This URL returns the collection of all account resources, as an Atom feed. 24 | /// If the contract exposes a large number of resources kinds, a functional group can be inserted before the 25 | /// resource kind segment (eventually a hierarchy of functional groups), which act as a folder (a hierarchy of folders) to organize the resources. 26 | /// Typical functional groups would be financials, commercials, HR, etc. 27 | /// NOTE Can be empty 28 | /// 29 | public string ResourceKind { get; set; } 30 | 31 | /// 32 | /// Initialises a new instance of the class. 33 | /// 34 | /// 35 | public IntermediateServicesRequest(ISDataService service) 36 | : base(service) 37 | { 38 | } 39 | 40 | protected override void BuildUrl(SDataUri uri) 41 | { 42 | base.BuildUrl(uri); 43 | 44 | if (!string.IsNullOrEmpty(ResourceKind)) 45 | { 46 | uri.AppendPath(ResourceKind); 47 | } 48 | 49 | uri.AppendPath(ServiceTerm); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/ReadCompletedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | public class ReadCompletedEventArgs : AsyncCompletedEventArgs 7 | { 8 | private readonly object _result; 9 | 10 | public ReadCompletedEventArgs(object result, Exception error, bool cancelled, object userState) 11 | : base(error, cancelled, userState) 12 | { 13 | _result = result; 14 | } 15 | 16 | public object Result 17 | { 18 | get 19 | { 20 | RaiseExceptionIfNecessary(); 21 | return _result; 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataClientException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// Exception for SDataClient 7 | /// 8 | public class SDataClientException : Exception 9 | { 10 | // Base Exception class constructors. 11 | /// 12 | /// constructor 13 | /// 14 | public SDataClientException() 15 | { 16 | } 17 | 18 | /// 19 | /// costructor 20 | /// 21 | /// 22 | public SDataClientException(string message) 23 | : base(message) 24 | { 25 | } 26 | 27 | /// 28 | /// constructor 29 | /// 30 | /// 31 | /// 32 | public SDataClientException(string message, Exception innerException) 33 | : base(message, innerException) 34 | { 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataEndPointCollectionRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | using Sage.SData.Client.Framework; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | /// 7 | /// SData request for an endpoint collection 8 | /// 9 | public class SDataEndPointCollectionRequest : SDataBaseRequest 10 | { 11 | /// 12 | /// Constructor 13 | /// 14 | /// ISDataService for this request 15 | public SDataEndPointCollectionRequest(ISDataService service) 16 | : base(service) 17 | { 18 | } 19 | 20 | /// 21 | /// Reads the AtomFeed for a resource collection 22 | /// 23 | /// AtomFeed 24 | public AtomFeed Read() 25 | { 26 | return Service.ReadFeed(this); 27 | } 28 | 29 | protected override void BuildUrl(SDataUri uri) 30 | { 31 | base.BuildUrl(uri); 32 | uri.AppendPath("$system"); 33 | uri.AppendPath("registry"); 34 | uri.AppendPath("endpoints"); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataOperationalRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Sage.SData.Client.Core 2 | { 3 | /// 4 | /// Base classes for non Resource based URLs 5 | /// 6 | public abstract class SDataOperationalRequest : SDataApplicationRequest 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | /// ISDataService for this request 12 | protected SDataOperationalRequest(ISDataService service) 13 | : base(service) 14 | { 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataResourceCollectionRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sage.SData.Client.Atom; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | /// 7 | /// SData URL for a resource collection 8 | /// 9 | public class SDataResourceCollectionRequest : SDataApplicationRequest 10 | { 11 | /// 12 | /// Indicates the index of the first resource returned by the query. This index is 1-based (not 0-based). 13 | /// 14 | public long? StartIndex 15 | { 16 | get { return Uri.StartIndex; } 17 | set { Uri.StartIndex = value; } 18 | } 19 | 20 | /// 21 | /// Indicates the number of resources requested by the service consumer. 22 | /// The service may choose to return a different number of resources and it 23 | /// indicates this by setting the itemsPerPage element in the returned feed. 24 | /// 25 | public long? Count 26 | { 27 | get { return Uri.Count; } 28 | set { Uri.Count = value; } 29 | } 30 | 31 | /// 32 | /// Constructor 33 | /// 34 | /// ISDataService for this request 35 | public SDataResourceCollectionRequest(ISDataService service) 36 | : base(service) 37 | { 38 | } 39 | 40 | /// 41 | /// Reads the AtomFeed for a resource collection 42 | /// 43 | /// AtomFeed 44 | /// 45 | /// 46 | /// 50 | /// 51 | /// 52 | public AtomFeed Read() 53 | { 54 | return Service.ReadFeed(this); 55 | } 56 | 57 | /// 58 | /// Performs initial read from AtomFeedReader 59 | /// 60 | /// 61 | public AtomFeedReader ExecuteReader() 62 | { 63 | var reader = new AtomFeedReader(this); 64 | return reader.Read() ? reader : null; 65 | } 66 | 67 | /// 68 | /// Performs initial read from AtomFeedReader 69 | /// 70 | /// the feed 71 | /// 72 | [Obsolete("Use the ExecuteReader method instead, which automatically fetches the feed's first page.")] 73 | public bool Read(AtomFeed feed) 74 | { 75 | return ExecuteReader() != null; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataResourcePropertyRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sage.SData.Client.Atom; 3 | using Sage.SData.Client.Framework; 4 | 5 | namespace Sage.SData.Client.Core 6 | { 7 | /// 8 | /// SData Resource Property URL 9 | /// 10 | public class SDataResourcePropertyRequest : SDataSingleResourceRequest 11 | { 12 | private readonly IList _properties; 13 | 14 | /// 15 | /// Dictionary containing the resource properties 16 | /// 17 | /// 18 | /// SData only allows “relationship properties” in this context, 19 | /// i.e., properties that point to another resource or to a collection of related resources. 20 | /// So, properties like postalAddress or contacts are valid in the example above 21 | /// (assuming that address and contact are treated as resource kinds by the service) 22 | /// but a property like accountName would not be allowed (at least in a first version of the SData standard, this restriction may be lifted later). 23 | /// If the relationship designates a single resource, as in the example above (an account has a single postal address), the URL returns an Atom entry. 24 | /// If the relationship designates a collection of resources (if we had used a property like addresses in the example above), the URL returns an Atom feed. 25 | /// The sme:isCollection schema attribute can be used to determine whether the relationships is a collection or not (see Relationship Definition section for details). 26 | /// SData only allows property segments following a URL that identifies a single resource. So, URLs like accounts('A001')/postalAddress or accounts('A001')/contacts 27 | /// are valid but a URL like accounts/postalAddress (all postal addresses of all accounts) is invalid. 28 | /// SData allows property segments to be chained, as long as the previous rule is satisfied. So, the following URLs are also valid: 29 | /// http://sdata.acme.com/sdata/sageApp/test/accounts('A001')/postalAddress/country 30 | /// http://sdata.acme.com/sdata/sageApp/test/accounts('A001')/addresses(type eq 'postal')/country 31 | /// 32 | public IList ResourceProperties 33 | { 34 | get { return _properties; } 35 | } 36 | 37 | /// 38 | /// Constructor 39 | /// 40 | /// ISDataService for this request 41 | public SDataResourcePropertyRequest(ISDataService service) 42 | : base(service) 43 | { 44 | _properties = new List(); 45 | } 46 | 47 | /// 48 | /// Reads the AtomFeed for the resource property 49 | /// 50 | /// AtomFeed 51 | /// 52 | /// 53 | /// 57 | /// 58 | /// 59 | public AtomFeed ReadFeed() 60 | { 61 | return Service.ReadFeed(this); 62 | } 63 | 64 | /// 65 | /// Reads the AtomEntry for the resource property 66 | /// 67 | /// AtomEntry 68 | /// 69 | /// 70 | /// 74 | /// 75 | /// 76 | public override AtomEntry Read() 77 | { 78 | return Service.ReadEntry(this); 79 | } 80 | 81 | protected override void BuildUrl(SDataUri uri) 82 | { 83 | base.BuildUrl(uri); 84 | 85 | foreach (var value in ResourceProperties) 86 | { 87 | uri.AppendPath(value); 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataResourceSchemaRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Framework; 2 | using Sage.SData.Client.Metadata; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | /// 7 | /// Request to to get resource schema 8 | /// 9 | public class SDataResourceSchemaRequest : SDataOperationalRequest 10 | { 11 | private const string SchemaTerm = "$schema"; 12 | 13 | /// 14 | /// Accessor method for version 15 | /// 16 | /// 17 | /// SData recommends that schema links include a version parameter. 18 | /// This enables consumers to cache them more efficiently (see Resource Versioning section for details). 19 | /// NOTE Not Required 20 | /// 21 | /// 22 | /// without resource kind http://sdata.acme.com/sdata/sageApp/test/$schema 23 | /// with resource kind and version http://sdata.acme.com/sdata/sageApp/test/accounts/$schema?version=5 24 | /// 25 | public string Version 26 | { 27 | get { return Uri["version"]; } 28 | set { Uri["version"] = value; } 29 | } 30 | 31 | /// 32 | /// Constructor 33 | /// 34 | /// ISDataService for this request 35 | public SDataResourceSchemaRequest(ISDataService service) 36 | : base(service) 37 | { 38 | } 39 | 40 | /// 41 | /// Reads the Xml Schema for a resource 42 | /// 43 | /// XmlSchema 44 | /// 45 | /// 46 | /// 50 | /// 51 | /// 52 | public SDataSchemaObject Read() 53 | { 54 | return Service.ReadSchema(this); 55 | } 56 | 57 | protected override void BuildUrl(SDataUri uri) 58 | { 59 | base.BuildUrl(uri); 60 | uri.AppendPath(SchemaTerm); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataServiceOperationRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sage.SData.Client.Atom; 3 | using Sage.SData.Client.Framework; 4 | 5 | namespace Sage.SData.Client.Core 6 | { 7 | /// 8 | /// Service Operation URL 9 | /// 10 | public class SDataServiceOperationRequest : SDataApplicationRequest 11 | { 12 | private const string ServiceTerm = "$service"; 13 | 14 | /// 15 | /// Accessor method for operationName 16 | /// 17 | /// 18 | /// This element identifies a service operation. The operation must be invoked by posting an Atom entry containing the parameters to this URL. 19 | /// The SData service will return the computed prices as an Atom entry containing the result (see the description of Synchronous Service Operations for details). 20 | /// In the example above, the input and output are Atom entries, but SData also supports Atom feeds as input and/or output to service operations 21 | /// (see Service Operations section for details). 22 | /// The $service component may be placed after the contract segment (after test in the example above), 23 | /// if it applies globally to the entire contract or it may be placed after the resource kind segment (as in the example above), if it applies to resources of a specific kind. 24 | /// 25 | public string OperationName { get; set; } 26 | 27 | /// 28 | /// The input entry containing parameter values to be submitted to the service. 29 | /// 30 | public AtomEntry Entry { get; set; } 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | /// ISDataService for this request 36 | public SDataServiceOperationRequest(ISDataService service) 37 | : base(service) 38 | { 39 | } 40 | 41 | /// 42 | /// Creates POST to the server 43 | /// 44 | /// AtomFeed returned from the server 45 | /// 46 | /// 47 | /// 51 | /// 52 | /// 53 | public AtomEntry Create() 54 | { 55 | if (Entry == null) 56 | { 57 | throw new InvalidOperationException("Request entry must be specified"); 58 | } 59 | 60 | return Service.CreateEntry(this, Entry); 61 | } 62 | 63 | /// 64 | /// Execute the service operation asynchronously. 65 | /// 66 | /// 67 | public AsyncRequest CreateAsync() 68 | { 69 | return Service.CreateAsync(this, Entry); 70 | } 71 | 72 | protected override void BuildUrl(SDataUri uri) 73 | { 74 | base.BuildUrl(uri); 75 | uri.AppendPath(ServiceTerm); 76 | 77 | if (!string.IsNullOrEmpty(OperationName)) 78 | { 79 | uri.AppendPath(OperationName); 80 | } 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataSystemRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | 3 | namespace Sage.SData.Client.Core 4 | { 5 | /// 6 | /// SData reserves the following URL for “system” resources and services: 7 | /// At this stage, SData only reserves the $system segment name, it does not standardize the URLs below this level. 8 | /// 9 | /// http://sdata.acme.com/sdata/$system 10 | public class SDataSystemRequest : SDataBaseRequest 11 | { 12 | /// 13 | /// Constructor 14 | /// 15 | /// ISDataService for this request 16 | public SDataSystemRequest(ISDataService service) 17 | : base(service) 18 | { 19 | } 20 | 21 | /// 22 | /// Sends a PUT request to the server based on the URL for the request 23 | /// 24 | /// AtomFeed returned from the server 25 | /// 26 | /// 27 | /// 31 | /// 32 | /// 33 | public AtomFeed Read() 34 | { 35 | return Service.ReadFeed(this); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Core/SDataTemplateResourceRequest.cs: -------------------------------------------------------------------------------- 1 | using Sage.SData.Client.Atom; 2 | using Sage.SData.Client.Framework; 3 | 4 | namespace Sage.SData.Client.Core 5 | { 6 | /// 7 | /// The template resource allows a service consumer to obtain the resource's default property values. 8 | /// For example, the URL in the example could be used to fill the contents of a “Create Account” form. 9 | /// The $template segment is only valid after the resource kind segment (accounts in the example). 10 | /// Template resources are usually read only, but some applications could expose them in read/write mode, typically to admin accounts. 11 | /// 12 | public class SDataTemplateResourceRequest : SDataOperationalRequest 13 | { 14 | private const string TemplateTerm = "$template"; 15 | 16 | /// 17 | /// gets the string version of this SData URL 18 | /// 19 | /// return the string 20 | public SDataTemplateResourceRequest(ISDataService service) 21 | : base(service) 22 | { 23 | } 24 | 25 | protected override void BuildUrl(SDataUri uri) 26 | { 27 | base.BuildUrl(uri); 28 | uri.AppendPath(TemplateTerm); 29 | } 30 | 31 | /// 32 | /// Reads the template 33 | /// 34 | /// AtomEntry representing the template 35 | /// 36 | /// 37 | /// 41 | /// 42 | /// 43 | public AtomEntry Read() 44 | { 45 | return Service.ReadEntry(this); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/OpenSearch/OpenSearchExtensionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Sage.SData.Client.Atom; 3 | using Sage.SData.Client.Common; 4 | 5 | namespace Sage.SData.Client.Extensions 6 | { 7 | /// 8 | /// Open Search Extensions 9 | /// 10 | public static class OpenSearchExtensionHelper 11 | { 12 | /// 13 | /// Extension method to retrieve opensearch items per page 14 | /// 15 | /// 16 | /// 17 | public static int? GetOpenSearchItemsPerPage(this AtomFeed feed) 18 | { 19 | var context = GetContext(feed, false); 20 | return context != null ? context.ItemsPerPage : null; 21 | } 22 | 23 | /// 24 | /// Extension method to retrieve opensearch total results 25 | /// 26 | /// 27 | /// 28 | public static int? GetOpenSearchTotalResults(this AtomFeed feed) 29 | { 30 | var context = GetContext(feed, false); 31 | return context != null ? context.TotalResults : null; 32 | } 33 | 34 | /// 35 | /// Extension method to retrieve opensearch start index 36 | /// 37 | /// 38 | /// 39 | public static int? GetOpenSearchStartIndex(this AtomFeed feed) 40 | { 41 | var context = GetContext(feed, false); 42 | return context != null ? context.StartIndex : null; 43 | } 44 | 45 | /// 46 | /// Extension method to set opensearch items per page 47 | /// 48 | /// 49 | /// 50 | public static void SetOpenSearchItemsPerPage(this AtomFeed feed, int value) 51 | { 52 | var context = GetContext(feed, true); 53 | context.ItemsPerPage = value; 54 | } 55 | 56 | /// 57 | /// Extension method to set opensearch total results 58 | /// 59 | /// 60 | /// 61 | public static void SetOpenSearchTotalResults(this AtomFeed feed, int value) 62 | { 63 | var context = GetContext(feed, true); 64 | context.TotalResults = value; 65 | } 66 | 67 | /// 68 | /// Extension method to set opensearch start index 69 | /// 70 | /// 71 | /// 72 | public static void SetOpenSearchStartIndex(this AtomFeed feed, int value) 73 | { 74 | var context = GetContext(feed, true); 75 | context.StartIndex = value; 76 | } 77 | 78 | private static OpenSearchExtensionContext GetContext(IExtensibleSyndicationObject entry, bool createIfMissing) 79 | { 80 | Guard.ArgumentNotNull(entry, "entry"); 81 | var extension = entry.Extensions.OfType().FirstOrDefault(); 82 | 83 | if (extension == null) 84 | { 85 | if (!createIfMissing) 86 | { 87 | return null; 88 | } 89 | 90 | extension = new OpenSearchExtension(); 91 | entry.AddExtension(extension); 92 | } 93 | 94 | return extension.Context; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SData/SDataExtensionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq; 3 | using Sage.SData.Client.Atom; 4 | using Sage.SData.Client.Common; 5 | using Sage.SData.Client.Framework; 6 | using Sage.SData.Client.Metadata; 7 | 8 | namespace Sage.SData.Client.Extensions 9 | { 10 | /// 11 | /// SDataExtension Helpers Extension Methods 12 | /// 13 | public static class SDataExtensionHelper 14 | { 15 | /// 16 | /// Extension method to retrieve sdata payload 17 | /// 18 | /// the entry 19 | /// 20 | public static SDataPayload GetSDataPayload(this AtomEntry entry) 21 | { 22 | var context = GetContext(entry, false); 23 | return context != null ? context.Payload : null; 24 | } 25 | 26 | /// 27 | /// Retrieves diagnosis from the feed 28 | /// 29 | /// the AtomFeed 30 | /// 31 | public static Collection GetSDataDiagnoses(this AtomFeed feed) 32 | { 33 | var context = GetContext(feed, true); 34 | return context != null ? context.Diagnoses : null; 35 | } 36 | 37 | /// 38 | /// Retrieves the diagnosis from an entry 39 | /// 40 | /// the AtomEntry 41 | /// 42 | public static Collection GetSDataDiagnoses(this AtomEntry entry) 43 | { 44 | var context = GetContext(entry, true); 45 | return context != null ? context.Diagnoses : null; 46 | } 47 | 48 | /// 49 | /// Retrieves the inline XML schema embedded in the feed 50 | /// 51 | /// 52 | /// 53 | public static SDataSchema GetSDataSchema(this AtomFeed feed) 54 | { 55 | var context = GetContext(feed, true); 56 | return context != null ? context.Schema : null; 57 | } 58 | 59 | /// 60 | /// Retrieves the inline XML schema embedded in the feed entry 61 | /// 62 | /// 63 | /// 64 | public static SDataSchema GetSDataSchema(this AtomEntry entry) 65 | { 66 | var context = GetContext(entry, true); 67 | return context != null ? context.Schema : null; 68 | } 69 | 70 | /// 71 | /// Extension method to set sdata payload 72 | /// 73 | /// 74 | /// 75 | public static void SetSDataPayload(this AtomEntry entry, SDataPayload payload) 76 | { 77 | var context = GetContext(entry, true); 78 | context.Payload = payload; 79 | } 80 | 81 | private static SDataExtensionContext GetContext(IExtensibleSyndicationObject entry, bool createIfMissing) 82 | { 83 | Guard.ArgumentNotNull(entry, "entry"); 84 | var extension = entry.Extensions.OfType().FirstOrDefault(); 85 | 86 | if (extension == null) 87 | { 88 | if (!createIfMissing) 89 | { 90 | return null; 91 | } 92 | 93 | extension = new SDataExtension(); 94 | entry.AddExtension(extension); 95 | } 96 | 97 | return extension.Context; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SData/SDataSimpleCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Xml; 5 | using System.Xml.XPath; 6 | using Sage.SData.Client.Common; 7 | 8 | namespace Sage.SData.Client.Extensions 9 | { 10 | [Serializable] 11 | public class SDataSimpleCollection : List 12 | { 13 | public SDataSimpleCollection(string itemElementName) 14 | { 15 | ItemElementName = itemElementName; 16 | } 17 | 18 | public SDataSimpleCollection() 19 | { 20 | } 21 | 22 | /// 23 | /// Specifies the local element name of the item when serialized to the XML Array. 24 | /// 25 | /// This is inferred from the first element's local name 26 | public string ItemElementName { get; set; } 27 | 28 | public bool Load(XPathNavigator source) 29 | { 30 | //------------------------------------------------------------ 31 | // Validate parameter 32 | //------------------------------------------------------------ 33 | Guard.ArgumentNotNull(source, "source"); 34 | 35 | var items = source.SelectChildren(XPathNodeType.Element).Cast(); 36 | return InternalLoad(items); 37 | } 38 | 39 | private bool InternalLoad(IEnumerable items) 40 | { 41 | var firstItem = items.FirstOrDefault(); 42 | if (firstItem == null) 43 | return true; 44 | 45 | ItemElementName = firstItem.LocalName; 46 | 47 | foreach (var item in items) 48 | { 49 | string nilValue; 50 | object value; 51 | 52 | if (item.TryGetAttribute("nil", Framework.Common.XSI.Namespace, out nilValue) && XmlConvert.ToBoolean(nilValue)) 53 | { 54 | value = null; 55 | } 56 | else 57 | { 58 | value = item.Value; 59 | } 60 | 61 | Add(value); 62 | } 63 | 64 | return true; 65 | } 66 | 67 | public void WriteTo(string name, string ns, XmlWriter writer) 68 | { 69 | if (String.IsNullOrEmpty(ItemElementName)) 70 | throw new InvalidOperationException("ItemElementName must be set"); 71 | 72 | writer.WriteStartElement(name, ns); 73 | 74 | foreach (var item in this) 75 | { 76 | WriteItemTo(ItemElementName, ns, item, writer); 77 | } 78 | 79 | writer.WriteEndElement(); 80 | } 81 | 82 | private static void WriteItemTo(string name, string ns, object value, XmlWriter writer) 83 | { 84 | if (value == null) 85 | { 86 | writer.WriteStartElement(name, ns); 87 | writer.WriteAttributeString("nil", Framework.Common.XSI.Namespace, XmlConvert.ToString(true)); 88 | writer.WriteEndElement(); 89 | } 90 | else 91 | { 92 | writer.WriteElementString(name, ns, SDataPayload.ValueToString(value)); 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SData/XPathNavigatorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Xml; 4 | using System.Xml.XPath; 5 | 6 | namespace Sage.SData.Client.Extensions 7 | { 8 | internal static class XPathNavigatorExtensions 9 | { 10 | public static bool HasAttribute(this XPathNavigator navigator, string localName, string namespaceUri) 11 | { 12 | var result = navigator.MoveToAttribute(localName, namespaceUri); 13 | 14 | if (result) 15 | { 16 | navigator.MoveToParent(); 17 | } 18 | 19 | return result; 20 | } 21 | 22 | public static bool TryGetAttribute(this XPathNavigator navigator, string localName, string namespaceUri, out string value) 23 | { 24 | var result = navigator.MoveToAttribute(localName, namespaceUri); 25 | 26 | if (result) 27 | { 28 | value = navigator.Value; 29 | navigator.MoveToParent(); 30 | } 31 | else 32 | { 33 | value = null; 34 | } 35 | 36 | return result; 37 | } 38 | 39 | public static IEnumerable> GetAllNamespaces(this XPathNavigator source) 40 | { 41 | return source.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml) 42 | .Concat(source.Select("descendant::*").Cast() 43 | .SelectMany(descendant => descendant.GetNamespacesInScope(XmlNamespaceScope.Local))); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SDataSync/SDataSyncExtensionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Sage.SData.Client.Atom; 3 | using Sage.SData.Client.Common; 4 | using Sage.SData.Client.Framework; 5 | 6 | namespace Sage.SData.Client.Extensions 7 | { 8 | /// 9 | /// Helper class for accessing atom feed and entry SDataSyncExtensions 10 | /// 11 | public static class SDataSyncExtensionHelper 12 | { 13 | /// 14 | /// Extension method to retrieve sdata sync mode 15 | /// 16 | /// 17 | /// 18 | public static SyncMode? GetSDataSyncMode(this AtomFeed feed) 19 | { 20 | var context = GetContext(feed, false); 21 | return context != null ? context.SyncMode : null; 22 | } 23 | 24 | /// 25 | /// Extension method to retrieve sdata sync digest 26 | /// 27 | /// 28 | /// 29 | public static Digest GetSDataSyncDigest(this AtomFeed feed) 30 | { 31 | var context = GetContext(feed, false); 32 | return context != null ? context.Digest : null; 33 | } 34 | 35 | /// 36 | /// Extension method to retrieve sdata sync state 37 | /// 38 | /// 39 | /// 40 | public static SyncState GetSDataSyncState(this AtomEntry entry) 41 | { 42 | var context = GetContext(entry, false); 43 | return context != null ? context.SyncState : null; 44 | } 45 | 46 | private static SDataSyncExtensionContext GetContext(IExtensibleSyndicationObject entry, bool createIfMissing) 47 | { 48 | Guard.ArgumentNotNull(entry, "entry"); 49 | var extension = entry.Extensions.OfType().FirstOrDefault(); 50 | 51 | if (extension == null) 52 | { 53 | if (!createIfMissing) 54 | { 55 | return null; 56 | } 57 | 58 | extension = new SDataSyncExtension(); 59 | entry.AddExtension(extension); 60 | } 61 | 62 | return extension.Context; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SimpleList/SimpleListDataType.cs: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | Modification History: 3 | ***************************************************************************** 4 | Date Author Description 5 | ***************************************************************************** 6 | 01/05/2008 brian.kuhn Created SimpleListDataType Enumeration 7 | ****************************************************************************/ 8 | using System; 9 | 10 | using Sage.SData.Client.Common; 11 | 12 | namespace Sage.SData.Client.Extensions 13 | { 14 | /// 15 | /// Represents the data-type of a simple list property. 16 | /// 17 | /// 18 | /// 19 | /// 20 | [Serializable()] 21 | public enum SimpleListDataType 22 | { 23 | /// 24 | /// No data-type specified. 25 | /// 26 | [EnumerationMetadata(DisplayName = "", AlternateValue = "")] 27 | None = 0, 28 | 29 | /// 30 | /// The data type of the simple list property represents a date-time value. 31 | /// 32 | [EnumerationMetadata(DisplayName = "Date", AlternateValue = "date")] 33 | Date = 1, 34 | 35 | /// 36 | /// The data type of the simple list property represents a numeric value. 37 | /// 38 | [EnumerationMetadata(DisplayName = "Number", AlternateValue = "number")] 39 | Number = 2, 40 | 41 | /// 42 | /// The data type of the simple list property represents a textual value. 43 | /// 44 | [EnumerationMetadata(DisplayName = "Text", AlternateValue = "text")] 45 | Text = 3 46 | } 47 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Extensions/SimpleList/SimpleListSyndicationExtensionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq; 3 | using Sage.SData.Client.Atom; 4 | using Sage.SData.Client.Common; 5 | 6 | namespace Sage.SData.Client.Extensions 7 | { 8 | /// 9 | /// SLE extension class 10 | /// 11 | public static class SimpleListSyndicationExtensionHelper 12 | { 13 | /// 14 | /// Gets information that allows the client to group or filter on the values of feed properties. 15 | /// 16 | /// 17 | /// A collection of objects that represent information that allows the client to group or filter on the values of feed properties. 18 | /// The default value is an empty collection. 19 | /// 20 | public static Collection GetSimpleListGrouping(this AtomFeed feed) 21 | { 22 | var context = GetContext(feed, true); 23 | return context.Grouping; 24 | } 25 | 26 | /// 27 | /// Gets information that allows the client to sort on the values of feed properties. 28 | /// 29 | /// 30 | /// A collection of objects that represent information that allows the client to sort on the values of feed properties. 31 | /// The default value is an empty collection. 32 | /// 33 | public static Collection GetSimpleListSorting(this AtomFeed feed) 34 | { 35 | var context = GetContext(feed, true); 36 | return context.Sorting; 37 | } 38 | 39 | /// 40 | /// Gets a value indicating if this feed is intended to be consumed as a list. 41 | /// 42 | /// true if the syndication feed is intended to be consumed as a list; otherwise false. 43 | /// 44 | /// This property allows the publisher of a feed document to indicate to the consumers of the feed that the feed is intended to be consumed as a list, 45 | /// and as such is the primary means for feed consumers to identify lists. 46 | /// 47 | public static bool? GetSimpleListTreatAsList(this AtomFeed feed) 48 | { 49 | var context = GetContext(feed, false); 50 | return context != null ? context.TreatAsList : (bool?) null; 51 | } 52 | 53 | /// 54 | /// Sets a value indicating if this feed is intended to be consumed as a list. 55 | /// 56 | /// true if the syndication feed is intended to be consumed as a list; otherwise false. 57 | /// 58 | /// This property allows the publisher of a feed document to indicate to the consumers of the feed that the feed is intended to be consumed as a list, 59 | /// and as such is the primary means for feed consumers to identify lists. 60 | /// 61 | public static void SetSimpleListTreatAsList(this AtomFeed feed, bool value) 62 | { 63 | var context = GetContext(feed, true); 64 | context.TreatAsList = value; 65 | } 66 | 67 | private static SimpleListSyndicationExtensionContext GetContext(IExtensibleSyndicationObject entry, bool createIfMissing) 68 | { 69 | Guard.ArgumentNotNull(entry, "entry"); 70 | var extension = entry.Extensions.OfType().FirstOrDefault(); 71 | 72 | if (extension == null) 73 | { 74 | if (!createIfMissing) 75 | { 76 | return null; 77 | } 78 | 79 | extension = new SimpleListSyndicationExtension(); 80 | entry.AddExtension(extension); 81 | } 82 | 83 | return extension.Context; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/AttachedFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Mime; 4 | using System.Text; 5 | using System.Web; 6 | using Sage.SData.Client.Mime; 7 | 8 | namespace Sage.SData.Client.Framework 9 | { 10 | /// 11 | /// Represents a file that's been attached to a request or response. 12 | /// 13 | public class AttachedFile 14 | { 15 | private readonly string _contentType; 16 | private readonly string _fileName; 17 | private readonly Stream _stream; 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// A multipart MIME part containing the attached file. 23 | public AttachedFile(MimePart part) 24 | : this(part.ContentType, GetFileName(part.ContentDisposition), part.Content) 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The MIME content type of an attached file. 32 | /// The file name of an attached file. 33 | /// The object that points to the content of an attached file. 34 | public AttachedFile(string contentType, string fileName, Stream stream) 35 | { 36 | _contentType = contentType; 37 | _fileName = fileName; 38 | _stream = stream; 39 | } 40 | 41 | private static string GetFileName(ContentDisposition contentDisposition) 42 | { 43 | if (contentDisposition.FileName != null) 44 | { 45 | return contentDisposition.FileName; 46 | } 47 | 48 | var fileName = contentDisposition.Parameters["filename*"]; 49 | if (fileName == null) 50 | { 51 | return null; 52 | } 53 | 54 | var pos = fileName.IndexOf("''", StringComparison.InvariantCulture); 55 | var encoding = Encoding.UTF8; 56 | if (pos >= 0) 57 | { 58 | try 59 | { 60 | encoding = Encoding.GetEncoding(fileName.Substring(0, pos)); 61 | } 62 | catch (ArgumentException) 63 | { 64 | } 65 | fileName = fileName.Substring(pos + 2); 66 | } 67 | 68 | return HttpUtility.UrlDecode(fileName, encoding); 69 | } 70 | 71 | /// 72 | /// Gets the MIME content type of an attached file. 73 | /// 74 | public string ContentType 75 | { 76 | get { return _contentType; } 77 | } 78 | 79 | /// 80 | /// Gets the file name of an attached file. 81 | /// 82 | public string FileName 83 | { 84 | get { return _fileName; } 85 | } 86 | 87 | /// 88 | /// Gets the object that points to the content of an attached file. 89 | /// 90 | public Stream Stream 91 | { 92 | get { return _stream; } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/HttpMethod.cs: -------------------------------------------------------------------------------- 1 | namespace Sage.SData.Client.Framework 2 | { 3 | /// 4 | /// Enum of HTTP methods. 5 | /// 6 | public enum HttpMethod 7 | { 8 | /// 9 | /// Get request. 10 | /// 11 | Get, 12 | /// 13 | /// Post request. 14 | /// 15 | Post, 16 | /// 17 | /// Put request. 18 | /// 19 | Put, 20 | /// 21 | /// Delete requets. 22 | /// 23 | Delete 24 | } 25 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/MediaType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2010. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use this 4 | // code. Please contact Sage (UK) if you do not have such a licence. Sage will take 5 | // appropriate legal action against those who make unauthorised use of this code. 6 | 7 | using System.Xml.Serialization; 8 | 9 | namespace Sage.SData.Client.Framework 10 | { 11 | /// 12 | /// Defines the list of supported media types. 13 | /// 14 | public enum MediaType 15 | { 16 | /// 17 | /// Text 18 | /// 19 | [XmlEnum(MediaTypeNames.TextMediaType)] Text, 20 | 21 | /// 22 | /// HTML 23 | /// 24 | [XmlEnum(MediaTypeNames.HtmlMediaType)] Html, 25 | 26 | /// 27 | /// ATOM feed syndication format 28 | /// 29 | [XmlEnum(MediaTypeNames.AtomMediaType)] Atom, 30 | 31 | /// 32 | /// ATOM entry syndication format 33 | /// 34 | [XmlEnum(MediaTypeNames.AtomEntryMediaType)] AtomEntry, 35 | 36 | /// 37 | /// RSS syndication format 38 | /// 39 | [XmlEnum(MediaTypeNames.RssMediaType)] Rss, 40 | 41 | /// 42 | /// XML format 43 | /// 44 | [XmlEnum(MediaTypeNames.XmlMediaType)] Xml, 45 | 46 | /// 47 | /// Image PNG format 48 | /// 49 | [XmlEnum(MediaTypeNames.ImagePngMediaType)] ImagePng, 50 | 51 | /// 52 | /// Image JPEG format 53 | /// 54 | [XmlEnum(MediaTypeNames.ImageJpegMediaType)] ImageJpeg, 55 | 56 | /// 57 | /// Image GIF format 58 | /// 59 | [XmlEnum(MediaTypeNames.ImageGifMediaType)] ImageGif, 60 | 61 | /// 62 | /// Image TIFF format 63 | /// 64 | [XmlEnum(MediaTypeNames.ImageTiffMediaType)] ImageTiff, 65 | 66 | /// 67 | /// Image BMP format 68 | /// 69 | [XmlEnum(MediaTypeNames.ImageBmpMediaType)] ImageBmp, 70 | 71 | /// 72 | /// XLST format 73 | /// 74 | [XmlEnum(MediaTypeNames.XsltMediaType)] Xslt, 75 | 76 | /// 77 | /// XSS format 78 | /// 79 | [XmlEnum(MediaTypeNames.CssMediaType)] Css, 80 | 81 | /// 82 | /// JSON format 83 | /// 84 | [XmlEnum(MediaTypeNames.JsonMediaType)] Json, 85 | 86 | /// 87 | /// BSON format 88 | /// 89 | [XmlEnum(MediaTypeNames.BsonMediaType)] Bson, 90 | 91 | /// 92 | /// Form format 93 | /// 94 | [XmlEnum(MediaTypeNames.FormMediaType)] Form, 95 | 96 | /// 97 | /// Multipart format 98 | /// 99 | Multipart 100 | } 101 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/RequestOperation.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2010. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use this 4 | // code. Please contact Sage (UK) if you do not have such a licence. Sage will take 5 | // appropriate legal action against those who make unauthorised use of this code. 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using Sage.SData.Client.Atom; 10 | 11 | namespace Sage.SData.Client.Framework 12 | { 13 | /// 14 | /// Defines an operation to peform during a request. 15 | /// 16 | public class RequestOperation 17 | { 18 | private IDictionary _form; 19 | private IList _files; 20 | 21 | /// 22 | /// Initialises a new instance of the class. 23 | /// 24 | public RequestOperation() 25 | : this(HttpMethod.Get) 26 | { 27 | } 28 | 29 | /// 30 | /// Initialises a new instance of the class. 31 | /// 32 | /// 33 | public RequestOperation(HttpMethod method) 34 | : this(method, null) 35 | { 36 | } 37 | 38 | /// 39 | /// Initialises a new instance of the class with 40 | /// the specified and method. 41 | /// 42 | /// One of the values 43 | /// The input resource involved in the operation. 44 | public RequestOperation(HttpMethod method, object resource) 45 | { 46 | Method = method; 47 | Resource = resource; 48 | } 49 | 50 | #region Properties 51 | 52 | /// 53 | /// Gets or sets the method for the request. 54 | /// 55 | public HttpMethod Method { get; set; } 56 | 57 | /// 58 | /// Gets or sets the predicate for the request. 59 | /// 60 | public string Predicate { get; set; } 61 | 62 | /// 63 | /// Gets or sets the input resource for the request. 64 | /// 65 | public object Resource { get; set; } 66 | 67 | /// 68 | /// Gets or sets the input content type for the request. 69 | /// 70 | public MediaType? ContentType { get; set; } 71 | 72 | /// 73 | /// Gets or sets the ETag value for the request. 74 | /// 75 | public string ETag { get; set; } 76 | 77 | /// 78 | /// Gets the form data associated with the request. 79 | /// 80 | public IDictionary Form 81 | { 82 | get { return _form ?? (_form = new Dictionary(StringComparer.InvariantCultureIgnoreCase)); } 83 | } 84 | 85 | /// 86 | /// Gets the files that will be attached to the request content. 87 | /// 88 | public IList Files 89 | { 90 | get { return _files ?? (_files = new List()); } 91 | } 92 | 93 | #endregion 94 | } 95 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/SDataException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | 7 | namespace Sage.SData.Client.Framework 8 | { 9 | /// 10 | /// The exception that is thrown when an error occurs on an SData server. 11 | /// 12 | public class SDataException : WebException 13 | { 14 | private readonly Collection _diagnoses; 15 | private readonly HttpStatusCode? _statusCode; 16 | 17 | /// 18 | /// Initializes a new instance. 19 | /// 20 | /// 21 | public SDataException(WebException innerException) 22 | : base(innerException.Message, innerException, innerException.Status, innerException.Response) 23 | { 24 | if (Response == null) 25 | { 26 | return; 27 | } 28 | 29 | var httpResponse = Response as HttpWebResponse; 30 | _statusCode = httpResponse != null ? httpResponse.StatusCode : (HttpStatusCode?) null; 31 | MediaType mediaType; 32 | 33 | if (MediaTypeNames.TryGetMediaType(Response.ContentType, out mediaType) && mediaType == MediaType.Xml) 34 | { 35 | using (var memoryStream = new MemoryStream()) 36 | { 37 | using (var responseStream = Response.GetResponseStream()) 38 | { 39 | responseStream.CopyTo(memoryStream); 40 | } 41 | 42 | memoryStream.Seek(0, SeekOrigin.Begin); 43 | _diagnoses = memoryStream.DeserializeXml(); 44 | 45 | if (_diagnoses == null) 46 | { 47 | memoryStream.Seek(0, SeekOrigin.Begin); 48 | var diagnosis = memoryStream.DeserializeXml(); 49 | 50 | if (diagnosis != null) 51 | { 52 | _diagnoses = new Collection {diagnosis}; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | /// 60 | /// Initializes a new instance. 61 | /// 62 | /// 63 | /// 64 | public SDataException(Collection diagnoses, HttpStatusCode statusCode) 65 | { 66 | _diagnoses = diagnoses; 67 | _statusCode = statusCode; 68 | } 69 | 70 | /// 71 | /// Gets the high level diagnostic information returned from the server. 72 | /// 73 | [Obsolete("Use the Diagnoses property instead.")] 74 | public Diagnosis Diagnosis 75 | { 76 | get { return _diagnoses != null && _diagnoses.Count > 0 ? _diagnoses[0] : null; } 77 | } 78 | 79 | /// 80 | /// 81 | /// 82 | public Collection Diagnoses 83 | { 84 | get { return _diagnoses; } 85 | } 86 | 87 | /// 88 | /// Gets the HTTP status code associated with the exception. 89 | /// 90 | public HttpStatusCode? StatusCode 91 | { 92 | get { return _statusCode; } 93 | } 94 | 95 | /// 96 | /// Gets a message that describes the exception. 97 | /// 98 | public override string Message 99 | { 100 | get 101 | { 102 | return _diagnoses != null 103 | ? string.Join(Environment.NewLine, _diagnoses.Select(diagnosis => diagnosis.Message).ToArray()) 104 | : base.Message; 105 | } 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/Severity.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2007. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use 4 | // this code. Please contact [email@sage.com] if you do not have such a licence. 5 | // Sage will take appropriate legal action against those who make unauthorised use of this 6 | // code. 7 | 8 | using System.Xml.Serialization; 9 | 10 | namespace Sage.SData.Client.Framework 11 | { 12 | /// 13 | /// Defines the severity of an error. 14 | /// 15 | public enum Severity 16 | { 17 | /// 18 | /// Informational message, does not require any special attention. 19 | /// 20 | [XmlEnum("info")] Info, 21 | 22 | /// 23 | /// Warning message: does not prevent operation from succeeding but may require attention. 24 | /// 25 | [XmlEnum("warning")] Warning, 26 | 27 | /// 28 | /// Transient error, operation failed but may succeed later in the same condition. 29 | /// 30 | [XmlEnum("transient")] Transient, 31 | 32 | /// 33 | /// Error, operation failed, request should be modified before resubmitting. 34 | /// 35 | [XmlEnum("error")] Error, 36 | 37 | /// 38 | /// Severe error, operation should not be reattempted (and other operations are likely to fail too). 39 | /// 40 | [XmlEnum("fatal")] Fatal, 41 | } 42 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml; 4 | using System.Xml.Serialization; 5 | 6 | namespace Sage.SData.Client.Framework 7 | { 8 | public static class StreamExtensions 9 | { 10 | public static void CopyTo(this Stream source, Stream destination) 11 | { 12 | var buffer = new byte[0x1000]; 13 | int num; 14 | while ((num = source.Read(buffer, 0, buffer.Length)) != 0) 15 | { 16 | destination.Write(buffer, 0, num); 17 | } 18 | } 19 | 20 | public static T DeserializeXml(this Stream stream) 21 | { 22 | var serializer = new XmlSerializer(typeof (T)); 23 | 24 | try 25 | { 26 | return (T) serializer.Deserialize(stream); 27 | } 28 | catch (XmlException) 29 | { 30 | } 31 | catch (InvalidOperationException) 32 | { 33 | } 34 | 35 | return default(T); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/SyncMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2007. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use 4 | // this code. Please contact [email@sage.com] if you do not have such a licence. 5 | // Sage will take appropriate legal action against those who make unauthorised use of this 6 | // code. 7 | 8 | using System.Xml.Serialization; 9 | 10 | namespace Sage.SData.Client.Framework 11 | { 12 | /// 13 | /// Defines the sync mode. 14 | /// 15 | public enum SyncMode 16 | { 17 | /// 18 | /// An alternative version of the resource. 19 | /// 20 | [XmlEnum("catchUp")] CatchUp, 21 | 22 | /// 23 | /// A resource related to this resource. 24 | /// 25 | [XmlEnum("immediate")] Immediate 26 | } 27 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/Tracking.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2010. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use this 4 | // code. Please contact Sage (UK) if you do not have such a licence. Sage will take 5 | // appropriate legal action against those who make unauthorised use of this code. 6 | 7 | using System.Xml.Serialization; 8 | 9 | namespace Sage.SData.Client.Framework 10 | { 11 | /// 12 | /// Represents tracking information used to track the progress of an 13 | /// asynchronous operation. 14 | /// 15 | [XmlRoot(Namespace = Common.SData.Namespace)] 16 | [XmlType(TypeName = "tracking", Namespace = Common.SData.Namespace)] 17 | public class Tracking 18 | { 19 | /// 20 | /// The current phase of the operation. 21 | /// 22 | [XmlElement("phase")] 23 | public string Phase { get; set; } 24 | 25 | /// 26 | /// More detailed information about the current phase of the operation. 27 | /// 28 | [XmlElement("phaseDetail")] 29 | public string PhaseDetail { get; set; } 30 | 31 | /// 32 | /// Percentage of the operation which is completed. 33 | /// 34 | [XmlElement("progress")] 35 | public decimal Progress { get; set; } 36 | 37 | /// 38 | /// Time elapsed since operation started, in seconds. 39 | /// 40 | [XmlElement("elapsedSeconds")] 41 | public decimal ElapsedSeconds { get; set; } 42 | 43 | /// 44 | /// Expected remaining time, in seconds 45 | /// 46 | [XmlElement("remainingSeconds")] 47 | public decimal RemainingSeconds { get; set; } 48 | 49 | /// 50 | /// Delay (in milliseconds) that the consumer should use 51 | /// before polling the service again. 52 | /// 53 | [XmlElement("pollingMillis")] 54 | public int PollingMillis { get; set; } 55 | } 56 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Framework/UriPathParser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Sage (UK) Limited 2010. All rights reserved. 2 | // This code may not be copied or used, except as set out in a written licence agreement 3 | // between the user and Sage (UK) Limited, which specifically permits the user to use this 4 | // code. Please contact Sage (UK) if you do not have such a licence. Sage will take 5 | // appropriate legal action against those who make unauthorised use of this code. 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Text.RegularExpressions; 10 | 11 | namespace Sage.SData.Client.Framework 12 | { 13 | /// 14 | /// Parses a Uri path into segments 15 | /// 16 | public static class UriPathParser 17 | { 18 | #region Constants 19 | 20 | private const string Pattern = @"(? 21 | [^/(]* # anything other than slash or open paren 22 | ) 23 | ( 24 | \( 25 | (? 26 | ( 27 | ('([^']|(''))*') # single quoted literal string 28 | | 29 | (""([^""]|(""""))*"") # double quoted literal string 30 | | 31 | ([^'"")]*) # anything other than quote or close paren 32 | )* 33 | ) 34 | \) 35 | )?"; 36 | 37 | private static readonly Regex Regex = new Regex(Pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); 38 | private static readonly UriPathSegment[] EmptyPath = new UriPathSegment[] {}; 39 | 40 | #endregion 41 | 42 | /// 43 | /// Parses the path of the specified into segments. 44 | /// 45 | /// The containing the path to parse into segments. 46 | /// An array of segments that form the path for the specified . 47 | public static UriPathSegment[] Parse(Uri uri) 48 | { 49 | return Parse(uri.AbsolutePath); 50 | } 51 | 52 | /// 53 | /// Parses the specified path into segments. 54 | /// 55 | /// The path to parse into segments. 56 | /// An array of segments that form the specified path. 57 | public static UriPathSegment[] Parse(string path) 58 | { 59 | if (string.IsNullOrEmpty(path)) 60 | return EmptyPath; 61 | 62 | var segments = new List(); 63 | var match = Regex.Match(path); 64 | 65 | while (match.Success) 66 | { 67 | var segment = match.Groups["segment"].Value; 68 | 69 | if (segment.Length != 0) 70 | segments.Add(new UriPathSegment(segment, match.Groups["predicate"].Value)); 71 | 72 | match = match.NextMatch(); 73 | } 74 | 75 | return segments.ToArray(); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/Action.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: Action.cs 239 2010-02-05 23:26:23Z azizatif $ 29 | 30 | namespace System 31 | { 32 | #if LINQBRIDGE_LIB 33 | public delegate void Action(); 34 | public delegate void Action(T1 arg1, T2 arg2); 35 | public delegate void Action(T1 arg1, T2 arg2, T3 arg3); 36 | public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); 37 | #else 38 | delegate void Action(); 39 | delegate void Action(T1 arg1, T2 arg2); 40 | delegate void Action(T1 arg1, T2 arg2, T3 arg3); 41 | delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); 42 | #endif 43 | } 44 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/ExtensionAttribute.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | namespace System.Runtime.CompilerServices 29 | { 30 | /// 31 | /// This attribute allows us to define extension methods without 32 | /// requiring .NET Framework 3.5. For more information, see the section, 33 | /// Extension Methods in .NET Framework 2.0 Apps, 34 | /// of Basic Instincts: Extension Methods 35 | /// column in MSDN Magazine, 36 | /// issue Nov 2007. 37 | /// 38 | 39 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] 40 | public sealed class ExtensionAttribute : Attribute { } 41 | } 42 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/Func.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: Func.cs 224 2009-10-04 07:13:08Z azizatif $ 29 | 30 | namespace System 31 | { 32 | #if LINQBRIDGE_LIB 33 | public delegate TResult Func(); 34 | public delegate TResult Func(T a); 35 | public delegate TResult Func(T1 arg1, T2 arg2); 36 | public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); 37 | public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); 38 | #else 39 | delegate TResult Func(); 40 | delegate TResult Func(T a); 41 | delegate TResult Func(T1 arg1, T2 arg2); 42 | delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); 43 | delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/IGrouping.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: IGrouping.cs 225 2009-10-04 07:16:14Z azizatif $ 29 | 30 | namespace System.Linq 31 | { 32 | #region Imports 33 | 34 | using System.Collections.Generic; 35 | 36 | #endregion 37 | 38 | /// 39 | /// Represents a collection of objects that have a common key. 40 | /// 41 | 42 | partial interface IGrouping : IEnumerable 43 | { 44 | /// 45 | /// Gets the key of the . 46 | /// 47 | 48 | TKey Key { get; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/ILookup.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: ILookup.cs 224 2009-10-04 07:13:08Z azizatif $ 29 | 30 | namespace System.Linq 31 | { 32 | using System.Collections.Generic; 33 | 34 | /// 35 | /// Defines an indexer, size property, and Boolean search method for 36 | /// data structures that map keys to 37 | /// sequences of values. 38 | /// 39 | 40 | partial interface ILookup : IEnumerable> 41 | { 42 | bool Contains(TKey key); 43 | int Count { get; } 44 | IEnumerable this[TKey key] { get; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/IOrderedEnumerable.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: IOrderedEnumerable.cs 224 2009-10-04 07:13:08Z azizatif $ 29 | 30 | namespace System.Linq 31 | { 32 | using System.Collections.Generic; 33 | 34 | /// 35 | /// Represents a sorted sequence. 36 | /// 37 | 38 | partial interface IOrderedEnumerable : IEnumerable 39 | { 40 | /// 41 | /// Performs a subsequent ordering on the elements of an 42 | /// according to a key. 43 | /// 44 | 45 | IOrderedEnumerable CreateOrderedEnumerable( 46 | Func keySelector, IComparer comparer, bool descending); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/Public.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: Public.cs 224 2009-10-04 07:13:08Z azizatif $ 29 | 30 | namespace System.Linq 31 | { 32 | #if LINQBRIDGE_LIB 33 | 34 | public partial class Enumerable { } 35 | public partial interface IGrouping { } 36 | public partial interface ILookup { } 37 | public partial interface IOrderedEnumerable { } 38 | 39 | #endif 40 | } 41 | -------------------------------------------------------------------------------- /Sage.SData.Client/LinqBridge/Tuple.cs: -------------------------------------------------------------------------------- 1 | #region License, Terms and Author(s) 2 | // 3 | // LINQBridge 4 | // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. 5 | // 6 | // Author(s): 7 | // 8 | // Atif Aziz, http://www.raboof.com 9 | // 10 | // This library is free software; you can redistribute it and/or modify it 11 | // under the terms of the New BSD License, a copy of which should have 12 | // been delivered along with this distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | // 26 | #endregion 27 | 28 | // $Id: Tuple.cs 215 2009-10-03 13:31:49Z azizatif $ 29 | 30 | namespace LinqBridge 31 | { 32 | #region Imports 33 | 34 | using System; 35 | using System.Collections.Generic; 36 | using System.Text; 37 | 38 | #endregion 39 | 40 | [ Serializable ] 41 | internal struct Tuple : IEquatable> 42 | { 43 | public TFirst First { get; private set; } 44 | public TSecond Second { get; private set; } 45 | 46 | public Tuple(TFirst first, TSecond second) : this() 47 | { 48 | First = first; 49 | Second = second; 50 | } 51 | 52 | public override bool Equals(object obj) 53 | { 54 | return obj != null 55 | && obj is Tuple 56 | && base.Equals((Tuple) obj); 57 | } 58 | 59 | public bool Equals(Tuple other) 60 | { 61 | return EqualityComparer.Default.Equals(other.First, First) 62 | && EqualityComparer.Default.Equals(other.Second, Second); 63 | } 64 | 65 | public override int GetHashCode() 66 | { 67 | var num = 0x7a2f0b42; 68 | num = (-1521134295 * num) + EqualityComparer.Default.GetHashCode(First); 69 | return (-1521134295 * num) + EqualityComparer.Default.GetHashCode(Second); 70 | } 71 | 72 | public override string ToString() 73 | { 74 | return string.Format(@"{{ First = {0}, Second = {1} }}", First, Second); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/BatchingMode.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Sage.SData.Client.Metadata 4 | { 5 | public enum BatchingMode 6 | { 7 | [XmlEnum("none")] None, 8 | [XmlEnum("sync")] Sync, 9 | [XmlEnum("async")] Async, 10 | [XmlEnum("syncOrAsync")] SyncOrAsync 11 | } 12 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/CollectionDebugView.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using Sage.SData.Client.Common; 5 | 6 | namespace Sage.SData.Client.Metadata 7 | { 8 | internal sealed class CollectionDebugView 9 | { 10 | private readonly ICollection _collection; 11 | 12 | public CollectionDebugView(ICollection collection) 13 | { 14 | Guard.ArgumentNotNull(collection, "collection"); 15 | _collection = collection; 16 | } 17 | 18 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 19 | public T[] Items 20 | { 21 | get { return _collection.ToArray(); } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/ComplianceLevel.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Sage.SData.Client.Metadata 4 | { 5 | public enum ComplianceLevel 6 | { 7 | [XmlEnum("may")] May, 8 | [XmlEnum("should")] Should, 9 | [XmlEnum("must")] Must 10 | } 11 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/InvocationMode.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Sage.SData.Client.Metadata 4 | { 5 | public enum InvocationMode 6 | { 7 | [XmlEnum("sync")] Sync, 8 | [XmlEnum("async")] Async, 9 | [XmlEnum("syncOrAsync")] SyncOrAsync 10 | } 11 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/KeyedCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using Sage.SData.Client.Common; 7 | 8 | namespace Sage.SData.Client.Metadata 9 | { 10 | [DebuggerDisplay("Count = {Count}")] 11 | [DebuggerTypeProxy(typeof (CollectionDebugView<>))] 12 | public class KeyedCollection : Collection 13 | { 14 | private readonly Func _selectKey; 15 | private readonly IDictionary _keyedItems; 16 | 17 | internal KeyedCollection(Func selectKey) 18 | { 19 | _selectKey = selectKey; 20 | _keyedItems = new Dictionary(); 21 | } 22 | 23 | public TItem this[TKey key] 24 | { 25 | get 26 | { 27 | TItem item; 28 | 29 | if (_keyedItems.TryGetValue(key, out item)) 30 | { 31 | var actualKey = _selectKey(item); 32 | 33 | if (!Equals(actualKey, key)) 34 | { 35 | _keyedItems[actualKey] = item; 36 | _keyedItems.Remove(key); 37 | item = default(TItem); 38 | } 39 | } 40 | 41 | if (Equals(item, default(TItem))) 42 | { 43 | item = this.FirstOrDefault(x => Equals(_selectKey(x), key)); 44 | 45 | if (!Equals(item, default(TItem))) 46 | { 47 | _keyedItems[key] = item; 48 | } 49 | } 50 | 51 | return item; 52 | } 53 | } 54 | 55 | protected override void InsertItem(int index, TItem item) 56 | { 57 | Guard.ArgumentNotNull(item, "item"); 58 | 59 | var key = _selectKey(item); 60 | _keyedItems[key] = item; 61 | base.InsertItem(index, item); 62 | } 63 | 64 | protected override void SetItem(int index, TItem item) 65 | { 66 | Guard.ArgumentNotNull(item, "item"); 67 | 68 | var key = _selectKey(this[index]); 69 | _keyedItems.Remove(key); 70 | key = _selectKey(item); 71 | _keyedItems[key] = item; 72 | base.SetItem(index, item); 73 | } 74 | 75 | protected override void RemoveItem(int index) 76 | { 77 | var key = _selectKey(this[index]); 78 | _keyedItems.Remove(key); 79 | base.RemoveItem(index); 80 | } 81 | 82 | protected override void ClearItems() 83 | { 84 | _keyedItems.Clear(); 85 | base.ClearItems(); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/KeyedEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Sage.SData.Client.Metadata 7 | { 8 | public class KeyedEnumerable : IEnumerable 9 | { 10 | private readonly IEnumerable _objects; 11 | private readonly Func _selectKey; 12 | 13 | internal KeyedEnumerable(IEnumerable objects, Func selectKey) 14 | { 15 | _objects = objects; 16 | _selectKey = selectKey; 17 | } 18 | 19 | public TItem this[TKey key] 20 | { 21 | get { return _objects.SingleOrDefault(type => Equals(_selectKey(type), key)); } 22 | } 23 | 24 | #region IEnumerable Members 25 | 26 | public IEnumerator GetEnumerator() 27 | { 28 | return _objects.GetEnumerator(); 29 | } 30 | 31 | IEnumerator IEnumerable.GetEnumerator() 32 | { 33 | return GetEnumerator(); 34 | } 35 | 36 | #endregion 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/KeyedObjectCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Sage.SData.Client.Common; 4 | 5 | namespace Sage.SData.Client.Metadata 6 | { 7 | [DebuggerDisplay("Count = {Count}")] 8 | [DebuggerTypeProxy(typeof (CollectionDebugView<>))] 9 | public class KeyedObjectCollection : KeyedCollection 10 | where T : SDataSchemaObject 11 | { 12 | private readonly SDataSchemaObject _owner; 13 | 14 | internal KeyedObjectCollection(SDataSchemaObject owner, Func selectKey) 15 | : base(obj => selectKey(obj) ?? "\0") 16 | { 17 | _owner = owner; 18 | } 19 | 20 | protected override void InsertItem(int index, T item) 21 | { 22 | Guard.ArgumentNotNull(item, "item"); 23 | item.Parent = _owner; 24 | base.InsertItem(index, item); 25 | } 26 | 27 | protected override void SetItem(int index, T item) 28 | { 29 | Guard.ArgumentNotNull(item, "item"); 30 | this[index].Parent = null; 31 | item.Parent = _owner; 32 | base.SetItem(index, item); 33 | } 34 | 35 | protected override void RemoveItem(int index) 36 | { 37 | this[index].Parent = null; 38 | base.RemoveItem(index); 39 | } 40 | 41 | protected override void ClearItems() 42 | { 43 | foreach (var item in this) 44 | { 45 | item.Parent = null; 46 | } 47 | 48 | base.ClearItems(); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/RelationshipType.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Sage.SData.Client.Metadata 4 | { 5 | public enum RelationshipType 6 | { 7 | [XmlEnum("parent")] Parent, 8 | [XmlEnum("child")] Child, 9 | [XmlEnum("reference")] Reference, 10 | [XmlEnum("association")] Association 11 | } 12 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaChoiceItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Xml.Schema; 4 | 5 | namespace Sage.SData.Client.Metadata 6 | { 7 | [DebuggerDisplay("{ElementName}")] 8 | public class SDataSchemaChoiceItem : SDataSchemaItem 9 | { 10 | private SDataSchemaTypeReference _type; 11 | 12 | public string ElementName { get; set; } 13 | 14 | public SDataSchemaTypeReference Type 15 | { 16 | get { return _type; } 17 | set 18 | { 19 | if (_type != value) 20 | { 21 | _type = value; 22 | value.Parent = this; 23 | } 24 | } 25 | } 26 | 27 | public override IEnumerable Children 28 | { 29 | get { return Type != null ? new[] {Type} : base.Children; } 30 | } 31 | 32 | protected internal override void Read(XmlSchemaObject obj) 33 | { 34 | var element = (XmlSchemaElement) obj; 35 | ElementName = element.Name; 36 | Type = element.SchemaTypeName; 37 | base.Read(obj); 38 | } 39 | 40 | protected internal override void Write(XmlSchemaObject obj) 41 | { 42 | var element = (XmlSchemaElement) obj; 43 | element.Name = ElementName; 44 | 45 | if (Type != null) 46 | { 47 | element.SchemaTypeName = Type.QualifiedName; 48 | } 49 | 50 | base.Write(obj); 51 | } 52 | 53 | public static implicit operator SDataSchemaChoiceItem(SDataSchemaType type) 54 | { 55 | var resource = type as SDataSchemaResourceType; 56 | return new SDataSchemaChoiceItem 57 | { 58 | ElementName = resource != null ? resource.ElementName : null, 59 | Type = type 60 | }; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaChoiceType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Xml.Schema; 4 | 5 | namespace Sage.SData.Client.Metadata 6 | { 7 | public class SDataSchemaChoiceType : SDataSchemaType 8 | { 9 | private IList _types; 10 | 11 | public SDataSchemaChoiceType() 12 | { 13 | } 14 | 15 | public SDataSchemaChoiceType(string baseName) 16 | : base(baseName, "choice") 17 | { 18 | } 19 | 20 | public IList Types 21 | { 22 | get { return _types ?? (_types = new List()); } 23 | } 24 | 25 | public decimal? MaxOccurs { get; set; } 26 | 27 | protected internal override void Read(XmlSchemaObject obj) 28 | { 29 | var type = (XmlSchemaComplexType) obj; 30 | 31 | if (type.Particle == null) 32 | { 33 | throw new InvalidOperationException(string.Format("Missing particle on choice type '{0}'", type.Name)); 34 | } 35 | 36 | var choice = type.Particle as XmlSchemaChoice; 37 | 38 | if (choice == null) 39 | { 40 | throw new InvalidOperationException(string.Format("Unexpected particle type '{0}' on choice type '{1}'", type.Particle.GetType(), type.Name)); 41 | } 42 | 43 | MaxOccurs = !string.IsNullOrEmpty(choice.MaxOccursString) ? choice.MaxOccurs : (decimal?) null; 44 | 45 | foreach (var item in choice.Items) 46 | { 47 | var element = item as XmlSchemaElement; 48 | 49 | if (element == null) 50 | { 51 | throw new InvalidOperationException(string.Format("Unexpected item type '{0}' on choice type '{1}'", item.GetType(), type.Name)); 52 | } 53 | 54 | var choiceType = new SDataSchemaChoiceItem(); 55 | choiceType.Read(element); 56 | Types.Add(choiceType); 57 | } 58 | 59 | base.Read(obj); 60 | } 61 | 62 | protected internal override void Write(XmlSchemaObject obj) 63 | { 64 | var type = (XmlSchemaComplexType) obj; 65 | var choice = new XmlSchemaChoice {MinOccurs = 0}; 66 | 67 | if (MaxOccurs != null) 68 | { 69 | choice.MaxOccurs = MaxOccurs.Value; 70 | } 71 | 72 | foreach (var choiceType in Types) 73 | { 74 | var element = new XmlSchemaElement(); 75 | choiceType.Write(element); 76 | choice.Items.Add(element); 77 | } 78 | 79 | type.Particle = choice; 80 | base.Write(obj); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaDocumentation.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Sage.SData.Client.Metadata 4 | { 5 | [DebuggerDisplay("{Text}")] 6 | public class SDataSchemaDocumentation : SDataSchemaObject 7 | { 8 | public string Language { get; set; } 9 | public string Text { get; set; } 10 | 11 | public static implicit operator SDataSchemaDocumentation(string text) 12 | { 13 | return new SDataSchemaDocumentation {Text = text}; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaEnumItem.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Xml.Schema; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | [DebuggerDisplay("{Value}")] 7 | public class SDataSchemaEnumItem : SDataSchemaItem 8 | { 9 | public string Value { get; set; } 10 | 11 | protected internal override void Read(XmlSchemaObject obj) 12 | { 13 | var facet = (XmlSchemaEnumerationFacet) obj; 14 | Value = facet.Value; 15 | base.Read(obj); 16 | } 17 | 18 | protected internal override void Write(XmlSchemaObject obj) 19 | { 20 | var facet = (XmlSchemaEnumerationFacet) obj; 21 | facet.Value = Value; 22 | base.Write(obj); 23 | } 24 | 25 | public static implicit operator SDataSchemaEnumItem(string value) 26 | { 27 | return new SDataSchemaEnumItem {Value = value}; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaEnumType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Xml.Schema; 4 | 5 | namespace Sage.SData.Client.Metadata 6 | { 7 | public class SDataSchemaEnumType : SDataSchemaValueType 8 | { 9 | private KeyedObjectCollection _items; 10 | 11 | public SDataSchemaEnumType() 12 | { 13 | } 14 | 15 | public SDataSchemaEnumType(string baseName) 16 | : base(baseName, "enum") 17 | { 18 | BaseType = XmlTypeCode.String; 19 | } 20 | 21 | public override IEnumerable Children 22 | { 23 | get { return Items.Cast(); } 24 | } 25 | 26 | public KeyedObjectCollection Items 27 | { 28 | get { return _items ?? (_items = new KeyedObjectCollection(this, item => item.Value)); } 29 | } 30 | 31 | protected internal override void Read(XmlSchemaObject obj) 32 | { 33 | var simpleType = (XmlSchemaSimpleType) obj; 34 | var restriction = (XmlSchemaSimpleTypeRestriction) simpleType.Content; 35 | 36 | foreach (var facet in restriction.Facets) 37 | { 38 | var item = new SDataSchemaEnumItem(); 39 | item.Read(facet); 40 | Items.Add(item); 41 | } 42 | 43 | base.Read(obj); 44 | } 45 | 46 | protected internal override void Write(XmlSchemaObject obj) 47 | { 48 | var simpleType = (XmlSchemaSimpleType) obj; 49 | var restriction = new XmlSchemaSimpleTypeRestriction(); 50 | 51 | foreach (var item in Items) 52 | { 53 | var facet = new XmlSchemaEnumerationFacet(); 54 | item.Write(facet); 55 | restriction.Facets.Add(facet); 56 | } 57 | 58 | simpleType.Content = restriction; 59 | base.Write(obj); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaNamedQueryType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | public class SDataSchemaNamedQueryType : SDataSchemaTopLevelType 7 | { 8 | private InvocationMode? _invocationMode; 9 | 10 | public SDataSchemaNamedQueryType() 11 | { 12 | } 13 | 14 | public SDataSchemaNamedQueryType(string elementName) 15 | : base(elementName) 16 | { 17 | } 18 | 19 | /// 20 | /// The supported invocation modes. 21 | /// 22 | public InvocationMode InvocationMode 23 | { 24 | get { return _invocationMode ?? InvocationMode.Sync; } 25 | set { _invocationMode = value; } 26 | } 27 | 28 | protected override bool ReadSmeAttribute(XmlAttribute attribute) 29 | { 30 | switch (attribute.LocalName) 31 | { 32 | case "invocationMode": 33 | _invocationMode = EnumEx.Parse(attribute.Value, true); 34 | return true; 35 | default: 36 | return base.ReadSmeAttribute(attribute); 37 | } 38 | } 39 | 40 | protected override void WriteSmeAttributes(ICollection attributes) 41 | { 42 | WriteSmeAttribute("role", "query", attributes); 43 | WriteSmeAttribute("invocationMode", _invocationMode, attributes); 44 | base.WriteSmeAttributes(attributes); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | public abstract class SDataSchemaObject 7 | { 8 | protected const string SmeNamespaceUri = "http://schemas.sage.com/sdata/sme/2007"; 9 | 10 | public SDataSchemaObject Parent { get; internal set; } 11 | 12 | public virtual IEnumerable Children 13 | { 14 | get { return Enumerable.Empty(); } 15 | } 16 | 17 | public IEnumerable Ancestors() 18 | { 19 | var current = Parent; 20 | 21 | while (current != null) 22 | { 23 | yield return current; 24 | current = current.Parent; 25 | } 26 | } 27 | 28 | public IEnumerable Descendents() 29 | { 30 | return Descendents(Children); 31 | } 32 | 33 | private static IEnumerable Descendents(IEnumerable items) 34 | { 35 | return items.Concat(items.SelectMany(item => Descendents(item.Children))); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaServiceOperationType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | public class SDataSchemaServiceOperationType : SDataSchemaTopLevelType 7 | { 8 | private InvocationMode? _invocationMode; 9 | 10 | public SDataSchemaServiceOperationType() 11 | { 12 | } 13 | 14 | public SDataSchemaServiceOperationType(string elementName) 15 | : base(elementName) 16 | { 17 | } 18 | 19 | /// 20 | /// The supported invocation modes. 21 | /// 22 | public InvocationMode InvocationMode 23 | { 24 | get { return _invocationMode ?? InvocationMode.Sync; } 25 | set { _invocationMode = value; } 26 | } 27 | 28 | protected override bool ReadSmeAttribute(XmlAttribute attribute) 29 | { 30 | switch (attribute.LocalName) 31 | { 32 | case "invocationMode": 33 | _invocationMode = EnumEx.Parse(attribute.Value, true); 34 | return true; 35 | default: 36 | return base.ReadSmeAttribute(attribute); 37 | } 38 | } 39 | 40 | protected override void WriteSmeAttributes(ICollection attributes) 41 | { 42 | WriteSmeAttribute("role", "serviceOperation", attributes); 43 | WriteSmeAttribute("invocationMode", _invocationMode, attributes); 44 | base.WriteSmeAttributes(attributes); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaSimpleType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Schema; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | public class SDataSchemaSimpleType : SDataSchemaValueType 7 | { 8 | private IList _facets; 9 | 10 | public SDataSchemaSimpleType() 11 | { 12 | } 13 | 14 | public SDataSchemaSimpleType(string baseName) 15 | : base(baseName, "type") 16 | { 17 | } 18 | 19 | public IList Facets 20 | { 21 | get { return _facets ?? (_facets = new List()); } 22 | } 23 | 24 | protected internal override void Read(XmlSchemaObject obj) 25 | { 26 | var simpleType = (XmlSchemaSimpleType) obj; 27 | var restriction = (XmlSchemaSimpleTypeRestriction) simpleType.Content; 28 | 29 | foreach (XmlSchemaFacet facet in restriction.Facets) 30 | { 31 | Facets.Add(facet); 32 | } 33 | 34 | base.Read(obj); 35 | } 36 | 37 | protected internal override void Write(XmlSchemaObject obj) 38 | { 39 | var simpleType = (XmlSchemaSimpleType) obj; 40 | var restriction = new XmlSchemaSimpleTypeRestriction(); 41 | 42 | foreach (var facet in Facets) 43 | { 44 | restriction.Facets.Add(facet); 45 | } 46 | 47 | simpleType.Content = restriction; 48 | base.Write(obj); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaTopLevelType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Xml; 4 | using System.Xml.Schema; 5 | 6 | namespace Sage.SData.Client.Metadata 7 | { 8 | [DebuggerDisplay("{ElementName}")] 9 | public abstract class SDataSchemaTopLevelType : SDataSchemaComplexType 10 | { 11 | protected SDataSchemaTopLevelType() 12 | { 13 | } 14 | 15 | protected SDataSchemaTopLevelType(string elementName) 16 | : base(elementName) 17 | { 18 | ElementName = elementName; 19 | } 20 | 21 | public string ElementName { get; set; } 22 | 23 | /// 24 | /// Relative URL to query resources or invoke the operation. 25 | /// 26 | public string Path { get; set; } 27 | 28 | /// 29 | /// Does the resource kind, service operation or named query provide a $template URL? 30 | /// 31 | public bool HasTemplate { get; set; } 32 | 33 | protected internal override void Read(XmlSchemaObject obj) 34 | { 35 | var element = obj as XmlSchemaElement; 36 | if (element != null) 37 | { 38 | ElementName = element.Name; 39 | } 40 | 41 | base.Read(obj); 42 | } 43 | 44 | protected override void ReadSmeAttributes(XmlSchemaObject obj) 45 | { 46 | if (obj is XmlSchemaElement) 47 | { 48 | base.ReadSmeAttributes(obj); 49 | } 50 | } 51 | 52 | protected override bool ReadSmeAttribute(XmlAttribute attribute) 53 | { 54 | switch (attribute.LocalName) 55 | { 56 | case "role": 57 | return true; 58 | case "path": 59 | Path = attribute.Value; 60 | return true; 61 | case "hasTemplate": 62 | HasTemplate = XmlConvert.ToBoolean(attribute.Value); 63 | return true; 64 | default: 65 | return base.ReadSmeAttribute(attribute); 66 | } 67 | } 68 | 69 | protected internal override void Write(XmlSchemaObject obj) 70 | { 71 | var element = obj as XmlSchemaElement; 72 | if (element != null) 73 | { 74 | element.Name = ElementName; 75 | } 76 | 77 | base.Write(obj); 78 | } 79 | 80 | protected override void WriteSmeAttributes(XmlSchemaObject obj) 81 | { 82 | if (obj is XmlSchemaElement) 83 | { 84 | base.WriteSmeAttributes(obj); 85 | } 86 | } 87 | 88 | protected override void WriteSmeAttributes(ICollection attributes) 89 | { 90 | WriteSmeAttribute("path", Path, attributes); 91 | WriteSmeAttribute("hasTemplate", HasTemplate, attributes); 92 | base.WriteSmeAttributes(attributes); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaType.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Xml; 3 | using System.Xml.Schema; 4 | 5 | namespace Sage.SData.Client.Metadata 6 | { 7 | [DebuggerDisplay("{Name}")] 8 | public abstract class SDataSchemaType : SDataSchemaItem 9 | { 10 | protected SDataSchemaType() 11 | { 12 | } 13 | 14 | protected SDataSchemaType(string baseName, string defaultSuffix) 15 | { 16 | Name = string.Format("{0}--{1}", baseName, defaultSuffix); 17 | } 18 | 19 | public string Name { get; set; } 20 | public string ListName { get; set; } 21 | public string ListItemName { get; set; } 22 | public XmlSchemaAnyAttribute ListAnyAttribute { get; set; } 23 | 24 | public XmlQualifiedName QualifiedName 25 | { 26 | get { return new XmlQualifiedName(Name, Schema != null ? Schema.TargetNamespace : null); } 27 | } 28 | 29 | public XmlQualifiedName ListQualifiedName 30 | { 31 | get { return new XmlQualifiedName(ListName, Schema != null ? Schema.TargetNamespace : null); } 32 | } 33 | 34 | protected internal override void Read(XmlSchemaObject obj) 35 | { 36 | var type = obj as XmlSchemaType; 37 | if (type != null) 38 | { 39 | Name = type.Name; 40 | } 41 | 42 | base.Read(obj); 43 | } 44 | 45 | protected internal override void Write(XmlSchemaObject obj) 46 | { 47 | var type = obj as XmlSchemaType; 48 | if (type != null) 49 | { 50 | type.Name = Name; 51 | } 52 | 53 | base.Write(obj); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaTypeReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Xml; 4 | using System.Xml.Schema; 5 | 6 | namespace Sage.SData.Client.Metadata 7 | { 8 | [DebuggerDisplay("{QualifiedName}")] 9 | public class SDataSchemaTypeReference : SDataSchemaObject 10 | { 11 | private XmlQualifiedName _name; 12 | private XmlTypeCode? _code; 13 | private SDataSchemaType _schemaType; 14 | 15 | public XmlQualifiedName QualifiedName 16 | { 17 | get 18 | { 19 | return SchemaType != null 20 | ? SchemaType.QualifiedName 21 | : Code != null 22 | ? new XmlQualifiedName(FormatCode(Code.Value), XmlSchema.Namespace) 23 | : _name; 24 | } 25 | set 26 | { 27 | if (value != _name) 28 | { 29 | XmlTypeCode code; 30 | 31 | if (value.Namespace == XmlSchema.Namespace && TryParseCode(value.Name, out code)) 32 | { 33 | Code = code; 34 | } 35 | else 36 | { 37 | _name = value; 38 | _code = null; 39 | _schemaType = null; 40 | } 41 | } 42 | } 43 | } 44 | 45 | public XmlTypeCode? Code 46 | { 47 | get { return _code; } 48 | set 49 | { 50 | if (_code != value) 51 | { 52 | _name = null; 53 | _code = value; 54 | _schemaType = null; 55 | } 56 | } 57 | } 58 | 59 | public SDataSchemaType SchemaType 60 | { 61 | get { return _schemaType; } 62 | set 63 | { 64 | if (_schemaType != value) 65 | { 66 | _name = null; 67 | _code = null; 68 | _schemaType = value; 69 | } 70 | } 71 | } 72 | 73 | private static bool TryParseCode(string value, out XmlTypeCode code) 74 | { 75 | if (value != null) 76 | { 77 | try 78 | { 79 | code = (XmlTypeCode) Enum.Parse(typeof (XmlTypeCode), value, true); 80 | return true; 81 | } 82 | catch (FormatException) 83 | { 84 | } 85 | } 86 | 87 | code = XmlTypeCode.None; 88 | return false; 89 | } 90 | 91 | private static string FormatCode(XmlTypeCode code) 92 | { 93 | var str = code.ToString(); 94 | return char.ToLower(str[0]) + str.Substring(1); 95 | } 96 | 97 | public static implicit operator SDataSchemaTypeReference(XmlQualifiedName name) 98 | { 99 | return new SDataSchemaTypeReference {QualifiedName = name}; 100 | } 101 | 102 | public static implicit operator SDataSchemaTypeReference(XmlTypeCode code) 103 | { 104 | return new SDataSchemaTypeReference {Code = code}; 105 | } 106 | 107 | public static implicit operator SDataSchemaTypeReference(SDataSchemaType type) 108 | { 109 | return new SDataSchemaTypeReference {SchemaType = type}; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Metadata/SDataSchemaValueType.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Schema; 3 | 4 | namespace Sage.SData.Client.Metadata 5 | { 6 | public abstract class SDataSchemaValueType : SDataSchemaType 7 | { 8 | private SDataSchemaTypeReference _baseType; 9 | 10 | protected SDataSchemaValueType() 11 | { 12 | } 13 | 14 | protected SDataSchemaValueType(string baseName, string defaultSuffix) 15 | : base(baseName, defaultSuffix) 16 | { 17 | } 18 | 19 | public SDataSchemaTypeReference BaseType 20 | { 21 | get { return _baseType; } 22 | set 23 | { 24 | if (_baseType != value) 25 | { 26 | _baseType = value; 27 | value.Parent = this; 28 | } 29 | } 30 | } 31 | 32 | public override IEnumerable Children 33 | { 34 | get { return BaseType != null ? new[] {BaseType} : base.Children; } 35 | } 36 | 37 | protected internal override void Read(XmlSchemaObject obj) 38 | { 39 | var simpleType = (XmlSchemaSimpleType) obj; 40 | var restriction = (XmlSchemaSimpleTypeRestriction) simpleType.Content; 41 | BaseType = restriction.BaseTypeName; 42 | base.Read(obj); 43 | } 44 | 45 | protected internal override void Write(XmlSchemaObject obj) 46 | { 47 | var simpleType = (XmlSchemaSimpleType) obj; 48 | var restriction = (XmlSchemaSimpleTypeRestriction) simpleType.Content; 49 | 50 | if (BaseType != null) 51 | { 52 | restriction.BaseTypeName = BaseType.QualifiedName; 53 | } 54 | 55 | base.Write(obj); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Sage.SData.Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/Sage.SData.Client/Properties/AssemblyInfo.cs -------------------------------------------------------------------------------- /demos/SDataClientApp/BaseControl.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | using Sage.SData.Client.Core; 3 | 4 | namespace SDataClientApp 5 | { 6 | public class BaseControl : UserControl 7 | { 8 | public ISDataService Service { get; set; } 9 | public ToolStripItem StatusLabel { get; set; } 10 | 11 | public new virtual void Refresh() 12 | { 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using Sage.SData.Client.Core; 4 | using SDataClientApp.Properties; 5 | 6 | namespace SDataClientApp 7 | { 8 | public partial class MainForm : Form 9 | { 10 | public MainForm() 11 | { 12 | InitializeComponent(); 13 | 14 | var service = new SDataService(); 15 | 16 | foreach (TabPage tab in tabControl1.TabPages) 17 | { 18 | ((BaseControl) tab.Controls[0]).Service = service; 19 | } 20 | 21 | tabControl1_SelectedIndexChanged(null, null); 22 | } 23 | 24 | protected override void OnFormClosed(FormClosedEventArgs e) 25 | { 26 | Settings.Default.Save(); 27 | base.OnFormClosed(e); 28 | } 29 | 30 | private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) 31 | { 32 | ((BaseControl) tabControl1.SelectedTab.Controls[0]).Refresh(); 33 | statusLabel.Text = string.Empty; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace SDataClientApp 5 | { 6 | internal static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | private static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new MainForm()); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/Properties/Settings.settings: -------------------------------------------------------------------------------- 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 | 10 34 | 35 | 36 | 1 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /demos/SDataClientApp/ResourceSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Windows.Forms; 4 | using Sage.SData.Client.Core; 5 | using Sage.SData.Client.Metadata; 6 | using SDataClientApp.Properties; 7 | 8 | namespace SDataClientApp 9 | { 10 | public partial class ResourceSchema : BaseControl 11 | { 12 | private SDataResourceSchemaRequest _sdataResourceSchemaRequest; 13 | private SDataSchema _schema; 14 | 15 | public ResourceSchema() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | public override void Refresh() 21 | { 22 | _sdataResourceSchemaRequest = new SDataResourceSchemaRequest(Service) {ResourceKind = tbSchemaResourceKind.Text}; 23 | tbSchemaURL.Text = _sdataResourceSchemaRequest.ToString(); 24 | } 25 | 26 | private void tbSchemaResourceKind_TextChanged(object sender, EventArgs e) 27 | { 28 | if (_sdataResourceSchemaRequest != null) 29 | { 30 | _sdataResourceSchemaRequest.ResourceKind = tbSchemaResourceKind.Text; 31 | tbSchemaURL.Text = _sdataResourceSchemaRequest.ToString(); 32 | } 33 | } 34 | 35 | private void btnSchemaRead_Click(object sender, EventArgs e) 36 | { 37 | try 38 | { 39 | _schema = (SDataSchema) _sdataResourceSchemaRequest.Read(); 40 | if (_schema != null) 41 | { 42 | MessageBox.Show(Resources.statusSchemaReadComplete); 43 | btnSchemaSave.Enabled = true; 44 | btnSchemaSave.Visible = true; 45 | lbSchemaFileName.Visible = true; 46 | tbSchemaFileName.Visible = true; 47 | } 48 | } 49 | catch (Exception ex) 50 | { 51 | MessageBox.Show(ex.Message); 52 | } 53 | } 54 | 55 | private void btnSchemaSave_Click(object sender, EventArgs e) 56 | { 57 | using (var stream = new FileStream(tbSchemaFileName.Text, FileMode.Create)) 58 | { 59 | _schema.Write(stream); 60 | } 61 | 62 | MessageBox.Show(Resources.statusSchemaSaveComplete); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/ResourceTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using Sage.SData.Client.Core; 4 | using Sage.SData.Client.Extensions; 5 | 6 | namespace SDataClientApp 7 | { 8 | public partial class ResourceTemplate : BaseControl 9 | { 10 | private SDataTemplateResourceRequest _sdataTemplateResourceRequest; 11 | 12 | public ResourceTemplate() 13 | { 14 | InitializeComponent(); 15 | } 16 | 17 | public override void Refresh() 18 | { 19 | try 20 | { 21 | _sdataTemplateResourceRequest = new SDataTemplateResourceRequest(Service) {ResourceKind = tbTemplateResourceKind.Text}; 22 | tbTemplateURL.Text = _sdataTemplateResourceRequest.ToString(); 23 | } 24 | catch (Exception ex) 25 | { 26 | MessageBox.Show(ex.Message); 27 | } 28 | } 29 | 30 | private void tbTemplateResourceKind_TextChanged(object sender, EventArgs e) 31 | { 32 | if (_sdataTemplateResourceRequest != null) 33 | { 34 | _sdataTemplateResourceRequest.ResourceKind = tbTemplateResourceKind.Text; 35 | tbTemplateURL.Text = _sdataTemplateResourceRequest.ToString(); 36 | } 37 | } 38 | 39 | private void btnTemplateRead_Click(object sender, EventArgs e) 40 | { 41 | try 42 | { 43 | var entry = _sdataTemplateResourceRequest.Read(); 44 | 45 | if (entry == null) 46 | { 47 | templatePayloadGrid.SelectedObject = null; 48 | MessageBox.Show("$template not supported"); 49 | } 50 | else 51 | { 52 | // show it in the grid 53 | templatePayloadGrid.SelectedObject = entry.GetSDataPayload(); 54 | } 55 | } 56 | catch (Exception ex) 57 | { 58 | MessageBox.Show(ex.Message); 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/ServiceConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sage.SData.Client.Framework; 3 | using SDataClientApp.Properties; 4 | 5 | namespace SDataClientApp 6 | { 7 | public partial class ServiceConfig : BaseControl 8 | { 9 | public ServiceConfig() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | public override void Refresh() 15 | { 16 | FormatURL(); 17 | } 18 | 19 | private void cbProtocol_SelectedIndexChanged(object sender, EventArgs e) 20 | { 21 | FormatURL(); 22 | } 23 | 24 | private void tbServer_TextChanged(object sender, EventArgs e) 25 | { 26 | FormatURL(); 27 | } 28 | 29 | private void tbApplication_TextChanged(object sender, EventArgs e) 30 | { 31 | FormatURL(); 32 | } 33 | 34 | private void tbContract_TextChanged(object sender, EventArgs e) 35 | { 36 | FormatURL(); 37 | } 38 | 39 | private void tbDataSet_TextChanged(object sender, EventArgs e) 40 | { 41 | FormatURL(); 42 | } 43 | 44 | private void FormatURL() 45 | { 46 | try 47 | { 48 | var server = tbServer.Text; 49 | var pos = server.IndexOf(':'); 50 | var uri = new SDataUri(); 51 | int port; 52 | 53 | if (pos >= 0 && int.TryParse(server.Substring(pos + 1), out port)) 54 | { 55 | server = server.Substring(0, pos); 56 | uri.Port = port; 57 | } 58 | 59 | uri.Scheme = cbProtocol.Text; 60 | uri.Host = server; 61 | uri.Server = tbVirtualDirectory.Text; 62 | uri.Product = tbApplication.Text; 63 | uri.Contract = tbContract.Text; 64 | uri.CompanyDataset = tbDataSet.Text; 65 | 66 | tbURL.Text = uri.ToString(); 67 | } 68 | catch (UriFormatException) 69 | { 70 | } 71 | } 72 | 73 | private void btnInitialize_Click(object sender, EventArgs e) 74 | { 75 | var server = tbServer.Text; 76 | var pos = server.IndexOf(':'); 77 | int port; 78 | 79 | if (pos >= 0 && int.TryParse(server.Substring(pos + 1), out port)) 80 | { 81 | server = server.Substring(0, pos); 82 | } 83 | else 84 | { 85 | port = 80; 86 | } 87 | 88 | Service.Protocol = cbProtocol.Text; 89 | Service.ServerName = server; 90 | Service.Port = port; 91 | Service.VirtualDirectory = tbVirtualDirectory.Text; 92 | Service.ApplicationName = tbApplication.Text; 93 | Service.ContractName = tbContract.Text; 94 | Service.DataSet = tbDataSet.Text; 95 | Service.UserName = tbUserName.Text; 96 | Service.Password = tbPassword.Text; 97 | 98 | StatusLabel.Text = Resources.statusInitializationComplete; 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /demos/SDataClientApp/app.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 | 10 39 | 40 | 41 | 1 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dependencies/Moq/Moq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/dependencies/Moq/Moq.dll -------------------------------------------------------------------------------- /dependencies/NUnit/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/dependencies/NUnit/nunit.framework.dll -------------------------------------------------------------------------------- /docs/Intro to SData CSharp Client Lib.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/docs/Intro to SData CSharp Client Lib.doc -------------------------------------------------------------------------------- /docs/SDataClientAPI.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saleslogix/SDataCSharpClientLib/0417efa2ededc49fc9b7ec07db025c168c1b450d/docs/SDataClientAPI.chm --------------------------------------------------------------------------------