Write up documentation on posthog-dotnet (#10589)

Co-authored-by: Ian Vanagas <34755028+ivanagas@users.noreply.github.com>
This commit is contained in:
Phil Haack
2025-02-10 07:34:07 -08:00
committed by GitHub
parent 1f2cee1576
commit 4fa912ddc0
19 changed files with 513 additions and 4 deletions

View File

@@ -149,6 +149,14 @@ if feature_flag.enabled == "variant-name" do
end
```
```dotnet
var featureFlag = await posthog.GetFeatureFlagAsync("experiment-feature-flag-key", "user_distinct_id");
if (featureFlag is { VariantKey: "variant-name" })
{
// Do something
}
```
</MultiLanguage>
> Since feature flags are not supported yet in our Java and Rust SDKs, to run an experiment using these SDKs see our docs on [how to run experiments without feature flags](/docs/experiments/running-experiments-without-feature-flags). This also applies to running experiments using our API.
@@ -230,6 +238,13 @@ posthog.capture(
);
```
```dotnet
posthog.Capture(
"distinct_id",
"event_name_of_your_goal_metric",
properties: new() { ["$feature/experiment-feature-flag-key"] = "variant-name" }
);
```
</MultiLanguage>
import Tab from "components/Tab"
@@ -238,6 +253,7 @@ import NodeMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags
import GoMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags-code-go-set-send-feature-flags-to-true.mdx"
import PythonMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags-code-python-set-send-feature-flags-to-true.mdx"
import PHPMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags-code-php-set-send-feature-flags-to-true.mdx"
import DotNetMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags-code-dotnet-set-send-feature-flags-to-true.mdx"
### Method 2: Set `send_feature_flags` to `true`
@@ -265,5 +281,8 @@ import PHPMethod2 from "../integrate/feature-flags-code/_snippets/feature-flags-
<Tab.Panel>
<GoMethod2 />
</Tab.Panel>
<Tab.Panel>
<DotNetMethod2 />
</Tab.Panel>
</Tab.Panels>
</Tab.Group>

View File

@@ -30,9 +30,10 @@ import ReactNativeInstall from '../integrate/_snippets/install-react-native.mdx'
import AndroidInstall from '../integrate/_snippets/install-android.mdx'
import IOSInstall from '../integrate/_snippets/install-ios.mdx'
import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
import DotNetInstall from '../integrate/_snippets/install-dotnet.mdx'
<!-- prettier-ignore -->
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Elixir', 'api']}>
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Elixir', '.NET', 'api']}>
<Tab.List>
<Tab>Web</Tab>
<Tab>React</Tab>
@@ -47,6 +48,7 @@ import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
<Tab>Java</Tab>
<Tab>Rust</Tab>
<Tab>Elixir</Tab>
<Tab>.NET</Tab>
<Tab>API</Tab>
</Tab.List>
<Tab.Panels>
@@ -93,6 +95,9 @@ import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
<Tab.Panel>
<ElixirInstall />
</Tab.Panel>
<Tab.Panel>
<DotNetInstall />
</Tab.Panel>
<Tab.Panel>
<blockquote class='warning-note'>
To run an experiment using the <a href="/docs/api">PostHog API</a>, see our docs on <a href="/docs/experiments/running-experiments-without-feature-flags">how to run experiments without feature flags</a>.

View File

@@ -123,6 +123,16 @@ posthog.capture(
);
```
```csharp
posthog.Capture(
"distinct_id",
"event_name_of_your_goal_metric",
properties: new() {
["$feature/experiment-feature-flag-key"] = "variant-name"
}
);
```
</MultiLanguage>
## Step 4 (optional): Send the `$feature_flag_called` event
@@ -245,4 +255,15 @@ posthog.capture(
);
```
```csharp
posthog.Capture(
"distinct_id",
"$feature_flag_called",
properties: new() {
["$feature_flag_response"] = "variant-name",
["feature_flag"] = "feature-flag-key"
}
);
```
</MultiLanguage>

View File

@@ -25,9 +25,10 @@ import AndroidFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/f
import IOSFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/feature-flags-code-ios.mdx'
import FlutterFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/feature-flags-code-flutter.mdx'
import ElixirFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/feature-flags-code-elixir.mdx'
import DotNetFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/feature-flags-code-dotnet.mdx'
<!-- prettier-ignore -->
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Flutter', 'Java', 'Rust', 'Elixir', 'api']}>
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Flutter', 'Java', 'Rust', 'Elixir', '.NET', 'api']}>
<Tab.List>
<Tab>Web</Tab>
<Tab>React</Tab>
@@ -43,6 +44,7 @@ import ElixirFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/fe
<Tab>Java</Tab>
<Tab>Rust</Tab>
<Tab>Elixir</Tab>
<Tab>.NET</Tab>
<Tab>API</Tab>
</Tab.List>
<Tab.Panels>
@@ -92,6 +94,9 @@ import ElixirFeatureFlagsCode from '../integrate/feature-flags-code/_snippets/fe
<Tab.Panel>
<ElixirFeatureFlagsCode />
</Tab.Panel>
<Tab.Panel>
<DotNetFeatureFlagsCode />
</Tab.Panel>
<Tab.Panel>
<APIFeatureFlagsCode />
</Tab.Panel>

View File

@@ -31,9 +31,10 @@ import JavaInstall from '../integrate/_snippets/install-java.mdx'
import RustInstall from '../integrate/_snippets/install-rust.mdx'
import FlutterInstall from '../integrate/_snippets/install-flutter.mdx'
import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
import DotNetInstall from '../integrate/_snippets/install-dotnet.mdx'
<!-- prettier-ignore -->
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Flutter', 'Elixir', 'api']}>
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Flutter', 'Elixir', '.NET', 'api']}>
<Tab.List>
<Tab>Web</Tab>
<Tab>React</Tab>
@@ -49,6 +50,7 @@ import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
<Tab>Rust</Tab>
<Tab>Flutter</Tab>
<Tab>Elixir</Tab>
<Tab>.NET</Tab>
<Tab>API</Tab>
</Tab.List>
<Tab.Panels>
@@ -98,6 +100,9 @@ import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
<Tab.Panel>
<ElixirInstall />
</Tab.Panel>
<Tab.Panel>
<DotNetInstall />
</Tab.Panel>
<Tab.Panel>
<APIInstall />
<blockquote>

View File

@@ -0,0 +1,55 @@
<DotNetInstall />
At the moment, ASP.NET Core is the only supported platform for the PostHog .NET SDK.
```bash
dotnet add package PostHog.AspNetCore
```
In your `Program.cs` file, add the following code:
```csharp
using PostHog.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.AddPostHog();
```
Make sure to configure PostHog with your project API key, instance address, and optional personal API key. For example, in appsettings.json:
```json
{
"PostHog": {
"ProjectApiKey": "phc_...",
"Host": "https://us.i.posthog.com"
}
}
```
> **Note:** If the host is not specified, the default host `https://us.i.posthog.com` is used.
Use a secrets manager to store your personal API key. For example, when developing locally you can use the `UserSecrets` feature of the `dotnet` CLI:
```bash
dotnet user-secrets init
dotnet user-secrets set "PostHog:PersonalApiKey" "phc_..."
```
You can find your project API key and instance address in the [project settings](https://app.posthog.com/project/settings) page in PostHog.
To see detailed logging, set the log level to `Debug` or `Trace` in `appsettings.json`:
```json
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"PostHog": "Trace"
}
},
...
}
```

View File

@@ -0,0 +1,13 @@
The `Capture()` method has an optional argument `sendFeatureFlags`, which is set to `false` by default. By setting this to `true`, feature flag information will automatically be sent with the event.
Note that by doing this, PostHog will make an additional request to fetch feature flag information before capturing the event. So this method is only recommended if you don't mind the extra API call and delay.
```csharp
posthog.Capture(
"distinct_id_of_your_user",
"event_name",
properties: null,
groups: null,
sendFeatureFlags: true
);
```

View File

@@ -0,0 +1,119 @@
There are 2 steps to implement feature flags in .NET:
### Step 1: Evaluate the feature flag value
#### Boolean feature flags
```csharp
var isMyFlagEnabled = await posthog.IsFeatureEnabledAsync(
"flag-key",
"distinct_id_of_your_user"
);
if (isMyFlagEnabled.GetValueOrDefault())
{
// Feature is enabled
}
else
{
// Feature is disabled
}
```
> **Note:** The `IsFeatureEnabledAsync` method returns a nullable boolean. If the flag is not found or evaluating it is inconclusive, it returns `null`.
#### Multivariate feature flags
```csharp
var flag = await posthog.GetFeatureFlagAsync(
"flag-key",
"distinct_id_of_your_user"
);
// replace "variant-key" with the key of your variant
if (flag is { VariantKey: "variant-key"} ) {
// Do something differently for this user
// Optional: fetch the payload
var matchedPayload = flag.Payload;
}
```
The `GetFeatureFlagAsync` method returns a nullable `FeatureFlag` object. If the flag is not found or evaluating it is inconclusive, it returns `null`. However, there is an implicit conversion to bool to make comparisons easier.
```csharp
if (await posthog.GetFeatureFlagAsync(
"flag-key",
"distinct_id_of_your_user")
)
{
// Do something differently for this user
}
```
import IncludePropertyInEvents from "./include-feature-flag-property-in-backend-events.mdx"
<IncludePropertyInEvents />
There are two methods you can use to include feature flag information in your events:
#### Method 1: Include the `$feature/feature_flag_name` property
In the event properties, include `$feature/feature_flag_name: variant_key`:
```csharp
posthog.Capture(
"distinct_id_of_your_user",
"event_name",
properties: new() {
// replace feature-flag-key with your flag key.
// Replace 'variant-key' with the key of your variant
["$feature/feature-flag-key"] = "variant-key"
}
);
```
#### Method 2: Set `send_feature_flags` to `true`
import DotNetSetSendFeatureFlagsTrue from "./feature-flags-code-dotnet-set-send-feature-flags-to-true.mdx"
<DotNetSetSendFeatureFlagsTrue />
### Fetching all flags for a user
You can fetch all flag values for a single user by calling `GetAllFeatureFlagsAsync()`.
This is useful when you need to fetch multiple flag values and don't want to make multiple requests.
```csharp
var flags = await posthog.GetAllFeatureFlagsAsync(
"distinct_id_of_your_user"
);
```
### Sending `$feature_flag_called` events
Capturing `$feature_flag_called` events enable PostHog to know when a flag was accessed by a user and thus provide [analytics and insights](/docs/product-analytics/insights) on the flag. By default, we send a these event when:
1. You call `posthog.GetFeatureFlagAsync()` or `posthog.IsFeatureEnabledAsync()`, AND
2. It's a new user, or the value of the flag has changed.
> *Note:* Tracking whether it's a new user or if a flag value has changed happens in a local cache. This means that if you reinitialize the PostHog client, the cache resets as well causing `$feature_flag_called` events to be sent again when calling `GetFeatureFlagAsync` or `IsFeatureEnabledAsync`. PostHog is built to handle this, and so duplicate `$feature_flag_called` events won't affect your analytics.
You can disable automatically the additional request to capture `$feature_flag_called` events. For example, when you don't need the analytics, or it's being called at such a high volume that sending events slows things down.
To disable it, set the `sendFeatureFlagsEvent` option in your function call, like so:
```csharp
var isMyFlagEnabled = await posthog.IsFeatureEnabledAsync(
"flag-key",
"distinct_id_of_your_user",
options: new FeatureFlagOptions
{
SendFeatureFlagEvents = true
}
);
// will not send `$feature_flag_called` events
```
import DotNetOverrideServerProperties from './override-server-properties/dotnet.mdx'
<DotNetOverrideServerProperties />

View File

@@ -0,0 +1,31 @@
import OverrideServerPropertiesIntro from './override-server-properties-intro.mdx'
<OverrideServerPropertiesIntro />
```csharp
var flag = await posthog.GetFeatureFlagAsync(
"flag-key",
"distinct_id_of_the_user",
options: new FeatureFlagOptions
{
PersonProperties = new() { ["property_name"] = "value" },
Groups = [
new Group("your_group_type", "your_group_id")
{
["group_property_name"] = "your group value"
},
new Group(
"another_group_type",
"another_group_id",
new Dictionary<string, object?>
{
["group_property_name"] = "another group value"
}
)
]
});
```
import OverrideGeoIPPropertiesSDK from './override-geoip-properties-SDKs.mdx'
<OverrideGeoIPPropertiesSDK />

View File

@@ -0,0 +1,37 @@
import SettingProperties from "./setting-properties-text.mdx"
import NamingTip from "./naming-tip.mdx"
import Intro from "./intro.mdx"
<Intro />
```csharp
posthog.Capture("distinct_id_of_the_user", "user_signed_up");
```
<NamingTip />
<SettingProperties />
```csharp
posthog.Capture(
"distinct_id_of_the_user",
"user_signed_up",
properties: new() {
["login_type"] = "email",
["is_free_trial"] = "true"
}
);
```
### Sending page views
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send `$pageview` events from your backend like so:
```csharp
using PostHog;
using Microsoft.AspNetCore.Http.Extensions;
posthog.CapturePageView(
"distinct_id_of_the_user",
context.HttpContext.Request.GetDisplayUrl());
```

View File

@@ -0,0 +1,10 @@
```csharp
posthog.Capture(
distinctId: "distinct_id",
eventName: "movie_played",
properties: new()
{
["movie_id"] = 123,
["category"] = "romcom",
});
```

View File

@@ -0,0 +1,7 @@
```csharp
await posthog.IdentifyAsync(
"distinct_id_of_the_user",
email: "john@doe.com",
name: "John Doe"
);
```

View File

@@ -0,0 +1,150 @@
---
title: .NET
sidebarTitle: .NET
sidebar: Docs
showTitle: true
github: 'https://github.com/PostHog/posthog-dotnet'
icon: >-
https://res.cloudinary.com/dmukukwp6/image/upload/dotnet_logo_7e446176f2.svg
features:
eventCapture: true
userIdentification: true
featureFlags: true
groupAnalytics: true
surveys: false
llmObservability: false
errorTracking: false
---
> ⚠️ **Warning:** This is in beta and may break.
This is an optional library you can install if you're working with .NET Core. It uses an internal queue to make calls fast and non-blocking. It also batches requests and flushes asynchronously, making it perfect to use in any part of your web app or other server side application that needs performance.
## Installation
import DotNetInstall from '../../integrate/_snippets/install-dotnet.mdx'
<DotNetInstall />
## Capturing events
import DotNetSendEvents from '../../integrate/send-events/_snippets/send-events-dotnet.mdx'
<DotNetSendEvents />
## Person profiles and properties
The .NET SDK captures identified events by default. These create [person profiles](/docs/data/persons). To set [person properties](/docs/data/user-properties) in these profiles, include them when capturing an event:
```csharp
posthog.Capture(
"distinct_id",
"event_name",
personPropertiesToSet: new() { ["name"] = "Max Hedgehog" },
personPropertiesToSetOnce: new() { ["initial_url"] = "/blog" }
);
```
For more details on the difference between `$set` and `$set_once`, see our [person properties docs](/docs/data/user-properties#what-is-the-difference-between-set-and-set_once).
To capture [anonymous events](/docs/data/anonymous-vs-identified-events) without person profiles, set the event's `$process_person_profile` property to `false`:
```csharp
posthog.Capture(
"distinct_id",
"event_name",
properties: new() {
["$process_person_profile"] = false
}
)
```
## Alias
Sometimes, you want to assign multiple distinct IDs to a single user. This is helpful when your primary distinct ID is inaccessible. For example, if a distinct ID used on the frontend is not available in your backend.
In this case, you can use `alias` to assign another distinct ID to the same user.
```csharp
await posthog.AliasAsync('current_distinct_id', 'new_distinct_id');
```
We strongly recommend reading our docs on [alias](/docs/product-analytics/identify#alias-assigning-multiple-distinct-ids-to-the-same-user) to best understand how to correctly use this method.
## Group analytics
Group analytics allows you to associate an event with a group (e.g. teams, organizations, etc.). Read the [group analytics](/docs/product-analytics/group-analytics) guide for more information.
> **Note:** This is a paid feature and is not available on the open-source or free cloud plan. Learn more on our [pricing page](/pricing).
To capture an event and associate it with a group, add the `groups` argument to your `Capture` call:
```csharp
postHogClient.Capture(
"user_distinct_id",
"some_event",
groups: [new Group("company", "company_id_in_your_db")]);
```
Update properties on a group, use the `GroupIdentifyAsync` method:
```csharp
await postHogClient.GroupIdentifyAsync(
type: "company",
key: "company_id_in_your_db",
name: "Awesome Inc.",
properties: new()
{
["employees"] = 11
}
);
```
The `name` is a special property which is used in the PostHog UI for the name of the group. If you don't specify a `name` property, the group ID will be used instead.
## Feature flags
import FeatureFlagsLibsIntro from "../_snippets/feature-flags-libs-intro.mdx"
<FeatureFlagsLibsIntro />
import DotNetFeatureFlagsCode from '../../integrate/feature-flags-code/_snippets/feature-flags-code-dotnet.mdx'
<DotNetFeatureFlagsCode />
### Local evaluation
import LocalEvaluationIntro from "../../feature-flags/snippets/local-evaluation-intro.mdx"
<LocalEvaluationIntro />
For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation).
## Experiments (A/B tests)
Since [experiments](/docs/experiments/manual) use feature flags, the code for running an experiment is very similar to the feature flags code:
```csharp
if (await posthog.GetFeatureFlagAsync(
"experiment-feature-flag-key",
"user_distinct_id")
is { VariantKey: "variant-name" })
{
// Do something
}
```
It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags).
## GeoIP properties
The posthog-dotnet library disregards the server IP, does not add the GeoIP properties, and does not use the values for feature flag evaluations.
## Serverless environments (Azure Functions/Render/Lambda/...)
By default, the library buffers events before sending them to the `/batch` endpoint, for better performance. This can
lead to lost events in serverless environments, if the .NET process is terminated by the platform before the buffer
is fully flushed. To avoid this, you can:
- ensure that `await posthog.FlushAsync()` is called after processing every request, by adding a middleware to your server: this allows `posthog.Capture()` to remain asynchronous for better performance.

View File

@@ -24,6 +24,7 @@ import JavaSendEvent from '../integrate/send-events/_snippets/send-events-java.m
import RustSendEvent from '../integrate/send-events/_snippets/send-events-rust.mdx'
import FlutterSendEvent from '../integrate/send-events/_snippets/send-events-flutter.mdx'
import ElixirSendEvent from '../integrate/send-events/_snippets/send-events-elixir.mdx'
import DotNetSendEvent from '../integrate/send-events/_snippets/send-events-dotnet.mdx'
Once your PostHog instance is up and running, the next step is to start sending events.
@@ -43,6 +44,7 @@ Once your PostHog instance is up and running, the next step is to start sending
'Rust',
'Elixir',
'Flutter',
'.NET',
'api']}>
<Tab.List>
<Tab>Web</Tab>
@@ -59,6 +61,7 @@ Once your PostHog instance is up and running, the next step is to start sending
<Tab>Rust</Tab>
<Tab>Elixir</Tab>
<Tab>Flutter</Tab>
<Tab>.NET</Tab>
<Tab>API</Tab>
</Tab.List>
<Tab.Panels>
@@ -104,6 +107,9 @@ Once your PostHog instance is up and running, the next step is to start sending
<Tab.Panel>
<FlutterSendEvent />
</Tab.Panel>
<Tab.Panel>
<DotNetSendEvent />
</Tab.Panel>
<Tab.Panel>
<APISendEvent />
</Tab.Panel>

