Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions build/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,45 @@ def _copy_examples(self):

logging.info(f'Copying {self._id} examples to {dst}')

content_filter = ex.get('content_filter')

for f in glob.glob(os.path.join(src, ex.get('pattern')), recursive=True):
# Apply content filter if specified
if content_filter:
with open(f, 'r', encoding='utf-8', errors='ignore') as cf:
file_lines = cf.readlines()
contains = content_filter.get('contains')
not_contains = content_filter.get('not_contains')
exclude_line = content_filter.get('exclude_line_contains')

if contains:
# At least one line must contain `contains`, ignoring
# any lines that also contain `exclude_line` (if set).
matched = any(
contains in line and
(exclude_line is None or exclude_line not in line)
for line in file_lines
)
if not matched:
logging.debug(
f'Skipping {f}: no qualifying line contains "{contains}"'
)
continue

if not_contains:
# No line may contain `not_contains`, ignoring any
# lines that also contain `exclude_line` (if set).
has_disqualifying = any(
not_contains in line and
(exclude_line is None or exclude_line not in line)
for line in file_lines
)
if has_disqualifying:
logging.debug(
f'Skipping {f}: found disqualifying line with "{not_contains}"'
)
continue

example_id = self._get_example_id_from_file(f)

if not example_id:
Expand Down
50 changes: 41 additions & 9 deletions build/local_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,34 @@
'node.js': 'Node.js',
'go': 'Go',
'c': 'C',
'c#': 'C#-Sync',
'c#': 'C#-Sync (NRedisStack)', # Default; overridden by content check in get_client_name_from_language_and_path
'java': 'Java-Sync', # Default to sync, could be overridden
'php': 'PHP',
'ruby': 'Ruby',
'redisvl': 'RedisVL',
'rust': 'Rust-Sync'
}

# Marker used to identify NRedisStack examples (matches any NRedisStack namespace import)
NREDISSTACK_IMPORT_MARKER = 'using NRedisStack'
# Test-infrastructure import that appears in every C# file regardless of client
NREDISSTACK_TEST_IMPORT = 'using NRedisStack.Tests'


def is_nredisstack_example(content: str) -> bool:
"""Return True if the file genuinely uses NRedisStack.

Checks line by line for NREDISSTACK_IMPORT_MARKER ('using NRedisStack'),
but ignores lines that contain NREDISSTACK_TEST_IMPORT ('using NRedisStack.Tests')
because that import appears in every C# test file as test-infrastructure
boilerplate, regardless of whether the example uses NRedisStack or plain
StackExchange.Redis.
"""
return any(
NREDISSTACK_IMPORT_MARKER in line and NREDISSTACK_TEST_IMPORT not in line
for line in content.splitlines()
)


def get_language_from_extension(filename: str) -> str:
"""Get language from file extension."""
Expand All @@ -60,8 +80,9 @@ def get_client_name_from_language(language: str) -> str:
return LANGUAGE_TO_CLIENT.get(language, language.title())


def get_client_name_from_language_and_path(language: str, path: str) -> str:
"""Get client name from language with path-based overrides.
def get_client_name_from_language_and_path(language: str, path: str,
content: str = '') -> str:
"""Get client name from language with path-based and content-based overrides.

For JavaScript (.js) files, override based on path substrings:
- If 'ioredis' in path -> ioredis
Expand All @@ -72,6 +93,12 @@ def get_client_name_from_language_and_path(language: str, path: str) -> str:
- If 'lettuce-async' in path -> Java-Async
- If 'lettuce-reactive' in path -> Java-Reactive

For C# (.cs) files, override based on path substrings and file content:
- Sync vs Async determined by 'async' appearing in the path
- NRedisStack vs SE.Redis determined by the presence of NREDISSTACK_IMPORT_MARKER
('using NRedisStack') anywhere in the file content, which matches both the root
namespace import and any subnamespace imports (e.g. 'using NRedisStack.Search;').

