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
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,29 @@ The Skills follow the [vercel-labs/skills](https://github.com/vercel-labs/skills

| Skill | Description |
|---|---|
| [`cdata-cli`](skills/cdata-cli/SKILL.md) | Connect, query, explore schema, run SQL, search/download/activate CData JDBC drivers, and generate source-specific skills via the `cdatacli` tool. |
| [`cdata-cli`](skills/cdata-cli/SKILL.md) | **Discovery** — connect, query, explore schema, run SQL, download/activate JDBC drivers, and generate source-specific skills via `cdatacli`. Foundation for the build skills below. |
| [`cdata-cli-python`](skills/cdata-cli-python/SKILL.md) | **Build** Python apps with the CData Python Connector (DB-API 2.0). |
| [`cdata-cli-adonet`](skills/cdata-cli-adonet/SKILL.md) | **Build** C# / .NET apps with the CData ADO.NET Data Provider (NuGet). |
| [`cdata-cli-odbc`](skills/cdata-cli-odbc/SKILL.md) | **Build** Node.js / non-JVM apps with the CData ODBC Driver. |
| [`cdata-cli-java`](skills/cdata-cli-java/SKILL.md) | **Build** Java apps with the CData JDBC Driver. |

## Install

Install the skills:
Install all skills:

```bash
npx skills add CDataSoftware/cli-skills
```

Or install individual skills by name:

```bash
npx skills add CDataSoftware/cli-skills --skill cdata-cli
npx skills add CDataSoftware/cli-skills --skill cdata-cli-python
```

The build skills assume `cdata-cli` for discovery — install it alongside whichever build skill(s) you need.

## Prerequisites

The `cdata-cli` skill drives the `cdatacli` executable — a Java CLI (requires Java 17+) for CData JDBC drivers. After installing the CLI, `cdatacli` is on `PATH` and discovers drivers from `./` or `./lib/` relative to the executable.
Expand Down
254 changes: 254 additions & 0 deletions skills/cdata-cli-adonet/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
---
name: cdata-cli-adonet
description: "Use when writing C# / .NET application code (also VB.NET, F#) that connects to a data source through a CData driver — after the connection and SQL have been validated with the cdata-cli discovery skill. Covers mapping the language to the CData ADO.NET Data Provider edition, adding the provider from NuGet (CData.<Source>), activating its license, and connecting via the ADO.NET classes (<Source>Connection / <Source>Command). This is the .NET build-phase companion to cdata-cli; invoke it whenever the target application runs on .NET."
license: MIT
metadata:
author: CData Software
version: "1.0"
---

# SKILL: CData CLI — .NET / ADO.NET Build

Build-phase companion to the **`cdata-cli`** skill. `cdata-cli` handles discovery
(connect, explore schema, validate SQL) using the JDBC driver; **this skill takes over
once you start writing .NET application code** using the **CData ADO.NET Data Provider**.

Everything validated during discovery carries straight over: all CData drivers share the
same relational model and SQL dialect, so table names, column names, and SQL confirmed via
`cdatacli` work unchanged through the ADO.NET provider.

---

## Language / Driver Edition

| Language | CData edition | .NET namespace |
|---|---|---|
| **C#** (also VB.NET, F#) | **CData ADO.NET Data Provider** | `System.Data.CData.<Source>` |

The provider follows standard ADO.NET naming — for `<Source>` (e.g. `Salesforce`):

- `<Source>Connection`, `<Source>Command`, `<Source>DataReader`, `<Source>DataAdapter`,
`<Source>Parameter`, `<Source>CommandBuilder`, `<Source>ConnectionStringBuilder`
- Assembly/DLL: `System.Data.CData.<Source>.dll`

---

## Prerequisite: Discovery Done First

This skill assumes `cdata-cli` has already been used to confirm the source connects and to
validate the exact tables/columns and SQL the app will run. Reuse those results here. If
discovery created a `cdatacli` connection that did an **OAuth** browser sign-in, note its
`OAuthSettingsLocation` — the .NET app can point at the same cached token file and skip
re-authenticating (see **Connect**).

> The CLI's `drivers download` is JDBC-only and cannot fetch the ADO.NET provider. It comes
> from NuGet (below).

---

## Step 1: Get the Provider (NuGet)

The ADO.NET provider is published on NuGet by **CDataSoftware** as **`CData.<Source>`**
(e.g. `CData.Salesforce`). The idiomatic install is a package reference in the project:

```bash
dotnet add package CData.<Source>
```

- Grab the plain **`CData.<Source>`** package — that's the ADO.NET provider. The
`CData.<Source>.EntityFrameworkCore*` packages are **EF Core add-ons**; only add those if
you're using Entity Framework.
- To pin a version: `dotnet add package CData.<Source> --version <x.y.z>`.

**Already installed locally?** The standalone ADO.NET provider *product* is a **separate
distribution** from the NuGet package and may expose a **different set of target folders**.
If it's installed on the machine, you can reference its DLL directly instead of pulling
from NuGet:

```
C:\Program Files\CData\CData ADO.NET Provider for <Source> <Year>\lib\<target>\System.Data.CData.<Source>.dll
```

where `<target>` is one of the folders present under `lib\` (e.g. `net8.0`, `net6.0`,
`netstandard2.0`).

---

## Step 2: Reference It & Pick a Target Framework

The NuGet package ships its build targets under `lib/`. The set can vary by connector and
version, so **check the package's `lib/` folder**; for the connector verified here it was
`netstandard2.0` and `net40`:

| Target in package | Use for |
|---|---|
| `netstandard2.0` | .NET Core / .NET 5+ (net6.0, net8.0, net10.0, …) — **needs license activation (Step 3)** |
| `net40` | .NET Framework (4.x) — **self-licenses on NuGet install** |

**Pick the `TargetFramework` from the installed SDK, not the runtime list.** `dotnet new
--framework` and the build only accept TFMs the installed **SDK** knows — a box with only
the .NET 10 SDK rejects `net6.0`/`net8.0` even though those *runtimes* exist. Check
`dotnet --version` (or `dotnet --list-sdks`) and default to the SDK's matching TFM (e.g.
.NET 10 SDK → `net10.0`, or `net10.0-windows` for a WinForms/WPF UI); since an SDK ships
its own runtime, that target both builds and runs.

Only if you deliberately target an **older** TFM do you also need that TFM's runtime
installed (`dotnet --list-runtimes`) — otherwise launch fails with *"You must install or
update .NET to run this application."* The `netstandard2.0` provider itself works across
net6.0 / net8.0 / net10.0, so the limiting factor is your toolchain, not the driver.

Two ways to reference the provider:

- **PackageReference** (from `dotnet add package`) — simplest; NuGet restores the DLL.
- **Direct `HintPath`** — reference the extracted `netstandard2.0\System.Data.CData.<Source>.dll`.
Useful when you want the DLL (and its activated `.lic`) in a known local path:

```xml
<ItemGroup>
<Reference Include="System.Data.CData.<Source>">
<HintPath>..\packages\CData.<Source>\lib\netstandard2.0\System.Data.CData.<Source>.dll</HintPath>
</Reference>
</ItemGroup>
```

---

## Step 3: Activate the License

> **A working `cdatacli` connection doesn't mean this is activated.** `cdatacli` runs on the
> JDBC driver, so it only proves *JDBC* is licensed — the ADO.NET provider is a separate license.

Licensing depends on the build target and is **per machine**, separate from the
JDBC/Python/ODBC editions:

- **.NET Framework (`net40`)** — the NuGet package **auto-installs a license on restore**;
no action needed.
- **.NET Core / .NET (`netstandard2.0`)** — **must be activated** with the `install-license`
tool bundled in the package's `tools/` folder, or the first query raises *"Could not find
a valid license…"*.

The tool is a .NET app. Its folder holds `install-license.dll`, `install-license.runtimeconfig.json`,
and `prod.inf`; find it under the package:

```
<project>\packages\CData.<Source>\tools\install-license.dll # extracted package
%USERPROFILE%\.nuget\packages\cdata.<source>\<ver>\tools\install-license.dll # global NuGet cache
```

It reads `prod.inf` from the current directory, so **run it from its own folder**. Because
it prompts for input, **have the user run it in a normal terminal — outside the AI coding
session** (an AI session can't reliably answer the prompts, and it hangs if run with no
arguments).

**Trial:** run it and answer the `Name:` / `Email:` prompts:

```powershell
cd "<project>\packages\CData.<Source>\tools"
dotnet .\install-license.dll
```

**Purchased key** (the key is a secret — also keep this outside an AI session):

```powershell
cd "<project>\packages\CData.<Source>\tools"
dotnet .\install-license.dll YOUR-PRODUCT-KEY
```

Activation writes `System.Data.CData.<Source>.lic` next to the provider DLL
(`lib\netstandard2.0\`). If you reference the DLL by `HintPath`, keep the `.lic` beside
that copy.

---

## Step 4: Connect (ADO.NET)

Standard ADO.NET usage — and unlike some other editions, these objects **do** implement
`IDisposable`, so `using` blocks are the right pattern:

```csharp
using System.Data.CData.Salesforce;

using var conn = new SalesforceConnection(connectionString);
conn.Open();

using var cmd = new SalesforceCommand(
"SELECT Id, Name FROM Account WHERE Name LIKE @name", conn);
cmd.Parameters.Add(new SalesforceParameter("@name", "%Acme%"));

using var reader = cmd.ExecuteReader();
while (reader.Read())
Console.WriteLine(reader["Name"]);
```

- **Named parameters** — placeholders are `@name` and you add `<Source>Parameter` objects.
Always parameterize user input.
- `ExecuteNonQuery()` for INSERT/UPDATE/DELETE; `ExecuteScalar()` for single values;
`<Source>DataAdapter` + `DataTable` to fill a grid.

### Connection string & auth (reuse discovery, keep secrets out of code)

Pass the same properties validated with `cdatacli`, from config (e.g. `appsettings.json`),
not hard-coded. For **OAuth** sources, point `OAuthSettingsLocation` at the token file the
discovery connection already populated so the app refreshes silently, no browser flow:

```text
AuthScheme=OAuth;InitiateOAuth=GETANDREFRESH;UseSandbox=true;OAuthSettingsLocation=C:\...\OAuthSettings-xxx.txt
```

Sources with **no embedded OAuth app** require the user's own `OAuthClientId`/
`OAuthClientSecret` even to refresh — read those from environment variables / user-secrets,
never commit them.

---

## Step 5: End-to-End Example

A minimal console/repository slice (wrap in WinForms/WPF/ASP.NET as needed):

```csharp
using System.Data;
using System.Data.CData.Salesforce;

const string CS =
@"AuthScheme=OAuth;InitiateOAuth=GETANDREFRESH;UseSandbox=true;OAuthSettingsLocation=C:\...\OAuthSettings-sbx.txt";

static IEnumerable<(string Id, string Name)> ListAccounts(string? search, int limit = 50)
{
using var conn = new SalesforceConnection(CS);
conn.Open();
var sql = "SELECT Id, Name FROM Account"
+ (string.IsNullOrWhiteSpace(search) ? "" : " WHERE Name LIKE @s")
+ $" ORDER BY Name LIMIT {limit}";
using var cmd = new SalesforceCommand(sql, conn);
if (!string.IsNullOrWhiteSpace(search))
cmd.Parameters.Add(new SalesforceParameter("@s", $"%{search}%"));
using var r = cmd.ExecuteReader();
while (r.Read())
yield return (r["Id"].ToString()!, r["Name"].ToString()!);
}

static void CreateAccount(string name, string? industry)
{
using var conn = new SalesforceConnection(CS);
conn.Open();
using var cmd = new SalesforceCommand(
"INSERT INTO Account (Name, Industry) VALUES (@n, @i)", conn);
cmd.Parameters.Add(new SalesforceParameter("@n", name));
cmd.Parameters.Add(new SalesforceParameter("@i", (object?)industry ?? DBNull.Value));
cmd.ExecuteNonQuery();
}
```

Build to confirm the reference resolves: `dotnet build`.

---

## Troubleshooting

| Error | Cause / fix |
|---|---|
| `Could not find a valid license for using CData ADO.NET Provider for <source>` | The `netstandard2.0` build isn't activated on this machine — run `install-license` from the package `tools/` folder (Step 3). `net40` self-licenses, so this only affects .NET Core / .NET targets. |
| `You must install or update .NET to run this application` | The target TFM's **runtime** isn't installed. Simplest: target the SDK's own version (Step 2), which ships a matching runtime; otherwise install the missing runtime. |
| `'OAuthClientId' and 'OAuthClientSecret' are needed to initiate OAuth` | Source has no embedded OAuth app; supply client id/secret in the connection string (from env vars / user-secrets), matching the app whose refresh token is cached. |
| Reference/`using System.Data.CData.<Source>` not found | Package not restored or wrong package. Ensure `dotnet add package CData.<Source>` (the plain provider, not an `EntityFrameworkCore` variant) and `dotnet restore`. |
| `install-license.dll` hangs or errors on `prod.inf` | Run it **from the `tools/` folder** with `Name`/`Email` (trial) or a product-key argument; don't run it with no arguments. |
Loading