{"id":29583545,"url":"https://github.com/easypost/easyvcr-csharp","last_synced_at":"2025-07-19T23:13:49.878Z","repository":{"id":37947823,"uuid":"468484216","full_name":"EasyPost/easyvcr-csharp","owner":"EasyPost","description":"EasyVCR is a .NET library for recording and replaying HTTP interactions, packed with advanced features to customize your testing experience. Based on the great Scotch library.","archived":false,"fork":false,"pushed_at":"2025-04-23T16:19:20.000Z","size":457,"stargazers_count":14,"open_issues_count":1,"forks_count":5,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-07-07T07:57:31.824Z","etag":null,"topics":["http","request","testing","vcr"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EasyPost.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-10T19:30:45.000Z","updated_at":"2025-04-23T16:19:23.000Z","dependencies_parsed_at":"2024-06-06T23:01:06.491Z","dependency_job_id":"69653bdd-88ab-475b-9af7-30a969506560","html_url":"https://github.com/EasyPost/easyvcr-csharp","commit_stats":{"total_commits":134,"total_committers":7,"mean_commits":"19.142857142857142","dds":0.5522388059701493,"last_synced_commit":"edf9882704932573c36a2b5b06ea97973a160787"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/EasyPost/easyvcr-csharp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyPost%2Feasyvcr-csharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyPost%2Feasyvcr-csharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyPost%2Feasyvcr-csharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyPost%2Feasyvcr-csharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EasyPost","download_url":"https://codeload.github.com/EasyPost/easyvcr-csharp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyPost%2Feasyvcr-csharp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266039073,"owners_count":23867824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","request","testing","vcr"],"created_at":"2025-07-19T23:13:48.248Z","updated_at":"2025-07-19T23:13:49.869Z","avatar_url":"https://github.com/EasyPost.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyVCR\r\n\r\n[![CI](https://github.com/EasyPost/easyvcr-csharp/workflows/CI/badge.svg)](https://github.com/EasyPost/easyvcr-csharp/actions?query=workflow%3ACI)\r\n[![Coverage Status](https://coveralls.io/repos/github/EasyPost/easyvcr-csharp/badge.svg?branch=master)](https://coveralls.io/github/EasyPost/easyvcr-csharp?branch=master)\r\n[![NuGet](https://img.shields.io/nuget/dt/EasyVCR)](https://www.nuget.org/packages/EasyVCR)\r\n\r\nEasyVCR is a library for recording and replaying HTTP interactions in your test suite.\r\n\r\nThis can be useful for speeding up your test suite, or for running your tests on a CI server which doesn't have\r\nconnectivity to the HTTP endpoints you need to interact with.\r\n\r\n## How to use EasyVCR\r\n\r\n#### Step 1\r\n\r\nRun your test suite locally against a real HTTP endpoint in recording mode\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\n// Create a cassette to handle HTTP interactions\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\n\r\n// create an EasyVcrHttpClient using the cassette\r\nvar recordingHttpClient = HttpClients.NewHttpClient(cassette, Mode.Record);\r\n\r\n// Use this EasyVcrHttpClient in any class making HTTP calls\r\n// Note: EasyVcrHttpClient implements HttpClient, so it can be used anywhere a HttpClient is expected\r\n// For example, RestSharp v107+ supports custom HTTP clients\r\nRestClient restClient = new RestClient(recordingHttpClient, new RestClientOptions());\r\n\r\n// Or make HTTP calls directly\r\nvar response = await recordingHttpClient.GetAsync(\"https://api.example.com/v1/users\");\r\n```\r\n\r\nReal HTTP calls will be made and recorded to the cassette file.\r\n\r\n#### Step 2\r\n\r\nSwitch to replay mode:\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\n// Create a cassette to handle HTTP interactions\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\n\r\n// create an EasyVcrHttpClient using the cassette\r\nvar replayingHttpClient = HttpClients.NewHttpClient(cassette, Mode.Replay);\r\n```\r\n\r\nNow when tests are run, no real HTTP calls will be made. Instead, the HTTP responses will be replayed from the cassette\r\nfile.\r\n\r\n### Available modes\r\n\r\n- `Mode.Auto`:  Play back a request if it has been recorded before, or record a new one if not. (default mode for `VCR`)\r\n- `Mode.Record`: Record a request, including overwriting any existing matching recording.\r\n- `Mode.Replay`: Replay a request. Throws an exception if no matching recording is found.\r\n- `Mode.Bypass`:  Do not record or replay any requests (client will behave like a normal HttpClient).\r\n\r\n## Features\r\n\r\n`EasyVCR` comes with a number of features, many of which can be customized via the `AdvancedOptions` class.\r\n\r\n### Censoring\r\n\r\nCensor sensitive data in the request and response, such as API keys and auth tokens.\r\n\r\nCan censor:\r\n\r\n- Request and response headers (via key name)\r\n- Request and response bodies (via key name) (JSON only)\r\n- Request query parameters (via key name)\r\n- Request URL path elements (via regex pattern matching)\r\n\r\n**Default**: *Disabled*\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\n\r\nvar headerCensors = new List\u003cKeyCensorElement\u003e {\r\n    new(\"Authorization\", false), // Hide the Authorization header\r\n};\r\nvar bodyCensors = new List\u003cKeyCensorElement\u003e {\r\n    new(\"table\", true), // Hide the table element (case sensitive) in the request and response body\r\n};\r\nvar pathCensors = new List\u003cPatternCensorElement\u003e {\r\n    new(\".*\\\\d{4}.*\"), // Hide any path element that contains 4 digits\r\n};\r\nvar censors = new Censors().CensorHeaders(headerCensors)\r\n                           .CensorBodyElements(bodyCensors)\r\n                           .CensorPathElements(pathCensors);\r\n\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    Censors = censors\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Record, advancedSettings);\r\n```\r\n\r\n### Delay\r\n\r\nSimulate a delay when replaying a recorded request, either using a specified delay or the original request duration.\r\n\r\nNOTE: Delays may suffer from a small margin of error on certain .NET versions. Do not rely on the delay being exact down\r\nto the millisecond.\r\n\r\n**Default**: *No delay*\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    SimulateDelay = true, // Simulate a delay of the original request duration when replaying (overrides ManualDelay)\r\n    ManualDelay = 1000 // Simulate a delay of 1000 milliseconds when replaying\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n### Expiration\r\n\r\nSet expiration dates for recorded requests, and decide what to do with expired recordings.\r\n\r\n**Default**: *No expiration*\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    ValidTimeFrame = new TimeFrame() {  // Any matching request is considered expired if it was recorded more than 30 days ago\r\n        Days = 30,\r\n    },\r\n    WhenExpired = ExpirationActions.ThrowException // Throw exception if the recording is expired\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n### Matching\r\n\r\nCustomize how a recorded request is determined to be a match to the current request.\r\n\r\n**Default**: *Method and full URL must match*\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    MatchRules = new MatchRules().ByBody().ByHeader(\"X-My-Header\"), // Match recorded requests by body and a specific header\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n### Ordering\r\n\r\nCustomize how elements of a recorded request are organized in the cassette file.\r\nHelpful to avoid unnecessary git differences between cassette file versions.\r\n\r\n**Default**: *Elements are stored alphabetically*\r\n\r\n**NOTE:** This setting must be used when creating the cassette.\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar order = new CassetteOrder.None(); // elements of each request in a cassette won't be ordered in any particular way\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\", order);\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n### Logging\r\n\r\nHave EasyVCR integrate with your custom logger to log warnings and errors.\r\n\r\n**Default**: *Logs to console*\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    Logger = new MyCustomLogger(), // Have EasyVCR use your custom logger when making log entries\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n### HttpClient Conversion\r\n\r\nOverride how HttpClient request and response objects are converted into `EasyVCR` request and response objects, and vice\r\nversa.\r\nUseful if `HttpClient` suffers breaking changes in future .NET versions.\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvar advancedOptions = new AdvancedOptions()\r\n{\r\n    InteractionConverter = new MyInteractionConverter(), // use a custom interaction converter by implementing IInteractionConverter\r\n};\r\n\r\nvar httpClient = HttpClients.NewHttpClient(cassette, Mode.Replay, advancedSettings);\r\n```\r\n\r\n## VCR\r\n\r\nIn addition to individual recordable HttpClient instances, `EasyVCR` also offers a built-in VCR, which can be used to\r\neasily switch between multiple cassettes and/or modes. Any advanced settings applied to the VCR will be applied on every\r\nrequest made using the VCR's HttpClient.\r\n\r\n```csharp\r\nusing EasyVCR;\r\n\r\nvar queryParameterCensors = new List\u003cKeyCensorElement\u003e {\r\n    new(\"api_key\", true), // Hide the api_key query parameter\r\n};\r\nvar advancedSettings = new AdvancedSettings\r\n{\r\n    Censors = new Censors().CensorQueryParameters(queryParameterCensors)\r\n};\r\n\r\n// Create a VCR with the advanced settings applied\r\nvar vcr = new VCR(advancedSettings);\r\n\r\n// Create a cassette and add it to the VCR\r\nvar cassette = new Cassette(\"path/to/cassettes\", \"my_cassette\");\r\nvcr.Insert(cassette);\r\n       \r\n// Set the VCR to record mode     \r\nvcr.Record();\r\n            \r\n// Get an HttpClient using the VCR\r\nvar httpClient = vcr.Client;\r\n            \r\n// Use the HttpClient as you would normally.\r\nvar response = await httpClient.GetAsync(\"https://google.com\");\r\n\r\n// Remove the cassette from the VCR            \r\nvcr.Eject();\r\n```\r\n\r\n#### Credit\r\n\r\n- [Scotch by Martin Leech](https://github.com/mleech/scotch), whose core functionality on which this is based.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasypost%2Feasyvcr-csharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasypost%2Feasyvcr-csharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasypost%2Feasyvcr-csharp/lists"}