diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a2bebb7c..910584a0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -30,13 +30,15 @@ jobs: dotnet-version: "6.0.x" - name: Verify README generation - uses: momentohq/standards-and-practices/github-actions/oss-readme-template@gh-actions-v1 + uses: momentohq/standards-and-practices/github-actions/oss-readme-template@gh-actions-v2 with: project_status: official project_stability: stable project_type: sdk sdk_language: .NET - usage_example_path: ./examples/MomentoUsage/Program.cs + template_file: ./README.template.md + output_file: ./README.md + dev_docs_slug: dotnet - name: Commitlint and Other Shared Build Steps uses: momentohq/standards-and-practices/github-actions/shared-build@gh-actions-v1 diff --git a/.github/workflows/on-push-to-main-branch.yaml b/.github/workflows/on-push-to-main-branch.yaml index 3f57668f..3ef97e4f 100644 --- a/.github/workflows/on-push-to-main-branch.yaml +++ b/.github/workflows/on-push-to-main-branch.yaml @@ -42,10 +42,12 @@ jobs: run: dotnet test -f ${{ matrix.target-framework }} tests/Integration/Momento.Sdk.Tests - name: Generate README - uses: momentohq/standards-and-practices/github-actions/generate-and-commit-oss-readme@gh-actions-v1 + uses: momentohq/standards-and-practices/github-actions/generate-and-commit-oss-readme@gh-actions-v2 with: project_status: official project_stability: stable project_type: sdk sdk_language: .NET - usage_example_path: ./examples/MomentoUsage/Program.cs + template_file: ./README.template.md + output_file: ./README.md + dev_docs_slug: dotnet diff --git a/README.old.md b/README.old.md new file mode 100644 index 00000000..59da2f6f --- /dev/null +++ b/README.old.md @@ -0,0 +1,184 @@ + + + +logo + +[![project status](https://momentohq.github.io/standards-and-practices/badges/project-status-official.svg)](https://github.com/momentohq/standards-and-practices/blob/main/docs/momento-on-github.md) +[![project stability](https://momentohq.github.io/standards-and-practices/badges/project-stability-stable.svg)](https://github.com/momentohq/standards-and-practices/blob/main/docs/momento-on-github.md) + +# Momento .NET Client Library + + +.NET client SDK for Momento Serverless Cache: a fast, simple, pay-as-you-go caching solution without +any of the operational overhead required by traditional caching solutions! + + + +Japanese: [日本語](README.ja.md) + +## Getting Started :running: + +### Requirements + +You will need the [`dotnet` runtime and command line tools](https://dotnet.microsoft.com/en-us/download). After installing them, you should have the `dotnet` command on your PATH. + +**IDE Notes**: You will most likely want an IDE that supports .NET development, such as [Microsoft Visual Studio](https://visualstudio.microsoft.com/vs), [JetBrains Rider](https://www.jetbrains.com/rider/), or [Microsoft Visual Studio Code](https://code.visualstudio.com/). + +### Examples + +Ready to dive right in? Just check out the [examples](./examples/README.md) directory for complete, working examples of +how to use the SDK. + +### Momento Response Types + +The return values of the methods on the Momento `CacheClient` class are designed to allow you to use your +IDE to help you easily discover all the possible responses, including errors. We use [pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching) to distinguish between different types of responses, +which means that you can get compile-time safety when interacting with the API, rather than having bugs sneak in at runtime. + +Here's an example: + +```csharp +CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); +if (getResponse is CacheGetResponse.Hit hitResponse) +{ + Console.WriteLine($"Looked up value: {hitResponse.ValueString}, Stored value: {VALUE}"); +} +else if (getResponse is CacheGetResponse.Error getError) +{ + Console.WriteLine($"Error getting value: {getError.Message}"); +} +``` + +See the [Error Handling](#error-handling) section below for more details. + +### Installation + +To create a new .NET project and add the Momento client library as a dependency: + +```bash +mkdir my-momento-dotnet-project +cd my-momento-dotnet-project +dotnet new console +dotnet add package Momento.Sdk +``` + +### Usage + +Here is a quickstart you can use in your own project: + +```csharp +using System; +using Momento.Sdk; +using Momento.Sdk.Auth; +using Momento.Sdk.Config; +using Momento.Sdk.Responses; + +ICredentialProvider authProvider = new EnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN"); +const string CACHE_NAME = "cache"; +const string KEY = "MyKey"; +const string VALUE = "MyData"; +TimeSpan DEFAULT_TTL = TimeSpan.FromSeconds(60); + +using (ICacheClient client = new CacheClient(Configurations.Laptop.V1(), authProvider, DEFAULT_TTL)) +{ + var createCacheResponse = await client.CreateCacheAsync(CACHE_NAME); + if (createCacheResponse is CreateCacheResponse.Error createError) + { + Console.WriteLine($"Error creating cache: {createError.Message}. Exiting."); + Environment.Exit(1); + } + + Console.WriteLine($"Setting key: {KEY} with value: {VALUE}"); + var setResponse = await client.SetAsync(CACHE_NAME, KEY, VALUE); + if (setResponse is CacheSetResponse.Error setError) + { + Console.WriteLine($"Error setting value: {setError.Message}. Exiting."); + Environment.Exit(1); + } + + Console.WriteLine($"Get value for key: {KEY}"); + CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); + if (getResponse is CacheGetResponse.Hit hitResponse) + { + Console.WriteLine($"Looked up value: {hitResponse.ValueString}, Stored value: {VALUE}"); + } + else if (getResponse is CacheGetResponse.Error getError) + { + Console.WriteLine($"Error getting value: {getError.Message}"); + } +} + +``` + +Note that the above code requires an environment variable named MOMENTO_AUTH_TOKEN which must +be set to a valid [Momento authentication token](https://docs.momentohq.com/docs/getting-started#obtain-an-auth-token). + +### Error Handling + +Error that occur in calls to CacheClient methods are surfaced to developers as part of the return values of +the calls, as opposed to by throwing exceptions. This makes them more visible, and allows your IDE to be more +helpful in ensuring that you've handled the ones you care about. (For more on our philosophy about this, see our +blog post on why [Exceptions are bugs](https://www.gomomento.com/blog/exceptions-are-bugs). And send us any +feedback you have!) + +The preferred way of interpreting the return values from CacheClient methods is using [Pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching). Here's a quick example: + +```csharp +CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); +if (getResponse is CacheGetResponse.Hit hitResponse) +{ + Console.WriteLine($"\nLooked up value: {hitResponse.ValueString}, Stored value: {VALUE}"); +} else { + // you can handle other cases via pattern matching in `else if` blocks, or a default case + // via the `else` block. For each return value your IDE should be able to give you code + // completion indicating the other possible types; in this case, `CacheGetResponse.Miss` and + // `CacheGetResponse.Error`. +} +``` + +Using this approach, you get a type-safe `hitResponse` object in the case of a cache hit. But if the cache read +results in a Miss or an error, you'll also get a type-safe object that you can use to get more info about what happened. + +In cases where you get an error response, `Error` types will always include an `ErrorCode` that you can use to check +the error type: + +```csharp +CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); +if (getResponse is CacheGetResponse.Error errorResponse) +{ + if (errorResponse.ErrorCode == MomentoErrorCode.TIMEOUT_ERROR) { + // this would represent a client-side timeout, and you could fall back to your original data source + } +} +``` + +Note that, outside of CacheClient responses, exceptions can occur and should be handled as usual. For example, trying +to instantiate a CacheClient with an invalid authentication token will result in an IllegalArgumentException being thrown. + +### Tuning + +Momento client-libraries provide pre-built configuration bundles out-of-the-box. We want to do the hard work of +tuning for different environments for you, so that you can focus on the things that are unique to your business. +(We even have a blog series about it! [Shockingly simple: Cache clients that do the hard work for you](https://www.gomomento.com/blog/shockingly-simple-cache-clients-that-do-the-hard-work-for-you)) + +You can find the pre-built configurations in our `Configurations` namespace. Some of the pre-built configurations that +you might be interested in: + +- `Configurations.Laptop` - this one is a development environment, just for poking around. It has relaxed timeouts + and assumes that your network latencies might be a bit high. +- `Configurations.InRegion.Default` - provides defaults suitable for an environment where your client is running in the same region as the Momento + service. It has more aggressive timeouts and retry behavior than the Laptop config. +- `Configurations.InRegion.LowLatency` - This config prioritizes keeping p99.9 latencies as low as possible, potentially sacrificing + some throughput to achieve this. Use this configuration if the most important factor is to ensure that cache + unavailability doesn't force unacceptably high latencies for your own application. + +We hope that these configurations will meet the needs of most users, but if you find them lacking in any way, please +open a github issue, or contact us at `support@momentohq.com`. We would love to hear about your use case so that we +can fix or extend the pre-built configs to support it. + +If you do need to customize your configuration beyond what our pre-builts provide, see the +[Advanced Configuration Guide](./docs/advanced-config.md). + +---------------------------------------------------------------------------------------- +For more info, visit our website at [https://gomomento.com](https://gomomento.com)! + diff --git a/README.template.md b/README.template.md index 1c96ee45..a28eb5c5 100644 --- a/README.template.md +++ b/README.template.md @@ -2,127 +2,32 @@ Japanese: [日本語](README.ja.md) -## Getting Started :running: +## Packages -### Requirements +The Momento Dotnet SDK package is available on nuget: [momentohq/client-sdk-dotnet](https://www.nuget.org/packages/Momento.Sdk). -You will need the [`dotnet` runtime and command line tools](https://dotnet.microsoft.com/en-us/download). After installing them, you should have the `dotnet` command on your PATH. - -**IDE Notes**: You will most likely want an IDE that supports .NET development, such as [Microsoft Visual Studio](https://visualstudio.microsoft.com/vs), [JetBrains Rider](https://www.jetbrains.com/rider/), or [Microsoft Visual Studio Code](https://code.visualstudio.com/). - -### Examples - -Ready to dive right in? Just check out the [examples](./examples/README.md) directory for complete, working examples of -how to use the SDK. - -### Momento Response Types - -The return values of the methods on the Momento `CacheClient` class are designed to allow you to use your -IDE to help you easily discover all the possible responses, including errors. We use [pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching) to distinguish between different types of responses, -which means that you can get compile-time safety when interacting with the API, rather than having bugs sneak in at runtime. - -Here's an example: - -```csharp -CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); -if (getResponse is CacheGetResponse.Hit hitResponse) -{ - Console.WriteLine($"Looked up value: {hitResponse.ValueString}, Stored value: {VALUE}"); -} -else if (getResponse is CacheGetResponse.Error getError) -{ - Console.WriteLine($"Error getting value: {getError.Message}"); -} -``` - -See the [Error Handling](#error-handling) section below for more details. - -### Installation - -To create a new .NET project and add the Momento client library as a dependency: - -```bash -mkdir my-momento-dotnet-project -cd my-momento-dotnet-project -dotnet new console -dotnet add package Momento.Sdk -``` - -### Usage +## Usage Here is a quickstart you can use in your own project: ```csharp -{{ usageExampleCode }} +{% include "./examples/MomentoUsage/Program.cs" %} ``` Note that the above code requires an environment variable named MOMENTO_AUTH_TOKEN which must be set to a valid [Momento authentication token](https://docs.momentohq.com/docs/getting-started#obtain-an-auth-token). -### Error Handling - -Error that occur in calls to CacheClient methods are surfaced to developers as part of the return values of -the calls, as opposed to by throwing exceptions. This makes them more visible, and allows your IDE to be more -helpful in ensuring that you've handled the ones you care about. (For more on our philosophy about this, see our -blog post on why [Exceptions are bugs](https://www.gomomento.com/blog/exceptions-are-bugs). And send us any -feedback you have!) - -The preferred way of interpreting the return values from CacheClient methods is using [Pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching). Here's a quick example: - -```csharp -CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); -if (getResponse is CacheGetResponse.Hit hitResponse) -{ - Console.WriteLine($"\nLooked up value: {hitResponse.ValueString}, Stored value: {VALUE}"); -} else { - // you can handle other cases via pattern matching in `else if` blocks, or a default case - // via the `else` block. For each return value your IDE should be able to give you code - // completion indicating the other possible types; in this case, `CacheGetResponse.Miss` and - // `CacheGetResponse.Error`. -} -``` +## Getting Started and Documentation -Using this approach, you get a type-safe `hitResponse` object in the case of a cache hit. But if the cache read -results in a Miss or an error, you'll also get a type-safe object that you can use to get more info about what happened. +Documentation is available on the [Momento Docs website](https://docs.momentohq.com). -In cases where you get an error response, `Error` types will always include an `ErrorCode` that you can use to check -the error type: +## Examples -```csharp -CacheGetResponse getResponse = await client.GetAsync(CACHE_NAME, KEY); -if (getResponse is CacheGetResponse.Error errorResponse) -{ - if (errorResponse.ErrorCode == MomentoErrorCode.TIMEOUT_ERROR) { - // this would represent a client-side timeout, and you could fall back to your original data source - } -} -``` - -Note that, outside of CacheClient responses, exceptions can occur and should be handled as usual. For example, trying -to instantiate a CacheClient with an invalid authentication token will result in an IllegalArgumentException being thrown. - -### Tuning - -Momento client-libraries provide pre-built configuration bundles out-of-the-box. We want to do the hard work of -tuning for different environments for you, so that you can focus on the things that are unique to your business. -(We even have a blog series about it! [Shockingly simple: Cache clients that do the hard work for you](https://www.gomomento.com/blog/shockingly-simple-cache-clients-that-do-the-hard-work-for-you)) - -You can find the pre-built configurations in our `Configurations` namespace. Some of the pre-built configurations that -you might be interested in: - -- `Configurations.Laptop` - this one is a development environment, just for poking around. It has relaxed timeouts - and assumes that your network latencies might be a bit high. -- `Configurations.InRegion.Default` - provides defaults suitable for an environment where your client is running in the same region as the Momento - service. It has more aggressive timeouts and retry behavior than the Laptop config. -- `Configurations.InRegion.LowLatency` - This config prioritizes keeping p99.9 latencies as low as possible, potentially sacrificing - some throughput to achieve this. Use this configuration if the most important factor is to ensure that cache - unavailability doesn't force unacceptably high latencies for your own application. +Ready to dive right in? Just check out the [examples](./examples/README.md) directory for complete, working examples of +how to use the SDK. -We hope that these configurations will meet the needs of most users, but if you find them lacking in any way, please -open a github issue, or contact us at `support@momentohq.com`. We would love to hear about your use case so that we -can fix or extend the pre-built configs to support it. +## Developing -If you do need to customize your configuration beyond what our pre-builts provide, see the -[Advanced Configuration Guide](./docs/advanced-config.md). +If you are interested in contributing to the SDK, please see the [CONTRIBUTING](./CONTRIBUTING.md) docs. {{ ossFooter }}