# .NET SDK

## Overview

The **OpenADR 3 VTN Client SDK for .NET** enables applications to interact with the Switch OpenADR 3 VTN API from .NET using C# and other .NET languages such as F#, and VB.NET. The SDK itself is written in C#, and some of its idiomatic patterns reflect that choice. It offers an asynchronous API based on the Task-based Asynchronous Pattern (TAP).

## Requirements

In order to use this SDK in your application ensure you have installed:

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

## Installation

This C# SDK client is provided as is and it is used in the .NET environment. It contains wrapper classes that you can use to call an OpenADR v3 Virtual Top Node (aka VTN) API from your application without having to deal with HTTP requests and responses. The SDK is used by the BL and/or VEN components which need to talk to an OpenADR VTN.

### Install using Visual Studio

1. In Solution Explorer, right-click the *Dependecies* on the project and select *Manage Nuget Packages…*
2. On the *Browse* tab search for **OpenAdr.Client**. Select the **OpenAdr.Client** package from the list, then click *Install.*

### Install using Package Manager Console

1. From the Visual Studio menu bar, click *Tools*
2. Select *NuGet Package Manager > Package Manager Console*.
3. In the console, enter the following package installation command to install the latest version:<br>

   ```markup
   PM> Install-Package OpenAdr.Client
   ```

### Install using dotnet CLI

1. Open a command line and switch to the directory that contains your project file (*.csproj*).
2. Use the following command to install the latest version of **OpenAdr.Client** package to that project:<br>

   ```markup
   dotnet add package OpenAdr.Client
   ```

## Usage

### Prerequisites

Before using and configuring the SDK in your application, you need to:

1. Create VTN credential client for your application as desribed in [Create credentials client](broken://pages/LoSLQ4c0nlugSKovAsrJ#create-credentials-client).
2. Note the *VTN URL*, for the selected environment under [VTN Endpoint](/openadr-3/overview.md#vtn-endpoint).
3. Note the *Token Endpoint* and *Scope* for the selected environment under [Token Endpoint](broken://pages/tS7owq0Ym62uSaXLjnwf).

Having this information you are ready to start configuring your application.

### Step by Step

1. Create new console application
2. Configure your application to use the SDK. The easiest way to configure the SDK in your client application is to add and use the *`appsettings.json`* file. Ensure that you have the following configuration available in your settings file (replace the values for *ClientId* and *ClientSecret* with the ones that you got when creating your VTN credential client):<br>

   ```json
   "OpenAdr": {
       "VtnClient": {
           "VtnUrl": "<vtn_url>",
           "Credentials": {
               "TokenEndpoint": "<token_endpoint>",
               "Audience": "<audience>",
               "ClientId": "<client_id>",
               "ClientSecret": "<client_secret>"
           }
       }
   }
   ```
3. Install the following NuGet packages to enable additional functionalities in your client application:<br>

   ```markup
   PM> Install-Package Microsoft.Extensions.DependencyInjection -Version 8.0.1
   PM> Install-Package Microsoft.Extensions.Hosting -Version 8.0.1
   PM> Install-Package Microsoft.Extensions.Configuration -Version 8.0.0
   ```
4. Sample *`Program.cs`* for your client application will look like the following:<br>

   ```csharp
   using Microsoft.Extensions.Configuration;
   using Microsoft.Extensions.DependencyInjection;
   using Microsoft.Extensions.Hosting;
   using OpenAdr.Client.Configuration;
   using OpenAdr.Client.Model;

   internal class Program
   {
       static async Task Main(string[] args)
       {
           var builder = Host.CreateDefaultBuilder(args)
               .ConfigureAppConfiguration((context, configBuilder) =>
               {
                   configBuilder.AddJsonFile("appsettings.json", false, true);
               })
               .ConfigureServices((context, services) =>
               {
                   services.AddLogging();
                   services.AddVtnClient(context.Configuration);
               });
           using var host = builder.Build();
           await host.StartAsync();
               
           var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
           lifetime.StopApplication();
           await host.WaitForShutdownAsync();
       }
   }
   ```
5. Create new hosted service which will repesent your client (aka VEN):<br>

   ```csharp
   using Microsoft.Extensions.Logging;
   using Microsoft.Extensions.Options;
   using OpenAdr.Client;
   using OpenAdr.Client.Configuration;
   using OpenAdr.Client.Model;
   using System.Xml;

   internal class MyVen
   {
       private readonly IVtnClient _client;
       private readonly OpenAdrConfiguration _configuration;
       private readonly ILogger<Ven> _logger;

       public MyVen(IVtnClient client, IOptionsSnapshot<OpenAdrConfiguration> options, ILogger<Ven> logger)
       {
           _client = client;
           _configuration = options.Value;
           _logger = logger;
       }

       /// <summary>
       /// Starts your VEN instance.
       /// </summary>
       public async Task Start()
       {
           // Get access token with the internal Auth endpoint of the VTN.
           var token = await _client.Auth.GetTokenAsync(_configuration.VtnClient.Credentials.ClientId, _configuration.VtnClient.Credentials.ClientSecret);
           _logger.LogInformation("Token: {Token}", token);

           // Search for programs.
           var program = (await _client.Programs.SearchProgramsAsync()).FirstOrDefault();
           if (program != null)
           {
               _logger.LogInformation("Program: {Program}", program.ToJson());

               // Create event.
               var interval = new Interval(1, payloads: new List<ValuesMap>
               {
                   new("PRICE", new List<ValuesMapValue> { new(25.33m) })
               });
               var @event = await _client.Events.CreateEventAsync(new Event(
                   programId: program.Id,
                   intervals: new List<Interval> { interval },
                   objectType: EventObjectType.EVENT,
                   eventName: "My Price Event",
                   priority: 0,
                   targets: new List<ValuesMap>
                   {
                       new("GROUP", new List<ValuesMapValue>
                       {
                           new("My VEN")
                       })
                   },
                   intervalPeriod: new IntervalPeriod(DateTime.UtcNow, XmlConvert.ToString(TimeSpan.FromHours(12))))
               );
               _logger.LogInformation(@event.ToJson());
           }
       }
   }
   ```
6. Register your service in *`Program.cs`* inside *`ConfigureServices`* method of the host builder and start it:<br>

   ```csharp
   ...
   .ConfigureServices((context, services) =>
   {
       ...
       services.AddTransient<MyVen>();
   });

   ...

   var ven = host.Services.GetRequiredService<MyVen>();
   await ven.Start();
   var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
   lifetime.StopApplication();
   await host.WaitForShutdownAsync();
   ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.switchmarket.se/libraries/.net-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
