├── .github └── workflows │ ├── pr-lint.yml │ └── test-and-deploy.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CSharpHTTPClient ├── App.config ├── CSharpHTTPClient.csproj ├── CSharpHTTPClient.sln ├── Client.cs ├── Properties │ └── AssemblyInfo.cs └── SendGridCSharpHTTPClient.nuspec ├── Example ├── .env_sample ├── App.config ├── Example.cs ├── Example.csproj ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── FIRST_TIMERS.md ├── LICENSE ├── Makefile ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── TROUBLESHOOTING.md ├── USAGE.md ├── UnitTest ├── Properties │ └── AssemblyInfo.cs ├── RequiredFilesExistTest.cs ├── UnitTest.cs ├── UnitTest.csproj └── packages.config ├── UseCases └── README.md ├── csharphttpclient.snk ├── static └── img │ ├── github-fork.png │ └── github-sign-up.png └── twilio_sendgrid_logo.png /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | on: 3 | pull_request_target: 4 | types: [ opened, edited, synchronize, reopened ] 5 | 6 | jobs: 7 | validate: 8 | name: Validate title 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: amannn/action-semantic-pull-request@v4 12 | with: 13 | types: chore docs fix feat test misc 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/test-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test and Deploy 2 | on: 3 | push: 4 | branches: [ '*' ] 5 | tags: [ '*' ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | # Run automatically at 8AM PST Monday-Friday 10 | - cron: '0 15 * * 1-5' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 20 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Setup .NET Core SDK 22 | uses: actions/setup-dotnet@v1.8.2 23 | with: 24 | dotnet-version: '3.1.x' 25 | 26 | - name: Build & Test 27 | run: make test 28 | - run: bash <(curl -s https://codecov.io/bash) 29 | deploy: 30 | name: Deploy 31 | if: success() && github.ref_type == 'tag' 32 | needs: [ test ] 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v2 36 | 37 | - name: Setup .NET Core SDK 38 | uses: actions/setup-dotnet@v1.8.2 39 | with: 40 | dotnet-version: '3.1.x' 41 | 42 | - name: Create GitHub Release 43 | uses: sendgrid/dx-automator/actions/release@main 44 | with: 45 | footer: '**[NuGet](https://www.nuget.org/packages/SendGrid.CSharp.HTTP.Client/${version})**' 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | - name: Publish package to NuGet 50 | run: | 51 | make test 52 | dotnet nuget push **/SendGrid*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json 53 | 54 | - name: Submit metric to Datadog 55 | uses: sendgrid/dx-automator/actions/datadog-release-metric@main 56 | env: 57 | DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} 58 | 59 | notify-on-failure: 60 | name: Slack notify on failure 61 | if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') 62 | needs: [ test, deploy ] 63 | runs-on: ubuntu-latest 64 | steps: 65 | - uses: rtCamp/action-slack-notify@v2 66 | env: 67 | SLACK_COLOR: failure 68 | SLACK_ICON_EMOJI: ':github:' 69 | SLACK_MESSAGE: ${{ format('Test *{0}*, Deploy *{1}*, {2}/{3}/actions/runs/{4}', needs.test.result, needs.deploy.result, github.server_url, github.repository, github.run_id) }} 70 | SLACK_TITLE: Action Failure - ${{ github.repository }} 71 | SLACK_USERNAME: GitHub Actions 72 | SLACK_MSG_AUTHOR: twilio-dx 73 | SLACK_FOOTER: Posted automatically using GitHub Actions 74 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 75 | MSG_MINIMAL: true 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CSharpHTTPClient/CSharpHTTPClient.sln.DotSettings.user 2 | CSharpHTTPClient/bin/ 3 | Example/bin/ 4 | CSharpHTTPClient/obj/ 5 | Example/obj/ 6 | UnitTest/bin/ 7 | UnitTest/obj/ 8 | *.suo 9 | CSharpHTTPClient/*/bin/ 10 | CSharpHTTPClient/*/obj/ 11 | .DS_store 12 | CSharpHTTPClient/CSharpHTTPClient.userprefs 13 | CSharpHTTPClient/packages/ 14 | CSharpHTTPClient/CSharpHTTPClient.sln.VisualState.xml 15 | *.PublicKey 16 | *.pfx 17 | .vs 18 | .history 19 | 20 | # Environment files 21 | .env/*.* -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | This project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | [2022-03-09] Version 3.4.12 7 | --------------------------- 8 | **Library - Chore** 9 | - [PR #109](https://github.com/sendgrid/csharp-http-client/pull/109): push Datadog Release Metric upon deploy success. Thanks to [@eshanholtz](https://github.com/eshanholtz)! 10 | 11 | 12 | [2022-02-09] Version 3.4.11 13 | --------------------------- 14 | **Library - Chore** 15 | - [PR #108](https://github.com/sendgrid/csharp-http-client/pull/108): add gh release to workflow. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)! 16 | - [PR #107](https://github.com/sendgrid/csharp-http-client/pull/107): merge test and deploy workflows. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)! 17 | 18 | 19 | [2022-01-12] Version 3.4.10 20 | --------------------------- 21 | **Library - Chore** 22 | - [PR #106](https://github.com/sendgrid/csharp-http-client/pull/106): update license year. Thanks to [@JenniferMah](https://github.com/JenniferMah)! 23 | 24 | 25 | [2021-12-01] Version 3.4.9 26 | -------------------------- 27 | **Library - Chore** 28 | - [PR #105](https://github.com/sendgrid/csharp-http-client/pull/105): fix gh action release workflow. Thanks to [@eshanholtz](https://github.com/eshanholtz)! 29 | - [PR #104](https://github.com/sendgrid/csharp-http-client/pull/104): migrate to GitHub Actions. Thanks to [@eshanholtz](https://github.com/eshanholtz)! 30 | 31 | 32 | [2020-08-19] Version 3.4.8 33 | -------------------------- 34 | **Library - Chore** 35 | - [PR #101](https://github.com/sendgrid/csharp-http-client/pull/101): update GitHub branch references to use HEAD. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 36 | 37 | 38 | [2020-04-15] Version 3.4.7 39 | -------------------------- 40 | **Library - Docs** 41 | - [PR #100](https://github.com/sendgrid/csharp-http-client/pull/100): baseline all the templated markdown docs. Thanks to [@childish-sambino](https://github.com/childish-sambino)! 42 | 43 | 44 | [2020-02-19] Version 3.4.6 45 | -------------------------- 46 | **Library - Chore** 47 | - [PR #99](https://github.com/sendgrid/csharp-http-client/pull/99): remove unused function. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 48 | 49 | 50 | [2020-02-05] Version 3.4.5 51 | -------------------------- 52 | **Library - Chore** 53 | - [PR #98](https://github.com/sendgrid/csharp-http-client/pull/98): add license to nuspec. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 54 | 55 | 56 | [2020-01-29] Version 3.4.4 57 | -------------------------- 58 | **Library - Fix** 59 | - [PR #97](https://github.com/sendgrid/csharp-http-client/pull/97): update deploy path for .nupkg. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 60 | 61 | 62 | [2020-01-29] Version 3.4.3 63 | -------------------------- 64 | **Library - Chore** 65 | - [PR #96](https://github.com/sendgrid/csharp-http-client/pull/96): add nuget pack. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 66 | 67 | 68 | [2020-01-28] Version 3.4.2 69 | -------------------------- 70 | **Library - Chore** 71 | - [PR #95](https://github.com/sendgrid/csharp-http-client/pull/95): updates for auto-deploy via Travis CI. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 72 | - [PR #93](https://github.com/sendgrid/csharp-http-client/pull/93): prep the repo for automated releasing. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 73 | - [PR #71](https://github.com/sendgrid/csharp-http-client/pull/71): Adds a Deploy Travis task that publishes to NuGet. Thanks to [@Gimly](https://github.com/Gimly)! 74 | 75 | **Library - Fix** 76 | - [PR #94](https://github.com/sendgrid/csharp-http-client/pull/94): nuget push flag. Thanks to [@thinkingserious](https://github.com/thinkingserious)! 77 | 78 | 79 | [2019-08-14] Version 3.4.1 80 | -------------------------- 81 | ### Added 82 | - [PR #90](https://github.com/sendgrid/csharp-http-client/pull/90): Twilio branding updates. 83 | 84 | ## [3.4.0] - 2019-08-14 85 | ### Added 86 | - [PR #26](https://github.com/sendgrid/csharp-http-client/pull/26): Add a Code Of Conduct. Big thanks to [Henrik Bergqvist](https://github.com/hbbq) for the pull request! 87 | - [PR #31](https://github.com/sendgrid/csharp-http-client/pull/31): Update README.md - moved logo to top, added license and more badges. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 88 | - [PR #32](https://github.com/sendgrid/csharp-http-client/pull/32): Add more SEO Friendly Section links. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 89 | - [PR #28](https://github.com/sendgrid/csharp-http-client/pull/28): Add an example of displaying request headers on Client. Big thanks to [Richard D](https://github.com/dutts) for the pull request! 90 | - [PR #38](https://github.com/sendgrid/csharp-http-client/pull/38): Add GitHub PR template. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 91 | - [PR #52](https://github.com/sendgrid/csharp-http-client/pull/52): Added unittest to check for specific repo files. Big thanks to [Manjiri Tapaswi](https://github.com/mptap) for the pull request! 92 | - [PR #42](https://github.com/sendgrid/csharp-http-client/pull/42): Added example file, updated .gitignore and README.md. Big thanks to [Diego Rocha](https://github.com/dhsrocha) for the pull request! 93 | - [PR #43](https://github.com/sendgrid/csharp-http-client/pull/43): Add USAGE.md. Big thanks to [Rohit Daryanani](https://github.com/rohitdaryanani) for the pull request! 94 | - [PR #68](https://github.com/sendgrid/csharp-http-client/pull/68): Created a UseCases directory. Big thanks to [Ed Parry](https://github.com/ed-parry) for the pull request! 95 | - [PR #78](https://github.com/sendgrid/csharp-http-client/pull/78): Document new Git workflow. Big thanks to [Shivam Agarwal](https://github.com/gr8shivam) for the pull request! 96 | - [PR #74](https://github.com/sendgrid/csharp-http-client/pull/74): Add first-timers.md file for newcomers. Big thanks to [Ely Alamillo](https://github.com/ely-alamillo) for the pull request! 97 | - [PR #62](https://github.com/sendgrid/csharp-http-client/pull/62): Added CodeCov support. Big thanks to [Zac Marcus](https://github.com/ZacMarcus) for the pull request! 98 | - [PR #60](https://github.com/sendgrid/csharp-http-client/pull/60): Add Code Review to Contributing.md. Big thanks to [Derek Neuland](https://github.com/derekneuland) for the pull request! 99 | 100 | ### Fixed 101 | - [PR #24](https://github.com/sendgrid/csharp-http-client/pull/24): Typo in README.md. Big thanks to [Cícero Pablo](https://github.com/ciceropablo) for the pull request! 102 | - [PR #35](https://github.com/sendgrid/csharp-http-client/pull/35): Typo in CONTRIBUTING.md. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 103 | - [PR #49](https://github.com/sendgrid/csharp-http-client/pull/49): Update the LICENSE copyright year. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 104 | - [PR #50](https://github.com/sendgrid/csharp-http-client/pull/50): Update the LICENSE date range and add a unit test. Big thanks to [Dawid Treściński](https://github.com/blitzerpl) for the pull request! 105 | - [PR #53](https://github.com/sendgrid/csharp-http-client/pull/53): Make sure LICENSE file test works cross-platform. Big thanks to [Adlan Razalan](https://github.com/adlan) for the pull request! 106 | - [PR #65](https://github.com/sendgrid/csharp-http-client/pull/65): Update license year. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 107 | - [PR #85](https://github.com/sendgrid/csharp-http-client/pull/85): Fix test looking for LICENSE.txt. Big thanks to [Ashley Roach](https://github.com/aroach) for the pull request! 108 | - [PR #84](https://github.com/sendgrid/csharp-http-client/pull/84): Fix link to license in the README. Big thanks to [Pranjal Vyas](https://github.com/vyaspranjal33) for the pull request! 109 | - [PR #83](https://github.com/sendgrid/csharp-http-client/pull/83): Fix link to feature requests in the README. Big thanks to [Sanjay Singh](https://github.com/sanjaysingh) for the pull request! 110 | - [PR #82](https://github.com/sendgrid/csharp-http-client/pull/82): Fix location of LICENSE.md file. Big thanks to [Chandler Weiner](https://github.com/crweiner) for the pull request! 111 | - [PR #77](https://github.com/sendgrid/csharp-http-client/pull/77): Fix tests looking for wrong file type for License. Big thanks to [Anna](https://github.com/AnnaDodson) for the pull request! 112 | - [PR #70](https://github.com/sendgrid/csharp-http-client/pull/70): Corrected *.md files using Grammarly. Big thanks to [Alex](https://github.com/pushkyn) for the pull request! 113 | 114 | ## [3.3.0] - 2017-04-17 115 | ### Added 116 | - #22: Added cancellation of requests using Cancellation Token 117 | - Big thanks to [aKzenT](https://github.com/aKzenT) for the pull request! 118 | 119 | ## [3.2.0] - 2017-04-11 120 | ### Added 121 | - #23: Timeout Parameter 122 | - Big thanks to [PandaBoy00](https://github.com/PandaBoy00) for the pull request! 123 | 124 | ## [3.1.0] - 2017-03-01 125 | ### Added 126 | - [PR #18](https://github.com/sendgrid/csharp-http-client/pull/18): Cache default httpclient 127 | - Big thanks to [Niels Timmermans](https://github.com/nillis) for the pull request! 128 | 129 | ## [3.0.0] - 2016-07-22 130 | ### BREAKING CHANGE 131 | - While your code may continue to work as before, the async behavior has changed, as we don't block on `Result` anymore 132 | - Fixes [issue #259](https://github.com/sendgrid/sendgrid-csharp/issues/259) in the sendgrid-csharp library 133 | - Updated examples and README to demonstrate await usage 134 | 135 | ## [2.0.7] - 2016-07-19 136 | ### Added 137 | - [Pull request #11](https://github.com/sendgrid/csharp-http-client/pull/11): Adding the option to set WebProxy object to be used on HttpClient 138 | - Big thanks to [Juliano Nunes](https://github.com/julianonunes) for the pull request! 139 | 140 | ## [2.0.6] - 2016-07-18 141 | ### Added 142 | - Sign assembly with a strong name 143 | 144 | ## [2.0.5] - 2016-07-14 145 | ### Fixed 146 | - Solves [issue #7](https://github.com/sendgrid/csharp-http-client/issues/7) 147 | - Solves [issue #256](https://github.com/sendgrid/sendgrid-csharp/issues/256) in the SendGrid C# Client 148 | - Do not try to encode the JSON request payload by replacing single quotes with double quotes 149 | - Updated examples and README to use JSON.NET to encode the payload 150 | - Thanks to [Gunnar Liljas](https://github.com/gliljas) for helping identify the issue! 151 | 152 | ## [2.0.2] - 2016-06-16 153 | ### Added 154 | - Fix async, per https://github.com/sendgrid/sendgrid-csharp/issues/235 155 | 156 | ## [2.0.1] - 2016-06-03 157 | ### Added 158 | - Sign assembly with a strong name 159 | 160 | ## [2.0.0] - 2016-06-03 161 | ### Changed 162 | - Made the Response variables non-redundant. e.g. response.ResponseBody becomes response.Body 163 | 164 | ## [1.0.2] - 2016-03-17 165 | ### Added 166 | - We are live! 167 | 168 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at open-source@twilio.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. 2 | 3 | All third party contributors acknowledge that any contributions they provide will be made under the same open source license that the open source project is provided under. 4 | 5 | - [Improvements to the Codebase](#improvements-to-the-codebase) 6 | - [Understanding the Code Base](#understanding-the-codebase) 7 | - [Testing](#testing) 8 | - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) 9 | - [Creating a Pull Request](#creating-a-pull-request) 10 | - [Code Reviews](#code-reviews) 11 | 12 | There are a few ways to contribute, which we'll enumerate below: 13 | 14 | 15 | ## Improvements to the Codebase 16 | 17 | We welcome direct contributions to the csharp-http-client code base. Thank you! 18 | 19 | ### Development Environment ### 20 | 21 | #### Install and Run Locally #### 22 | 23 | ##### Prerequisites ##### 24 | 25 | - .NET version 4.5.2 26 | - Microsoft Visual Studio Community 2015 or greater 27 | 28 | ##### Initial setup: ##### 29 | 30 | ```bash 31 | git clone https://github.com/sendgrid/csharp-http-client.git 32 | ``` 33 | 34 | Open `csharp-http-client/CSharpHTTPClient/CSharpHTTPClient.sln` 35 | 36 | ##### Execute: ##### 37 | 38 | SSee the [Example project](Example) to get started quickly. 39 | 40 | 41 | ## Understanding the Code Base 42 | 43 | **/Example/Example.cs** 44 | 45 | Working examples that demonstrate usage. 46 | 47 | **/CSharpHTTPClient/Client.cs** 48 | 49 | An HTTP client with a fluent interface using method chaining and reflection. By returning a new object on [TryGetMember](CSharpHTTPClient/Client.cs#L191) and [_()](CSharpHTTPClient/Client.cs#L180), we can dynamically build the URL using method chaining and [TryGetMember](CSharpHTTPClient/Client.cs#L191) allows us to dynamically receive the method calls to achieve reflection. 50 | 51 | This allows for the following mapping from a URL to a method chain: 52 | 53 | `/api_client/{api_key_id}/version` maps to `client.api_client._(api_key_id).version.()` where is a supported [Method](CSharpHTTPClient/Client.cs#L71). 54 | 55 | 56 | ## Testing 57 | 58 | All PRs require passing tests before the PR will be reviewed. 59 | 60 | All test files are in the [`UnitTest`](UnitTest) directory. 61 | 62 | For the purposes of contributing to this repo, please update the [`UnitTest.cs`](UnitTest/UnitTest.cs) file with unit tests as you modify the code. 63 | 64 | From the Visual Studio menu: `Tests->Run->All Tests` 65 | 66 | 67 | ## Style Guidelines & Naming Conventions 68 | 69 | Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning. In this case, we generally follow the [C# Naming Conventions](https://msdn.microsoft.com/library/ms229045(v=vs.100).aspx) and the suggestions provided by the Visual Studio IDE. 70 | 71 | 72 | ## Creating a Pull Request 73 | 74 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, 75 | and configure the remotes: 76 | 77 | ```bash 78 | # Clone your fork of the repo into the current directory 79 | git clone https://github.com/sendgrid/csharp-http-client 80 | # Navigate to the newly cloned directory 81 | cd csharp-http-client 82 | # Assign the original repo to a remote called "upstream" 83 | git remote add upstream https://github.com/sendgrid/csharp-http-client 84 | ``` 85 | 86 | 2. If you cloned a while ago, get the latest changes from upstream: 87 | 88 | ```bash 89 | git checkout development 90 | git pull upstream development 91 | ``` 92 | 93 | 3. Create a new topic branch (off the main project development branch) to 94 | contain your feature, change, or fix: 95 | 96 | ```bash 97 | git checkout -b development 98 | ``` 99 | 100 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 101 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 102 | or your code is unlikely to be merged into the main project. Use Git's 103 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 104 | feature to tidy up your commits before making them public. 105 | 106 | 4a. Create tests. 107 | 108 | 4b. Create or update the example code that demonstrates the functionality of this change to the code. 109 | 110 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 111 | 112 | ```bash 113 | git pull [--rebase] upstream development 114 | ``` 115 | 116 | 6. Push your topic branch up to your fork: 117 | 118 | ```bash 119 | git push origin 120 | ``` 121 | 122 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 123 | with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 124 | 125 | ## Code Reviews 126 | If you can, please look at open PRs and review them. Give feedback and help us merge these PRs much faster! If you don't know how, Github has some great information on how to review a Pull Request. 127 | -------------------------------------------------------------------------------- /CSharpHTTPClient/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CSharpHTTPClient/CSharpHTTPClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Twilio 6 | A Simple Fluent REST API Client. 7 | 8 | 9 | Debug 10 | AnyCPU 11 | {26C4841F-EC62-4EC7-B16E-3A7386EA36DC} 12 | Library 13 | Properties 14 | SendGrid.CSharp.HTTP.Client 15 | SendGrid.CSharp.HTTP.Client 16 | v4.5 17 | 512 18 | true 19 | 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | 43 | 44 | true 45 | 46 | 47 | ../csharphttpclient.snk 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 78 | 79 | -------------------------------------------------------------------------------- /CSharpHTTPClient/CSharpHTTPClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpHTTPClient", "CSharpHTTPClient.csproj", "{26C4841F-EC62-4EC7-B16E-3A7386EA36DC}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "..\Example\Example.csproj", "{490AD14D-B821-435A-BEC8-F4DFE34E6556}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "..\UnitTest\UnitTest.csproj", "{DF845C59-4B39-4A8A-AC89-E5336B57076B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {26C4841F-EC62-4EC7-B16E-3A7386EA36DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {26C4841F-EC62-4EC7-B16E-3A7386EA36DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {26C4841F-EC62-4EC7-B16E-3A7386EA36DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {26C4841F-EC62-4EC7-B16E-3A7386EA36DC}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {490AD14D-B821-435A-BEC8-F4DFE34E6556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {490AD14D-B821-435A-BEC8-F4DFE34E6556}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {490AD14D-B821-435A-BEC8-F4DFE34E6556}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {490AD14D-B821-435A-BEC8-F4DFE34E6556}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {DF845C59-4B39-4A8A-AC89-E5336B57076B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {DF845C59-4B39-4A8A-AC89-E5336B57076B}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {DF845C59-4B39-4A8A-AC89-E5336B57076B}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {DF845C59-4B39-4A8A-AC89-E5336B57076B}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /CSharpHTTPClient/Client.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Net.Http.Headers; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Web.Script.Serialization; 11 | using System.Web; 12 | using System.Threading; 13 | 14 | namespace SendGrid.CSharp.HTTP.Client 15 | { 16 | public class Response 17 | { 18 | public HttpStatusCode StatusCode; 19 | public HttpContent Body; 20 | public HttpResponseHeaders Headers; 21 | 22 | /// 23 | /// Holds the response from an API call. 24 | /// 25 | /// https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx 26 | /// https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx 27 | /// https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx 28 | public Response(HttpStatusCode statusCode, HttpContent responseBody, HttpResponseHeaders responseHeaders) 29 | { 30 | StatusCode = statusCode; 31 | Body = responseBody; 32 | Headers = responseHeaders; 33 | } 34 | 35 | /// 36 | /// Converts string formatted response body to a Dictionary. 37 | /// 38 | /// https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx 39 | /// Dictionary object representation of HttpContent 40 | public virtual Dictionary DeserializeResponseBody(HttpContent content) 41 | { 42 | JavaScriptSerializer jss = new JavaScriptSerializer(); 43 | var dsContent = jss.Deserialize>(content.ReadAsStringAsync().Result); 44 | return dsContent; 45 | } 46 | 47 | /// 48 | /// Converts string formatted response headers to a Dictionary. 49 | /// 50 | /// https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx 51 | /// Dictionary object representation of HttpRepsonseHeaders 52 | public virtual Dictionary DeserializeResponseHeaders(HttpResponseHeaders content) 53 | { 54 | var dsContent = new Dictionary(); 55 | foreach (var pair in content) 56 | { 57 | dsContent.Add(pair.Key, pair.Value.First()); 58 | } 59 | return dsContent; 60 | } 61 | 62 | } 63 | 64 | 65 | public class Client : DynamicObject 66 | { 67 | public string Host; 68 | public Dictionary RequestHeaders; 69 | public string Version; 70 | public string UrlPath; 71 | public string MediaType; 72 | public WebProxy WebProxy; 73 | public TimeSpan Timeout; 74 | 75 | public enum Methods 76 | { 77 | DELETE, GET, PATCH, POST, PUT 78 | } 79 | 80 | private int TimeoutDefault = 10; 81 | 82 | /// 83 | /// REST API client. 84 | /// 85 | /// Base url (e.g. https://api.sendgrid.com) 86 | /// A dictionary of request headers 87 | /// API version, override AddVersion to customize 88 | /// Path to endpoint (e.g. /path/to/endpoint) 89 | /// Fluent interface to a REST API 90 | public Client(WebProxy webProxy, string host, Dictionary requestHeaders = null, string version = null, string urlPath = null) 91 | : this(host, requestHeaders, version, urlPath) 92 | { 93 | WebProxy = webProxy; 94 | } 95 | 96 | 97 | /// 98 | /// REST API client. 99 | /// 100 | /// Base url (e.g. https://api.sendgrid.com) 101 | /// A dictionary of request headers 102 | /// API version, override AddVersion to customize 103 | /// Path to endpoint (e.g. /path/to/endpoint) 104 | /// Set an Timeout parameter for the HTTP Client 105 | /// Fluent interface to a REST API 106 | public Client(string host, Dictionary requestHeaders = null, string version = null, string urlPath = null, TimeSpan? timeOut = null) 107 | { 108 | Host = host; 109 | if(requestHeaders != null) 110 | { 111 | AddRequestHeader(requestHeaders); 112 | } 113 | Version = (version != null) ? version : null; 114 | UrlPath = (urlPath != null) ? urlPath : null; 115 | Timeout = (timeOut != null) ? (TimeSpan)timeOut : TimeSpan.FromSeconds(TimeoutDefault); 116 | } 117 | 118 | /// 119 | /// Add requestHeaders to the API call 120 | /// 121 | /// A dictionary of request headers 122 | public void AddRequestHeader(Dictionary requestHeaders) 123 | { 124 | RequestHeaders = (RequestHeaders != null) 125 | ? RequestHeaders.Union(requestHeaders).ToDictionary(pair => pair.Key, pair => pair.Value) : requestHeaders; 126 | } 127 | 128 | /// 129 | /// Build the final URL 130 | /// 131 | /// A string of JSON formatted query parameters (e.g {'param': 'param_value'}) 132 | /// Final URL 133 | private string BuildUrl(string queryParams = null) 134 | { 135 | string endpoint = null; 136 | 137 | if( Version != null) 138 | { 139 | endpoint = Host + "/" + Version + UrlPath; 140 | } 141 | else 142 | { 143 | endpoint = Host + UrlPath; 144 | } 145 | 146 | if (queryParams != null) 147 | { 148 | JavaScriptSerializer jss = new JavaScriptSerializer(); 149 | var ds_query_params = jss.Deserialize>(queryParams); 150 | var query = HttpUtility.ParseQueryString(string.Empty); 151 | foreach (var pair in ds_query_params) 152 | { 153 | query[pair.Key] = pair.Value.ToString(); 154 | } 155 | string queryString = query.ToString(); 156 | endpoint = endpoint + "?" + queryString; 157 | } 158 | 159 | return endpoint; 160 | } 161 | 162 | /// 163 | /// Create a new Client object for method chaining 164 | /// 165 | /// Name of url segment to add to the URL 166 | /// A new client object with "name" added to the URL 167 | private Client BuildClient(string name = null) 168 | { 169 | string endpoint; 170 | 171 | if (name != null) 172 | { 173 | endpoint = UrlPath + "/" + name; 174 | } 175 | else 176 | { 177 | endpoint = UrlPath; 178 | } 179 | 180 | UrlPath = null; // Reset the current object's state before we return a new one 181 | return new Client(Host, RequestHeaders, Version, endpoint, Timeout); 182 | 183 | } 184 | 185 | /// 186 | /// Add the authorization header, override to customize 187 | /// 188 | /// Authorization header 189 | /// Authorization value to add to the header 190 | public virtual AuthenticationHeaderValue AddAuthorization(KeyValuePair header) 191 | { 192 | string[] split = header.Value.Split(new char[0]); 193 | return new AuthenticationHeaderValue(split[0], split[1]); 194 | } 195 | 196 | /// 197 | /// Add the version of the API, override to customize 198 | /// 199 | /// Version string to add to the URL 200 | public virtual void AddVersion(string version) 201 | { 202 | Version = version; 203 | } 204 | 205 | /// 206 | /// Deal with special cases and URL parameters 207 | /// 208 | /// Name of URL segment 209 | /// A new client object with "name" added to the URL 210 | public Client _(string name) 211 | { 212 | return BuildClient(name); 213 | } 214 | 215 | /// 216 | /// Reflection. We capture undefined variable access here 217 | /// 218 | /// The calling object properties 219 | /// The callback 220 | /// The callback returns a new client object with "name" added to the URL 221 | public override bool TryGetMember(GetMemberBinder binder, out object result) 222 | { 223 | result = BuildClient(binder.Name); 224 | return true; 225 | } 226 | 227 | /// 228 | /// Reflection. We capture the final method call here 229 | /// 230 | /// The calling object properties 231 | /// The calling object's arguements 232 | /// If "version", returns new client with version attached 233 | /// If "method", returns a Response object 234 | /// The callback is described in "result" 235 | public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 236 | { 237 | if (binder.Name == "version") 238 | { 239 | AddVersion(args[0].ToString()); 240 | result = BuildClient(); 241 | return true; 242 | } 243 | 244 | if( Enum.IsDefined(typeof(Methods), binder.Name.ToUpper())) 245 | { 246 | CancellationToken cancellationToken = CancellationToken.None; 247 | string queryParams = null; 248 | string requestBody = null; 249 | int i = 0; 250 | 251 | foreach (object obj in args) 252 | { 253 | string name = binder.CallInfo.ArgumentNames.Count > i ? 254 | binder.CallInfo.ArgumentNames[i] : null; 255 | if (name == "queryParams") 256 | { 257 | queryParams = obj.ToString(); 258 | } 259 | else if (name == "requestBody") 260 | { 261 | requestBody = obj.ToString(); 262 | } 263 | else if (name == "requestHeaders") 264 | { 265 | AddRequestHeader((Dictionary)obj); 266 | } 267 | else if (name == "cancellationToken") 268 | { 269 | cancellationToken = (CancellationToken)obj; 270 | } 271 | i++; 272 | } 273 | result = RequestAsync(binder.Name.ToUpper(), requestBody: requestBody, queryParams: queryParams, cancellationToken: cancellationToken).ConfigureAwait(false); 274 | return true; 275 | } 276 | else 277 | { 278 | result = null; 279 | return false; 280 | } 281 | 282 | } 283 | 284 | /// 285 | /// Make the call to the API server, override for testing or customization 286 | /// 287 | /// Client object ready for communication with API 288 | /// The parameters for the API call 289 | /// A token that allows cancellation of the http request 290 | /// Response object 291 | public async virtual Task MakeRequest(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken = default(CancellationToken)) 292 | { 293 | 294 | HttpResponseMessage response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false); 295 | return new Response(response.StatusCode, response.Content, response.Headers); 296 | } 297 | 298 | /// 299 | /// Prepare for async call to the API server 300 | /// 301 | /// HTTP verb 302 | /// A token that allows cancellation of the http request 303 | /// JSON formatted string 304 | /// JSON formatted queary paramaters 305 | /// Response object 306 | private async Task RequestAsync(string method, String requestBody = null, String queryParams = null, CancellationToken cancellationToken = default(CancellationToken)) 307 | { 308 | using (var client = new HttpClient()) 309 | { 310 | try 311 | { 312 | // Build the URL 313 | client.BaseAddress = new Uri(Host); 314 | client.Timeout = Timeout; 315 | string endpoint = BuildUrl(queryParams); 316 | 317 | 318 | // Build the request headers 319 | client.DefaultRequestHeaders.Accept.Clear(); 320 | if(RequestHeaders != null) 321 | { 322 | foreach (KeyValuePair header in RequestHeaders) 323 | { 324 | if (header.Key == "Authorization") 325 | { 326 | client.DefaultRequestHeaders.Authorization = AddAuthorization(header); 327 | } 328 | else if (header.Key == "Content-Type") 329 | { 330 | MediaType = header.Value; 331 | client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaType)); 332 | } 333 | else 334 | { 335 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 336 | } 337 | } 338 | } 339 | 340 | // Build the request body 341 | StringContent content = null; 342 | if (requestBody != null) 343 | { 344 | content = new StringContent(requestBody, Encoding.UTF8, MediaType); 345 | } 346 | 347 | // Build the final request 348 | HttpRequestMessage request = new HttpRequestMessage 349 | { 350 | Method = new HttpMethod(method), 351 | RequestUri = new Uri(endpoint), 352 | Content = content 353 | }; 354 | return await MakeRequest(client, request, cancellationToken).ConfigureAwait(false); 355 | 356 | } 357 | catch(TaskCanceledException) 358 | { 359 | throw; 360 | } 361 | catch (Exception ex) 362 | { 363 | HttpResponseMessage response = new HttpResponseMessage(); 364 | string message; 365 | message = (ex is HttpRequestException) ? ".NET HttpRequestException" : ".NET Exception"; 366 | message = message + ", raw message: \n\n"; 367 | response.Content = new StringContent(message + ex.Message); 368 | return new Response(response.StatusCode, response.Content, response.Headers); 369 | } 370 | } 371 | } 372 | } 373 | } -------------------------------------------------------------------------------- /CSharpHTTPClient/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SendGrid.CSharp.HTTP.Client")] 8 | [assembly: AssemblyDescription("A Simple Fluent REST API Client.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Twilio SendGrid")] 11 | [assembly: AssemblyProduct("SendGrid.CSharp.HTTP.Client")] 12 | [assembly: AssemblyCopyright("Copyright Twilio SendGrid 2020")] 13 | 14 | // Setting ComVisible to false makes the types in this assembly not visible 15 | // to COM components. If you need to access a type in this assembly from 16 | // COM, set the ComVisible attribute to true on that type. 17 | [assembly: ComVisible(false)] 18 | 19 | // The following GUID is for the ID of the typelib if this project is exposed to COM 20 | [assembly: Guid("26c4841f-ec62-4ec7-b16e-3a7386ea36dc")] 21 | -------------------------------------------------------------------------------- /CSharpHTTPClient/SendGridCSharpHTTPClient.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SendGrid.CSharp.HTTP.Client 5 | $authors$ 6 | $title$ 7 | $authors$ 8 | 3.4.12 9 | https://sendgrid.com/ 10 | https://sendgrid.com/wp-content/themes/sgdotcom/pages/resource/brand//2016/SendGrid-Logomark.png 11 | false 12 | Copyright Twilio SendGrid 2020 13 | $description$ 14 | MIT 15 | Twilio SendGrid Email Mail Microsoft Azure Transactional .NET Core 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example/.env_sample: -------------------------------------------------------------------------------- 1 | export SENDGRID_API_KEY='' -------------------------------------------------------------------------------- /Example/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Example/Example.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SendGrid.CSharp.HTTP.Client; 4 | using System.Web.Script.Serialization; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | 8 | // This is a working example, using the Twilio SendGrid API 9 | // You will need a Twilio SendGrid account and an active API Key 10 | // They key should be stored in an environment variable called SENDGRID_API_KEY 11 | namespace Example 12 | { 13 | class Example 14 | { 15 | static void Main(string[] args) 16 | { 17 | Execute().Wait(); 18 | } 19 | 20 | static async Task Execute() 21 | { 22 | String host = "https://e9sk3d3bfaikbpdq7.stoplight-proxy.io"; 23 | Dictionary globalRequestHeaders = new Dictionary(); 24 | string apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY", EnvironmentVariableTarget.User); 25 | globalRequestHeaders.Add("Authorization", "Bearer " + apiKey); 26 | globalRequestHeaders.Add("Content-Type", "application/json"); 27 | 28 | String version = "v3"; 29 | dynamic client = new Client(host: host, requestHeaders: globalRequestHeaders, version: version); 30 | 31 | // GET Collection 32 | string queryParams = @"{ 33 | 'limit': 100 34 | }"; 35 | Dictionary requestHeaders = new Dictionary(); 36 | requestHeaders.Add("X-Test", "test"); 37 | dynamic response = await client.api_keys.get(queryParams: queryParams, requestHeaders: requestHeaders); 38 | Console.WriteLine(response.StatusCode); 39 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 40 | Console.WriteLine(response.Headers.ToString()); 41 | 42 | Console.WriteLine("\n\nPress any key to continue to POST."); 43 | Console.ReadLine(); 44 | 45 | // POST 46 | string requestBody = @"{ 47 | 'name': 'My API Key 5', 48 | 'scopes': [ 49 | 'mail.send', 50 | 'alerts.create', 51 | 'alerts.read' 52 | ] 53 | }"; 54 | Object json = JsonConvert.DeserializeObject(requestBody); 55 | requestHeaders.Clear(); 56 | requestHeaders.Add("X-Test", "test2"); 57 | response = await client.api_keys.post(requestBody: json.ToString(), requestHeaders: requestHeaders); 58 | Console.WriteLine(response.StatusCode); 59 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 60 | Console.WriteLine(response.Headers.ToString()); 61 | JavaScriptSerializer jss = new JavaScriptSerializer(); 62 | var ds_response = jss.Deserialize>(response.Body.ReadAsStringAsync().Result); 63 | string api_key_id = ds_response["api_key_id"]; 64 | 65 | Console.WriteLine("\n\nPress any key to continue to GET single."); 66 | Console.ReadLine(); 67 | 68 | // GET Single 69 | response = await client.api_keys._(api_key_id).get(); 70 | Console.WriteLine(response.StatusCode); 71 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 72 | Console.WriteLine(response.Headers.ToString()); 73 | 74 | Console.WriteLine("\n\nPress any key to continue to PATCH."); 75 | Console.ReadLine(); 76 | 77 | // PATCH 78 | requestBody = @"{ 79 | 'name': 'A New Hope' 80 | }"; 81 | json = JsonConvert.DeserializeObject(requestBody); 82 | response = await client.api_keys._(api_key_id).patch(requestBody: json.ToString()); 83 | Console.WriteLine(response.StatusCode); 84 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 85 | Console.WriteLine(response.Headers.ToString()); 86 | 87 | Console.WriteLine("\n\nPress any key to continue to PUT."); 88 | Console.ReadLine(); 89 | 90 | // PUT 91 | requestBody = @"{ 92 | 'name': 'A New Hope', 93 | 'scopes': [ 94 | 'user.profile.read', 95 | 'user.profile.update' 96 | ] 97 | }"; 98 | json = JsonConvert.DeserializeObject(requestBody); 99 | response = await client.api_keys._(api_key_id).put(requestBody: json.ToString()); 100 | Console.WriteLine(response.StatusCode); 101 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 102 | Console.WriteLine(response.Headers.ToString()); 103 | 104 | Console.WriteLine("\n\nPress any key to continue to DELETE."); 105 | Console.ReadLine(); 106 | 107 | // DELETE 108 | response = await client.api_keys._(api_key_id).delete(); 109 | Console.WriteLine(response.StatusCode); 110 | Console.WriteLine(response.Headers.ToString()); 111 | 112 | Console.WriteLine("\n\nPress any key to exit."); 113 | Console.ReadLine(); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Example/Example.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {490AD14D-B821-435A-BEC8-F4DFE34E6556} 8 | Exe 9 | Properties 10 | Example 11 | Example 12 | v4.5 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\CSharpHTTPClient\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 39 | True 40 | 41 | 42 | 43 | 44 | ..\CSharpHTTPClient\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {26c4841f-ec62-4ec7-b16e-3a7386ea36dc} 67 | CSharpHTTPClient 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /Example/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Example")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Example")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("490ad14d-b821-435a-bec8-f4dfe34e6556")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("3.4.1")] 36 | [assembly: AssemblyFileVersion("3.4.1")] 37 | -------------------------------------------------------------------------------- /Example/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FIRST_TIMERS.md: -------------------------------------------------------------------------------- 1 | # How To Contribute to Twilio SendGrid Repositories via GitHub 2 | Contributing to the Twilio SendGrid repositories is easy! 3 | 4 | To make a pull request, follow these steps: 5 | 6 | 1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of Twilio SendGrid, please use your full name with your GitHub account and enter Twilio SendGrid as your company so we can easily identify you. 7 | 8 | 9 | 10 | 2. __[Fork](https://help.github.com/fork-a-repo/)__ the [csharp-http-client](https://github.com/sendgrid/csharp-http-client) repository: 11 | 12 | 13 | 14 | 3. __Clone__ your fork via the following commands: 15 | 16 | ```bash 17 | # Clone your fork of the repo into the current directory 18 | git clone https://github.com/your_username/csharp-http-client 19 | # Navigate to the newly cloned directory 20 | cd csharp-http-client 21 | # Assign the original repo to a remote called "upstream" 22 | git remote add upstream https://github.com/sendgrid/csharp-http-client 23 | ``` 24 | 25 | > Don't forget to replace *your_username* in the URL by your real GitHub username. 26 | 27 | 4. __Create a new topic branch__ (off the main project development branch) to contain your feature, change, or fix: 28 | 29 | ```bash 30 | git checkout -b 31 | ``` 32 | 33 | 5. __Commit your changes__ in logical chunks. 34 | 35 | Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. 36 | 37 | 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: 38 | 39 | ```bash 40 | git pull [--rebase] upstream main 41 | ``` 42 | 43 | 7. __Push__ your topic branch up to your fork: 44 | 45 | ```bash 46 | git push origin 47 | ``` 48 | 49 | 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 50 | 51 | ## Important notice 52 | 53 | Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](CONTRIBUTING.md) file. 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2023, Twilio SendGrid, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test install 2 | 3 | install: 4 | nuget restore CSharpHTTPClient/CSharpHTTPClient.sln 5 | nuget install NUnit.Runners -Version 2.6.4 -OutputDirectory testrunner 6 | 7 | test: install 8 | xbuild /p:Configuration=Release CSharpHTTPClient/CSharpHTTPClient.sln 9 | mono ./testrunner/NUnit.Runners.2.6.4/tools/nunit-console.exe UnitTest/bin/Release/UnitTest.dll -domain:None 10 | nuget pack ./CSharpHTTPClient/CSharpHTTPClient.csproj -Properties Configuration=Release 11 | curl -s https://codecov.io/bash > .codecov 12 | chmod +x .codecov 13 | ./.codecov 14 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | # Fixes # 18 | 19 | A short description of what this PR does. 20 | 21 | ### Checklist 22 | - [x] I acknowledge that all my contributions will be made under the project's license 23 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) 24 | - [ ] I have read the [Contribution Guidelines](https://github.com/sendgrid/csharp-http-client/blob/main/CONTRIBUTING.md) and my PR follows them 25 | - [ ] I have titled the PR appropriately 26 | - [ ] I have updated my branch with the main branch 27 | - [ ] I have added tests that prove my fix is effective or that my feature works 28 | - [ ] I have added the necessary documentation about the functionality in the appropriate .md file 29 | - [ ] I have added inline documentation to the code I modified 30 | 31 | If you have questions, please file a [support ticket](https://support.sendgrid.com). 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![SendGrid Logo](twilio_sendgrid_logo.png) 2 | 3 | [![Test and Deploy](https://github.com/sendgrid/csharp-http-client/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/sendgrid/csharp-http-client/actions/workflows/test-and-deploy.yml) 4 | [![NuGet](https://img.shields.io/nuget/v/SendGrid.CSharp.Http.Client.svg)](https://www.nuget.org/packages/SendGrid.CSharp.HTTP.Client) 5 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 6 | [![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/csharp-http-client.svg)](https://github.com/sendgrid/csharp-http-client/graphs/contributors) 8 | 9 | **Quickly and easily access any RESTful or RESTful-like API.** 10 | 11 | If you are looking for the Twilio SendGrid API client library, please see [this repo](https://github.com/sendgrid/sendgrid-csharp). 12 | 13 | # Table of Contents 14 | 15 | * [Announcements](#announcements) 16 | * [Installation](#installation) 17 | * [Quick Start](#quick-start) 18 | * [Library Usage Documentation](USAGE.md) 19 | * [Use Cases](#use-cases) 20 | * [How to Contribute](#contribute) 21 | * [Thanks](#thanks) 22 | * [About](#about) 23 | * [Support](#support) 24 | * [License](#license) 25 | 26 | 27 | # Announcements 28 | All updates to this project are documented in our [CHANGELOG](CHANGELOG.md). 29 | 30 | 31 | # Installation 32 | 33 | ## Prerequisites 34 | 35 | - .NET Framework 4.5+ 36 | 37 | ## Install Package 38 | 39 | To use CSharp.HTTP.Client in your C# project, you can either download the Twilio SendGrid C# .NET libraries directly from our Github repository or, if you have the NuGet package manager installed, you can grab them automatically. 40 | 41 | ``` 42 | PM> Install-Package SendGrid.CSharp.Http.Client 43 | ``` 44 | 45 | Once you have the library properly referenced in your project, you can include calls to them in your code. 46 | For a sample implementation, check the [Example](Example) folder. 47 | 48 | Add the following namespace to use the library: 49 | ```csharp 50 | using SendGrid.CSharp.HTTP.Client; 51 | ``` 52 | 53 | 54 | # Quick Start 55 | 56 | Here is a quick example: 57 | 58 | `GET /your/api/{param}/call` 59 | 60 | ```csharp 61 | using SendGrid.CSharp.HTTP.Client; 62 | globalRequestHeaders.Add("Authorization", "Bearer XXXXXXX"); 63 | dynamic client = new Client(host: baseUrl, requestHeaders: globalRequestHeaders); 64 | var response = await client.your.api._(param).call.get() 65 | Console.WriteLine(response.StatusCode); 66 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 67 | Console.WriteLine(response.Headers.ToString()); 68 | ``` 69 | 70 | `POST /your/api/{param}/call` with headers, query parameters and a request body with versioning. 71 | 72 | ```csharp 73 | using SendGrid.CSharp.HTTP.Client; 74 | using Newtonsoft.Json; 75 | globalRequestHeaders.Add("Authorization", "Bearer XXXXXXX"); 76 | dynamic client = new Client(host: baseUrl, requestHeaders: globalRequestHeaders); 77 | string queryParams = @"{'Hello': 0, 'World': 1}"; 78 | requestHeaders.Add("X-Test", "test"); 79 | string requestBody = @"{'some': 1, 'awesome': 2, 'data': 3}"; 80 | Object json = JsonConvert.DeserializeObject(requestBody); 81 | var response = await client.your.api._(param).call.post(requestBody: json.ToString(), 82 | queryParams: queryParams, 83 | requestHeaders: requestHeaders) 84 | Console.WriteLine(response.StatusCode); 85 | Console.WriteLine(response.Body.ReadAsStringAsync().Result); 86 | Console.WriteLine(response.Headers.ToString()); 87 | ``` 88 | 89 | 90 | # Use Cases 91 | 92 | You can find a selection of use cases for this library in our [Use Cases](/UseCases/README.md) directory. 93 | 94 | 95 | # How to Contribute 96 | 97 | We encourage contribution to our projects, please see our [CONTRIBUTING](CONTRIBUTING.md) guide for details. 98 | 99 | Quick links: 100 | 101 | - [Feature Request](CONTRIBUTING.md#feature-request) 102 | - [Bug Reports](CONTRIBUTING.md#submit-a-bug-report) 103 | - [Improvements to the Codebase](CONTRIBUTING.md#improvements-to-the-codebase) 104 | 105 | 106 | # Thanks 107 | 108 | We were inspired by the work done on [birdy](https://github.com/inueni/birdy) and [universalclient](https://github.com/dgreisen/universalclient). 109 | 110 | 111 | # About 112 | 113 | csharp-http-client is maintained and funded by Twilio SendGrid, Inc. The names and logos for csharp-http-client are trademarks of Twilio SendGrid, Inc. 114 | 115 | 116 | 117 | If you need help using SendGrid, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com). 118 | 119 | 120 | # License 121 | [The MIT License (MIT)](LICENSE) 122 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | If you have a SendGrid issue, please contact our [support team](https://support.sendgrid.com). 2 | 3 | ## Table of Contents 4 | 5 | * [Viewing the Request Body](#request-body) 6 | 7 | 8 | ## Viewing the Request Body 9 | 10 | When debugging or testing, it may be useful to examine the raw request body to compare against the [documented format](https://sendgrid.com/docs/API_Reference/api_v3.html). 11 | 12 | e.g. on a Client instance, myClient. 13 | 14 | ```csharp 15 | foreach (KeyValuePair kvp in myClient.RequestHeaders) 16 | { 17 | Console.WriteLine("Name = {0}, Value = {1}", kvp.Key, kvp.Value); 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | - [Example Code](Example/Example.cs) 4 | 5 | ## Environment Variables 6 | 7 | You can do the following to create a .env file: 8 | 9 | ```cp .env_example .env``` 10 | 11 | Then, just add your API Key into your .env file. 12 | -------------------------------------------------------------------------------- /UnitTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnitTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnitTest")] 13 | [assembly: AssemblyCopyright("Copyright Twilio SendGrid © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("df845c59-4b39-4a8a-ac89-e5336b57076b")] 24 | 25 | -------------------------------------------------------------------------------- /UnitTest/RequiredFilesExistTest.cs: -------------------------------------------------------------------------------- 1 | namespace SendGrid.Tests 2 | { 3 | 4 | public class TestRequiredFilesExist { 5 | 6 | // ./Docker or docker/Docker 7 | public void checkDockerExists() { 8 | boolean dockerExists = File.Exists("./Docker") || 9 | File.Exists("./docker/Docker"); 10 | Assert.True(dockerExists); 11 | } 12 | 13 | // ./docker-compose.yml or ./docker/docker-compose.yml 14 | public void checkDockerComposeExists() { 15 | boolean dockerComposeExists = File.Exists("./docker-compose.yml") || 16 | File.Exists("./docker/docker-compose.yml"); 17 | Assert.True(dockerComposeExists); 18 | } 19 | 20 | // ./.env_sample 21 | public void checkEnvSampleExists() { 22 | Assert.True(File.Exists("./.env_sample")); 23 | } 24 | 25 | // ./.gitignore 26 | public void checkGitIgnoreExists() { 27 | Assert.True(File.Exists("./.gitignore")); 28 | } 29 | 30 | // ./.codeclimate.yml 31 | public void checkCodeClimateExists() { 32 | Assert.True(File.Exists("./.codeclimate.yml")); 33 | } 34 | 35 | // ./CHANGELOG.md 36 | public void checkChangelogExists() { 37 | Assert.True(File.Exists("./CHANGELOG.md")); 38 | } 39 | 40 | // ./CODE_OF_CONDUCT.md 41 | public void checkCodeOfConductExists() { 42 | Assert.True(File.Exists("./CODE_OF_CONDUCT.md")); 43 | } 44 | 45 | // ./CONTRIBUTING.md 46 | public void checkContributingGuideExists() { 47 | Assert.True(File.Exists("./CONTRIBUTING.md")); 48 | } 49 | 50 | // ./LICENSE 51 | public void checkLicenseExists() { 52 | Assert.True(File.Exists("./LICENSE")); 53 | } 54 | 55 | // ./PULL_REQUEST_TEMPLATE.md 56 | public void checkPullRequestExists() { 57 | Assert.True(File.Exists("./PULL_REQUEST_TEMPLATE.md")); 58 | } 59 | 60 | // ./README.md 61 | public void checkReadMeExists() { 62 | Assert.True(File.Exists("./README.md")); 63 | } 64 | 65 | // ./TROUBLESHOOTING.md 66 | public void checkTroubleShootingGuideExists() { 67 | Assert.True(File.Exists("./TROUBLESHOOTING.md")); 68 | } 69 | 70 | // ./USAGE.md 71 | public void checkUsageGuideExists() { 72 | Assert.True(File.Exists("./USAGE.md")); 73 | } 74 | 75 | // ./USE_CASES.md 76 | public void checkUseCases() { 77 | Assert.True(File.Exists("./USE_CASES.md")); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /UnitTest/UnitTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using SendGrid.CSharp.HTTP.Client; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using System.Net.Http; 7 | using System.Text; 8 | using System.Net; 9 | using System.Threading; 10 | using System.IO; 11 | using System.Linq; 12 | 13 | namespace UnitTest 14 | { 15 | 16 | // Mock the Client so that we intercept network calls 17 | public class MockClient : Client 18 | { 19 | public MockClient(string host, Dictionary requestHeaders = null, string version = null, string urlPath = null) : base (host, requestHeaders, version, urlPath) 20 | { 21 | } 22 | 23 | public override Task MakeRequest(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken) 24 | { 25 | return Task.Factory.StartNew(() => 26 | { 27 | 28 | HttpResponseMessage response = new HttpResponseMessage(); 29 | response.Content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json"); 30 | response.StatusCode = HttpStatusCode.OK; 31 | 32 | cancellationToken.ThrowIfCancellationRequested(); 33 | 34 | return new Response(response.StatusCode, response.Content, response.Headers); 35 | }, cancellationToken); 36 | } 37 | } 38 | 39 | [TestFixture] 40 | public class TestClient 41 | { 42 | [Test] 43 | public void TestInitialization() 44 | { 45 | var host = "http://api.test.com"; 46 | Dictionary requestHeaders = new Dictionary(); 47 | var version = "v3"; 48 | var urlPath = "/test/url/path"; 49 | var test_client = new MockClient(host: host, requestHeaders: requestHeaders, version: version, urlPath: urlPath); 50 | requestHeaders.Add("Authorization", "Bearer SG.XXXX"); 51 | requestHeaders.Add("Content-Type", "application/json"); 52 | requestHeaders.Add("X-TEST", "test"); 53 | Assert.IsNotNull(test_client); 54 | Assert.AreEqual(host, test_client.Host); 55 | Assert.AreEqual(requestHeaders, test_client.RequestHeaders); 56 | Assert.AreEqual(version, test_client.Version); 57 | Assert.AreEqual(urlPath, test_client.UrlPath); 58 | } 59 | 60 | [Test] 61 | public void TestReflection() 62 | { 63 | var host = "http://api.test.com"; 64 | dynamic test_client = new MockClient(host: host); 65 | dynamic url1 = test_client.my.test.path; 66 | Assert.AreEqual(url1.UrlPath, "/my/test/path"); 67 | url1 = test_client.my._("test").path; 68 | Assert.AreEqual(url1.UrlPath, "/my/test/path"); 69 | url1 = test_client.version("v4").my.test.path; 70 | Assert.AreEqual(url1.Version, "v4"); 71 | Assert.AreEqual(url1.UrlPath, "/my/test/path"); 72 | url1 = url1.final.result; 73 | Assert.AreEqual(url1.UrlPath, "/my/test/path/final/result"); 74 | } 75 | 76 | [Test] 77 | public async void TestMethodCall() 78 | { 79 | var host = "http://api.test.com"; 80 | dynamic test_client = new MockClient(host: host); 81 | Response response = await test_client.get(); 82 | Assert.IsNotNull(response); 83 | Assert.AreEqual(response.StatusCode, HttpStatusCode.OK); 84 | var content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json"); 85 | Assert.AreEqual(response.Body.ReadAsStringAsync().Result, content.ReadAsStringAsync().Result); 86 | } 87 | 88 | [Test] 89 | [ExpectedException(typeof(TaskCanceledException))] 90 | public async void TestMethodCallWithCancellationToken() 91 | { 92 | var cancellationTokenSource = new CancellationTokenSource(); 93 | cancellationTokenSource.Cancel(); 94 | 95 | var host = "http://api.test.com"; 96 | dynamic test_client = new MockClient(host: host); 97 | Response response = await test_client.get(cancellationToken: cancellationTokenSource.Token); 98 | } 99 | } 100 | 101 | [TestFixture] 102 | public class TestRepositoryFiles 103 | { 104 | [Test] 105 | public void TestLicenseEndYear() 106 | { 107 | var licensePath = Path.Combine("..", "..", "..", "LICENSE"); 108 | string line = File.ReadLines(licensePath).Skip(2).Take(1).First(); 109 | 110 | Assert.AreEqual(DateTime.Now.Year.ToString(), line.Substring(14, 4)); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /UnitTest/UnitTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {DF845C59-4B39-4A8A-AC89-E5336B57076B} 7 | Library 8 | Properties 9 | UnitTest 10 | UnitTest 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | 41 | ..\CSharpHTTPClient\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.core.dll 42 | True 43 | 44 | 45 | ..\CSharpHTTPClient\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.core.interfaces.dll 46 | True 47 | 48 | 49 | ..\CSharpHTTPClient\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.framework.dll 50 | True 51 | 52 | 53 | ..\CSharpHTTPClient\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.util.dll 54 | True 55 | 56 | 57 | ..\CSharpHTTPClient\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll 58 | True 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | {26c4841f-ec62-4ec7-b16e-3a7386ea36dc} 78 | CSharpHTTPClient 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | False 89 | 90 | 91 | False 92 | 93 | 94 | False 95 | 96 | 97 | False 98 | 99 | 100 | 101 | 102 | 103 | 104 | 111 | -------------------------------------------------------------------------------- /UnitTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UseCases/README.md: -------------------------------------------------------------------------------- 1 | # Use Cases 2 | 3 | This directory provides examples for specific use cases of this library. Please [open an issue](https://github.com/sendgrid/csharp-http-client/issues) or make a pull request for any use cases you would like us to document here. Thank you! -------------------------------------------------------------------------------- /csharphttpclient.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/csharp-http-client/f0927ddc10918450c833d37a41affc83f2fac525/csharphttpclient.snk -------------------------------------------------------------------------------- /static/img/github-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/csharp-http-client/f0927ddc10918450c833d37a41affc83f2fac525/static/img/github-fork.png -------------------------------------------------------------------------------- /static/img/github-sign-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/csharp-http-client/f0927ddc10918450c833d37a41affc83f2fac525/static/img/github-sign-up.png -------------------------------------------------------------------------------- /twilio_sendgrid_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/csharp-http-client/f0927ddc10918450c833d37a41affc83f2fac525/twilio_sendgrid_logo.png --------------------------------------------------------------------------------