Substring checks are case-sensitive and can appear anywhere in the path.
"""
if language == 'node.js':
Expand All @@ -90,10 +117,9 @@ def get_client_name_from_language_and_path(language: str, path: str) -> str:
if 'rust-sync' in path:
return 'Rust-Sync'
if language == 'c#':
if 'async' in path:
return 'C#-Async'
if 'sync' in path:
return 'C#-Sync'
variant = 'Async' if 'async' in path else 'Sync'
client = 'NRedisStack' if is_nredisstack_example(content) else 'SE.Redis'
return f'C#-{variant} ({client})'
# Default behavior for all languages (and Java fallback)
return get_client_name_from_language(language)

Expand Down Expand Up @@ -180,11 +206,17 @@ def process_local_examples(local_examples_dir: str = 'local_examples',
target_file = os.path.join(target_dir, target_filename)
shutil.copy2(source_file, target_file)

# Read source file content for content-based client detection
# (must be done before Example processes the copy, which strips markers)
with open(source_file, 'r', encoding='utf-8', errors='ignore') as sf:
source_content = sf.read()

# Process with Example class
example = Example(language, target_file)

# Get client name (with Java path-based overrides)
client_name = get_client_name_from_language_and_path(language, source_file)
# Get client name (with path-based and content-based overrides)
client_name = get_client_name_from_language_and_path(
language, source_file, source_content)

# Create metadata
example_metadata = {
Expand Down
8 changes: 5 additions & 3 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ tagManagerId = "GTM-TKZ6J9R"
gitHubRepo = "https://github.com/redis/docs"

# Display and sort order for client examples
clientsExamples = ["Python", "Node.js", "ioredis", "Java-Sync", "Lettuce-Sync", "Java-Async", "Java-Reactive", "Go", "C", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Ruby", "Rust-Sync", "Rust-Async"]
clientsExamples = ["Python", "Node.js", "ioredis", "Java-Sync", "Lettuce-Sync", "Java-Async", "Java-Reactive", "Go", "C", "C#-Sync (NRedisStack)", "C#-Async (NRedisStack)", "C#-Sync (SE.Redis)", "C#-Async (SE.Redis)", "RedisVL", "PHP", "Ruby", "Rust-Sync", "Rust-Async"]
searchService = "/convai/api/search-service"
ratingsService = "/docusight/api/rate/docs"

Expand All @@ -70,8 +70,10 @@ rdi_current_version = "1.16.2"
"Java-Reactive"={quickstartSlug="lettuce", langId="java", clientId="lettuce", clientName="Lettuce", mappingClientId="lettuce_reactive"}
"Go"={quickstartSlug="go", langId="go", clientId="go-redis", clientName="go-redis", mappingClientId="go-redis"}
"C"={quickstartSlug="hiredis", langId="c", clientId="hiredis", clientName="hiredis", mappingClientId=""}
"C#-Sync"={quickstartSlug="dotnet", langId="csharp", clientId="stackexchange-redis", clientName="StackExchange.Redis", mappingClientId="nredisstack_sync"}
"C#-Async"={quickstartSlug="dotnet", langId="csharp", clientId="stackexchange-redis", clientName="StackExchange.Redis", mappingClientId="nredisstack_async"}
"C#-Sync (NRedisStack)"={quickstartSlug="dotnet", langId="csharp", clientId="nredisstack", clientName="NRedisStack", mappingClientId="nredisstack_sync"}
"C#-Async (NRedisStack)"={quickstartSlug="dotnet", langId="csharp", clientId="nredisstack", clientName="NRedisStack", mappingClientId="nredisstack_async"}
"C#-Sync (SE.Redis)"={quickstartSlug="dotnet", langId="csharp", clientId="stackexchange-redis", clientName="StackExchange.Redis", mappingClientId="nredisstack_sync"}
"C#-Async (SE.Redis)"={quickstartSlug="dotnet", langId="csharp", clientId="stackexchange-redis", clientName="StackExchange.Redis", mappingClientId="nredisstack_async"}
"RedisVL"={quickstartSlug="redis-vl", langId="python", clientId="redis-vl", clientName="RedisVL", mappingClientId="redis_vl"}
"PHP"={quickstartSlug="php", langId="php", clientId="predis", clientName="Predis", mappingClientId="php"}
"Ruby"={quickstartSlug="redis-rb", langId="ruby", clientId="redis-rb", clientName="redis-rb", mappingClientId="redis_rb"}
Expand Down
2 changes: 1 addition & 1 deletion content/develop/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ or analyze and manage your database with our
| | Get started | Document search | Vector search |
|:----- | :-----: | :-----: | :-----:|
| [Python]({{< relref "/develop/clients/redis-py" >}}) | [See Python examples]({{< relref "/develop/clients/redis-py/connect" >}}) | [See Python examples]({{< relref "/develop/clients/redis-py/queryjson" >}}) | [See Python examples]({{< relref "/develop/clients/redis-py/vecsearch" >}}) |
| [C#/.NET]({{< relref "/develop/clients/dotnet" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/connect" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/queryjson" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/vecsearch" >}}) |
| [C#/.NET]({{< relref "/develop/clients/dotnet" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/connect" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/nredisstack/queryjson" >}}) | [See C# examples]({{< relref "/develop/clients/dotnet/nredisstack/vecsearch" >}}) |
| [Node.js]({{< relref "/develop/clients/nodejs" >}}) | [See JS examples]({{< relref "/develop/clients/nodejs/connect" >}}) | [See JS examples]({{< relref "/develop/clients/nodejs/queryjson" >}}) | [See JS examples]({{< relref "/develop/clients/nodejs/vecsearch" >}}) |
| [Java (Jedis)]({{< relref "/develop/clients/jedis" >}}) | [See Java examples]({{< relref "/develop/clients/jedis/connect" >}}) | [See Java examples]({{< relref "/develop/clients/jedis/queryjson" >}}) | [See Java examples]({{< relref "/develop/clients/jedis/vecsearch" >}}) |
| [Java (Lettuce)]({{< relref "/develop/clients/lettuce" >}}) | [See Java examples]({{< relref "/develop/clients/lettuce/connect" >}}) | [See Java examples]({{< relref "/develop/clients/lettuce/queryjson" >}}) | [See Java examples]({{< relref "/develop/clients/lettuce/vecsearch" >}}) |
Expand Down
2 changes: 1 addition & 1 deletion content/develop/ai/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ This page is organized into a few sections depending on what you're trying to do

#### Learn how to index and query vector embeddings
* [redis-py (Python)]({{< relref "/develop/clients/redis-py/vecsearch" >}})
* [NRedisStack (C#/.NET)]({{< relref "/develop/clients/dotnet/vecsearch" >}})
* [NRedisStack (C#/.NET)]({{< relref "/develop/clients/dotnet/nredisstack/vecsearch" >}})
* [node-redis (JavaScript)]({{< relref "/develop/clients/nodejs/vecsearch" >}})
* [Jedis (Java)]({{< relref "/develop/clients/jedis/vecsearch" >}})
* [go-redis (Go)]({{< relref "/develop/clients/go/vecsearch" >}})
Expand Down
34 changes: 29 additions & 5 deletions content/develop/clients/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ for nine main languages:
| :-- | :-- | :-- | :-- |
| [Python](https://www.python.org/) | [`redis-py`](https://github.com/redis/redis-py) |[`redis-py` guide]({{< relref "/develop/clients/redis-py" >}}) | Yes |
| [Python](https://www.python.org/) | [`RedisVL`](https://github.com/redis/redis-vl-python) |[RedisVL guide]({{< relref "/develop/ai/redisvl" >}}) | Yes
| [C#/.NET](https://learn.microsoft.com/en-us/dotnet/csharp/) | [`NRedisStack`](https://github.com/redis/NRedisStack) |[`NRedisStack` guide]({{< relref "/develop/clients/dotnet" >}}) | Yes |
| [C#/.NET](https://learn.microsoft.com/en-us/dotnet/csharp/) | [`StackExchange.Redis`](https://github.com/StackExchange/StackExchange.Redis) |[`StackExchange.Redis` guide]({{< relref "/develop/clients/dotnet" >}}) | Yes |
| [C#/.NET](https://learn.microsoft.com/en-us/dotnet/csharp/) | [`NRedisStack`](https://github.com/redis/NRedisStack) |[`NRedisStack` guide]({{< relref "/develop/clients/dotnet/nredisstack" >}}) | Yes |
| [JavaScript](https://nodejs.org/en) | [`node-redis`](https://github.com/redis/node-redis) | [`node-redis` guide]({{< relref "/develop/clients/nodejs" >}}) | Yes |
| [JavaScript](https://nodejs.org/en) | [`ioredis`](https://github.com/redis/ioredis) | [`ioredis` guide]({{< relref "/develop/clients/ioredis" >}}) | Yes |
| [Java](https://www.java.com/en/) | [`Jedis`](https://github.com/redis/jedis) | [`Jedis` guide]({{< relref "/develop/clients/jedis" >}}) | Yes |
Expand Down Expand Up @@ -113,8 +114,14 @@ between the options for each language.

### C#

- [`NRedisStack`](https://github.com/redis/NRedisStack) is the recommended C# client
library for most use cases.
- [`StackExchange.Redis`](https://github.com/StackExchange/StackExchange.Redis) is the
recommended C# client library for using the core Redis data types and commands.
- [`NRedisStack`](https://github.com/redis/NRedisStack) builds upon
`StackExchange.Redis` with
support for an extended set of data types and features, such as
[JSON]({{< relref "/develop/data-types/json" >}}),
[Redis search]({{< relref "/develop/ai/search-and-query" >}}), and
[Time series]({{< relref "/develop/data-types/timeseries" >}}).
- [RedisOM for .NET](https://github.com/redis/redis-om-dotnet) is an object mapping library that
provides a high-level API for working with Redis data structures.

Expand Down Expand Up @@ -199,9 +206,26 @@ questions:
nextQuestion: phpLowLevelQuestion
dotnet:
value: "C#"
nextQuestion: dotnetLowLevelQuestion

dotnetLowLevelQuestion:
text: |
Do you need Redis Stack features such as JSON,
Search, vector search, or Time series?
whyAsk: |
StackExchange.Redis is the recommended client for core Redis commands,
while NRedisStack extends it with support for Redis Stack data types and features
answers:
yes:
value: "Yes"
outcome:
label: Use NRedisStack
id: nredisStackOutcome
id: nRedisStackOutcome
no:
value: "No"
outcome:
label: Use StackExchange.Redis
id: stackExchangeRedisOutcome

pythonLowLevelQuestion:
text: |
Expand Down Expand Up @@ -285,4 +309,4 @@ questions:
outcome:
label: Use Predis
id: predisOutcome
```
```
48 changes: 21 additions & 27 deletions content/develop/clients/dotnet/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,67 +11,61 @@ categories:
- kubernetes
- clients
description: Connect your .NET application to a Redis database
linkTitle: NRedisStack (C#/.NET)
title: NRedisStack guide (C#/.NET)
linkTitle: StackExchange.Redis (C#/.NET)
title: StackExchange.Redis guide (C#/.NET)
weight: 3
---

[NRedisStack](https://github.com/redis/NRedisStack) is the .NET client for Redis.
The sections below explain how to install `NRedisStack` and connect your application
to a Redis database.
[StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis) is the main
.NET client for Redis. It provides an API for the core Redis data types and commands.
A separate library,
[NRedisStack](https://github.com/redis/NRedisStack), builds upon `StackExchange.Redis` with
support for an extended set of data types and features, such as [JSON]({{< relref "/develop/data-types/json" >}}),
[Redis search]({{< relref "/develop/ai/search-and-query" >}}),
[probabilistic data types]({{< relref "/develop/data-types/probabilistic" >}}), and
[Time series]({{< relref "/develop/data-types/timeseries" >}}).

`NRedisStack` requires a running Redis server. See [here]({{< relref "/operate/oss_and_stack/install/" >}}) for Redis Open Source installation instructions.
The sections below explain how to install `StackExchange.Redis` and connect your application
to a Redis database. See the [NRedisStack guide]({{< relref "/develop/clients/dotnet/nredisstack" >}}) for information about installing and using `NRedisStack` to access the extended feature set.

`StackExchange.Redis` requires a running Redis server. See [here]({{< relref "/operate/oss_and_stack/install/" >}}) for Redis Open Source installation instructions.

{{< note >}}
You can also access Redis with an object-mapping client interface. See
[Redis OM for .NET]({{< relref "/integrate/redisom-for-net" >}})
for more information.
{{< /note >}}

## Install

Using the `dotnet` CLI, run:

```bash
dotnet add package NRedisStack
dotnet add package StackExchange.Redis
```

## Connect and test

Add the following imports to your source file:

{{< clients-example set="landing" step="import" lang_filter="C#-Sync,C#-Async" description="Foundational: Import required NRedisStack namespaces for Redis client functionality" difficulty="beginner" >}}
{{< clients-example set="landing" step="import" lang_filter="C#-Sync (SE.Redis),C#-Async (SE.Redis)" description="Foundational: Import required SE.Redis namespaces for Redis client functionality" difficulty="beginner" >}}
Comment thread
cursor[bot] marked this conversation as resolved.
{{< /clients-example >}}

Connect to localhost on port 6379. The client supports both synchronous and asynchronous commands.

{{< clients-example set="landing" step="connect" lang_filter="C#-Sync,C#-Async" description="Foundational: Connect to a Redis server and establish a client connection" difficulty="beginner" >}}
{{< clients-example set="landing" step="connect" lang_filter="C#-Sync (SE.Redis),C#-Async (SE.Redis)" description="Foundational: Connect to a Redis server and establish a client connection" difficulty="beginner" >}}
{{< /clients-example >}}

You can test the connection by storing and retrieving a simple string.

{{< clients-example set="landing" step="set_get_string" lang_filter="C#-Sync,C#-Async" description="Foundational: Set and retrieve string values using SET and GET commands" difficulty="beginner" >}}
{{< clients-example set="landing" step="set_get_string" lang_filter="C#-Sync (SE.Redis),C#-Async (SE.Redis)" description="Foundational: Set and retrieve string values using SET and GET commands" difficulty="beginner" >}}
{{< /clients-example >}}

Store and retrieve a HashMap.

{{< clients-example set="landing" step="set_get_hash" lang_filter="C#-Sync,C#-Async" description="Foundational: Store and retrieve hash data structures using HSET and HGETALL" difficulty="beginner" >}}
{{< clients-example set="landing" step="set_get_hash" lang_filter="C#-Sync (SE.Redis),C#-Async (SE.Redis)" description="Foundational: Store and retrieve hash data structures using HSET and HGETALL" difficulty="beginner" >}}
{{< /clients-example >}}

## Redis Open Source modules

To access Redis Open Source capabilities, use the appropriate interface like this:

```cs
IBloomCommands bf = db.BF();
ICuckooCommands cf = db.CF();
ICmsCommands cms = db.CMS();
IGraphCommands graph = db.GRAPH();
ITopKCommands topk = db.TOPK();
ITdigestCommands tdigest = db.TDIGEST();
ISearchCommands ft = db.FT();
IJsonCommands json = db.JSON();
ITimeSeriesCommands ts = db.TS();
```

## More information

See the other pages in this section for more information and examples.
Loading
Loading