# Standalone Activities .NET Quickstart

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.

> Execute a Standalone Activity with the Temporal .NET SDK without writing a Workflow.

# Quickstart

Standalone Activities are Activities that run independently, without being orchestrated by a
Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone
Activity directly from a Temporal Client.

The way you write the Activity and register it with a Worker is identical to [Workflow
Activities](/develop/dotnet/activities/basics#develop-activity). The only difference is that you execute a
Standalone Activity directly from your Temporal Client.

> **📝 Note:**
>
> This documentation uses source code from the [StandaloneActivity](https://github.com/temporalio/samples-dotnet/tree/main/src/StandaloneActivity) sample project.
>

## Get started with Standalone Activities 

Prerequisites:

- **[.NET](https://dotnet.microsoft.com/download)** 8.0+

- **Temporal .NET SDK** (v1.12.0 or higher). See the [.NET Quickstart](/develop/dotnet/set-up-your-local-dotnet) for install instructions.

- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`.

Start the Temporal development server with `temporal server start-dev`.

This command automatically starts the Temporal development server with the Web UI, and creates the `default` Namespace.
It uses an in-memory database, so do not use it for real use cases.

The Temporal Server will now be available for client connections on `localhost:7233`, and the
Temporal Web UI will now be accessible at [http://localhost:8233](http://localhost:8233).

```bash
brew install temporal
```

```bash
temporal --version
```

```bash
temporal server start-dev
```

## Clone the sample

Clone the [samples-dotnet](https://github.com/temporalio/samples-dotnet) repository to follow along:

```
git clone https://github.com/temporalio/samples-dotnet.git
cd samples-dotnet
```

The sample project is structured as follows:

```
src/StandaloneActivity/
├── MyActivities.cs
├── Program.cs
├── README.md
└── TemporalioSamples.StandaloneActivity.csproj
```

## Define your Activity 

An Activity in the Temporal .NET SDK is a method decorated with the `[Activity]` attribute. The way
you write a Standalone Activity is identical to how you write an Activity orchestrated by a Workflow.
In fact, the same Activity can be executed both as a Standalone Activity and as a Workflow Activity.

[src/StandaloneActivity/MyActivities.cs](https://github.com/temporalio/samples-dotnet/blob/main/src/StandaloneActivity/MyActivities.cs)

```csharp
namespace TemporalioSamples.StandaloneActivity;

using Temporalio.Activities;

public static class MyActivities
{
    [Activity]
    public static Task<string> ComposeGreetingAsync(ComposeGreetingInput input) =>
        Task.FromResult($"{input.Greeting}, {input.Name}!");
}

public record ComposeGreetingInput(string Greeting, string Name);
```

## Run a Worker with the Activity registered 

Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities —
you create a Worker, register the Activity, and run the Worker. The Worker doesn't need to know
whether the Activity will be invoked from a Workflow or as a Standalone Activity. See [How to develop
a Worker](/develop/dotnet/workers/run-worker-process) for more details on Worker setup and
configuration options.

[src/StandaloneActivity/Program.cs](https://github.com/temporalio/samples-dotnet/blob/main/src/StandaloneActivity/Program.cs)

Open a new terminal, navigate to the `samples-dotnet` directory, and run the Worker.
Leave this terminal running - the Worker needs to stay up to process activities.

```csharp
using Microsoft.Extensions.Logging;
using Temporalio.Client;
using Temporalio.Common.EnvConfig;
using Temporalio.Worker;
using TemporalioSamples.StandaloneActivity;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
connectOptions.LoggerFactory = LoggerFactory.Create(builder =>
    builder.
        AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] ").
        SetMinimumLevel(LogLevel.Information));
var client = await TemporalClient.ConnectAsync(connectOptions);

const string taskQueue = "standalone-activity-sample";

using var tokenSource = new CancellationTokenSource();
Console.CancelKeyPress += (_, eventArgs) =>
{
    tokenSource.Cancel();
    eventArgs.Cancel = true;
};

using var worker = new TemporalWorker(
    client,
    new TemporalWorkerOptions(taskQueue).
        AddActivity(MyActivities.ComposeGreetingAsync));

await worker.ExecuteAsync(tokenSource.Token);
```

```bash
dotnet run --project src/StandaloneActivity worker
```

## Execute a Standalone Activity 

Use
[`client.ExecuteActivityAsync()`](https://dotnet.temporal.io/api/Temporalio.Client.ITemporalClientExtensions.html)
to execute a Standalone Activity and wait for the result. Call this from your application code, not
from inside a Workflow Definition. This durably enqueues your Standalone Activity in the Temporal
Server, waits for it to be executed on your Worker, and then returns the result.

[src/StandaloneActivity/Program.cs](https://github.com/temporalio/samples-dotnet/blob/main/src/StandaloneActivity/Program.cs)

You can pass the Activity as either a lambda expression or a string Activity type name.

`StartActivityOptions` requires `Id`, `TaskQueue`, and at least one of `ScheduleToCloseTimeout` or
`StartToCloseTimeout`. See
[`StartActivityOptions`](https://dotnet.temporal.io/api/Temporalio.Client.StartActivityOptions.html)
in the API reference for the full set of options.

To run it:

1. Make sure the Temporal Server is running (from the [Get Started](#get-started) step above).
2. Make sure the Worker is running (from the [Run a Worker](#run-worker) step above).
3. Open a new terminal, navigate to the `samples-dotnet` directory, and run `dotnet run --project src/StandaloneActivity execute-activity`.

Or use the Temporal CLI.

```csharp
using Temporalio.Client;
using Temporalio.Common.EnvConfig;
using TemporalioSamples.StandaloneActivity;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
var client = await TemporalClient.ConnectAsync(connectOptions);

var result = await client.ExecuteActivityAsync(
    () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
    new("standalone-activity-id", "standalone-activity-sample")
    {
        ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
    });
Console.WriteLine($"Activity result: {result}");
```

```csharp
// Using a lambda expression (type-safe)
var result = await client.ExecuteActivityAsync(
    () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
    new("standalone-activity-id", "standalone-activity-sample")
    {
        ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
    });

// Using a string type name
var result = await client.ExecuteActivityAsync<string>(
    "ComposeGreeting",
    new object?[] { new ComposeGreetingInput("Hello", "World") },
    new("standalone-activity-id", "standalone-activity-sample")
    {
        ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
    });
```

```bash
dotnet run --project src/StandaloneActivity execute-activity
```

```bash
temporal activity execute \\
  --type ComposeGreeting \\
  --activity-id standalone-activity-id \\
  --task-queue standalone-activity-sample \\
  --schedule-to-close-timeout 10s \\
  --input '{"Greeting": "Hello", "Name": "World"}'
```

## Run with Temporal Cloud

All code samples on this page use
[`ClientEnvConfig.LoadClientConnectOptions()`](https://dotnet.temporal.io/api/Temporalio.Common.EnvConfig.ClientEnvConfig.html)
to configure the Temporal Client connection. It responds to [environment
variables](/references/client-environment-configuration) and [TOML configuration
files](/references/client-environment-configuration), so the same code works against a local dev
server and Temporal Cloud without changes. See [Run Standalone Activities with Temporal
Cloud](/develop/dotnet/activities/standalone-activities#run-standalone-activities-temporal-cloud) in the Feature Guide
for mTLS and API key setup.

## Next steps

- **[Standalone Activities Feature Guide](/develop/dotnet/activities/standalone-activities)**: Start without waiting, get handles, list and count Activities, and connect to Temporal Cloud.
- **[Activity basics](/develop/dotnet/activities/basics)**: How to write and register Activities with the .NET SDK.