View File

@@ -24,6 +24,7 @@ import JavaInstall from '../integrate/_snippets/install-java.mdx'
import RustInstall from '../integrate/_snippets/install-rust.mdx'
import FlutterInstall from '../integrate/_snippets/install-flutter.mdx'
import ElixirInstall from '../integrate/_snippets/install-elixir.mdx'
import DotNetInstall from '../integrate/_snippets/install-dotnet.mdx'
Product analytics enable you to gather and analyze data about how users interact with your product.
@@ -32,7 +33,7 @@ To start, install PostHog in the app you want to collect data in.
> **Tip**: Even if you have multiple customer-facing products (e.g., a marketing website + iOS app + web app), it's best to have them share the same project. This enables you to track the user across their journey across different platforms. See [organizations & projects docs](/manual/organizations-and-projects) for more.
<!-- prettier-ignore -->
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Elixir', 'Flutter', 'guides', 'api']}>
<Tab.Group tabs={['Web', 'React', 'Node.js', 'Python', 'PHP', 'Ruby', 'Go', 'React Native', 'Android', 'iOS', 'Java', 'Rust', 'Elixir', 'Flutter', '.NET', 'guides', 'api']}>
<Tab.List>
<Tab>Web</Tab>
<Tab>React</Tab>
@@ -48,6 +49,7 @@ To start, install PostHog in the app you want to collect data in.
<Tab>Rust</Tab>
<Tab>Elixir</Tab>
<Tab>Flutter</Tab>
<Tab>.NET</Tab>
<Tab count="11">Framework guides</Tab>
<Tab>API</Tab>
</Tab.List>
@@ -94,6 +96,9 @@ To start, install PostHog in the app you want to collect data in.
<Tab.Panel>
<FlutterInstall />
</Tab.Panel>
<Tab.Panel>
<DotNetInstall />
</Tab.Panel>
<Tab.Panel>
<Frameworks />
</Tab.Panel>

