├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.sh ├── package.sh ├── push.sh ├── runtests.sh ├── scripts └── assets │ └── avatar.png ├── src ├── ChatterToolkitForNET │ ├── ChatterClient.cs │ ├── ChatterToolkitForNET.csproj │ ├── IChatterClient.cs │ ├── Models │ │ ├── Actor.cs │ │ ├── Address.cs │ │ ├── Attachment.cs │ │ ├── Capabilities.cs │ │ ├── ChatterActivity.cs │ │ ├── ChatterInfluence.cs │ │ ├── ClientInfo.cs │ │ ├── Comment.cs │ │ ├── CommentPage.cs │ │ ├── Content.cs │ │ ├── FeedBody.cs │ │ ├── FeedItem.cs │ │ ├── FeedItemInput.cs │ │ ├── FeedItemPage.cs │ │ ├── FeedItemPreambleMessageBody.cs │ │ ├── FeedItemTopics.cs │ │ ├── FollowingCounts.cs │ │ ├── Group.cs │ │ ├── GroupDetail.cs │ │ ├── GroupInformation.cs │ │ ├── GroupPage.cs │ │ ├── Like.cs │ │ ├── LikePage.cs │ │ ├── LikesMessage.cs │ │ ├── MessageBodyInput.cs │ │ ├── MessageSegment.cs │ │ ├── MessageSegmentInput.cs │ │ ├── ModerationFlags.cs │ │ ├── Motif.cs │ │ ├── MySubscription.cs │ │ ├── ObjectFeedItemInput.cs │ │ ├── PhoneNumber.cs │ │ ├── Photo.cs │ │ ├── Reference.cs │ │ ├── SharedFeedItemInput.cs │ │ ├── Topic.cs │ │ ├── TopicCollection.cs │ │ ├── UserDetail.cs │ │ ├── UserPage.cs │ │ └── UserSummary.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── tools │ │ └── Install.ps1 ├── CommonLibrariesForNET │ ├── Attributes │ │ ├── CreateableAttribute.cs │ │ └── UpdateableAttribute.cs │ ├── AuthenticationClient.cs │ ├── Common.cs │ ├── CommonLibrariesForNET.csproj │ ├── Extensions │ │ └── HttpContentCompressedDataExtensions.cs │ ├── ForceAuthException.cs │ ├── ForceException.cs │ ├── IAttributedObject.cs │ ├── IAuthenticationClient.cs │ ├── IForceException.cs │ ├── IJsonHttpClient.cs │ ├── IServiceHttpClient.cs │ ├── IXmlHttpClient.cs │ ├── Internals │ │ ├── BaseHttpClient.cs │ │ └── BaseHttpClientException.cs │ ├── JsonHttpClient.cs │ ├── Models │ │ ├── Json │ │ │ ├── AnonymousExecutionResponse.cs │ │ │ ├── Attributes.cs │ │ │ ├── AuthErrorResponse.cs │ │ │ ├── AuthToken.cs │ │ │ ├── CreateRequest.cs │ │ │ ├── DescribeGlobalResult.cs │ │ │ ├── DisplayTypes.cs │ │ │ ├── Error.cs │ │ │ ├── ErrorResponse.cs │ │ │ ├── ErrorResponses.cs │ │ │ ├── ErrorResult.cs │ │ │ ├── ObjectAttributes.cs │ │ │ ├── QueryResult.cs │ │ │ ├── ResponseTypes.cs │ │ │ ├── SaveResponse.cs │ │ │ ├── SaveResult.cs │ │ │ ├── SuccessResponse.cs │ │ │ ├── UserInfo.cs │ │ │ └── Version.cs │ │ └── Xml │ │ │ ├── BatchInfoResult.cs │ │ │ ├── BatchResult.cs │ │ │ ├── BatchResultErrors.cs │ │ │ ├── BatchResultList.cs │ │ │ ├── ISObjectList.cs │ │ │ ├── JobInfo.cs │ │ │ ├── JobInfoResult.cs │ │ │ ├── JobInfoState.cs │ │ │ ├── SObject.cs │ │ │ └── SObjectList.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Serializer │ │ ├── CreateableContractResolver.cs │ │ └── UpdateableContractResolver.cs │ ├── Soql │ │ ├── DataMemberSelectListResolver.cs │ │ ├── ISelectListResolver.cs │ │ └── JsonPropertySelectListResolver.cs │ └── XmlHttpClient.cs ├── ForceTookitForNet.snk ├── ForceToolkitForNET.sln ├── ForceToolkitForNET │ ├── BulkConstants.cs │ ├── ForceClient.cs │ ├── ForceToolkitForNET.csproj │ ├── IForceClient.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── tools │ │ └── Install.ps1 └── NuGet.Config └── tests ├── ForceToolkitForNET.Tests.sln └── ForceToolkitForNET.Tests ├── BulkForceClientFunctionalTests.cs ├── BulkForceClientUnitTests.cs ├── BulkTests.cs ├── ChatterClientFunctionalTests.cs ├── CommonFunctionalTests.cs ├── CommonUnitTests.cs ├── ForceClientFunctionalTests.cs ├── ForceClientUnitTests.cs ├── ForceToolkitForNET.Tests.csproj ├── Helpers ├── AssertEx.cs ├── AuthenticationClientRouteHandler.cs ├── BulkFakeHttpRequestHandler.cs ├── BulkServiceClientRouteHandler.cs ├── ExpectedException.cs ├── FakeHttpRequestHandler.cs ├── JsonContent.cs ├── ServiceClientRouteHandler.cs └── XmlContent.cs ├── KnownGoodContent └── UserObjectDescribeMetadata.json ├── Models ├── Account.cs ├── AtrributedAccount.cs ├── Contact.cs ├── ContactsAccountNameQuery.cs ├── DeletedRecord.cs ├── Event.cs ├── ObjectDescribeMetadata.cs ├── ObjectFieldMetadata.cs └── UpdatedRecord.cs └── Properties └── AssemblyInfo.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | *.userprefs 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Rr]elease/ 20 | x64/ 21 | *_i.c 22 | *_p.c 23 | *.ilk 24 | *.meta 25 | *.obj 26 | *.pch 27 | *.pdb 28 | *.pgc 29 | *.pgd 30 | *.rsp 31 | *.sbr 32 | *.tlb 33 | *.tli 34 | *.tlh 35 | *.tmp 36 | *.log 37 | *.vspscc 38 | *.vssscc 39 | .builds 40 | 41 | # Visual C++ cache files 42 | ipch/ 43 | *.aps 44 | *.ncb 45 | *.opensdf 46 | *.sdf 47 | 48 | # Visual Studio profiler 49 | *.psess 50 | *.vsp 51 | *.vspx 52 | 53 | # Guidance Automation Toolkit 54 | *.gpState 55 | 56 | # ReSharper is a .NET coding add-in 57 | _ReSharper* 58 | 59 | # NCrunch 60 | *.ncrunch* 61 | .*crunch*.local.xml 62 | 63 | # Installshield output folder 64 | [Ee]xpress 65 | 66 | # DocProject is a documentation generator add-in 67 | DocProject/buildhelp/ 68 | DocProject/Help/*.HxT 69 | DocProject/Help/*.HxC 70 | DocProject/Help/*.hhc 71 | DocProject/Help/*.hhk 72 | DocProject/Help/*.hhp 73 | DocProject/Help/Html2 74 | DocProject/Help/html 75 | 76 | # Click-Once directory 77 | publish 78 | 79 | # Publish Web Output 80 | *.Publish.xml 81 | 82 | # NuGet Packages Directory 83 | packages 84 | 85 | # Windows Azure Build Output 86 | csx 87 | *.build.csdef 88 | 89 | # Windows Store app package directory 90 | AppPackages/ 91 | 92 | # Others 93 | [Bb]in 94 | [Oo]bj 95 | sql 96 | TestResults 97 | [Tt]est[Rr]esult* 98 | *.Cache 99 | ClientBin 100 | [Ss]tyle[Cc]op.* 101 | ~$* 102 | *.dbmdl 103 | Generated_Code #added for RIA/Silverlight projects 104 | 105 | # Backup & report files from converting an old project file to a newer 106 | # Visual Studio version. Backup files are not needed, because we have git ;-) 107 | _UpgradeReport_Files/ 108 | Backup*/ 109 | UpgradeLog*.XML 110 | 111 | # OS junk files 112 | *.DS_Store 113 | [Tt]humbs.db 114 | 115 | # For NuGet packages 116 | artifacts 117 | 118 | # Windows Azure Publish Settings contain security keys for accessing your Windows Azure account 119 | .publishsettings 120 | 121 | # Test 122 | testrunner 123 | scripts/output.txt 124 | 125 | .vscode 126 | coverage.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | mono: none 3 | dotnet: 2.2.401 4 | 5 | env: 6 | global: 7 | - secure: "cTZ/NtbAT83dysNpzuRWbh0Cia4YY4WnWqx0dFq98rNeXE02+UjCL7q0dWmhkSxvP8YYvXMXj+13J/NAH0sPyrXR+BIOsDEpR8aoB6gaGh5H6FkONq41JZcfFd5/s4OsuZ/QlMSK21oAPOZU9K+tHjrb5xUf9osey9OBx+HNlcY=" #ConsumerKey 8 | - secure: "Fmz1IrfGgcKKIAvBccKn5Hi/kKpE+Hs/hJAOIhTBniInMcoE0dcUCNYCV16uYjDvUsVNDDi0Tz/bk/UJh8kZNPJkkCQfys60l7Bl/mZ2r6umaBuiS0Xp0ZKSabsCnCLZWUSfIJdCEMgqBWOFNicfuXHRd/h0n31Pe2qFOwCzwA8=" #ConsumerSecret 9 | - secure: "M1875n8CTGSc50Vufd+V4FgdvdSHPqvnHLJmk3MBSCSPRBQ15FvxtSCPY24cDgCzNyOA3dSOkISGj1bwNj607QB4ao1sFK8ytIhwFgSC3udlSUu/b+3FyI1RSD5j5ZT9qB74nna+0hsijU6txMAf8vVWI9dorZCYCDAlaSEbU1Y=" #Username 10 | - secure: "gKbbduuB3GslGVGr0IsFnearI2EDm/PD/EYum2zRDvZsRHy2b4uMl2tpSCjF382PKXWk46ZJ2c2zIvqcxgfHc0NDqloMAH6wwE4VnEDBk5j22X+ea50tdjB0r+RcjG5SbdjqYSSUxM3Ygngl87LfWAZGPWfL5Nm14L/4rhT3cj8=" #Password 11 | - secure: "Ez7qB2PZ/gBXCdOirR0jqcOYDRK9DtPiBFg9p9LTo4VTNZ6UqBrpPLsKGyQSry/zzvI532Y8vtOPL8PNpBaGOexyJ6M0fWQUjjT0/+p53w3syhYRiqJZOiY0PWoq2beRYIFScUNzbaRdZL4cDNsLHaNV+h8KGTYZ+gVXhYerU94=" #OrganizationId 12 | 13 | script: 14 | - dotnet build src/ForceToolkitForNET.sln -f netstandard2.0 15 | - dotnet test tests/ForceToolkitForNET.Tests.sln --list-tests 16 | - dotnet test tests/ForceToolkitForNET.Tests.sln /p:CollectCoverage=true 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, salesforce.com 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | * Neither the name of the salesforce.com nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | rm -rf src/CommonLibrariesForNET/bin 2 | rm -rf src/CommonLibrariesForNET/obj 3 | rm -rf src/ChatterToolkitForNET/bin 4 | rm -rf src/ChatterToolkitForNET/obj 5 | rm -rf src/ForceToolkitForNET/bin 6 | rm -rf src/ForceToolkitForNET/obj 7 | 8 | dotnet clean src/ForceToolkitForNET.sln 9 | dotnet build src/ForceToolkitForNET.sln -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | rm -rf "artifacts" 2 | mkdir "artifacts" 3 | 4 | dotnet clean src/ForceToolkitForNET.sln 5 | 6 | dotnet build src/ForceToolkitForNET.sln -c Release /p:DebugType=Full 7 | 8 | dotnet build src/ForceToolkitForNET.sln -c Debug /p:DebugType=Full 9 | 10 | dotnet pack src/ForceToolkitForNET/ForceToolkitForNET.csproj -o "..\..\artifacts" --include-symbols --include-source 11 | 12 | dotnet pack src/ChatterToolkitForNET/ChatterToolkitForNET.csproj -o "..\..\artifacts" --include-symbols --include-source 13 | 14 | cp artifacts/DeveloperForce.Chatter.$1.nupkg artifacts/DeveloperForce.Chatter.$1.nupkg.zip 15 | 16 | cp artifacts/DeveloperForce.Force.$1.nupkg artifacts/DeveloperForce.Force.$1.nupkg.zip 17 | 18 | unzip artifacts/DeveloperForce.Chatter.$1.nupkg.zip -d artifacts/DeveloperForce.Chatter 19 | 20 | unzip artifacts/DeveloperForce.Force.$1.nupkg.zip -d artifacts/DeveloperForce.Force 21 | 22 | chmod +r artifacts/DeveloperForce.Chatter/DeveloperForce.Chatter.nuspec 23 | 24 | chmod +r artifacts/DeveloperForce.Force/DeveloperForce.Force.nuspec -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | dotnet nuget push artifacts/DeveloperForce.Force.$2.nupkg -k $1 -s https://api.nuget.org/v3/index.json 2 | 3 | dotnet nuget push artifacts/DeveloperForce.Chatter.$2.nupkg -k $1 -s https://api.nuget.org/v3/index.json -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | dotnet clean tests/ForceToolkitForNET.Tests.sln 2 | dotnet build tests/ForceToolkitForNET.Tests.sln 3 | dotnet test tests/ForceToolkitForNET.Tests.sln --list-tests 4 | dotnet test tests/ForceToolkitForNET.Tests.sln /p:CollectCoverage=true -------------------------------------------------------------------------------- /scripts/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wadewegner/Force.com-Toolkit-for-NET/279cefeca536c13f8018ac5f80de4d81291d0dd7/scripts/assets/avatar.png -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/ChatterClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Salesforce.Chatter.Models; 5 | using Salesforce.Common; 6 | 7 | namespace Salesforce.Chatter 8 | { 9 | public class ChatterClient : IChatterClient, IDisposable 10 | { 11 | private readonly JsonHttpClient _jsonHttpClient; 12 | private readonly string _itemsOrElements; 13 | 14 | public ChatterClient(string instanceUrl, string accessToken, string apiVersion) 15 | : this(instanceUrl, accessToken, apiVersion, new HttpClient()) 16 | { 17 | } 18 | 19 | public ChatterClient(string instanceUrl, string accessToken, string apiVersion, HttpClient httpClient) 20 | { 21 | _jsonHttpClient = new JsonHttpClient(instanceUrl, apiVersion, accessToken, httpClient); 22 | 23 | // A change in endpoint for feed item was introduced in v31 of the API. 24 | _itemsOrElements = float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30 ? "feed-elements" : "feed-items"; 25 | } 26 | 27 | public Task FeedsAsync() 28 | { 29 | return _jsonHttpClient.HttpGetAsync("chatter/feeds"); 30 | } 31 | 32 | public Task MeAsync() 33 | { 34 | return _jsonHttpClient.HttpGetAsync("chatter/users/me"); 35 | } 36 | 37 | public Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId) 38 | { 39 | // Feed items not available post v30.0 40 | if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) 41 | { 42 | return _jsonHttpClient.HttpPostAsync(feedItemInput, "chatter/feed-elements"); 43 | } 44 | 45 | return _jsonHttpClient.HttpPostAsync(feedItemInput, string.Format("chatter/feeds/news/{0}/{1}", userId, _itemsOrElements)); 46 | } 47 | 48 | public Task PostFeedItemToObjectAsync(ObjectFeedItemInput envelope) 49 | { 50 | return _jsonHttpClient.HttpPostAsync(envelope, "chatter/feed-elements/"); 51 | } 52 | 53 | public Task PostFeedItemWithAttachmentAsync(ObjectFeedItemInput envelope, byte[] fileContents, string fileName) 54 | { 55 | return _jsonHttpClient.HttpBinaryDataPostAsync("chatter/feed-elements/", envelope, fileContents, "feedElementFileUpload", fileName); 56 | } 57 | 58 | public Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId) 59 | { 60 | if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) 61 | { 62 | return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/capabilities/comments/items", _itemsOrElements, feedId)); 63 | } 64 | 65 | return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/comments", _itemsOrElements, feedId)); 66 | } 67 | 68 | public Task LikeFeedItemAsync(string feedId) 69 | { 70 | if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) 71 | { 72 | return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/capabilities/chatter-likes/items", _itemsOrElements, feedId)); 73 | } 74 | 75 | return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/likes", _itemsOrElements, feedId)); 76 | } 77 | 78 | public Task ShareFeedItemAsync(string feedId, string userId) 79 | { 80 | var sharedFeedItem = new SharedFeedItemInput { SubjectId = userId }; 81 | 82 | if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) 83 | { 84 | sharedFeedItem.OriginalFeedElementId = feedId; 85 | return _jsonHttpClient.HttpPostAsync(sharedFeedItem, "chatter/feed-elements"); 86 | } 87 | 88 | sharedFeedItem.OriginalFeedItemId = feedId; 89 | return _jsonHttpClient.HttpPostAsync(sharedFeedItem, string.Format("chatter/feeds/user-profile/{0}/{1}", userId, _itemsOrElements)); 90 | } 91 | 92 | public Task GetMyNewsFeedAsync(string query = "") 93 | { 94 | var url = string.Format("chatter/feeds/news/me/{0}", _itemsOrElements); 95 | 96 | if (!string.IsNullOrEmpty(query)) 97 | url += string.Format("?q={0}", query); 98 | 99 | return _jsonHttpClient.HttpGetAsync(url); 100 | } 101 | 102 | public Task GetGroupsAsync() 103 | { 104 | return _jsonHttpClient.HttpGetAsync("chatter/groups"); 105 | } 106 | 107 | public Task GetGroupFeedAsync(string groupId) 108 | { 109 | return _jsonHttpClient.HttpGetAsync(string.Format("chatter/feeds/record/{0}/{1}", _itemsOrElements, groupId)); 110 | } 111 | 112 | public Task GetUsersAsync() 113 | { 114 | return _jsonHttpClient.HttpGetAsync("chatter/users"); 115 | } 116 | 117 | public Task GetTopicsAsync() 118 | { 119 | return _jsonHttpClient.HttpGetAsync("connect/topics"); 120 | } 121 | 122 | public void Dispose() 123 | { 124 | _jsonHttpClient.Dispose(); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/ChatterToolkitForNET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0;net452;net462;net472 4 | $(TargetsForTfmSpecificBuildOutput);IncludeSalesforceCommon 5 | Salesforce.Chatter 6 | Salesforce.Chatter 7 | true 8 | ..\ForceTookitForNet.snk 9 | Salesforce.Chatter 10 | salesforce.com 11 | Salesforce.Chatter 12 | 13 | Copyright © 2018 14 | false 15 | 1.0.0.0 16 | 1.0.0.0 17 | 18 | 19 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.5.2\1.0.1\lib\net452\ 20 | 21 | 22 | 23 | 24 | 25 | 26 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.6.2\1.0.1\lib\net462\ 27 | 28 | 29 | 30 | 31 | 32 | 33 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.7.2\1.0.0\lib\net472\ 34 | 35 | 36 | 37 | 38 | 39 | 40 | DeveloperForce.Chatter 41 | DeveloperForce.Chatter 42 | 2.1.0 43 | wadewegner 44 | The DeveloperForce.Chatter NuGet provides a .NET library for interacting with the Salesforce Lightning Chatter APIs. 45 | https://raw.github.com/developerforce/Force.com-Toolkit-for-NET/master/LICENSE 46 | https://github.com/developerforce/Force.com-Toolkit-for-NET/ 47 | https://raw.github.com/developerforce/Force.com-Toolkit-for-NET/master/scripts/assets/avatar.png 48 | Copyright 2018 49 | salesforce forcedotcom force.com force rest api 50 | 51 | 52 | true 53 | ..\ForceTookitForNet.snk 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/IChatterClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Salesforce.Chatter.Models; 3 | 4 | namespace Salesforce.Chatter 5 | { 6 | public interface IChatterClient 7 | { 8 | Task FeedsAsync(); 9 | Task MeAsync(); 10 | Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId); 11 | Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId); 12 | Task LikeFeedItemAsync(string feedId); 13 | Task ShareFeedItemAsync(string feedId, string userId); 14 | Task GetMyNewsFeedAsync(string query = ""); 15 | Task GetGroupsAsync(); 16 | Task GetGroupFeedAsync(string groupId); 17 | } 18 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Actor.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Actor 6 | { 7 | [JsonProperty(PropertyName = "companyName")] 8 | public string CompanyName { get; set; } 9 | 10 | [JsonProperty(PropertyName = "firstName")] 11 | public string FirstName { get; set; } 12 | 13 | [JsonProperty(PropertyName = "id")] 14 | public string Id { get; set; } 15 | 16 | [JsonProperty(PropertyName = "isActive")] 17 | public bool IsActive { get; set; } 18 | 19 | [JsonProperty(PropertyName = "isInThisCommunity")] 20 | public bool IsInThisCommunity { get; set; } 21 | 22 | [JsonProperty(PropertyName = "lastName")] 23 | public string LastName { get; set; } 24 | 25 | [JsonProperty(PropertyName = "motif")] 26 | public Motif Motif { get; set; } 27 | 28 | [JsonProperty(PropertyName = "mySubscription")] 29 | public Reference MySubscription { get; set; } 30 | 31 | [JsonProperty(PropertyName = "name")] 32 | public string Name { get; set; } 33 | 34 | [JsonProperty(PropertyName = "photo")] 35 | public Photo Photo { get; set; } 36 | 37 | [JsonProperty(PropertyName = "title")] 38 | public string Title { get; set; } 39 | 40 | [JsonProperty(PropertyName = "type")] 41 | public string Type { get; set; } 42 | 43 | [JsonProperty(PropertyName = "url")] 44 | public string Url { get; set; } 45 | 46 | [JsonProperty(PropertyName = "userType")] 47 | public string UserType { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Address.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Address 6 | { 7 | [JsonProperty(PropertyName = "city")] 8 | public string City { get; set; } 9 | 10 | [JsonProperty(PropertyName = "country")] 11 | public string Country { get; set; } 12 | 13 | [JsonProperty(PropertyName = "formattedAddress")] 14 | public string FormattedAddress { get; set; } 15 | 16 | [JsonProperty(PropertyName = "state")] 17 | public string State { get; set; } 18 | 19 | [JsonProperty(PropertyName = "street")] 20 | public string Street { get; set; } 21 | 22 | [JsonProperty(PropertyName = "zip")] 23 | public string Zip { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Attachment.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class Attachment 7 | { 8 | [JsonProperty(PropertyName = "attachmentType")] 9 | public string AttachmentType { get; set; } 10 | 11 | [JsonProperty(PropertyName = "url")] 12 | public string Url { get; set; } 13 | 14 | [JsonProperty(PropertyName = "urlName")] 15 | public string UrlName { get; set; } 16 | 17 | [JsonProperty(PropertyName = "pollChoices")] 18 | public List PollChoices { get; set; } 19 | 20 | [JsonProperty(PropertyName = "developerName")] 21 | public string DeveloperName { get; set; } 22 | 23 | [JsonProperty(PropertyName = "namespacePrefix")] 24 | public string NamespacePrefix { get; set; } 25 | 26 | [JsonProperty(PropertyName = "parameters")] 27 | public string Parameters { get; set; } 28 | 29 | [JsonProperty(PropertyName = "height")] 30 | public string Height { get; set; } 31 | 32 | [JsonProperty(PropertyName = "title")] 33 | public string Title { get; set; } 34 | 35 | [JsonProperty(PropertyName = "contentDocumentId")] 36 | public string ContentDocumentId { get; set; } 37 | 38 | [JsonProperty(PropertyName = "description")] 39 | public string Description { get; set; } 40 | } 41 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Capabilities.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Capabilities 6 | { 7 | [JsonProperty(PropertyName = "content")] 8 | public Content Content { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/ChatterActivity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class ChatterActivity 6 | { 7 | [JsonProperty(PropertyName = "commentCount")] 8 | public int CommentCount { get; set; } 9 | 10 | [JsonProperty(PropertyName = "commentReceivedCount")] 11 | public int CommentReceivedCount { get; set; } 12 | 13 | [JsonProperty(PropertyName = "likeReceivedCount")] 14 | public int LikeReceivedCount { get; set; } 15 | 16 | [JsonProperty(PropertyName = "postCount")] 17 | public int PostCount { get; set; } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/ChatterInfluence.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class ChatterInfluence 6 | { 7 | [JsonProperty(PropertyName = "percentile")] 8 | public string Percentile { get; set; } 9 | 10 | [JsonProperty(PropertyName = "rank")] 11 | public int Rank { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/ClientInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class ClientInfo 6 | { 7 | [JsonProperty(PropertyName = "applicationName")] 8 | public string ApplicationName { get; set; } 9 | 10 | [JsonProperty(PropertyName = "applicationUrl")] 11 | public string ApplicationUrl { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Comment.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Comment 6 | { 7 | [JsonProperty(PropertyName = "attachment")] 8 | public object Attachment { get; set; } 9 | 10 | [JsonProperty(PropertyName = "body")] 11 | public FeedBody Body { get; set; } 12 | 13 | [JsonProperty(PropertyName = "clientInfo")] 14 | public ClientInfo ClientInfo { get; set; } 15 | 16 | [JsonProperty(PropertyName = "createdDate")] 17 | public string CreatedDate { get; set; } 18 | 19 | [JsonProperty(PropertyName = "feedItem")] 20 | public Reference FeedItem { get; set; } 21 | 22 | [JsonProperty(PropertyName = "id")] 23 | public string Id { get; set; } 24 | 25 | [JsonProperty(PropertyName = "isDeleteRestricted")] 26 | public bool IsDeleteRestricted { get; set; } 27 | 28 | [JsonProperty(PropertyName = "likes")] 29 | public LikePage Likes { get; set; } 30 | 31 | [JsonProperty(PropertyName = "likesMessage")] 32 | public LikeMessageBody LikesMessage { get; set; } 33 | 34 | [JsonProperty(PropertyName = "myLike")] 35 | public Reference MyLike { get; set; } 36 | 37 | [JsonProperty(PropertyName = "parent")] 38 | public Reference Parent { get; set; } 39 | 40 | [JsonProperty(PropertyName = "relativeCreatedDate")] 41 | public string RelativeCreatedDate { get; set; } 42 | 43 | [JsonProperty(PropertyName = "type")] 44 | public string Type { get; set; } 45 | 46 | [JsonProperty(PropertyName = "url")] 47 | public string Url { get; set; } 48 | 49 | [JsonProperty(PropertyName = "user")] 50 | public UserSummary User { get; set; } 51 | } 52 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/CommentPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class CommentPage 7 | { 8 | [JsonProperty(PropertyName = "comments")] 9 | public List Comments { get; set; } 10 | 11 | [JsonProperty(PropertyName = "currentPageUrl")] 12 | public string CurrentPageUrl { get; set; } 13 | 14 | [JsonProperty(PropertyName = "nextPageUrl")] 15 | public string NextPageUrl { get; set; } 16 | 17 | [JsonProperty(PropertyName = "total")] 18 | public int Total { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Content.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Content 6 | { 7 | [JsonProperty(PropertyName = "description")] 8 | public string Description { get; set; } 9 | 10 | [JsonProperty(PropertyName = "title")] 11 | public string Title { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedBody.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class FeedBody 7 | { 8 | [JsonProperty(PropertyName = "messageSegments")] 9 | public List MessageSegments { get; set; } 10 | 11 | [JsonProperty(PropertyName = "text")] 12 | public string Text { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class FeedItem 6 | { 7 | [JsonProperty(PropertyName = "actor")] 8 | public Actor Actor { get; set; } 9 | 10 | [JsonProperty(PropertyName = "attachment")] 11 | public object Attachment { get; set; } 12 | 13 | [JsonProperty(PropertyName = "body")] 14 | public FeedBody Body { get; set; } 15 | 16 | [JsonProperty(PropertyName = "canShare")] 17 | public bool CanShare { get; set; } 18 | 19 | [JsonProperty(PropertyName = "clientInfo")] 20 | public ClientInfo ClientInfo { get; set; } 21 | 22 | [JsonProperty(PropertyName = "comments")] 23 | public CommentPage Comments { get; set; } 24 | 25 | [JsonProperty(PropertyName = "createdDate")] 26 | public string CreatedDate { get; set; } 27 | 28 | [JsonProperty(PropertyName = "event")] 29 | public bool Event { get; set; } 30 | 31 | [JsonProperty(PropertyName = "id")] 32 | public string Id { get; set; } 33 | 34 | [JsonProperty(PropertyName = "isBookmarkedByCurrentUser")] 35 | public bool IsBookmarkedByCurrentUser { get; set; } 36 | 37 | [JsonProperty(PropertyName = "isDeleteRestricted")] 38 | public bool IsDeleteRestricted { get; set; } 39 | 40 | [JsonProperty(PropertyName = "isLikedByCurrentUser")] 41 | public bool IsLikedByCurrentUser { get; set; } 42 | 43 | [JsonProperty(PropertyName = "likes")] 44 | public LikePage Likes { get; set; } 45 | 46 | [JsonProperty(PropertyName = "likesMessage")] 47 | public LikeMessageBody LikesMessage { get; set; } 48 | 49 | [JsonProperty(PropertyName = "myLike")] 50 | public Reference MyLike { get; set; } 51 | 52 | [JsonProperty(PropertyName = "modifiedDate")] 53 | public string ModifiedDate { get; set; } 54 | 55 | [JsonProperty(PropertyName = "moderationFlags")] 56 | public ModerationFlags ModerationFlags { get; set; } 57 | 58 | [JsonProperty(PropertyName = "originalFeedItem")] 59 | public Reference OriginalFeedItem { get; set; } 60 | 61 | [JsonProperty(PropertyName = "originalFeedItemActor")] 62 | public UserSummary OriginalFeedItemActor { get; set; } 63 | 64 | [JsonProperty(PropertyName = "parent")] 65 | public UserSummary Parent { get; set; } 66 | 67 | [JsonProperty(PropertyName = "photoUrl")] 68 | public string PhotoUrl { get; set; } 69 | 70 | [JsonProperty(PropertyName = "preamble")] 71 | public FeedItemPreambleMessageBody Preamble { get; set; } 72 | 73 | [JsonProperty(PropertyName = "relativeCreatedDate")] 74 | public string RelativeCreatedDate { get; set; } 75 | 76 | [JsonProperty(PropertyName = "topics")] 77 | public FeedItemTopics Topics { get; set; } 78 | 79 | [JsonProperty(PropertyName = "type")] 80 | public string Type { get; set; } 81 | 82 | [JsonProperty(PropertyName = "url")] 83 | public string Url { get; set; } 84 | 85 | [JsonProperty(PropertyName = "visibility")] 86 | public string Visibility { get; set; } 87 | } 88 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedItemInput.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class FeedItemInput 7 | { 8 | [JsonProperty(PropertyName = "attachment")] 9 | public Attachment Attachment { get; set; } 10 | 11 | [JsonProperty(PropertyName = "body")] 12 | public MessageBodyInput Body { get; set; } 13 | 14 | [JsonProperty(PropertyName = "subjectId")] 15 | public String SubjectId { get; set; } 16 | 17 | [JsonProperty(PropertyName = "feedElementType")] 18 | public String FeedElementType { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedItemPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class FeedItemPage 7 | { 8 | [JsonProperty(PropertyName = "currentPageUrl")] 9 | public string CurrentPageUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "isModifiedToken")] 12 | public string IsModifiedToken { get; set; } 13 | 14 | [JsonProperty(PropertyName = "isModifiedUrl")] 15 | public string IsModifiedUrl { get; set; } 16 | 17 | [JsonProperty(PropertyName = "items")] 18 | public List Items { get; set; } 19 | 20 | [JsonProperty(PropertyName = "nextPageUrl")] 21 | public string NextPageUrl { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedItemPreambleMessageBody.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class FeedItemPreambleMessageBody 7 | { 8 | [JsonProperty(PropertyName = "messageSegments")] 9 | public List MessageSegments { get; set; } 10 | 11 | [JsonProperty(PropertyName = "text")] 12 | public string Text { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FeedItemTopics.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class FeedItemTopics 7 | { 8 | [JsonProperty(PropertyName = "topics")] 9 | public List Topics { get; set; } 10 | 11 | [JsonProperty(PropertyName = "canAssignTopics")] 12 | public bool CanAssignTopics { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/FollowingCounts.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class FollowingCounts 6 | { 7 | [JsonProperty(PropertyName = "people")] 8 | public int People { get; set; } 9 | 10 | [JsonProperty(PropertyName = "records")] 11 | public int Records { get; set; } 12 | 13 | [JsonProperty(PropertyName = "total")] 14 | public int Total { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Group.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Group 6 | { 7 | [JsonProperty(PropertyName = "canHaveChatterGuests")] 8 | public bool CanHaveChatterGuests { get; set; } 9 | 10 | [JsonProperty(PropertyName = "community")] 11 | public Reference Community { get; set; } 12 | 13 | [JsonProperty(PropertyName = "description")] 14 | public string Description { get; set; } 15 | 16 | [JsonProperty(PropertyName = "emailToChatterAddress")] 17 | public string EmailToChatterAddress { get; set; } 18 | 19 | [JsonProperty(PropertyName = "isArchived")] 20 | public bool IsArchived { get; set; } 21 | 22 | [JsonProperty(PropertyName = "isAutoArchiveDisabled")] 23 | public bool IsAutoArchiveDisabled { get; set; } 24 | 25 | [JsonProperty(PropertyName = "fileCount")] 26 | public int FileCount { get; set; } 27 | 28 | [JsonProperty(PropertyName = "id")] 29 | public string Id { get; set; } 30 | 31 | [JsonProperty(PropertyName = "lastFeedItemPostDate")] 32 | public string LastFeedItemPostDate { get; set; } 33 | 34 | [JsonProperty(PropertyName = "memberCount")] 35 | public int MemberCount { get; set; } 36 | 37 | [JsonProperty(PropertyName = "motif")] 38 | public Motif Motif { get; set; } 39 | 40 | [JsonProperty(PropertyName = "myRole")] 41 | public string MyRole { get; set; } 42 | 43 | [JsonProperty(PropertyName = "mySubscription")] 44 | public Reference MySubscription { get; set; } 45 | 46 | [JsonProperty(PropertyName = "name")] 47 | public string Name { get; set; } 48 | 49 | [JsonProperty(PropertyName = "owner")] 50 | public UserSummary Owner { get; set; } 51 | 52 | [JsonProperty(PropertyName = "photo")] 53 | public Photo Photo { get; set; } 54 | 55 | [JsonProperty(PropertyName = "type")] 56 | public string Type { get; set; } 57 | 58 | [JsonProperty(PropertyName = "url")] 59 | public string Url { get; set; } 60 | 61 | [JsonProperty(PropertyName = "visibility")] 62 | public string Visibility { get; set; } 63 | } 64 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/GroupDetail.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class GroupDetail 6 | { 7 | 8 | [JsonProperty(PropertyName = "canHaveChatterGuests")] 9 | public bool CanHaveChatterGuests { get; set; } 10 | 11 | [JsonProperty(PropertyName = "community")] 12 | public Reference Community { get; set; } 13 | 14 | [JsonProperty(PropertyName = "description")] 15 | public string Description { get; set; } 16 | 17 | [JsonProperty(PropertyName = "emailToChatterAddress")] 18 | public string EmailToChatterAddress { get; set; } 19 | 20 | [JsonProperty(PropertyName = "fileCount")] 21 | public int? FileCount { get; set; } 22 | 23 | [JsonProperty(PropertyName = "id")] 24 | public string Id { get; set; } 25 | 26 | [JsonProperty(PropertyName = "information")] 27 | public GroupInformation Information { get; set; } 28 | 29 | [JsonProperty(PropertyName = "lastFeedItemPostDate")] 30 | public string LastFeedItemPostDate { get; set; } 31 | 32 | [JsonProperty(PropertyName = "memberCount")] 33 | public int MemberCount { get; set; } 34 | 35 | [JsonProperty(PropertyName = "motif")] 36 | public Motif Motif { get; set; } 37 | 38 | [JsonProperty(PropertyName = "myRole")] 39 | public string MyRole { get; set; } 40 | 41 | [JsonProperty(PropertyName = "mySubscription")] 42 | public Reference MySubscription { get; set; } 43 | 44 | [JsonProperty(PropertyName = "name")] 45 | public string Name { get; set; } 46 | 47 | [JsonProperty(PropertyName = "owner")] 48 | public UserSummary Owner { get; set; } 49 | 50 | [JsonProperty(PropertyName = "photo")] 51 | public Photo Photo { get; set; } 52 | 53 | [JsonProperty(PropertyName = "type")] 54 | public string Type { get; set; } 55 | 56 | [JsonProperty(PropertyName = "url")] 57 | public string Url { get; set; } 58 | 59 | [JsonProperty(PropertyName = "visibility")] 60 | public string Visibility { get; set; } 61 | } 62 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/GroupInformation.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class GroupInformation 6 | { 7 | [JsonProperty(PropertyName = "text")] 8 | public string Text { get; set; } 9 | 10 | [JsonProperty(PropertyName = "title")] 11 | public string Title { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/GroupPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class GroupPage 7 | { 8 | [JsonProperty(PropertyName = "currentPageUrl")] 9 | public string CurrentPageUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "groups")] 12 | public List Groups { get; set; } 13 | 14 | [JsonProperty(PropertyName = "nextPageUrl")] 15 | public string NextPageUrl { get; set; } 16 | 17 | [JsonProperty(PropertyName = "previousPageUrl")] 18 | public string PreviousPageUrl { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Like.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Like 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "likedItem")] 11 | public Reference LikedItem { get; set; } 12 | 13 | [JsonProperty(PropertyName = "url")] 14 | public string Url { get; set; } 15 | 16 | [JsonProperty(PropertyName = "user")] 17 | public UserSummary User { get; set; } 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/LikePage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class LikePage 7 | { 8 | [JsonProperty(PropertyName = "currentPageUrl")] 9 | public string CurrentPageUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "likes")] 12 | public List Likes { get; set; } 13 | 14 | [JsonProperty(PropertyName = "nextPageUrl")] 15 | public string NextPageUrl { get; set; } 16 | 17 | [JsonProperty(PropertyName = "previousPageUrl")] 18 | public string PreviousPageUrl { get; set; } 19 | 20 | [JsonProperty(PropertyName = "total")] 21 | public int Total { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/LikesMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class LikeMessageBody 7 | { 8 | [JsonProperty(PropertyName = "messageSegments")] 9 | public List MessageSegments { get; set; } 10 | 11 | [JsonProperty(PropertyName = "text")] 12 | public string Text { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/MessageBodyInput.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class MessageBodyInput 7 | { 8 | [JsonProperty(PropertyName = "messageSegments")] 9 | public List MessageSegments { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/MessageSegment.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class MessageSegment 6 | { 7 | [JsonProperty(PropertyName = "motif")] 8 | public Motif Motif { get; set; } 9 | 10 | [JsonProperty(PropertyName = "record")] 11 | public object Record { get; set; } 12 | 13 | [JsonProperty(PropertyName = "reference")] 14 | public Reference Reference { get; set; } 15 | 16 | [JsonProperty(PropertyName = "text")] 17 | public string Text { get; set; } 18 | 19 | [JsonProperty(PropertyName = "type")] 20 | public string Type { get; set; } 21 | 22 | [JsonProperty(PropertyName = "url")] 23 | public string Url { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/MessageSegmentInput.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class MessageSegmentInput 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "tag")] 11 | public string Tag { get; set; } 12 | 13 | [JsonProperty(PropertyName = "text")] 14 | public string Text { get; set; } 15 | 16 | [JsonProperty(PropertyName = "type")] 17 | public string Type { get; set; } 18 | 19 | [JsonProperty(PropertyName = "url")] 20 | public string Url { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/ModerationFlags.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class ModerationFlags 6 | { 7 | [JsonProperty(PropertyName = "flagCount")] 8 | public int FlagCount { get; set; } 9 | 10 | [JsonProperty(PropertyName = "flaggedByMe")] 11 | public bool FlaggedByMe { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Motif.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Motif 6 | { 7 | [JsonProperty(PropertyName = "color")] 8 | public string Color { get; set; } 9 | 10 | [JsonProperty(PropertyName = "largeIconUrl")] 11 | public string LargeIconUrl { get; set; } 12 | 13 | [JsonProperty(PropertyName = "mediumIconUrl")] 14 | public string MediumIconUrl { get; set; } 15 | 16 | [JsonProperty(PropertyName = "smallIconUrl")] 17 | public string SmallIconUrl { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/MySubscription.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class MySubscription 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "url")] 11 | public string Url { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/ObjectFeedItemInput.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class ObjectFeedItemInput : FeedItemInput 6 | { 7 | [JsonProperty(PropertyName = "feedElementType")] 8 | readonly public string FeedItem = "FeedItem"; 9 | 10 | [JsonProperty(PropertyName = "subjectId")] 11 | public string ObjectId { get; set; } 12 | 13 | [JsonProperty(PropertyName = "capabilities")] 14 | public Capabilities Capabilities { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/PhoneNumber.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class PhoneNumber 6 | { 7 | [JsonProperty(PropertyName = "phoneNumber")] 8 | public string Number { get; set; } 9 | 10 | [JsonProperty(PropertyName = "type")] 11 | public string Type { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Photo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Photo 6 | { 7 | [JsonProperty(PropertyName = "fullEmailPhotoUrl")] 8 | public string FullEmailPhotoUrl { get; set; } 9 | 10 | [JsonProperty(PropertyName = "largePhotoUrl")] 11 | public string LargePhotoUrl { get; set; } 12 | 13 | [JsonProperty(PropertyName = "photoVersionId")] 14 | public string PhotoVersionId { get; set; } 15 | 16 | [JsonProperty(PropertyName = "smallPhotoUrl")] 17 | public string SmallPhotoUrl { get; set; } 18 | 19 | [JsonProperty(PropertyName = "standardEmailPhotoUrl")] 20 | public string StandardEmailPhotoUrl { get; set; } 21 | 22 | [JsonProperty(PropertyName = "url")] 23 | public string Url { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Reference.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Reference 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "url")] 11 | public string Url { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/SharedFeedItemInput.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | /// 6 | /// This class is similar to the FeedItemInput class, but only contains one of the optional properties. 7 | /// This property takes precedence over all other parameters. 8 | /// 9 | public class SharedFeedItemInput 10 | { 11 | [JsonProperty(PropertyName = "originalFeedItemId")] 12 | public string OriginalFeedItemId { get; set; } 13 | 14 | [JsonProperty(PropertyName = "subjectId")] 15 | public string SubjectId { get; set; } 16 | 17 | [JsonProperty(PropertyName = "originalFeedElementId")] 18 | public string OriginalFeedElementId { get; set; } 19 | 20 | [JsonProperty(PropertyName = "userId")] 21 | public string UserId { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/Topic.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class Topic 6 | { 7 | [JsonProperty(PropertyName = "createdDate")] 8 | public string CreatedDate { get; set; } 9 | 10 | [JsonProperty(PropertyName = "description")] 11 | public string Description { get; set; } 12 | 13 | [JsonProperty(PropertyName = "id")] 14 | public string Id { get; set; } 15 | 16 | [JsonProperty(PropertyName = "name")] 17 | public string Name { get; set; } 18 | 19 | [JsonProperty(PropertyName = "talkingAbout")] 20 | public int? TalkingAbout { get; set; } 21 | 22 | [JsonProperty(PropertyName = "url")] 23 | public string Url { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/TopicCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class TopicCollection 7 | { 8 | [JsonProperty(PropertyName = "currentPageUrl")] 9 | public string CurrentPageUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "nextPageUrl")] 12 | public string NextPageUrl { get; set; } 13 | 14 | [JsonProperty(PropertyName = "topics")] 15 | public List Topics { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/UserDetail.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class UserDetail 7 | { 8 | [JsonProperty(PropertyName = "aboutMe")] 9 | public string aboutMe { get; set; } 10 | 11 | [JsonProperty(PropertyName = "address")] 12 | public Address address { get; set; } 13 | 14 | [JsonProperty(PropertyName = "chatterActivity")] 15 | public ChatterActivity chatterActivity { get; set; } 16 | 17 | [JsonProperty(PropertyName = "chatterInfluence")] 18 | public ChatterInfluence chatterInfluence { get; set; } 19 | 20 | [JsonProperty(PropertyName = "companyName")] 21 | public string companyName { get; set; } 22 | 23 | [JsonProperty(PropertyName = "email")] 24 | public string email { get; set; } 25 | 26 | [JsonProperty(PropertyName = "firstName")] 27 | public string firstName { get; set; } 28 | 29 | [JsonProperty(PropertyName = "followersCount")] 30 | public int followersCount { get; set; } 31 | 32 | [JsonProperty(PropertyName = "followingCounts")] 33 | public FollowingCounts followingCounts { get; set; } 34 | 35 | [JsonProperty(PropertyName = "groupCount")] 36 | public int groupCount { get; set; } 37 | 38 | [JsonProperty(PropertyName = "id")] 39 | public string id { get; set; } 40 | 41 | [JsonProperty(PropertyName = "isActive")] 42 | public bool isActive { get; set; } 43 | 44 | [JsonProperty(PropertyName = "isInThisCommunity")] 45 | public bool isInThisCommunity { get; set; } 46 | 47 | [JsonProperty(PropertyName = "lastName")] 48 | public string lastName { get; set; } 49 | 50 | [JsonProperty(PropertyName = "managerId")] 51 | public string managerId { get; set; } 52 | 53 | [JsonProperty(PropertyName = "managerName")] 54 | public string managerName { get; set; } 55 | 56 | [JsonProperty(PropertyName = "motif")] 57 | public Motif motif { get; set; } 58 | 59 | [JsonProperty(PropertyName = "mySubscription")] 60 | public Reference mySubscription { get; set; } 61 | 62 | [JsonProperty(PropertyName = "name")] 63 | public string name { get; set; } 64 | 65 | [JsonProperty(PropertyName = "phoneNumbers")] 66 | public List phoneNumbers { get; set; } 67 | 68 | [JsonProperty(PropertyName = "photo")] 69 | public Photo photo { get; set; } 70 | 71 | [JsonProperty(PropertyName = "thanksReceived")] 72 | public int? thanksReceived { get; set; } 73 | 74 | [JsonProperty(PropertyName = "title")] 75 | public string title { get; set; } 76 | 77 | [JsonProperty(PropertyName = "type")] 78 | public string type { get; set; } 79 | 80 | [JsonProperty(PropertyName = "url")] 81 | public string url { get; set; } 82 | 83 | [JsonProperty(PropertyName = "username")] 84 | public string username { get; set; } 85 | 86 | [JsonProperty(PropertyName = "userType")] 87 | public string userType { get; set; } 88 | } 89 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/UserPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Chatter.Models 5 | { 6 | public class UserPage 7 | { 8 | [JsonProperty(PropertyName = "currentPageUrl")] 9 | public string CurrentPageUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "nextPageUrl")] 12 | public string NextPageUrl { get; set; } 13 | 14 | [JsonProperty(PropertyName = "previousPageUrl")] 15 | public string PreviousPageUrl { get; set; } 16 | 17 | [JsonProperty(PropertyName = "users")] 18 | public List Users { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Models/UserSummary.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Chatter.Models 4 | { 5 | public class UserSummary 6 | { 7 | [JsonProperty(PropertyName = "companyName")] 8 | public string CompanyName { get; set; } 9 | 10 | [JsonProperty(PropertyName = "firstName")] 11 | public string FirstName { get; set; } 12 | 13 | [JsonProperty(PropertyName = "id")] 14 | public string Id { get; set; } 15 | 16 | [JsonProperty(PropertyName = "isActive")] 17 | public bool IsActive { get; set; } 18 | 19 | [JsonProperty(PropertyName = "isInThisCommunity")] 20 | public bool IsInThisCommunity { get; set; } 21 | 22 | [JsonProperty(PropertyName = "lastName")] 23 | public string LastName { get; set; } 24 | 25 | [JsonProperty(PropertyName = "motif")] 26 | public Motif Motif { get; set; } 27 | 28 | [JsonProperty(PropertyName = "mySubscription")] 29 | public Reference MySubscription { get; set; } 30 | 31 | [JsonProperty(PropertyName = "name")] 32 | public string Name { get; set; } 33 | 34 | [JsonProperty(PropertyName = "photo")] 35 | public Photo Photo { get; set; } 36 | 37 | [JsonProperty(PropertyName = "title")] 38 | public string Title { get; set; } 39 | 40 | [JsonProperty(PropertyName = "type")] 41 | public string Type { get; set; } 42 | 43 | [JsonProperty(PropertyName = "url")] 44 | public string Url { get; set; } 45 | 46 | [JsonProperty(PropertyName = "userType")] 47 | public string UserType { get; set; } 48 | } 49 | } -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: NeutralResourcesLanguage("en")] -------------------------------------------------------------------------------- /src/ChatterToolkitForNET/tools/Install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $readmeFile = "http://www.wadewegner.com/2014/01/announcing-the-salesforce-toolkits-for-net/" 4 | $DTE.ItemOperations.Navigate($readmeFile, [EnvDTE.vsNavigateOptions]::vsNavigateOptionsNewWindow) -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Attributes/CreateableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Salesforce.Common.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 6 | public class CreateableAttribute : Attribute 7 | { 8 | public bool Createable { get; private set; } 9 | 10 | public CreateableAttribute(bool createable) 11 | { 12 | Createable = createable; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Attributes/UpdateableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Salesforce.Common.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 6 | public class UpdateableAttribute : Attribute 7 | { 8 | public bool Updateable { get; private set; } 9 | 10 | public UpdateableAttribute(bool updateable) 11 | { 12 | Updateable = updateable; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/AuthenticationClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Linq; 8 | using Salesforce.Common.Models.Json; 9 | 10 | namespace Salesforce.Common 11 | { 12 | public class AuthenticationClient : IAuthenticationClient, IDisposable 13 | { 14 | public string InstanceUrl { get; set; } 15 | public string AccessToken { get; set; } 16 | public string RefreshToken { get; set; } 17 | public string Id { get; set; } 18 | public string ApiVersion { get; set; } 19 | 20 | private const string UserAgent = "forcedotcom-toolkit-dotnet"; 21 | private const string TokenRequestEndpointUrl = "https://login.salesforce.com/services/oauth2/token"; 22 | private readonly HttpClient _httpClient; 23 | private readonly bool _disposeHttpClient; 24 | 25 | public AuthenticationClient(string apiVersion = "v36.0") 26 | : this(new HttpClient(), apiVersion) 27 | { 28 | } 29 | 30 | public AuthenticationClient(HttpClient httpClient, string apiVersion = "v36.0", bool callerWillDisposeHttpClient = false) 31 | { 32 | if (httpClient == null) throw new ArgumentNullException("httpClient"); 33 | 34 | _httpClient = httpClient; 35 | _disposeHttpClient = !callerWillDisposeHttpClient; 36 | ApiVersion = apiVersion; 37 | } 38 | 39 | public Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password) 40 | { 41 | return UsernamePasswordAsync(clientId, clientSecret, username, password, TokenRequestEndpointUrl); 42 | } 43 | 44 | public async Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl) 45 | { 46 | if (string.IsNullOrEmpty(clientId)) throw new ArgumentNullException("clientId"); 47 | if (string.IsNullOrEmpty(clientSecret)) throw new ArgumentNullException("clientSecret"); 48 | if (string.IsNullOrEmpty(username)) throw new ArgumentNullException("username"); 49 | if (string.IsNullOrEmpty(password)) throw new ArgumentNullException("password"); 50 | if (string.IsNullOrEmpty(tokenRequestEndpointUrl)) throw new ArgumentNullException("tokenRequestEndpointUrl"); 51 | if (!Uri.IsWellFormedUriString(tokenRequestEndpointUrl, UriKind.Absolute)) throw new FormatException("tokenRequestEndpointUrl"); 52 | 53 | var content = new FormUrlEncodedContent(new[] 54 | { 55 | new KeyValuePair("grant_type", "password"), 56 | new KeyValuePair("client_id", clientId), 57 | new KeyValuePair("client_secret", clientSecret), 58 | new KeyValuePair("username", username), 59 | new KeyValuePair("password", password) 60 | }); 61 | 62 | var request = new HttpRequestMessage 63 | { 64 | Method = HttpMethod.Post, 65 | RequestUri = new Uri(tokenRequestEndpointUrl), 66 | Content = content 67 | }; 68 | 69 | request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); 70 | 71 | var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); 72 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 73 | 74 | if (responseMessage.IsSuccessStatusCode) 75 | { 76 | var authToken = JsonConvert.DeserializeObject(response); 77 | 78 | AccessToken = authToken.AccessToken; 79 | InstanceUrl = authToken.InstanceUrl; 80 | Id = authToken.Id; 81 | } 82 | else 83 | { 84 | var errorResponse = JsonConvert.DeserializeObject(response); 85 | throw new ForceAuthException(errorResponse.Error, errorResponse.ErrorDescription, responseMessage.StatusCode); 86 | } 87 | } 88 | 89 | public Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code) 90 | { 91 | return WebServerAsync(clientId, clientSecret, redirectUri, code, TokenRequestEndpointUrl); 92 | } 93 | 94 | public async Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl) 95 | { 96 | if (string.IsNullOrEmpty(clientId)) throw new ArgumentNullException("clientId"); 97 | if (string.IsNullOrEmpty(clientSecret)) throw new ArgumentNullException("clientSecret"); 98 | if (string.IsNullOrEmpty(redirectUri)) throw new ArgumentNullException("redirectUri"); 99 | if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) throw new FormatException("redirectUri"); 100 | if (string.IsNullOrEmpty(code)) throw new ArgumentNullException("code"); 101 | if (string.IsNullOrEmpty(tokenRequestEndpointUrl)) throw new ArgumentNullException("tokenRequestEndpointUrl"); 102 | if (!Uri.IsWellFormedUriString(tokenRequestEndpointUrl, UriKind.Absolute)) throw new FormatException("tokenRequestEndpointUrl"); 103 | 104 | var content = new FormUrlEncodedContent(new[] 105 | { 106 | new KeyValuePair("grant_type", "authorization_code"), 107 | new KeyValuePair("client_id", clientId), 108 | new KeyValuePair("client_secret", clientSecret), 109 | new KeyValuePair("redirect_uri", redirectUri), 110 | new KeyValuePair("code", code) 111 | }); 112 | 113 | var request = new HttpRequestMessage 114 | { 115 | Method = HttpMethod.Post, 116 | RequestUri = new Uri(tokenRequestEndpointUrl), 117 | Content = content 118 | }; 119 | 120 | request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); 121 | 122 | var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); 123 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 124 | 125 | if (responseMessage.IsSuccessStatusCode) 126 | { 127 | var authToken = JsonConvert.DeserializeObject(response); 128 | 129 | AccessToken = authToken.AccessToken; 130 | InstanceUrl = authToken.InstanceUrl; 131 | Id = authToken.Id; 132 | RefreshToken = authToken.RefreshToken; 133 | } 134 | else 135 | { 136 | try 137 | { 138 | var errorResponse = JsonConvert.DeserializeObject(response); 139 | throw new ForceAuthException(errorResponse.Error, errorResponse.ErrorDescription); 140 | } 141 | catch (Exception ex) 142 | { 143 | throw new ForceAuthException(Error.UnknownException, ex.Message); 144 | } 145 | 146 | } 147 | } 148 | 149 | public Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret = "") 150 | { 151 | return TokenRefreshAsync(clientId, refreshToken, clientSecret, TokenRequestEndpointUrl); 152 | } 153 | 154 | public async Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret, string tokenRequestEndpointUrl) 155 | { 156 | var url = Common.FormatRefreshTokenUrl( 157 | tokenRequestEndpointUrl, 158 | clientId, 159 | refreshToken, 160 | clientSecret); 161 | 162 | var request = new HttpRequestMessage 163 | { 164 | Method = HttpMethod.Post, 165 | RequestUri = new Uri(url) 166 | }; 167 | 168 | request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); 169 | 170 | var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); 171 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 172 | 173 | if (responseMessage.IsSuccessStatusCode) 174 | { 175 | var authToken = JsonConvert.DeserializeObject(response); 176 | 177 | AccessToken = authToken.AccessToken; 178 | RefreshToken = refreshToken; 179 | InstanceUrl = authToken.InstanceUrl; 180 | Id = authToken.Id; 181 | } 182 | else 183 | { 184 | var errorResponse = JsonConvert.DeserializeObject(response); 185 | throw new ForceException(errorResponse.Error, errorResponse.ErrorDescription); 186 | } 187 | } 188 | 189 | 190 | public async Task GetLatestVersionAsync() 191 | { 192 | try 193 | { 194 | string serviceURL = InstanceUrl + @"/services/data/"; 195 | HttpResponseMessage responseMessage = await _httpClient.GetAsync(serviceURL); 196 | 197 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 198 | if (responseMessage.IsSuccessStatusCode) 199 | { 200 | try 201 | { 202 | var jToken = JToken.Parse(response); 203 | if (jToken.Type == JTokenType.Array) 204 | { 205 | var jArray = JArray.Parse(response); 206 | List versionList = JsonConvert.DeserializeObject>(jArray.ToString()); 207 | if (versionList != null && versionList.Count > 0) 208 | { 209 | versionList.Sort(); 210 | if (!string.IsNullOrEmpty(versionList.Last().version)) 211 | ApiVersion = "v" + versionList.Last().version; 212 | } 213 | } 214 | } 215 | catch (Exception e) 216 | { 217 | throw new ForceException(Error.UnknownException, e.Message); 218 | } 219 | } 220 | else 221 | { 222 | var errorResponse = JsonConvert.DeserializeObject(response); 223 | throw new ForceException(errorResponse.Error, errorResponse.ErrorDescription); 224 | } 225 | } 226 | catch (Exception ex) 227 | { 228 | throw new ForceAuthException(Error.UnknownException, ex.Message); 229 | } 230 | } 231 | 232 | public void Dispose() 233 | { 234 | if (_disposeHttpClient) 235 | { 236 | _httpClient.Dispose(); 237 | } 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Common.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Salesforce.Common.Models.Json; 3 | 4 | namespace Salesforce.Common 5 | { 6 | public static class Common 7 | { 8 | public static Uri FormatUrl(string resourceName, string instanceUrl, string apiVersion) 9 | { 10 | if (string.IsNullOrEmpty(resourceName)) throw new ArgumentNullException("resourceName"); 11 | if (string.IsNullOrEmpty(instanceUrl)) throw new ArgumentNullException("instanceUrl"); 12 | if (string.IsNullOrEmpty(apiVersion)) throw new ArgumentNullException("apiVersion"); 13 | 14 | if (resourceName.StartsWith("/services/data", StringComparison.CurrentCultureIgnoreCase)) 15 | { 16 | return new Uri(new Uri(instanceUrl), resourceName); 17 | } 18 | 19 | if (resourceName.StartsWith("/services/async", StringComparison.CurrentCultureIgnoreCase)) 20 | { 21 | return new Uri(new Uri(instanceUrl), string.Format(resourceName, apiVersion)); 22 | } 23 | 24 | return new Uri(new Uri(instanceUrl), string.Format("/services/data/{0}/{1}", apiVersion, resourceName)); 25 | } 26 | 27 | public static Uri FormatCustomUrl(string customApi, string parameters, string instanceUrl) 28 | { 29 | if (string.IsNullOrEmpty(customApi)) throw new ArgumentNullException("customApi"); 30 | if (string.IsNullOrEmpty(parameters)) throw new ArgumentNullException("parameters"); 31 | if (string.IsNullOrEmpty(instanceUrl)) throw new ArgumentNullException("instanceUrl"); 32 | 33 | return new Uri(string.Format("{0}/services/apexrest/{1}{2}", instanceUrl, customApi, parameters)); 34 | } 35 | 36 | public static Uri FormatRestApiUrl(string customApi, string instanceUrl) 37 | { 38 | if (string.IsNullOrEmpty(customApi)) throw new ArgumentNullException("customApi"); 39 | if (string.IsNullOrEmpty(instanceUrl)) throw new ArgumentNullException("instanceUrl"); 40 | 41 | return new Uri(string.Format("{0}/services/apexrest/{1}", instanceUrl, customApi)); 42 | } 43 | 44 | public static string FormatAuthUrl( 45 | string loginUrl, 46 | ResponseTypes responseType, 47 | string clientId, 48 | string redirectUrl, 49 | DisplayTypes display = DisplayTypes.Page, 50 | bool immediate = false, 51 | string state = "", 52 | string scope = "") 53 | { 54 | if (string.IsNullOrEmpty(loginUrl)) throw new ArgumentNullException("loginUrl"); 55 | if (string.IsNullOrEmpty(clientId)) throw new ArgumentNullException("clientId"); 56 | if (string.IsNullOrEmpty(redirectUrl)) throw new ArgumentNullException("redirectUrl"); 57 | 58 | var url = 59 | string.Format( 60 | "{0}?response_type={1}&client_id={2}&redirect_uri={3}&display={4}&immediate={5}&state={6}&scope={7}", 61 | loginUrl, 62 | responseType.ToString().ToLower(), 63 | clientId, 64 | redirectUrl, 65 | display.ToString().ToLower(), 66 | immediate, 67 | state, 68 | scope); 69 | 70 | return url; 71 | } 72 | 73 | public static string FormatRefreshTokenUrl( 74 | string tokenRefreshUrl, 75 | string clientId, 76 | string refreshToken, 77 | string clientSecret = "") 78 | { 79 | if (tokenRefreshUrl == null) throw new ArgumentNullException("tokenRefreshUrl"); 80 | if (clientId == null) throw new ArgumentNullException("clientId"); 81 | if (refreshToken == null) throw new ArgumentNullException("refreshToken"); 82 | 83 | var clientSecretQuerystring = ""; 84 | if (!string.IsNullOrEmpty(clientSecret)) 85 | { 86 | clientSecretQuerystring = string.Format("&client_secret={0}", clientSecret); 87 | } 88 | 89 | var url = 90 | string.Format( 91 | "{0}?grant_type=refresh_token&client_id={1}{2}&refresh_token={3}", 92 | tokenRefreshUrl, 93 | clientId, 94 | clientSecretQuerystring, 95 | refreshToken); 96 | 97 | return url; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/CommonLibrariesForNET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0;net452;net462;net472 4 | Salesforce.Common 5 | Salesforce.Common 6 | true 7 | ..\ForceTookitForNet.snk 8 | Salesforce.Common 9 | salesforce.com 10 | Salesforce.Common 11 | 12 | Copyright © 2018 13 | false 14 | 1.0.0.0 15 | 1.0.0.0 16 | 17 | 18 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.5.2\1.0.1\lib\net452\ 19 | 20 | 21 | 22 | 23 | 24 | 25 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.6.2\1.0.1\lib\net462\ 26 | 27 | 28 | 29 | 30 | 31 | 32 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.7.2\1.0.0\lib\net472\ 33 | 34 | 35 | 36 | 37 | 38 | 39 | true 40 | ..\ForceTookitForNet.snk 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Extensions/HttpContentCompressedDataExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | 9 | namespace Salesforce.Common 10 | { 11 | /// 12 | /// Extension methods for . 13 | /// 14 | public static class HttpContentCompressedDataExtensions 15 | { 16 | /// 17 | /// Content-Encoding default value 18 | /// 19 | public const string GZipEncoding = "gzip"; 20 | 21 | /// 22 | /// Returns the response content to string. It decompresses the content if needed 23 | /// 24 | /// Http Response Message 25 | /// Http Response content as string 26 | public static async Task ReadAsDecompressedStringAsync(this HttpContent responseContent) 27 | { 28 | string content; 29 | 30 | if (responseContent == null) 31 | { 32 | return string.Empty; 33 | } 34 | 35 | // Check if the response content is gzip encoded. Gzipped response length is less than the actual and thereby less 36 | // payload over the network. 37 | if (responseContent.Headers.ContentEncoding.Contains(GZipEncoding,StringComparer.OrdinalIgnoreCase)) 38 | { 39 | var responseStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false); 40 | var unzippedContent = new GZipStream(responseStream, CompressionMode.Decompress); 41 | content = await(new StreamReader(unzippedContent)).ReadToEndAsync(); 42 | } 43 | else 44 | { 45 | content = await responseContent.ReadAsStringAsync().ConfigureAwait(false); 46 | } 47 | 48 | return content; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/ForceAuthException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using Salesforce.Common.Models.Json; 4 | 5 | namespace Salesforce.Common 6 | { 7 | public class ForceAuthException : Exception 8 | { 9 | public string[] Fields { get; private set; } 10 | public HttpStatusCode HttpStatusCode { get; private set; } 11 | public Error Error { get; private set; } 12 | 13 | public ForceAuthException(string error, string description) 14 | : this(ParseError(error), description) 15 | { 16 | } 17 | 18 | public ForceAuthException(string error, string description, string[] fields) 19 | : this(error, description) 20 | { 21 | Fields = fields; 22 | } 23 | 24 | public ForceAuthException(Error error, string description, string[] fields) 25 | : this(error, description) 26 | { 27 | Fields = fields; 28 | } 29 | 30 | public ForceAuthException(string error, string description, HttpStatusCode httpStatusCode) 31 | : this(ParseError(error), description) 32 | { 33 | this.HttpStatusCode = httpStatusCode; 34 | } 35 | 36 | public ForceAuthException(Error error, string description) 37 | : base(description) 38 | { 39 | Error = error; 40 | Fields = new string[0]; 41 | HttpStatusCode = new HttpStatusCode(); 42 | } 43 | 44 | private static Error ParseError(string error) 45 | { 46 | Error value; 47 | return Enum.TryParse(error.Replace("_", ""), true, out value) ? value : Error.Unknown; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/ForceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using Salesforce.Common.Models; 4 | using Salesforce.Common.Models.Json; 5 | 6 | namespace Salesforce.Common 7 | { 8 | public class ForceException : Exception, IForceException 9 | { 10 | public string[] Fields { get; private set; } 11 | public HttpStatusCode HttpStatusCode { get; private set; } 12 | public Error Error { get; private set; } 13 | 14 | public ForceException(string error, string description) 15 | : this(ParseError(error), description) 16 | { 17 | } 18 | 19 | public ForceException(string error, string description, string[] fields) 20 | : this(error, description) 21 | { 22 | Fields = fields; 23 | } 24 | 25 | public ForceException(Error error, string description, string[] fields) 26 | : this(error, description) 27 | { 28 | Fields = fields; 29 | } 30 | 31 | public ForceException(string error, string description, HttpStatusCode httpStatusCode) 32 | : this(ParseError(error), description) 33 | { 34 | this.HttpStatusCode = httpStatusCode; 35 | } 36 | 37 | public ForceException(Error error, string description) 38 | : base(description) 39 | { 40 | Error = error; 41 | Fields = new string[0]; 42 | HttpStatusCode = new HttpStatusCode(); 43 | } 44 | 45 | private static Error ParseError(string error) 46 | { 47 | Error value; 48 | return Enum.TryParse(error.Replace("_", ""), true, out value) ? value : Error.Unknown; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IAttributedObject.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Salesforce.Common.Models.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Salesforce.Common 10 | { 11 | /// 12 | /// Interface enforcing implementation of Attributes Property for multiple record updates 13 | /// 14 | public interface IAttributedObject 15 | { 16 | [JsonProperty(PropertyName = "attributes")] 17 | ObjectAttributes Attributes { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IAuthenticationClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Salesforce.Common 5 | { 6 | public interface IAuthenticationClient : IDisposable 7 | { 8 | string InstanceUrl { get; set; } 9 | string RefreshToken { get; set; } 10 | string AccessToken { get; set; } 11 | string Id { get; set; } 12 | string ApiVersion { get; set; } 13 | 14 | Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password); 15 | Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl); 16 | Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code); 17 | Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl); 18 | Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret = ""); 19 | Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret, string tokenRequestEndpointUrl); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IForceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | namespace Salesforce.Common 5 | { 6 | public interface IForceException 7 | { 8 | Exception GetBaseException(); 9 | string ToString(); 10 | IDictionary Data { get; } 11 | Exception InnerException { get; } 12 | string Message { get; } 13 | string StackTrace { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IJsonHttpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Salesforce.Common.Models.Json; 5 | using Newtonsoft.Json; 6 | 7 | namespace Salesforce.Common 8 | { 9 | public interface IJsonHttpClient : IDisposable 10 | { 11 | 12 | // GET 13 | Task HttpGetAsync(string urlSuffix); 14 | Task HttpGetAsync(Uri uri); 15 | Task> HttpGetAsync(string urlSuffix, string nodeName); 16 | Task HttpGetRestApiAsync(string apiName); 17 | 18 | // POST 19 | Task HttpPostAsync(object inputObject, string urlSuffix); 20 | Task HttpPostAsync(object inputObject, Uri uri); 21 | Task HttpPostRestApiAsync(string apiName, object inputObject); 22 | Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName); 23 | 24 | // PATCH 25 | Task HttpPatchAsync(object inputObject, string urlSuffix); 26 | Task HttpPatchAsync(object inputObject, Uri uri); 27 | Task HttpPatchAsync(object inputObject, string urlSuffix, bool ignoreNull); 28 | Task HttpPatchAsync(object inputObject, Uri uri, NullValueHandling nullValueHandling); 29 | 30 | // DELETE 31 | Task HttpDeleteAsync(string urlSuffix); 32 | Task HttpDeleteAsync(Uri uri); 33 | } 34 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IServiceHttpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Salesforce.Common.Models; 5 | using Salesforce.Common.Models.Json; 6 | 7 | namespace Salesforce.Common 8 | { 9 | public interface IServiceHttpClient : IDisposable 10 | { 11 | Task HttpGetAsync(string urlSuffix); 12 | Task HttpGetRestApiAsync(string apiName); 13 | Task> HttpGetAsync(string urlSuffix, string nodeName); 14 | Task HttpGetAsync(Uri uri); 15 | Task HttpPostRestApiAsync(string apiName, object inputObject); 16 | Task HttpPostAsync(object inputObject, string urlSuffix); 17 | Task HttpPostAsync(object inputObject, Uri uri); 18 | Task HttpPatchAsync(object inputObject, string urlSuffix); 19 | Task HttpDeleteAsync(string urlSuffix); 20 | Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName); 21 | } 22 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/IXmlHttpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Salesforce.Common 5 | { 6 | public interface IXmlHttpClient: IDisposable 7 | { 8 | // GET 9 | Task HttpGetAsync(string urlSuffix); 10 | Task HttpGetAsync(Uri uri); 11 | 12 | // POST 13 | Task HttpPostAsync(object inputObject, string urlSuffix); 14 | Task HttpPostAsync(object inputObject, Uri uri); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Internals/BaseHttpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Internals 9 | { 10 | public abstract class BaseHttpClient : IDisposable 11 | { 12 | private const string UserAgent = "forcedotcom-toolkit-dotnet"; 13 | private readonly string _contentType; 14 | private readonly bool _disposeHttpClient; 15 | 16 | 17 | protected readonly string InstanceUrl; 18 | protected string ApiVersion; 19 | protected readonly HttpClient HttpClient; 20 | 21 | internal BaseHttpClient(string instanceUrl, string apiVersion, string contentType, HttpClient httpClient, bool callerWillDisposeHttpClient = false) 22 | { 23 | if (string.IsNullOrEmpty(instanceUrl)) throw new ArgumentNullException("instanceUrl"); 24 | if (string.IsNullOrEmpty(apiVersion)) throw new ArgumentNullException("apiVersion"); 25 | if (string.IsNullOrEmpty(contentType)) throw new ArgumentNullException("contentType"); 26 | if (httpClient == null) throw new ArgumentNullException("httpClient"); 27 | 28 | InstanceUrl = instanceUrl; 29 | ApiVersion = apiVersion; 30 | _contentType = contentType; 31 | _disposeHttpClient = !callerWillDisposeHttpClient; 32 | HttpClient = httpClient; 33 | 34 | HttpClient.DefaultRequestHeaders.UserAgent.Clear(); 35 | HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); 36 | 37 | HttpClient.DefaultRequestHeaders.Accept.Clear(); 38 | HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_contentType)); 39 | 40 | //HttpClient.DefaultRequestHeaders.AcceptEncoding.Clear(); 41 | //HttpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); 42 | } 43 | 44 | public string GetApiVersion() 45 | { 46 | return ApiVersion; 47 | } 48 | 49 | protected async Task HttpGetAsync(Uri uri) 50 | { 51 | var responseMessage = await HttpClient.GetAsync(uri).ConfigureAwait(false); 52 | if (responseMessage.StatusCode == HttpStatusCode.NoContent) 53 | { 54 | return string.Empty; 55 | } 56 | 57 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 58 | if (responseMessage.IsSuccessStatusCode) 59 | { 60 | return response; 61 | } 62 | 63 | throw new BaseHttpClientException(response, responseMessage.StatusCode); 64 | } 65 | 66 | protected async Task HttpPostAsync(string payload, Uri uri) 67 | { 68 | var content = new StringContent(payload, Encoding.UTF8, _contentType); 69 | 70 | var responseMessage = await HttpClient.PostAsync(uri, content).ConfigureAwait(false); 71 | if (responseMessage.StatusCode == HttpStatusCode.NoContent) 72 | { 73 | return string.Empty; 74 | } 75 | 76 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 77 | if (responseMessage.IsSuccessStatusCode) 78 | { 79 | return response; 80 | } 81 | 82 | throw new BaseHttpClientException(response, responseMessage.StatusCode); 83 | } 84 | 85 | protected async Task HttpPatchAsync(string payload, Uri uri) 86 | { 87 | var content = new StringContent(payload, Encoding.UTF8, _contentType); 88 | 89 | var request = new HttpRequestMessage 90 | { 91 | RequestUri = uri, 92 | Method = new HttpMethod("PATCH"), 93 | Content = content 94 | }; 95 | 96 | var responseMessage = await HttpClient.SendAsync(request).ConfigureAwait(false); 97 | if (responseMessage.StatusCode == HttpStatusCode.NoContent) 98 | { 99 | return string.Empty; 100 | } 101 | 102 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 103 | if (responseMessage.IsSuccessStatusCode) 104 | { 105 | return response; 106 | } 107 | 108 | throw new BaseHttpClientException(response, responseMessage.StatusCode); 109 | } 110 | 111 | protected async Task HttpDeleteAsync(Uri uri) 112 | { 113 | var responseMessage = await HttpClient.DeleteAsync(uri).ConfigureAwait(false); 114 | if (responseMessage.StatusCode == HttpStatusCode.NoContent) 115 | { 116 | return string.Empty; 117 | } 118 | 119 | var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); 120 | if (responseMessage.IsSuccessStatusCode) 121 | { 122 | return response; 123 | } 124 | 125 | throw new BaseHttpClientException(response, responseMessage.StatusCode); 126 | } 127 | 128 | public void Dispose() 129 | { 130 | if (_disposeHttpClient) 131 | { 132 | HttpClient.Dispose(); 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Internals/BaseHttpClientException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace Salesforce.Common.Internals 5 | { 6 | internal sealed class BaseHttpClientException : Exception 7 | { 8 | private readonly HttpStatusCode _httpStatusCode; 9 | 10 | internal BaseHttpClientException(string response, HttpStatusCode statusCode) : base(response) 11 | { 12 | _httpStatusCode = statusCode; 13 | } 14 | 15 | internal HttpStatusCode GetStatus() 16 | { 17 | return _httpStatusCode; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/AnonymousExecutionResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Common.Models.Json 4 | { 5 | public class AnonymousExecutionResponse 6 | { 7 | [JsonProperty(PropertyName = "line")] 8 | public int Line { get; set; } 9 | [JsonProperty(PropertyName = "column")] 10 | public int Column { get; set; } 11 | [JsonProperty(PropertyName = "compiled")] 12 | public bool Compiled { get; set; } 13 | [JsonProperty(PropertyName = "success")] 14 | public bool Success { get; set; } 15 | [JsonProperty(PropertyName = "exceptionStackTrace")] 16 | public string ExceptionStackTrace { get; set; } 17 | [JsonProperty(PropertyName = "exceptionMessage")] 18 | public string ExceptionMessage { get; set; } 19 | [JsonProperty(PropertyName = "compileProblem")] 20 | public string CompileProblem { get; set; } 21 | 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/Attributes.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class AttributeInfo 11 | { 12 | [JsonProperty(PropertyName = "type")] 13 | public string TypeName { get; set; } 14 | 15 | [JsonProperty(PropertyName = "referenceId")] 16 | public string ReferenceId { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/AuthErrorResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Common.Models.Json 4 | { 5 | public class AuthErrorResponse 6 | { 7 | [JsonProperty(PropertyName = "error_description")] 8 | public string ErrorDescription; 9 | 10 | [JsonProperty(PropertyName = "error")] 11 | public string Error; 12 | } 13 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/AuthToken.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Common.Models.Json 4 | { 5 | public class AuthToken 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id; 9 | 10 | [JsonProperty(PropertyName = "issued_at")] 11 | public string IssuedAt; 12 | 13 | [JsonProperty(PropertyName = "instance_url")] 14 | public string InstanceUrl; 15 | 16 | [JsonProperty(PropertyName = "signature")] 17 | public string Signature; 18 | 19 | [JsonProperty(PropertyName = "access_token")] 20 | public string AccessToken; 21 | 22 | [JsonProperty(PropertyName = "refresh_token")] 23 | public string RefreshToken; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/CreateRequest.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class CreateRequest 11 | { 12 | [JsonProperty(PropertyName = "records")] 13 | public List Records { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/DescribeGlobalResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Common.Models.Json 5 | { 6 | public class DescribeGlobalResult 7 | { 8 | [JsonProperty(PropertyName = "encoding")] 9 | public string Encoding { get; set; } 10 | 11 | [JsonProperty(PropertyName = "maxBatchSize")] 12 | public int MaxBatchSize { get; set; } 13 | 14 | [JsonProperty(PropertyName = "sobjects")] 15 | public List SObjects { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/DisplayTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Common.Models.Json 2 | { 3 | public enum DisplayTypes 4 | { 5 | Page, 6 | Popup, 7 | Touch, 8 | Mobile 9 | } 10 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/Error.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Common.Models.Json 2 | { 3 | public enum Error 4 | { 5 | Unknown, 6 | InvalidClient, 7 | UnsupportedGrantType, 8 | InvalidGrant, 9 | AuthenticationFailure, 10 | InvalidPassword, 11 | ClientIdentifierInvalid, 12 | NotFound, 13 | MalformedQuery, 14 | FieldCustomValidationException, 15 | InvalidFieldForInsertUpdate, 16 | InvalidClientId, 17 | InvalidField, 18 | RequiredFieldMissing, 19 | StringTooLong, 20 | EntityIsDeleted, 21 | FieldIntegrityException, 22 | ApiCurrentlyDisabled, 23 | ApiDisabledForOrg, 24 | CantAddStandardPortalUserToTerritory, 25 | CircularObjectGraph, 26 | ClientNotAccessibleForUser, 27 | ClientRequiredUpdateForUser, 28 | DeleteRequiredOnCascade, 29 | DuplicateCommNickname, 30 | EmailBatchSizeLimitExceeded, 31 | EmailToCaseInvalidRouting, 32 | EmailToCaseLimitExceeded, 33 | EmailToCaseNotEnabled, 34 | ExceededIdLimit, 35 | ExceededLeadConvertLimit, 36 | ExceededMaxSizeRequest, 37 | ExceededMaxTypesLimit, 38 | ExceededQuota, 39 | FunctionalityNotEnabled, 40 | InactiveOwnerOrUser, 41 | InactivePortal, 42 | InsufficientAccess, 43 | InvalidAssignmentRule, 44 | InvalidBatchSize, 45 | InvalidCrossReferenceKey, 46 | InvalidFilterLanguage, 47 | InvalidFilterValue, 48 | InvalidIdField, 49 | InvalidGoogleDocsUrl, 50 | InvalidLocator, 51 | InvalidLogin, 52 | InvalidNewPassword, 53 | InvalidOperation, 54 | InvalidOperationWithExpiredPassword, 55 | InvalidQueryFilterOperator, 56 | InvalidQueryLocator, 57 | InvalidQueryScope, 58 | InvalidReplicationDate, 59 | InvalidSetupOwner, 60 | InvalidSearch, 61 | InvalidSearchScope, 62 | InvalidSessionId, 63 | InvalidSoapHeader, 64 | InvalidSsoGatewayUrl, 65 | InvalidType, 66 | InvalidTypeForOperation, 67 | LimitExceeded, 68 | LoginDuringRestrictedDomain, 69 | LoginDUringRestrictedTime, 70 | MalformedId, 71 | MalformedSearch, 72 | MissingArgument, 73 | MixedDmlOperation, 74 | NotModified, 75 | NoSoftphoneLayout, 76 | NumberOutsideValidRange, 77 | OperationTooLarge, 78 | OrgLocked, 79 | OrgNotOwnedByInstance, 80 | PasswordLockout, 81 | PortalNoAccess, 82 | QueryTimeout, 83 | QueryTooComplicated, 84 | RequestLimitExceeded, 85 | RequestRunningTooLong, 86 | ServerUnavailable, 87 | SsoServiceDown, 88 | TooManyApexRequests, 89 | TrialExpired, 90 | UnsupportedApiVersion, 91 | UnsupportedClient, 92 | AllOrNoneOperationRolledBack, 93 | AlreadyInProcess, 94 | AssigneeTypeRequired, 95 | BadCustomEntityParentDomain, 96 | BccNotAllowedIfBccComplianceEnabled, 97 | BccSelfNotAllowedIfBccComplianceEnabled, 98 | CannotCascadeProductActive, 99 | CannotChangeFileTypeOfApexReferencedField, 100 | CannotCreateAnotherManagedPackage, 101 | CannotDeactivateDivision, 102 | CannotDeleteLastDatedConversionRate, 103 | CannotDeleteManagedObject, 104 | CannotDisableLastAdmin, 105 | CannotEnableIpRestrictedRequests, 106 | CannotInsertUpdateActivateEntity, 107 | CannotModifyManagedObject, 108 | CannotRenameApexReferencedField, 109 | CannotRenameApexReferencedObject, 110 | CannotReparentRecord, 111 | CannotResolveName, 112 | CannotUpdateConvertedLead, 113 | CannotDisableCorpCurrency, 114 | CanntUnsetCorpCurrency, 115 | ChildShareFailsParent, 116 | CircularDependency, 117 | CommunityNotAccessible, 118 | CustomClobFieldLimitExceeded, 119 | CustomEntityOrFieldLimit, 120 | CustomFieldIndexLimitExceeded, 121 | CustomIndexExists, 122 | CustomLinkLimitExceeded, 123 | CustomTabLimitExceeded, 124 | DeleteFailed, 125 | DependencyExists, 126 | DuplicateCaseSolution, 127 | DuplicateCustomEntityDefinition, 128 | DuplicateCustomTabMotif, 129 | DuplicateDeveloperName, 130 | DuplicatesDetected, 131 | DuplicateExternalId, 132 | DuplicateMasterLabel, 133 | DuplicateSenderDisplayName, 134 | DuplicateUsername, 135 | DuplicateValue, 136 | EmailAddressBounced, 137 | EmailNotProcessedDueToPriorError, 138 | EmailOptedOut, 139 | EmailTemplateFormulaError, 140 | EmailTemplateMergefieldAccessError, 141 | EmailTemplateMergefieldError, 142 | EmailTemplateMergaefieldValueError, 143 | EmailTemplateProcessingError, 144 | EmptyScontrolFileName, 145 | EntityFailedIflastmodifiedOnUpdate, 146 | EntityIsArchived, 147 | EnvironmentHubMembershipConflict, 148 | ErrorInMailer, 149 | FailedActivation, 150 | FieldFilterValidationException, 151 | FilteredLookupLimitExceeded, 152 | HtmlFileUploadNotAllowed, 153 | ImageTooLarge, 154 | InsertUpdateDeleteNotAllowedDuringMaintance, 155 | InsufficientAccessOnCrossReferenceEntity, 156 | InsufficientAccessOrReadonly, 157 | InvalidAccessLevel, 158 | InvalidArgumentType, 159 | InvalidAssigneeType, 160 | InvalidBatchOperation, 161 | InvalidContentType, 162 | InvalidCreditCardInfo, 163 | InvalidCrossReferenceTypeForField, 164 | InvalidCurrencyConvRate, 165 | InvalidCurrencyCorpRate, 166 | InvalidCurrencyIso, 167 | InvalidEmailAddress, 168 | InvalidEmptyKeyOwner, 169 | InvalidEventSubscription, 170 | InvalidFieldWhenUsingTemplate, 171 | InvalidFilterAction, 172 | InvalidInetAddress, 173 | InvalidLineItemCloneState, 174 | InvalidMasterOrTranslatedSolution, 175 | InvalidMessageIdReference, 176 | InvalidOperator, 177 | InvalidOrNullForRestrictedPicklist, 178 | InvalidPartnerNetworkStatus, 179 | InvalidPersonAccountOperation, 180 | InvalidReadOnlyUserDml, 181 | InvalidSaveAsActivityFlag, 182 | InvalidStatus, 183 | InvalidTypeOnFieldInRecord, 184 | IpRangeLimitExceeded, 185 | JigsawImportLimitExceeded, 186 | LicenseLimitExceeded, 187 | LightPortalUserException, 188 | LoginChallengeIssued, 189 | LoginChallengePending, 190 | LoginMustUseSecurityToken, 191 | ManagerNotDefined, 192 | MassmailRetryLimitExceeded, 193 | MaximumCcemailsExceeded, 194 | MaximumDashboardComponentsExceeded, 195 | MaximumHierarchyLevelsReached, 196 | MaximumSizeOfAttachment, 197 | MaximumSizeOfDocument, 198 | MaxActionsPerRuleExceeded, 199 | MaxActiveRulesExceeded, 200 | MaxApprovalStepsExceeded, 201 | MaxFormulasPerRuleExceeded, 202 | MaxRulesExceeded, 203 | MaxRuleEntriesExceeded, 204 | MaxTaskDescriptionExceeded, 205 | MaxTmRulesExceeded, 206 | MaxTmRuleItemsExceeded, 207 | MergeFailed, 208 | NonuniqueShippingAddress, 209 | NoApplicableProcess, 210 | NoAttachmentPermission, 211 | NoInactiveDivisonMembers, 212 | NoMassMailPermission, 213 | NumHistoryFieldsBySobjectExceeded, 214 | OpWithInvalidUserTypeException, 215 | OptedOutOfMassMail, 216 | PackageLicenseRequired, 217 | PortalUserAlreadyExistsForContact, 218 | PrivateContactOnAsset, 219 | RecordInUseByWorkflow, 220 | SelfRefenceFromTrigger, 221 | ShareNeededForChildOwner, 222 | SingleEmailLimitExceeded, 223 | StandardPriceNotDefined, 224 | StorageLimitExceeded, 225 | TabsetLimitExceeded, 226 | TemplateNotActive, 227 | TerritoryRealignInProcess, 228 | TextDataOutsideSupportedCharset, 229 | TooManyEnumValue, 230 | TransferRequiresRead, 231 | UnableToLockRow, 232 | UnavailableRecordTypeException, 233 | UndeleteFailed, 234 | UnknownException, 235 | UnspecifiedEmailAddress, 236 | UnsupportedApexTriggerOperation, 237 | UnverifiedSenderAddress, 238 | WeblinkSizeLimitExceeded, 239 | WrongControllerType, 240 | NonJsonErrorResponse, 241 | WeblinkUrlInvalid 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Common.Models.Json 5 | { 6 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", 7 | ElementName = "error", 8 | IsNullable = false)] 9 | public class ErrorResponse 10 | { 11 | [XmlElement(ElementName = "exceptionMessage")] 12 | [JsonProperty(PropertyName = "message")] 13 | public string Message; 14 | 15 | [XmlElement(ElementName = "exceptionCode")] 16 | [JsonProperty(PropertyName = "errorCode")] 17 | public string ErrorCode; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/ErrorResponses.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Salesforce.Common.Models.Json 4 | { 5 | public class ErrorResponses : List { } 6 | } 7 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/ErrorResult.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class ErrorResult 11 | { 12 | [JsonProperty(PropertyName = "statusCode")] 13 | public string StatusCode { get; set; } 14 | 15 | [JsonProperty(PropertyName = "message")] 16 | public string Message { get; set; } 17 | 18 | [JsonProperty(PropertyName = "fields")] 19 | public List Fields { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/ObjectAttributes.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class ObjectAttributes 11 | { 12 | [JsonProperty(PropertyName = "type")] 13 | public string Type { get; set; } 14 | 15 | [JsonProperty(PropertyName = "referenceId")] 16 | public string ReferenceId { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/QueryResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Common.Models.Json 5 | { 6 | public class QueryResult 7 | { 8 | [JsonProperty(PropertyName = "nextRecordsUrl")] 9 | public string NextRecordsUrl { get; set; } 10 | 11 | [JsonProperty(PropertyName = "totalSize")] 12 | public int TotalSize { get; set; } 13 | 14 | [JsonProperty(PropertyName = "done")] 15 | public bool Done { get; set; } 16 | 17 | [JsonProperty(PropertyName = "records")] 18 | public List Records { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/ResponseTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Common.Models.Json 2 | { 3 | public enum ResponseTypes 4 | { 5 | Code, 6 | Token 7 | } 8 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/SaveResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class SaveResponse 11 | { 12 | [JsonProperty(PropertyName = "hasErrors")] 13 | public bool HasErrors { get; set; } 14 | 15 | [JsonProperty(PropertyName = "results")] 16 | public List Results { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/SaveResult.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Salesforce.Common.Models.Json 9 | { 10 | public class SaveResult 11 | { 12 | [JsonProperty(PropertyName = "id")] 13 | public string Id { get; set; } 14 | 15 | [JsonProperty(PropertyName = "referenceId")] 16 | public string ReferenceId { get; set; } 17 | 18 | [JsonProperty(PropertyName = "errors")] 19 | public Error[] Errors { get; set; } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/SuccessResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Salesforce.Common.Models.Json 4 | { 5 | public class SuccessResponse 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id; 9 | 10 | [JsonProperty(PropertyName = "success")] 11 | public bool Success; 12 | 13 | [JsonProperty(PropertyName = "errors")] 14 | public object Errors; 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/UserInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Common.Models.Json 5 | { 6 | public class UserInfo 7 | { 8 | [JsonProperty(PropertyName = "id")] 9 | public string Id; 10 | 11 | [JsonProperty(PropertyName = "asserted_user")] 12 | public bool AssertedUser; 13 | 14 | [JsonProperty(PropertyName = "user_id")] 15 | public string UserId; 16 | 17 | [JsonProperty(PropertyName = "organization_id")] 18 | public string OrganizationId; 19 | 20 | [JsonProperty(PropertyName = "username")] 21 | public string Username; 22 | 23 | [JsonProperty(PropertyName = "nick_name")] 24 | public string NickName; 25 | 26 | [JsonProperty(PropertyName = "display_name")] 27 | public string DisplayName; 28 | 29 | [JsonProperty(PropertyName = "email")] 30 | public string Email; 31 | 32 | [JsonProperty(PropertyName = "email_verified")] 33 | public bool EmailVerified; 34 | 35 | [JsonProperty(PropertyName = "first_name")] 36 | public string FirstName; 37 | 38 | [JsonProperty(PropertyName = "last_name")] 39 | public string LastName; 40 | 41 | [JsonProperty(PropertyName = "status")] 42 | public Dictionary Status; 43 | 44 | [JsonProperty(PropertyName = "Photos")] 45 | public Dictionary Photos; 46 | 47 | [JsonProperty(PropertyName = "AddressStreet")] 48 | public string AddressStreet; 49 | 50 | [JsonProperty(PropertyName = "AddressCity")] 51 | public string AddressCity; 52 | 53 | [JsonProperty(PropertyName = "AddressState")] 54 | public string AddressState; 55 | 56 | [JsonProperty(PropertyName = "AddressCountry")] 57 | public string AddressCountry; 58 | 59 | [JsonProperty(PropertyName = "addr_zip")] 60 | public string AddressZip; 61 | 62 | [JsonProperty(PropertyName = "mobile_phone")] 63 | public string MobilePhone; 64 | 65 | [JsonProperty(PropertyName = "mobile_phone_verified")] 66 | public bool MobilePhoneVerified; 67 | 68 | [JsonProperty(PropertyName = "urls")] 69 | public Dictionary Urls; 70 | 71 | [JsonProperty(PropertyName = "active")] 72 | public bool Active; 73 | 74 | [JsonProperty(PropertyName = "user_type")] 75 | public string UserType; 76 | 77 | [JsonProperty(PropertyName = "language")] 78 | public string Language; 79 | 80 | [JsonProperty(PropertyName = "locale")] 81 | public string Locale; 82 | 83 | [JsonProperty(PropertyName = "utcOffset")] 84 | public string UtcOffset; 85 | 86 | [JsonProperty(PropertyName = "last_modified_date")] 87 | public string LastModifiedDate; 88 | 89 | [JsonProperty(PropertyName = "is_app_installed")] 90 | public bool IsAppInstalled; 91 | 92 | [JsonProperty(PropertyName = "custom_attributes")] 93 | public Dictionary CustomAttributes; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Json/Version.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Salesforce.Common.Models.Json 6 | { 7 | public class Version : IComparable 8 | { 9 | public string label { get; set; } 10 | public string url { get; set; } 11 | public string version { get; set; } 12 | 13 | public int CompareTo(Version other) 14 | { 15 | if (other == null) 16 | return -1; 17 | return string.Compare(version, other.version); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/BatchInfoResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Salesforce.Common.Models.Xml 5 | { 6 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", 7 | ElementName = "batchInfo", 8 | IsNullable = false)] 9 | public class BatchInfoResult 10 | { 11 | [XmlElement(ElementName = "id")] 12 | public string Id { get; set; } 13 | 14 | [XmlElement(ElementName = "jobId")] 15 | public string JobId { get; set; } 16 | 17 | [XmlElement(ElementName = "state")] 18 | public string State { get; set; } 19 | 20 | [XmlElement(ElementName = "createdDate")] 21 | public DateTime CreatedDate { get; set; } 22 | 23 | [XmlElement(ElementName = "systemModstamp")] 24 | public DateTime SystemModstamp { get; set; } 25 | 26 | [XmlElement(ElementName = "numberRecordsProcessed")] 27 | public int NumberRecordsProcessed { get; set; } 28 | 29 | protected bool Equals(BatchInfoResult other) 30 | { 31 | return string.Equals(Id, other.Id); 32 | } 33 | 34 | public override bool Equals(object obj) 35 | { 36 | if (ReferenceEquals(null, obj)) return false; 37 | if (ReferenceEquals(this, obj)) return true; 38 | return obj.GetType() == GetType() && Equals((BatchInfoResult) obj); 39 | } 40 | 41 | public override int GetHashCode() 42 | { 43 | return (Id != null ? Id.GetHashCode() : 0); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/BatchResult.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Salesforce.Common.Models.Xml 4 | { 5 | [XmlType(TypeName = "result")] 6 | public class BatchResult 7 | { 8 | [XmlElement(ElementName = "id")] 9 | public string Id { get; set; } 10 | 11 | [XmlElement(ElementName = "success")] 12 | public bool Success { get; set; } 13 | 14 | [XmlElement(ElementName = "created")] 15 | public bool Created { get; set; } 16 | 17 | [XmlElement(ElementName = "errors")] 18 | public BatchResultErrors Errors { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/BatchResultErrors.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Serialization; 3 | 4 | namespace Salesforce.Common.Models.Xml 5 | { 6 | [XmlType(TypeName = "errors")] 7 | public class BatchResultErrors 8 | { 9 | [XmlElement(ElementName = "fields")] 10 | public List Fields { get; set; } 11 | 12 | [XmlElement(ElementName = "message")] 13 | public string Message { get; set; } 14 | 15 | [XmlElement(ElementName = "statusCode")] 16 | public string StatusCode { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/BatchResultList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Serialization; 3 | 4 | namespace Salesforce.Common.Models.Xml 5 | { 6 | [XmlRoot(ElementName = "results", 7 | Namespace = "http://www.force.com/2009/06/asyncapi/dataload")] 8 | public class BatchResultList 9 | { 10 | public BatchResultList() 11 | { 12 | Items = new List(); 13 | } 14 | 15 | [XmlElement("result")] 16 | public List Items; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/ISObjectList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Serialization; 3 | 4 | namespace Salesforce.Common.Models.Xml 5 | { 6 | public interface ISObjectList : IList, IXmlSerializable 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/JobInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Salesforce.Common.Models.Xml 4 | { 5 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", 6 | ElementName = "jobInfo", 7 | IsNullable = false)] 8 | public class JobInfo 9 | { 10 | [XmlElement(ElementName = "operation")] 11 | public string Operation { get; set; } 12 | 13 | [XmlElement(ElementName = "object")] 14 | public string Object { get; set; } 15 | 16 | [XmlElement(ElementName = "externalIdFieldName")] 17 | public string ExternalIdFieldName { get; set; } 18 | 19 | [XmlIgnore] 20 | public bool ExternalIdFieldNameSpecified => !string.IsNullOrEmpty(ExternalIdFieldName); 21 | 22 | [XmlElement(ElementName = "contentType")] 23 | public string ContentType { get; set; } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/JobInfoResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Salesforce.Common.Models.Xml 5 | { 6 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", 7 | ElementName = "jobInfo", 8 | IsNullable = false)] 9 | public class JobInfoResult : JobInfo 10 | { 11 | [XmlElement(ElementName = "id")] 12 | public string Id { get; set; } 13 | 14 | [XmlElement(ElementName = "createdById")] 15 | public string CreatedById { get; set; } 16 | 17 | [XmlElement(ElementName = "createdDate")] 18 | public DateTime CreatedDate { get; set; } 19 | 20 | [XmlElement(ElementName = "systemModstamp")] 21 | public DateTime SystemModstamp { get; set; } 22 | 23 | [XmlElement(ElementName = "state")] 24 | public string State { get; set; } 25 | 26 | [XmlElement(ElementName = "concurrencyMode")] 27 | public string ConcurrencyMode { get; set; } 28 | 29 | [XmlElement(ElementName = "numberBatchesQueued")] 30 | public int NumberBatchesQueued { get; set; } 31 | 32 | [XmlElement(ElementName = "numberBatchesInProgress")] 33 | public int NumberBatchesInProgress { get; set; } 34 | 35 | [XmlElement(ElementName = "numberBatchesCompleted")] 36 | public int NumberBatchesCompleted { get; set; } 37 | 38 | [XmlElement(ElementName = "numberBatchesFailed")] 39 | public int NumberBatchesFailed { get; set; } 40 | 41 | [XmlElement(ElementName = "numberBatchesTotal")] 42 | public int NumberBatchesTotal { get; set; } 43 | 44 | [XmlElement(ElementName = "numberRecordsProcessed")] 45 | public int NumberRecordsProcessed { get; set; } 46 | 47 | [XmlElement(ElementName = "numberRetries")] 48 | public int NumberRetries { get; set; } 49 | 50 | [XmlElement(ElementName = "apiVersion")] 51 | public float ApiVersion { get; set; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/JobInfoState.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Salesforce.Common.Models.Xml 4 | { 5 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", 6 | ElementName = "jobInfo", 7 | IsNullable = false)] 8 | public class JobInfoState 9 | { 10 | [XmlElement(ElementName = "state")] 11 | public string State { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/SObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Xml; 4 | using System.Xml.Schema; 5 | using System.Xml.Serialization; 6 | 7 | namespace Salesforce.Common.Models.Xml 8 | { 9 | public sealed class SObject : Dictionary, IXmlSerializable 10 | { 11 | 12 | public XmlSchema GetSchema() 13 | { 14 | return null; 15 | } 16 | 17 | public void ReadXml(XmlReader reader) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | 22 | public void WriteXml(XmlWriter writer) 23 | { 24 | writer.WriteRaw(""); 25 | foreach (var entry in this) 26 | { 27 | var value = entry.Value as IXmlSerializable; 28 | if (value != null) 29 | { 30 | writer.WriteRaw(string.Format("<{0}>", entry.Key)); 31 | value.WriteXml(writer); 32 | writer.WriteRaw(string.Format("", entry.Key)); 33 | } 34 | else 35 | { 36 | writer.WriteRaw(string.Format("<{0}>{1}", entry.Key, entry.Value)); 37 | } 38 | } 39 | writer.WriteRaw(""); 40 | } 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Models/Xml/SObjectList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Xml; 5 | using System.Xml.Schema; 6 | using System.Xml.Serialization; 7 | 8 | namespace Salesforce.Common.Models.Xml 9 | { 10 | [XmlRoot(Namespace = "http://www.force.com/2009/06/asyncapi/dataload", ElementName = "sObjects")] 11 | public sealed class SObjectList : List, ISObjectList 12 | { 13 | 14 | public XmlSchema GetSchema() 15 | { 16 | return null; 17 | } 18 | 19 | public void ReadXml(XmlReader reader) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | 24 | public void WriteXml(XmlWriter writer) 25 | { 26 | foreach (var entry in this) 27 | { 28 | var value = entry as IXmlSerializable; 29 | if (value != null) 30 | { 31 | value.WriteXml(writer); 32 | } 33 | else 34 | { 35 | var xmlSerializer = new XmlSerializer(typeof(T), new XmlRootAttribute("sObject")); 36 | var ns = new XmlSerializerNamespaces(); 37 | ns.Add(string.Empty, string.Empty); 38 | var settings = new XmlWriterSettings {OmitXmlDeclaration = true}; 39 | var stringBuilder = new StringBuilder(); 40 | using (var xmlWriter = XmlWriter.Create(stringBuilder, settings)) 41 | { 42 | xmlSerializer.Serialize(xmlWriter, entry, ns); 43 | } 44 | writer.WriteRaw(stringBuilder.ToString()); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: NeutralResourcesLanguage("en")] 13 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Serializer/CreateableContractResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Newtonsoft.Json; 6 | using Newtonsoft.Json.Serialization; 7 | using Salesforce.Common.Attributes; 8 | 9 | namespace Salesforce.Common.Serializer 10 | { 11 | public class CreateableContractResolver : DefaultContractResolver 12 | { 13 | protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) 14 | { 15 | return base.CreateProperties(type, memberSerialization) 16 | .Where(p => IsPropertyCreatable(type, p)) 17 | .ToList(); 18 | } 19 | 20 | private static bool IsPropertyCreatable(Type type, JsonProperty property) 21 | { 22 | var isCreateable = true; 23 | var propInfo = type.GetRuntimeProperty(property.PropertyName); 24 | 25 | if (propInfo != null) 26 | { 27 | var createableAttr = propInfo.GetCustomAttribute(typeof(CreateableAttribute), false); 28 | isCreateable = createableAttr == null || ((CreateableAttribute)createableAttr).Createable; 29 | } 30 | 31 | return isCreateable; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Serializer/UpdateableContractResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Newtonsoft.Json; 6 | using Newtonsoft.Json.Serialization; 7 | using Salesforce.Common.Attributes; 8 | 9 | namespace Salesforce.Common.Serializer 10 | { 11 | public class UpdateableContractResolver : DefaultContractResolver 12 | { 13 | protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) 14 | { 15 | return base.CreateProperties(type, memberSerialization) 16 | .Where(p => IsPropertyUpdateable(type, p)) 17 | .ToList(); 18 | } 19 | 20 | private static bool IsPropertyUpdateable(Type type, JsonProperty property) 21 | { 22 | var isUpdateable = true; 23 | var propInfo = type.GetRuntimeProperty(property.PropertyName); 24 | 25 | if (propInfo != null) 26 | { 27 | var updateableAttr = propInfo.GetCustomAttribute(typeof(UpdateableAttribute), false); 28 | isUpdateable = updateableAttr == null || ((UpdateableAttribute)updateableAttr).Updateable; 29 | } 30 | 31 | return isUpdateable; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Soql/DataMemberSelectListResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Salesforce.Common.Soql 6 | { 7 | public class DataMemberSelectListResolver : ISelectListResolver 8 | { 9 | public string GetFieldsList() 10 | { 11 | var fields = typeof(T).GetRuntimeProperties() 12 | .Where(p => { 13 | var customAttribute = p.GetCustomAttribute(); 14 | return (customAttribute == null); 15 | }) 16 | .Select(p => { 17 | var customAttribute = p.GetCustomAttribute(); 18 | return (customAttribute == null || customAttribute.Name == null) ? p.Name : customAttribute.Name; 19 | }); 20 | 21 | return string.Join(", ", fields); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Soql/ISelectListResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Salesforce.Common.Soql 8 | { 9 | public interface ISelectListResolver 10 | { 11 | string GetFieldsList(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/Soql/JsonPropertySelectListResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using Newtonsoft.Json; 4 | 5 | namespace Salesforce.Common.Soql 6 | { 7 | public class JsonPropertySelectListResolver : ISelectListResolver 8 | { 9 | private bool _ignorePropsWithoutAttribute; 10 | public JsonPropertySelectListResolver(bool ignorePropsWithoutAttribute = false) 11 | { 12 | _ignorePropsWithoutAttribute = ignorePropsWithoutAttribute; 13 | } 14 | 15 | public string GetFieldsList() 16 | { 17 | var propInfo = typeof(T).GetRuntimeProperties(); 18 | 19 | if (_ignorePropsWithoutAttribute) 20 | propInfo = propInfo.Where(p => p.GetCustomAttribute() != null); 21 | 22 | var fields = propInfo.Select(p => { 23 | var customAttribute = p.GetCustomAttribute(); 24 | return (customAttribute == null || customAttribute.PropertyName == null) ? p.Name : customAttribute.PropertyName; 25 | }); 26 | 27 | return string.Join(", ", fields); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/CommonLibrariesForNET/XmlHttpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using System.Xml; 6 | using System.Xml.Serialization; 7 | using Salesforce.Common.Internals; 8 | using Salesforce.Common.Models.Json; 9 | 10 | namespace Salesforce.Common 11 | { 12 | public class XmlHttpClient : BaseHttpClient, IXmlHttpClient 13 | { 14 | public XmlHttpClient(string instanceUrl, string apiVersion, string accessToken, HttpClient httpClient, bool callerWillDisposeHttpClient = false) 15 | : base(instanceUrl, apiVersion, "application/xml", httpClient, callerWillDisposeHttpClient) 16 | { 17 | if (ApiVersion.StartsWith("v", StringComparison.OrdinalIgnoreCase)) 18 | { 19 | ApiVersion = ApiVersion.Substring(1); 20 | } 21 | HttpClient.DefaultRequestHeaders.Add("X-SFDC-Session", accessToken); 22 | } 23 | 24 | // GET 25 | 26 | public async Task HttpGetAsync(string urlSuffix) 27 | { 28 | var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); 29 | return await HttpGetAsync(url); 30 | } 31 | 32 | public async Task HttpGetAsync(Uri uri) 33 | { 34 | try 35 | { 36 | var response = await HttpGetAsync(uri); 37 | return DeserializeXmlString(response); 38 | } 39 | catch (BaseHttpClientException e) 40 | { 41 | throw ParseForceException(e.Message); 42 | } 43 | } 44 | 45 | // POST 46 | 47 | public async Task HttpPostAsync(object inputObject, string urlSuffix) 48 | { 49 | var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); 50 | return await HttpPostAsync(inputObject, url); 51 | } 52 | 53 | public async Task HttpPostAsync(object inputObject, Uri uri) 54 | { 55 | var postBody = SerializeXmlObject(inputObject); 56 | try 57 | { 58 | var response = await HttpPostAsync(postBody, uri); 59 | return DeserializeXmlString(response); 60 | } 61 | catch (BaseHttpClientException e) 62 | { 63 | throw ParseForceException(e.Message); 64 | } 65 | } 66 | 67 | // HELPER METHODS 68 | 69 | private static ForceException ParseForceException(string responseMessage) 70 | { 71 | var errorResponse = DeserializeXmlString(responseMessage); 72 | return new ForceException(errorResponse.ErrorCode, errorResponse.Message); 73 | } 74 | 75 | private static string SerializeXmlObject(object inputObject) 76 | { 77 | var xmlSerializer = new XmlSerializer(inputObject.GetType()); 78 | var stringWriter = new StringWriter(); 79 | string result; 80 | using (var writer = XmlWriter.Create(stringWriter)) 81 | { 82 | xmlSerializer.Serialize(writer, inputObject); 83 | result = stringWriter.ToString(); 84 | } 85 | return result; 86 | } 87 | 88 | private static T DeserializeXmlString(string inputString) 89 | { 90 | var serializer = new XmlSerializer(typeof(T)); 91 | T result; 92 | using (TextReader reader = new StringReader(inputString)) 93 | { 94 | result = (T) serializer.Deserialize(reader); 95 | } 96 | return result; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/ForceTookitForNet.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wadewegner/Force.com-Toolkit-for-NET/279cefeca536c13f8018ac5f80de4d81291d0dd7/src/ForceTookitForNet.snk -------------------------------------------------------------------------------- /src/ForceToolkitForNET.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForceToolkitForNET", "ForceToolkitForNET\ForceToolkitForNET.csproj", "{557C1C7D-B9CF-475D-B938-047003142B56}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLibrariesForNET", "CommonLibrariesForNET\CommonLibrariesForNET.csproj", "{D759EF69-D74C-4429-B3A0-CA7D879AE561}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatterToolkitForNET", "ChatterToolkitForNET\ChatterToolkitForNET.csproj", "{9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|x64.Build.0 = Debug|Any CPU 29 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {557C1C7D-B9CF-475D-B938-047003142B56}.Debug|x86.Build.0 = Debug|Any CPU 31 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|x64.ActiveCfg = Release|Any CPU 34 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|x64.Build.0 = Release|Any CPU 35 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|x86.ActiveCfg = Release|Any CPU 36 | {557C1C7D-B9CF-475D-B938-047003142B56}.Release|x86.Build.0 = Release|Any CPU 37 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|x64.Build.0 = Debug|Any CPU 41 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Debug|x86.Build.0 = Debug|Any CPU 43 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|x64.ActiveCfg = Release|Any CPU 46 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|x64.Build.0 = Release|Any CPU 47 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|x86.ActiveCfg = Release|Any CPU 48 | {D759EF69-D74C-4429-B3A0-CA7D879AE561}.Release|x86.Build.0 = Release|Any CPU 49 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|x64.ActiveCfg = Debug|Any CPU 52 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|x64.Build.0 = Debug|Any CPU 53 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|x86.ActiveCfg = Debug|Any CPU 54 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Debug|x86.Build.0 = Debug|Any CPU 55 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|x64.ActiveCfg = Release|Any CPU 58 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|x64.Build.0 = Release|Any CPU 59 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|x86.ActiveCfg = Release|Any CPU 60 | {9D998DDE-14CC-4D2C-ABB6-1F2D34AE3F6F}.Release|x86.Build.0 = Release|Any CPU 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /src/ForceToolkitForNET/BulkConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Force 2 | { 3 | public static class BulkConstants 4 | { 5 | public sealed class OperationType 6 | { 7 | public static readonly OperationType Insert = new OperationType("insert"); 8 | public static readonly OperationType Update = new OperationType("update"); 9 | public static readonly OperationType Upsert = new OperationType("upsert"); 10 | public static readonly OperationType Delete = new OperationType("delete"); 11 | public static readonly OperationType HardDelete = new OperationType("hardDelete"); 12 | 13 | private readonly string _value; 14 | 15 | private OperationType(string value) 16 | { 17 | _value = value; 18 | } 19 | 20 | public string Value() 21 | { 22 | return _value; 23 | } 24 | } 25 | 26 | public sealed class BatchState 27 | { 28 | public static readonly BatchState Queued = new BatchState("Queued"); 29 | public static readonly BatchState InProgress = new BatchState("InProgress"); 30 | public static readonly BatchState Completed = new BatchState("Completed"); 31 | public static readonly BatchState Failed = new BatchState("Failed"); 32 | public static readonly BatchState NotProcessed = new BatchState("Not Processed"); 33 | 34 | private readonly string _value; 35 | 36 | private BatchState(string value) 37 | { 38 | _value = value; 39 | } 40 | 41 | public string Value() 42 | { 43 | return _value; 44 | } 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ForceToolkitForNET/ForceToolkitForNET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0;net452;net462;net472 4 | $(TargetsForTfmSpecificBuildOutput);IncludeSalesforceCommon 5 | Salesforce.Force 6 | Salesforce.Force 7 | true 8 | ..\ForceTookitForNet.snk 9 | Salesforce.Force 10 | salesforce.com 11 | Salesforce.Force 12 | 13 | Copyright © 2018 14 | false 15 | 1.0.0.0 16 | 1.0.0.0 17 | 18 | 19 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.5.2\1.0.1\lib\net452\ 20 | 21 | 22 | 23 | 24 | 25 | 26 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.6.2\1.0.1\lib\net462\ 27 | 28 | 29 | 30 | 31 | 32 | 33 | $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.7.2\1.0.0\lib\net472\ 34 | 35 | 36 | 37 | 38 | 39 | 40 | DeveloperForce.Force 41 | DeveloperForce.Force 42 | 2.1.0 43 | wadewegner 44 | The DeveloperForce.Force NuGet provides a .NET library for interacting with Salesforce Lightning REST APIs. 45 | https://raw.github.com/developerforce/Force.com-Toolkit-for-NET/master/LICENSE 46 | https://github.com/developerforce/Force.com-Toolkit-for-NET/ 47 | https://raw.github.com/developerforce/Force.com-Toolkit-for-NET/master/scripts/assets/avatar.png 48 | Copyright 2018 49 | salesforce forcedotcom force.com force rest api 50 | 51 | 52 | true 53 | ..\ForceTookitForNet.snk 54 | false 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/ForceToolkitForNET/IForceClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Salesforce.Common.Models.Json; 5 | using Salesforce.Common.Models.Xml; 6 | 7 | namespace Salesforce.Force 8 | { 9 | public interface IForceClient : IDisposable 10 | { 11 | 12 | // STANDARD 13 | Task> QueryAsync(string query); 14 | Task> QueryContinuationAsync(string nextRecordsUrl); 15 | Task> QueryAllAsync(string query); 16 | Task QueryByIdAsync(string objectName, string recordId); 17 | Task QueryAllFieldsByIdAsync(string objectName, string recordId); 18 | Task QueryAllFieldsByExternalIdAsync(string objectName, string externalIdFieldName, string externalId); 19 | Task ExecuteRestApiAsync(string apiName); 20 | Task ExecuteRestApiAsync(string apiName, object inputObject); 21 | Task CreateAsync(string objectName, object record); 22 | Task CreateAsync(string objectName, CreateRequest request); 23 | Task UpdateAsync(string objectName, string recordId, object record); 24 | Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record); 25 | Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record, bool ignoreNull); 26 | Task DeleteAsync(string objectName, string recordId); 27 | Task DeleteExternalAsync(string objectName, string externalFieldName, string externalId); 28 | Task> GetObjectsAsync(); 29 | Task BasicInformationAsync(string objectName); 30 | Task DescribeAsync(string objectName); 31 | Task GetDeleted(string objectName, DateTime startDateTime, DateTime endDateTime); 32 | Task GetUpdated(string objectName, DateTime startDateTime, DateTime endDateTime); 33 | Task DescribeLayoutAsync(string objectName); 34 | Task DescribeLayoutAsync(string objectName, string recordTypeId); 35 | Task RecentAsync(int limit = 200); 36 | Task> SearchAsync(string query); 37 | Task UserInfo(string url); 38 | Task GetBlobAsync(String objectName, String objectId, String fieldName); 39 | Task GetFieldsCommaSeparatedListAsync(string objectName); 40 | Task ExecuteAnonymousAsync(string apex); 41 | 42 | // BULK 43 | Task> RunJobAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists); 44 | Task> RunJobAndPollAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists); 45 | Task CreateJobAsync(string objectName, BulkConstants.OperationType operationType); 46 | Task CreateJobBatchAsync(JobInfoResult jobInfo, ISObjectList recordsObject); 47 | Task CreateJobBatchAsync(string jobId, ISObjectList recordsObject); 48 | Task CloseJobAsync(JobInfoResult jobInfo); 49 | Task CloseJobAsync(string jobId); 50 | Task PollJobAsync(JobInfoResult jobInfo); 51 | Task PollJobAsync(string jobId); 52 | Task PollBatchAsync(BatchInfoResult batchInfo); 53 | Task PollBatchAsync(string batchId, string jobId); 54 | Task GetBatchResultAsync(BatchInfoResult batchInfo); 55 | Task GetBatchResultAsync(string batchId, string jobId); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/ForceToolkitForNET/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: NeutralResourcesLanguage("en")] 13 | -------------------------------------------------------------------------------- /src/ForceToolkitForNET/tools/Install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $readmeFile = "http://www.wadewegner.com/2014/01/announcing-the-salesforce-toolkits-for-net/" 4 | $DTE.ItemOperations.Navigate($readmeFile, [EnvDTE.vsNavigateOptions]::vsNavigateOptionsNewWindow) -------------------------------------------------------------------------------- /src/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForceToolkitForNET.Tests", "ForceToolkitForNET.Tests\ForceToolkitForNET.Tests.csproj", "{732F58EE-5777-4568-81F2-2F37FD957969}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|x64.ActiveCfg = Debug|Any CPU 24 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|x64.Build.0 = Debug|Any CPU 25 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|x86.ActiveCfg = Debug|Any CPU 26 | {732F58EE-5777-4568-81F2-2F37FD957969}.Debug|x86.Build.0 = Debug|Any CPU 27 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|x64.ActiveCfg = Release|Any CPU 30 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|x64.Build.0 = Release|Any CPU 31 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|x86.ActiveCfg = Release|Any CPU 32 | {732F58EE-5777-4568-81F2-2F37FD957969}.Release|x86.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/BulkTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Xml; 5 | using System.Threading.Tasks; 6 | using System.Xml.Serialization; 7 | using NUnit.Framework; 8 | using Salesforce.Common; 9 | 10 | namespace Salesforce.Force.Tests 11 | { 12 | [TestFixture] 13 | public class BulkTests 14 | { 15 | private const string UserAgent = "forcedotcom-toolkit-dotnet"; 16 | 17 | [Test] 18 | public async Task Requests_CheckHttpRequestMessage_HttpGetXml() 19 | { 20 | var client = new HttpClient(new BulkServiceClientRouteHandler(r => 21 | { 22 | // the v should be removed... 23 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/32/brad"); 24 | 25 | Assert.IsNotNull(r.Headers.UserAgent); 26 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v32"); 27 | 28 | Assert.IsNotNull(r.Headers.GetValues("X-SFDC-Session")); 29 | Assert.IsTrue(r.Headers.GetValues("X-SFDC-Session").Count() == 1); 30 | Assert.AreEqual(r.Headers.GetValues("X-SFDC-Session").First(), "accessToken"); 31 | }, new object())); 32 | 33 | using (var httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) 34 | { 35 | await httpClient.HttpGetAsync("brad"); 36 | } 37 | } 38 | 39 | [Test] 40 | public async Task Requests_CheckHttpRequestMessageAndResponseDeserialization_HttpPostXml() 41 | { 42 | var testObject = new SerializerTest { TestField = "testMessage" }; 43 | var client = new HttpClient(new BulkServiceClientRouteHandler(r => 44 | { 45 | // the v should be removed... 46 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/32/brad"); 47 | 48 | Assert.IsNotNull(r.Headers.UserAgent); 49 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v32"); 50 | 51 | Assert.IsNotNull(r.Headers.GetValues("X-SFDC-Session")); 52 | Assert.IsTrue(r.Headers.GetValues("X-SFDC-Session").Count() == 1); 53 | Assert.AreEqual(r.Headers.GetValues("X-SFDC-Session").First(), "accessToken"); 54 | 55 | // check the object is serialized as expected 56 | var serializedPayload = MimicSerialization(testObject); 57 | var stringContent = r.Content.ReadAsStringAsync().Result; 58 | Assert.AreEqual(serializedPayload, stringContent); 59 | 60 | }, testObject)); // pass in the object to be returned (Same object roundtripped here for simplicity) 61 | 62 | using (var httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) 63 | { 64 | var result = await httpClient.HttpPostAsync(testObject, "brad"); 65 | Assert.AreEqual(testObject.TestField, result.TestField); 66 | } 67 | } 68 | 69 | [XmlRoot(ElementName = "test_Object")] 70 | public class SerializerTest 71 | { 72 | [XmlElement(ElementName = "test_Field")] 73 | public string TestField { get; set; } 74 | } 75 | 76 | private static string MimicSerialization(object inputObject) 77 | { 78 | var xmlSerializer = new XmlSerializer(inputObject.GetType()); 79 | var stringWriter = new StringWriter(); 80 | string result; 81 | using (var writer = XmlWriter.Create(stringWriter)) 82 | { 83 | xmlSerializer.Serialize(writer, inputObject); 84 | result = stringWriter.ToString(); 85 | } 86 | return result; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/ChatterClientFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | using NUnit.Framework; 8 | using Salesforce.Chatter.Models; 9 | using Salesforce.Common; 10 | 11 | namespace Salesforce.Chatter.FunctionalTests 12 | { 13 | [TestFixture] 14 | public class ChatterClientTests 15 | { 16 | private static string _consumerKey = ConfigurationManager.AppSettings["ConsumerKey"]; 17 | private static string _consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"]; 18 | private static string _username = ConfigurationManager.AppSettings["Username"]; 19 | private static string _password = ConfigurationManager.AppSettings["Password"]; 20 | 21 | private AuthenticationClient _auth; 22 | private ChatterClient _chatterClient; 23 | 24 | [OneTimeSetUp] 25 | public void Init() 26 | { 27 | if (string.IsNullOrEmpty(_consumerKey) && string.IsNullOrEmpty(_consumerSecret) && string.IsNullOrEmpty(_username) && string.IsNullOrEmpty(_password)) 28 | { 29 | _consumerKey = Environment.GetEnvironmentVariable("ConsumerKey"); 30 | _consumerSecret = Environment.GetEnvironmentVariable("ConsumerSecret"); 31 | _username = Environment.GetEnvironmentVariable("Username"); 32 | _password = Environment.GetEnvironmentVariable("Password"); 33 | } 34 | 35 | // Use TLS 1.2 (instead of defaulting to 1.0) 36 | const int SecurityProtocolTypeTls11 = 768; 37 | const int SecurityProtocolTypeTls12 = 3072; 38 | ServicePointManager.SecurityProtocol |= (SecurityProtocolType)(SecurityProtocolTypeTls12 | SecurityProtocolTypeTls11); 39 | 40 | _auth = new AuthenticationClient(); 41 | _auth.UsernamePasswordAsync(_consumerKey, _consumerSecret, _username, _password).Wait(); 42 | 43 | _chatterClient = new ChatterClient(_auth.InstanceUrl, _auth.AccessToken, _auth.ApiVersion); 44 | } 45 | 46 | [Test] 47 | public void Chatter_IsNotNull() 48 | { 49 | Assert.IsNotNull(_chatterClient); 50 | } 51 | 52 | [Test] 53 | public async Task Chatter_Feeds_IsNotNull() 54 | { 55 | var feeds = await _chatterClient.FeedsAsync(); 56 | 57 | Assert.IsNotNull(feeds); 58 | } 59 | 60 | [Test] 61 | public async Task Chatter_Users_Me_IsNotNull() 62 | { 63 | var me = await _chatterClient.MeAsync(); 64 | 65 | Assert.IsNotNull(me); 66 | } 67 | 68 | [Test] 69 | public async Task Chatter_Users_Me_Id_IsNotNull() 70 | { 71 | var me = await _chatterClient.MeAsync(); 72 | 73 | Assert.IsNotNull(me.id); 74 | } 75 | 76 | [Test] 77 | public async Task Chatter_PostFeedItem() 78 | { 79 | var feedItem = await postFeedItem(_chatterClient); 80 | Assert.IsNotNull(feedItem); 81 | } 82 | 83 | [Test] 84 | public async Task Chatter_Add_Comment() 85 | { 86 | var feedItem = await postFeedItem(_chatterClient); 87 | var feedId = feedItem.Id; 88 | 89 | var messageSegment = new MessageSegmentInput 90 | { 91 | Text = "Comment testing 1, 2, 3", 92 | Type = "Text" 93 | }; 94 | 95 | var body = new MessageBodyInput { MessageSegments = new List { messageSegment } }; 96 | var commentInput = new FeedItemInput 97 | { 98 | Attachment = null, 99 | Body = body 100 | }; 101 | 102 | var comment = await _chatterClient.PostFeedItemCommentAsync(commentInput, feedId); 103 | Assert.IsNotNull(comment); 104 | } 105 | 106 | [Test] 107 | public async Task Chatter_Add_Comment_With_Mention_IsNotNull() 108 | { 109 | var feedItem = await postFeedItem(_chatterClient); 110 | var feedId = feedItem.Id; 111 | 112 | var me = await _chatterClient.MeAsync(); 113 | var meId = me.id; 114 | 115 | var messageSegment1 = new MessageSegmentInput 116 | { 117 | Id = meId, 118 | Type = "Mention", 119 | }; 120 | 121 | var messageSegment2 = new MessageSegmentInput 122 | { 123 | Text = "Comment testing 1, 2, 3", 124 | Type = "Text", 125 | }; 126 | 127 | var body = new MessageBodyInput 128 | { 129 | MessageSegments = new List 130 | { 131 | messageSegment1, 132 | messageSegment2 133 | } 134 | }; 135 | var commentInput = new FeedItemInput 136 | { 137 | Attachment = null, 138 | Body = body 139 | }; 140 | 141 | var comment = await _chatterClient.PostFeedItemCommentAsync(commentInput, feedId); 142 | Assert.IsNotNull(comment); 143 | } 144 | 145 | [Test] 146 | public async Task Chatter_Like_FeedItem_IsNotNull() 147 | { 148 | var feedItem = await postFeedItem(_chatterClient); 149 | var feedId = feedItem.Id; 150 | 151 | var liked = await _chatterClient.LikeFeedItemAsync(feedId); 152 | 153 | Assert.IsNotNull(liked); 154 | } 155 | 156 | [Test] 157 | public async Task Chatter_Share_FeedItem_IsNotNull() 158 | { 159 | var feedItem = await postFeedItem(_chatterClient); 160 | var feedId = feedItem.Id; 161 | 162 | var me = await _chatterClient.MeAsync(); 163 | var meId = me.id; 164 | 165 | var sharedFeedItem = await _chatterClient.ShareFeedItemAsync(feedId, meId); 166 | 167 | Assert.IsNotNull(sharedFeedItem); 168 | } 169 | 170 | [Test] 171 | public async Task Chatter_Get_My_News_Feed_IsNotNull() 172 | { 173 | var myNewsFeeds = await _chatterClient.GetMyNewsFeedAsync(); 174 | 175 | Assert.IsNotNull(myNewsFeeds); 176 | } 177 | 178 | [Test] 179 | public async Task Chatter_Get_My_News_Feed_WithQuery_IsNotNull() 180 | { 181 | var myNewsFeeds = await _chatterClient.GetMyNewsFeedAsync("wade"); 182 | 183 | Assert.IsNotNull(myNewsFeeds); 184 | } 185 | 186 | [Test] 187 | public async Task Chatter_Get_Groups_IsNotNull() 188 | { 189 | var groups = await _chatterClient.GetGroupsAsync(); 190 | 191 | Assert.IsNotNull(groups); 192 | } 193 | 194 | [Test] 195 | public async Task Chatter_Get_Group_News_Feed_IsNotNull() 196 | { 197 | var groups = await _chatterClient.GetGroupsAsync(); 198 | if (groups.Groups.Count > 0) 199 | { 200 | var groupId = groups.Groups[0].Id; 201 | var groupFeed = await _chatterClient.GetGroupFeedAsync(groupId); 202 | 203 | Assert.IsNotNull(groupFeed); 204 | } 205 | else 206 | { 207 | Assert.AreEqual(0, groups.Groups.Count); 208 | } 209 | } 210 | 211 | [Test] 212 | public async Task Chatter_Get_Topics_IsNotNull() 213 | { 214 | var topics = await _chatterClient.GetTopicsAsync(); 215 | 216 | Assert.IsNotNull(topics); 217 | } 218 | 219 | [Test] 220 | public async Task Chatter_Get_Users_IsNotNull() 221 | { 222 | var users = await _chatterClient.GetUsersAsync(); 223 | 224 | Assert.IsNotNull(users); 225 | } 226 | 227 | #region private functions 228 | private async Task postFeedItem(ChatterClient chatter) 229 | { 230 | var me = await chatter.MeAsync(); 231 | var id = me.id; 232 | 233 | var messageSegment = new MessageSegmentInput 234 | { 235 | Text = "Testing 1, 2, 3", 236 | Type = "Text" 237 | }; 238 | 239 | var body = new MessageBodyInput { MessageSegments = new List { messageSegment } }; 240 | var feedItemInput = new FeedItemInput() 241 | { 242 | Attachment = null, 243 | Body = body, 244 | SubjectId = id, 245 | FeedElementType = "FeedItem" 246 | }; 247 | 248 | var feedItem = await chatter.PostFeedItemAsync(feedItemInput, id); 249 | return feedItem; 250 | } 251 | #endregion 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/CommonFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | using NUnit.Framework; 8 | using Salesforce.Force.Tests.Models; 9 | using Salesforce.Common; 10 | using Salesforce.Common.Models.Json; 11 | using Salesforce.Common.Models.Xml; 12 | 13 | namespace Salesforce.Force.Tests 14 | { 15 | [TestFixture] 16 | public class CommonFunctionalTests 17 | { 18 | private static string _consumerKey = ConfigurationManager.AppSettings["ConsumerKey"]; 19 | private static string _consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"]; 20 | private static string _username = ConfigurationManager.AppSettings["Username"]; 21 | private static string _password = ConfigurationManager.AppSettings["Password"]; 22 | 23 | private AuthenticationClient _auth; 24 | private JsonHttpClient _jsonHttpClient; 25 | 26 | [OneTimeSetUp] 27 | public void Init() 28 | { 29 | if (string.IsNullOrEmpty(_consumerKey) && string.IsNullOrEmpty(_consumerSecret) && string.IsNullOrEmpty(_username) && string.IsNullOrEmpty(_password)) 30 | { 31 | _consumerKey = Environment.GetEnvironmentVariable("ConsumerKey"); 32 | _consumerSecret = Environment.GetEnvironmentVariable("ConsumerSecret"); 33 | _username = Environment.GetEnvironmentVariable("Username"); 34 | _password = Environment.GetEnvironmentVariable("Password"); 35 | } 36 | 37 | // Use TLS 1.2 (instead of defaulting to 1.0) 38 | 39 | const int SecurityProtocolTypeTls11 = 768; 40 | const int SecurityProtocolTypeTls12 = 3072; 41 | 42 | ServicePointManager.SecurityProtocol |= (SecurityProtocolType)(SecurityProtocolTypeTls12 | SecurityProtocolTypeTls11); 43 | 44 | //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 45 | 46 | _auth = new AuthenticationClient(); 47 | _auth.UsernamePasswordAsync(_consumerKey, _consumerSecret, _username, _password).Wait(); 48 | 49 | _jsonHttpClient = new JsonHttpClient(_auth.InstanceUrl, _auth.ApiVersion, _auth.AccessToken, new HttpClient()); 50 | } 51 | 52 | [Test] 53 | public async Task Get_UserInfo() 54 | { 55 | var objectName = new FormUrlEncodedContent(new[] 56 | { 57 | new KeyValuePair("AccessToken", _auth.AccessToken) 58 | }); 59 | 60 | var response = await _jsonHttpClient.HttpGetAsync(new Uri(_auth.Id)); 61 | 62 | Assert.IsNotNull(response); 63 | } 64 | 65 | [Test] 66 | public async Task Query_Describe() 67 | { 68 | const string objectName = "Account"; 69 | var response = await _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}", objectName)); 70 | 71 | Assert.IsNotNull(response); 72 | } 73 | 74 | [Test] 75 | public async Task Query_Objects() 76 | { 77 | var response = await _jsonHttpClient.HttpGetAsync>(string.Format("sobjects")); 78 | 79 | Assert.IsTrue(response.MaxBatchSize > 0); 80 | Assert.IsTrue(response.SObjects.Count > 0); 81 | } 82 | 83 | [Test] 84 | public async Task Query_Select_Account() 85 | { 86 | const string query = "SELECT Id FROM Account"; 87 | var response = await _jsonHttpClient.HttpGetAsync>(string.Format("query?q={0}", query)); 88 | 89 | Assert.IsTrue(response.TotalSize > 0); 90 | Assert.IsTrue(response.Records.Count > 0); 91 | } 92 | 93 | [Test] 94 | public async Task Query_Select_Count() 95 | { 96 | const string query = "SELECT count() FROM Account"; 97 | var response = await _jsonHttpClient.HttpGetAsync>(string.Format("query?q={0}", query)); 98 | 99 | Assert.IsTrue(response.TotalSize > 0); 100 | Assert.IsTrue(response.Records.Count == 0); 101 | } 102 | 103 | [Test] 104 | public void Auth_UsernamePassword_HasAccessToken() 105 | { 106 | Assert.That(_auth.AccessToken, Is.Not.Null.And.Not.Empty); 107 | } 108 | 109 | [Test] 110 | public void Auth_UsernamePassword_HasInstanceUrl() 111 | { 112 | Assert.That(_auth.InstanceUrl, Is.Not.Null.And.Not.Empty); 113 | } 114 | 115 | [Test] 116 | public async Task Auth_InvalidLogin() 117 | { 118 | try 119 | { 120 | await _auth.UsernamePasswordAsync(_consumerKey, _consumerSecret, _username, "WRONGPASSWORD"); 121 | } 122 | catch (ForceAuthException ex) 123 | { 124 | Assert.IsNotNull(ex); 125 | Assert.IsNotNull(ex.Message); 126 | Assert.IsNotNull(ex.Error); 127 | Assert.IsNotNull(ex.HttpStatusCode); 128 | 129 | Assert.AreEqual(ex.Message, "authentication failure"); 130 | Assert.AreEqual(ex.Error, Error.InvalidGrant); 131 | Assert.AreEqual(ex.HttpStatusCode, HttpStatusCode.BadRequest); 132 | } 133 | } 134 | 135 | [Test] 136 | public async Task Auth_InvalidRequestEndpointUrl() 137 | { 138 | const string requestEndpointUrl = "https://login.salesforce.com/services/oauth2/authorizeee"; // typo in the url 139 | 140 | try 141 | { 142 | await _auth.WebServerAsync("clientId", "clientSecret", "sfdc://success", "code", requestEndpointUrl); 143 | } 144 | catch (ForceAuthException ex) 145 | { 146 | Assert.IsNotNull(ex); 147 | 148 | Assert.AreEqual(ex.Error, Error.UnknownException); 149 | Assert.AreEqual(ex.Message, "Unexpected character encountered while parsing value: <. Path '', line 0, position 0."); 150 | } 151 | } 152 | 153 | [Test] 154 | public async Task Upsert_Update_CheckReturn() 155 | { 156 | var account = new Account { Name = "New Account ExternalID", Description = "New Account Description" }; 157 | var response = await _jsonHttpClient.HttpPatchAsync(account, string.Format("sobjects/{0}/{1}/{2}", "Account", "ExternalID__c", "2")); 158 | 159 | Assert.IsNotNull(response); 160 | } 161 | 162 | [Test] 163 | public async Task Upsert_New_CheckReturnInclude() 164 | { 165 | var account = new Account { Name = "New Account" + DateTime.Now.Ticks, Description = "New Account Description" + DateTime.Now.Ticks }; 166 | var response = await _jsonHttpClient.HttpPatchAsync(account, string.Format("sobjects/{0}/{1}/{2}", "Account", "ExternalID__c", DateTime.Now.Ticks)); 167 | 168 | Assert.IsNotNull(response); 169 | Assert.IsNotNull(response.Id); 170 | } 171 | 172 | [Test] 173 | public async Task BadTokenHandling() 174 | { 175 | var badToken = "badtoken"; 176 | var serviceHttpClient = new JsonHttpClient(_auth.InstanceUrl, _auth.ApiVersion, badToken, new HttpClient()); 177 | 178 | const string query = "SELECT count() FROM Account"; 179 | 180 | try 181 | { 182 | await serviceHttpClient.HttpGetAsync>(string.Format("query?q={0}", query)); 183 | } 184 | catch (ForceException ex) 185 | { 186 | Assert.IsNotNull(ex); 187 | Assert.IsNotNull(ex.Message); 188 | Assert.That(ex.Message, Is.EqualTo("Session expired or invalid")); 189 | Assert.IsNotNull(ex.Error); 190 | } 191 | } 192 | 193 | [Test] 194 | public async Task BadTokenHandlingWithXml() 195 | { 196 | var badToken = "badtoken"; 197 | var serviceHttpClient = new XmlHttpClient(_auth.InstanceUrl, _auth.ApiVersion, badToken, new HttpClient()); 198 | 199 | var jobInfo = new JobInfo 200 | { 201 | ContentType = "XML", 202 | Object = "BadObject", 203 | Operation = "BadOperation" 204 | }; 205 | 206 | try 207 | { 208 | await serviceHttpClient.HttpPostAsync(jobInfo, "/services/async/{0}/job"); 209 | } 210 | catch (ForceException ex) 211 | { 212 | Assert.IsNotNull(ex); 213 | Assert.IsNotNull(ex.Message); 214 | Assert.That(ex.Message, Is.EqualTo("Invalid session id")); 215 | Assert.IsNotNull(ex.Error); 216 | } 217 | } 218 | 219 | [Test] 220 | public void CheckInterfaces() 221 | { 222 | using (IAuthenticationClient aa = new AuthenticationClient()) 223 | { 224 | Assert.IsNotNull(aa); 225 | } 226 | using (IJsonHttpClient aa = new JsonHttpClient("instanceUrl", "apiVersion", "accessToken", new HttpClient())) 227 | { 228 | Assert.IsNotNull(aa); 229 | } 230 | using (IXmlHttpClient aa = new XmlHttpClient("instanceUrl", "apiVersion", "accessToken", new HttpClient())) 231 | { 232 | Assert.IsNotNull(aa); 233 | } 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/CommonUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using NUnit.Framework; 5 | using Salesforce.Common; 6 | 7 | namespace Salesforce.Force.Tests 8 | { 9 | [TestFixture] 10 | public class CommonUnitTests 11 | { 12 | private const string UserAgent = "forcedotcom-toolkit-dotnet"; 13 | 14 | [Test] 15 | public void Auth_HasApiVersion() 16 | { 17 | var auth = new AuthenticationClient(); 18 | Assert.That(auth.ApiVersion, Is.Not.Null.And.Not.Empty); 19 | } 20 | 21 | [Test] 22 | public async Task Auth_UsernamePassword_Check() 23 | { 24 | const string consumerKey = "CONSUMERKEY"; 25 | const string consumerSecret = "CONSUMERSECRET"; 26 | const string username = "USERNAME"; 27 | const string password = "PASSWORD"; 28 | 29 | var client = new HttpClient(new AuthenticationClientRouteHandler(r => 30 | { 31 | Assert.IsNotNull(r.Content); 32 | Assert.AreEqual(r.Content.ToString(), "System.Net.Http.FormUrlEncodedContent"); 33 | })); 34 | 35 | using (var auth = new AuthenticationClient(client)) 36 | { 37 | await auth.UsernamePasswordAsync(consumerKey, consumerSecret, username, password); 38 | 39 | Assert.IsNotNull(auth.AccessToken); 40 | Assert.IsNotNull(auth.ApiVersion); 41 | Assert.IsNotNull(auth.InstanceUrl); 42 | Assert.AreEqual(auth.AccessToken, "AccessToken"); 43 | Assert.AreEqual(auth.ApiVersion, "v36.0"); 44 | Assert.AreEqual(auth.InstanceUrl, "InstanceUrl"); 45 | } 46 | } 47 | 48 | [Test] 49 | public async Task Requests_CheckHttpRequestMessage_HttpGet() 50 | { 51 | var client = new HttpClient(new ServiceClientRouteHandler(r => 52 | { 53 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/v36/wade"); 54 | 55 | Assert.IsNotNull(r.Headers.UserAgent); 56 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v36"); 57 | 58 | Assert.IsNotNull(r.Headers.Authorization); 59 | Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); 60 | })); 61 | 62 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 63 | { 64 | try { 65 | await httpClient.HttpGetAsync("wade"); 66 | } catch { 67 | // do nothing 68 | } 69 | } 70 | } 71 | 72 | [Test] 73 | public async Task Requests_CheckHttpRequestMessage_HttpGet_WithNode() 74 | { 75 | var client = new HttpClient(new ServiceClientRouteHandler(r => 76 | { 77 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/v36/wade"); 78 | 79 | Assert.IsNotNull(r.Headers.UserAgent); 80 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v36"); 81 | 82 | Assert.IsNotNull(r.Headers.Authorization); 83 | Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); 84 | })); 85 | 86 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 87 | { 88 | try { 89 | await httpClient.HttpGetAsync("wade"); 90 | } catch { 91 | // do nothing 92 | } 93 | } 94 | } 95 | 96 | [Test] 97 | public async Task Requests_CheckHttpRequestMessage_HttpPost() 98 | { 99 | var client = new HttpClient(new ServiceClientRouteHandler(r => 100 | { 101 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/v36/wade"); 102 | 103 | Assert.IsNotNull(r.Headers.UserAgent); 104 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v36"); 105 | 106 | Assert.IsNotNull(r.Headers.Authorization); 107 | Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); 108 | })); 109 | 110 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 111 | { 112 | try { 113 | await httpClient.HttpPostAsync(null, "wade"); 114 | } catch { 115 | // do nothing 116 | } 117 | } 118 | } 119 | 120 | [Test] 121 | public async Task Requests_CheckHttpRequestMessage_HttpPatch() 122 | { 123 | var client = new HttpClient(new ServiceClientRouteHandler(r => 124 | { 125 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/v36/wade"); 126 | 127 | Assert.IsNotNull(r.Headers.UserAgent); 128 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v36"); 129 | 130 | Assert.IsNotNull(r.Headers.Authorization); 131 | Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); 132 | })); 133 | 134 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 135 | { 136 | try { 137 | await httpClient.HttpPatchAsync(null, "wade"); 138 | } catch { 139 | // do nothing 140 | } 141 | } 142 | } 143 | 144 | [Test] 145 | public async Task Requests_CheckHttpRequestMessage_HttpDelete() 146 | { 147 | var client = new HttpClient(new ServiceClientRouteHandler(r => 148 | { 149 | Assert.AreEqual(r.RequestUri.ToString(), "http://localhost:1899/services/data/v36/wade"); 150 | 151 | Assert.IsNotNull(r.Headers.UserAgent); 152 | Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v36"); 153 | 154 | Assert.IsNotNull(r.Headers.Authorization); 155 | Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); 156 | })); 157 | 158 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 159 | { 160 | try { 161 | await httpClient.HttpDeleteAsync("wade"); 162 | } catch { 163 | // do nothing 164 | } 165 | } 166 | } 167 | 168 | [Test] 169 | public async Task Requests_CheckCustomRequestsHeaders() 170 | { 171 | var client = new HttpClient(new ServiceClientRouteHandler(r => 172 | { 173 | Assert.IsNotNull(r.Headers.GetValues("headername")); 174 | Assert.AreEqual(r.Headers.GetValues("headername").FirstOrDefault(), "headervalue"); 175 | })); 176 | 177 | client.DefaultRequestHeaders.Add("headername", "headervalue"); 178 | 179 | using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) 180 | { 181 | try { 182 | await httpClient.HttpGetAsync("wade"); 183 | } catch { 184 | // do nothing 185 | } 186 | } 187 | } 188 | 189 | [Test] 190 | public void NewServiceHttpClient_ResetsUserAgents() 191 | { 192 | var httpClientUserAgent = UserAgent + "/v36"; 193 | 194 | var httpClient = new HttpClient(); 195 | httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(httpClientUserAgent); 196 | httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(httpClientUserAgent); 197 | Assert.AreEqual(httpClientUserAgent + " " + httpClientUserAgent, httpClient.DefaultRequestHeaders.UserAgent.ToString()); 198 | 199 | var serviceClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", httpClient); 200 | 201 | // Ensure the old user agent header is replaced. 202 | Assert.AreEqual(httpClientUserAgent, httpClient.DefaultRequestHeaders.UserAgent.ToString()); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/ForceClientUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using NUnit.Framework; 5 | using System.Net; 6 | using Salesforce.Force.Tests.Models; 7 | 8 | namespace Salesforce.Force.Tests 9 | { 10 | [TestFixture] 11 | public class ForceClientUnitTests 12 | { 13 | private const string UserAgent = "forcedotcom-toolkit-dotnet"; 14 | private const string ApiVersion = "v36"; 15 | 16 | [Test] 17 | public async Task Requests_CheckHttpRequestMessage_UserAgent() 18 | { 19 | var httpClient = new HttpClient(new ServiceClientRouteHandler(r => Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v32"))); 20 | var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); 21 | 22 | try 23 | { 24 | // suppress error; we only care about checking the header 25 | await forceClient.QueryAsync("query"); 26 | } 27 | catch 28 | { 29 | // do nothing 30 | } 31 | } 32 | 33 | [Test] 34 | public async Task GetBasicInformationAsync_EmptyObjectName_ThrowsException() 35 | { 36 | var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) { Content = new JsonContent(new { }) }; 37 | var httpClient = new HttpClient(new FakeHttpRequestHandler(expectedResponse)); 38 | var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); 39 | 40 | Action asserts = exception => Assert.That(exception.Message, Is.Not.Null); 41 | await AssertEx.ThrowsAsync(() => forceClient.BasicInformationAsync(""), asserts); 42 | } 43 | 44 | [Test] 45 | public async Task GetBasicInformationAsync_ValidObjectName_ReturnsParsedResponse() 46 | { 47 | var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) 48 | { 49 | Content = JsonContent.FromFile("KnownGoodContent/UserObjectDescribeMetadata.json") 50 | }; 51 | var httpClient = new HttpClient(new FakeHttpRequestHandler(expectedResponse)); 52 | var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); 53 | 54 | var result = await forceClient.BasicInformationAsync("ValidObjectName"); 55 | 56 | Assert.IsNotNull(result.Name); 57 | Assert.AreEqual("User", result.Name); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/ForceToolkitForNET.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp2.0 4 | Salesforce.Force.Tests 5 | Salesforce.Force.Tests 6 | true 7 | ..\..\src\ForceTookitForNet.snk 8 | Salesforce.Force.Tests 9 | salesforce.com 10 | Salesforce.Force.Tests 11 | 12 | Copyright © 2018 13 | false 14 | 1.0.0.0 15 | 1.0.0.0 16 | 17 | 18 | true 19 | ..\..\src\ForceTookitForNet.snk 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | runtime; build; native; contentfiles; analyzers 29 | all 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Always 41 | 42 | 43 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/AssertEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using NUnit.Framework; 4 | 5 | namespace Salesforce.Force.Tests 6 | { 7 | public static class AssertEx 8 | { 9 | public static async Task ThrowsAsync(Func func) where TException : class 10 | { 11 | await ThrowsAsync(func, exception => { }); 12 | } 13 | 14 | public static async Task ThrowsAsync(Func func, Action action) where TException : class 15 | { 16 | var exception = default(TException); 17 | var expected = typeof(TException); 18 | Type actual = null; 19 | try 20 | { 21 | await func(); 22 | } 23 | catch (Exception e) 24 | { 25 | exception = e as TException; 26 | actual = e.GetType(); 27 | } 28 | 29 | Assert.AreEqual(expected, actual); 30 | action(exception); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/AuthenticationClientRouteHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Salesforce.Common.Models.Json; 7 | 8 | namespace Salesforce.Force.Tests 9 | { 10 | internal class AuthenticationClientRouteHandler : DelegatingHandler 11 | { 12 | readonly Action _testingAction; 13 | 14 | public AuthenticationClientRouteHandler(Action testingAction) 15 | { 16 | _testingAction = testingAction; 17 | } 18 | 19 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) 20 | { 21 | _testingAction(request); 22 | 23 | var resp = new HttpResponseMessage(HttpStatusCode.OK) 24 | { 25 | Content = new JsonContent(new AuthToken 26 | { 27 | AccessToken = "AccessToken", 28 | Id = "Id", 29 | InstanceUrl = "InstanceUrl", 30 | IssuedAt = "IssuedAt", 31 | Signature = "Signature" 32 | }) 33 | }; 34 | 35 | var tsc = new TaskCompletionSource(); 36 | tsc.SetResult(resp); 37 | return tsc.Task; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/BulkFakeHttpRequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Salesforce.Force.Tests 8 | { 9 | public class BulkFakeHttpRequestHandler : DelegatingHandler 10 | { 11 | readonly List> _testingActions; 12 | readonly List _expectedResponses; 13 | private int _callNum; 14 | 15 | public BulkFakeHttpRequestHandler(List expectedResponses, List> testingActions) 16 | { 17 | _expectedResponses = expectedResponses; 18 | _testingActions = testingActions; 19 | } 20 | 21 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) 22 | { 23 | _testingActions[_callNum](request); 24 | var tsc = new TaskCompletionSource(); 25 | tsc.SetResult(_expectedResponses[_callNum]); 26 | _callNum++; 27 | return tsc.Task; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/BulkServiceClientRouteHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Salesforce.Force.Tests 8 | { 9 | internal class BulkServiceClientRouteHandler : DelegatingHandler 10 | { 11 | readonly Action _testingAction; 12 | public readonly HttpResponseMessage Response; 13 | 14 | public BulkServiceClientRouteHandler(Action testingAction, object response) 15 | { 16 | _testingAction = testingAction; 17 | Response = new HttpResponseMessage(HttpStatusCode.OK) 18 | { 19 | Content = new XmlContent(response) 20 | }; 21 | } 22 | 23 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) 24 | { 25 | _testingAction(request); 26 | var tsc = new TaskCompletionSource(); 27 | tsc.SetResult(Response); 28 | return tsc.Task; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/ExpectedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework.Interfaces; 3 | using NUnit.Framework.Internal; 4 | using NUnit.Framework.Internal.Commands; 5 | 6 | namespace NUnit.Framework 7 | { 8 | /// 9 | /// A simple ExpectedExceptionAttribute 10 | /// 11 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 12 | public class ExpectedExceptionAttribute : NUnitAttribute, IWrapTestMethod 13 | { 14 | private readonly Type _expectedExceptionType; 15 | 16 | public ExpectedExceptionAttribute(Type type) 17 | { 18 | _expectedExceptionType = type; 19 | } 20 | 21 | public TestCommand Wrap(TestCommand command) 22 | { 23 | return new ExpectedExceptionCommand(command, _expectedExceptionType); 24 | } 25 | 26 | private class ExpectedExceptionCommand : DelegatingTestCommand 27 | { 28 | private readonly Type _expectedType; 29 | 30 | public ExpectedExceptionCommand(TestCommand innerCommand, Type expectedType) 31 | : base(innerCommand) 32 | { 33 | _expectedType = expectedType; 34 | } 35 | 36 | public override TestResult Execute(TestExecutionContext context) 37 | { 38 | Type caughtType = null; 39 | 40 | try 41 | { 42 | innerCommand.Execute(context); 43 | } 44 | catch (Exception ex) 45 | { 46 | if (ex is NUnitException) 47 | ex = ex.InnerException; 48 | caughtType = ex.GetType(); 49 | } 50 | 51 | if (caughtType == _expectedType) 52 | context.CurrentResult.SetResult(ResultState.Success); 53 | else if (caughtType != null) 54 | context.CurrentResult.SetResult(ResultState.Failure, 55 | string.Format("Expected {0} but got {1}", _expectedType.Name, caughtType.Name)); 56 | else 57 | context.CurrentResult.SetResult(ResultState.Failure, 58 | string.Format("Expected {0} but no exception was thrown", _expectedType.Name)); 59 | 60 | return context.CurrentResult; 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/FakeHttpRequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Salesforce.Force.Tests 6 | { 7 | public class FakeHttpRequestHandler : DelegatingHandler 8 | { 9 | readonly HttpResponseMessage _expectedResponse; 10 | 11 | public FakeHttpRequestHandler(HttpResponseMessage expectedResponse) 12 | { 13 | _expectedResponse = expectedResponse; 14 | } 15 | 16 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) 17 | { 18 | var tsc = new TaskCompletionSource(); 19 | tsc.SetResult(_expectedResponse); 20 | return tsc.Task; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/JsonContent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | 8 | namespace Salesforce.Force.Tests 9 | { 10 | public class JsonContent : HttpContent 11 | { 12 | private readonly MemoryStream _stream = new MemoryStream(); 13 | 14 | public JsonContent(object value) 15 | { 16 | Headers.ContentType = new MediaTypeHeaderValue("application/json"); 17 | var jw = new JsonTextWriter(new StreamWriter(_stream)) { Formatting = Formatting.Indented }; 18 | var serializer = new JsonSerializer(); 19 | serializer.Serialize(jw, value); 20 | jw.Flush(); 21 | _stream.Position = 0; 22 | } 23 | 24 | protected JsonContent(string content) 25 | { 26 | Headers.ContentType = new MediaTypeHeaderValue("application/json"); 27 | var sw = new StreamWriter(_stream); 28 | sw.Write(content); 29 | sw.Flush(); 30 | _stream.Position = 0; 31 | } 32 | 33 | public static HttpContent FromFile(string filepath) 34 | { 35 | string content = File.ReadAllText(filepath); 36 | return new JsonContent(content); 37 | } 38 | 39 | protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) 40 | { 41 | return _stream.CopyToAsync(stream); 42 | } 43 | 44 | protected override bool TryComputeLength(out long length) 45 | { 46 | length = _stream.Length; 47 | return true; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/ServiceClientRouteHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Salesforce.Force.Tests 8 | { 9 | internal class ServiceClientRouteHandler : DelegatingHandler 10 | { 11 | readonly Action _testingAction; 12 | 13 | public ServiceClientRouteHandler(Action testingAction) 14 | { 15 | _testingAction = testingAction; 16 | } 17 | 18 | //protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) 19 | //{ 20 | // _testingAction(request); 21 | // var resp = new HttpResponseMessage(HttpStatusCode.OK) 22 | // { 23 | // Content = new JsonContent(new 24 | // { 25 | // records = new JsonContent(new 26 | // { 27 | // Success = true, 28 | // Message = "Success" 29 | // }) 30 | // }) 31 | // }; 32 | 33 | // var tsc = new TaskCompletionSource(); 34 | // tsc.SetResult(resp); 35 | // return tsc.Task; 36 | //} 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Helpers/XmlContent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Threading.Tasks; 6 | using System.Xml; 7 | using System.Xml.Serialization; 8 | 9 | namespace Salesforce.Force.Tests 10 | { 11 | public class XmlContent : HttpContent 12 | { 13 | private readonly MemoryStream _stream = new MemoryStream(); 14 | 15 | public XmlContent(object value) 16 | { 17 | Headers.ContentType = new MediaTypeHeaderValue("application/xml"); 18 | var xmlSerializer = new XmlSerializer(value.GetType()); 19 | using (var writer = XmlWriter.Create(_stream)) 20 | { 21 | xmlSerializer.Serialize(writer, value); 22 | } 23 | _stream.Position = 0; 24 | } 25 | 26 | protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) 27 | { 28 | return _stream.CopyToAsync(stream); 29 | } 30 | 31 | protected override bool TryComputeLength(out long length) 32 | { 33 | length = _stream.Length; 34 | return true; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/Account.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Force.Tests.Models 2 | { 3 | public class Account 4 | { 5 | public string Id { get; set; } 6 | public string Name { get; set; } 7 | public string Description { get; set; } 8 | public string ExternalId__c { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/AtrributedAccount.cs: -------------------------------------------------------------------------------- 1 | using Salesforce.Common; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Salesforce.Common.Models.Json; 8 | 9 | namespace Salesforce.Force.Tests.Models 10 | { 11 | public class AtrributedAccount : Account, IAttributedObject 12 | { 13 | public ObjectAttributes Attributes { get; set; } 14 | 15 | public AtrributedAccount() 16 | { 17 | Attributes = new ObjectAttributes() 18 | { 19 | Type = "Account" 20 | }; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/Contact.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Salesforce.Common; 8 | using Salesforce.Common.Attributes; 9 | 10 | namespace Salesforce.Force.Tests.Models 11 | { 12 | public class Contact 13 | { 14 | [Updateable(false), Createable(false)] 15 | public string Id { get; set; } 16 | 17 | [Updateable(false), Createable(false)] 18 | public bool IsDeleted { get; set; } 19 | 20 | public string MasterRecordId { get; set; } 21 | 22 | [Updateable(false), Createable(false)] 23 | public string AccountId { get; set; } 24 | 25 | public string LastName { get; set; } 26 | 27 | public string FirstName { get; set; } 28 | 29 | public string Salutation { get; set; } 30 | 31 | [Updateable(false), Createable(false)] 32 | public string Name { get; set; } 33 | 34 | public string OtherStreet { get; set; } 35 | 36 | public string OtherCity { get; set; } 37 | 38 | public string OtherState { get; set; } 39 | 40 | public string OtherPostalCode { get; set; } 41 | 42 | public string OtherCountry { get; set; } 43 | 44 | [Updateable(false), Createable(false)] 45 | public double? OtherLatitude { get; set; } 46 | 47 | [Updateable(false), Createable(false)] 48 | public double? OtherLongitude { get; set; } 49 | 50 | public object OtherAddress { get; set; } 51 | 52 | public string MailingStreet { get; set; } 53 | 54 | public string MailingCity { get; set; } 55 | 56 | public string MailingState { get; set; } 57 | 58 | public string MailingPostalCode { get; set; } 59 | 60 | public string MailingCountry { get; set; } 61 | 62 | [Updateable(false), Createable(false)] 63 | public double? MailingLatitude { get; set; } 64 | 65 | [Updateable(false), Createable(false)] 66 | public double? MailingLongitude { get; set; } 67 | 68 | [Updateable(false), Createable(false)] 69 | public object MailingAddress { get; set; } 70 | 71 | public string ReportsToId { get; set; } 72 | 73 | public string Title { get; set; } 74 | 75 | public string Department { get; set; } 76 | 77 | public string AssistantName { get; set; } 78 | 79 | public string LeadSource { get; set; } 80 | 81 | public DateTimeOffset? Birthdate { get; set; } 82 | 83 | public string Description { get; set; } 84 | 85 | public string OwnerId { get; set; } 86 | 87 | [Updateable(false), Createable(false)] 88 | public DateTimeOffset CreatedDate { get; set; } 89 | 90 | [Updateable(false), Createable(false)] 91 | public string CreatedById { get; set; } 92 | 93 | [Updateable(false), Createable(false)] 94 | public DateTimeOffset LastModifiedDate { get; set; } 95 | 96 | [Updateable(false), Createable(false)] 97 | public string LastModifiedById { get; set; } 98 | 99 | [Updateable(false), Createable(false)] 100 | public DateTimeOffset SystemModstamp { get; set; } 101 | 102 | [Updateable(false), Createable(false)] 103 | public DateTimeOffset? LastActivityDate { get; set; } 104 | 105 | [Updateable(false), Createable(false)] 106 | public DateTimeOffset? LastCURequestDate { get; set; } 107 | 108 | [Updateable(false), Createable(false)] 109 | public DateTimeOffset? LastCUUpdateDate { get; set; } 110 | 111 | [Updateable(false), Createable(false)] 112 | public DateTimeOffset? LastViewedDate { get; set; } 113 | 114 | [Updateable(false), Createable(false)] 115 | public DateTimeOffset? LastReferencedDate { get; set; } 116 | 117 | [Updateable(false), Createable(false)] 118 | public string EmailBouncedReason { get; set; } 119 | 120 | [Updateable(false), Createable(false)] 121 | public DateTimeOffset? EmailBouncedDate { get; set; } 122 | 123 | [Updateable(false), Createable(false)] 124 | public bool IsEmailBounced { get; set; } 125 | 126 | [Updateable(false), Createable(false)] 127 | public string Jigsaw { get; set; } 128 | 129 | [Updateable(false), Createable(false)] 130 | public string JigsawContactId { get; set; } 131 | 132 | public string Level__c { get; set; } 133 | 134 | public string Languages__c { get; set; } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/ContactsAccountNameQuery.cs: -------------------------------------------------------------------------------- 1 | namespace Salesforce.Force.Tests.Models.QueryTest 2 | { 3 | public class Contact 4 | { 5 | public string AccountId { get; set; } 6 | public Account Account { get; set; } 7 | public string Email { get; set; } 8 | public string Phone { get; set; } 9 | public string Name { get; set; } 10 | public string Title { get; set; } 11 | public string MobilePhone { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/DeletedRecord.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Force.Tests.Models 5 | { 6 | public class DeletedRecord 7 | { 8 | [JsonProperty(PropertyName = "id")] 9 | public string Id { get; set; } 10 | 11 | [JsonProperty(PropertyName = "deletedDate")] 12 | public string DeletedDate { get; set; } 13 | } 14 | 15 | public class DeletedRecordRootObject 16 | { 17 | [JsonProperty(PropertyName = "deletedRecords")] 18 | public List DeletedRecords { get; set; } 19 | 20 | [JsonProperty(PropertyName = "earliestDateAvailable")] 21 | public string EarliestDateAvailable { get; set; } 22 | 23 | [JsonProperty(PropertyName = "latestDateCovered")] 24 | public string LatestDateCovered { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Salesforce.Force.Tests.Models 4 | { 5 | public class Event 6 | { 7 | public string Id { get; set; } 8 | public string Description { get; set; } 9 | public string Subject { get; set; } 10 | public string WhatId { get; set; } 11 | public DateTime ActivityDate { get; set; } 12 | public DateTime ActivityDateTime { get; set; } 13 | public int DurationInMinutes { get; set; } 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/ObjectDescribeMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Salesforce.Force.Tests.Models 8 | { 9 | public class ObjectDescribeMetadata 10 | { 11 | public ObjectFieldMetadata[] Fields { get; set; } 12 | public string Label { get; set; } 13 | public string LabelPlural { get; set; } 14 | public string Name { get; set; } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/ObjectFieldMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Salesforce.Force.Tests.Models 7 | { 8 | public class ObjectFieldMetadata 9 | { 10 | public string Name { get; set; } 11 | public string Label { get; set; } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Models/UpdatedRecord.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Salesforce.Force.Tests.Models 5 | { 6 | public class UpdatedRecordRootObject 7 | { 8 | [JsonProperty(PropertyName = "ids")] 9 | public List Ids { get; set; } 10 | 11 | [JsonProperty(PropertyName = "latestDateCovered")] 12 | public string LatestDateCovered { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/ForceToolkitForNET.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: NeutralResourcesLanguage("en")] 13 | --------------------------------------------------------------------------------