View File

@@ -84,6 +84,7 @@ Your primary responsibility is simply to make sure SDK questions get some love.
- [posthog-java](https://github.com/PostHog/posthog-java)
- [posthog-rs (Rust)](https://posthog.com/docs/libraries/rust)
- [posthog-go](https://posthog.com/docs/libraries/go)
- [posthog-dotnet](https://github.com/PostHog/posthog-dotnet)
- Others, see https://posthog.com/docs/libraries
You don't have to be an expert in all of the SDKs, but it can be a great opportunity to dive into parts unknown.

View File

@@ -12,6 +12,7 @@ require('prismjs/components/prism-elixir')
require('prismjs/components/prism-rust')
require('prismjs/components/prism-kotlin')
require('prismjs/components/prism-groovy')
require('prismjs/components/prism-csharp')
type LanguageMap = {
[key: string]: {
@@ -32,6 +33,7 @@ type LanguageMap = {
| 'vue'
| 'svelte'
| 'astro'
| 'csharp'
label: React.ReactNode
}
}
@@ -235,6 +237,10 @@ const languageMap: LanguageMap = {
language: 'rust',
label: 'Hog',
},
csharp: {
language: 'csharp',
label: 'C#',
},
}
export default languageMap

View File

@@ -113,6 +113,16 @@ const librariesData = {
/>
),
},
{
name: '.NET',
url: '/docs/libraries/dotnet',
icon: (
<CloudinaryImage
src="https://res.cloudinary.com/dmukukwp6/image/upload/dotnet_logo_7e446176f2.svg"
alt=".NET"
/>
),
},
{
name: 'More',
url: '/docs/libraries',

View File

@@ -1360,6 +1360,10 @@ export const docsMenu = {
name: 'Rust',
url: '/docs/libraries/rust',
},
{
name: '.NET',
url: '/docs/libraries/dotnet',
},
],
},
{