使用 Azure Cosmos DB 模拟器在本地进行开发

模拟器的一个常见用例是在构建应用程序时充当开发数据库。 使用模拟器进行开发可帮助你了解为 Azure Cosmos DB 等数据库创建和建模数据的特点,且不会产生任何服务费用。 此外,将模拟器用作自动化工作流的一部分,可以确保能够运行相同的集成测试套件。 模拟器可以确保在本地开发计算机和远程持续集成作业中运行相同的测试。

先决条件

安装模拟器

模拟器有多个变体,每个变体的安装过程都相对顺畅。

要开始使用,请从 Microsoft 容器注册表 (MCR) 获取容器映像的 Linux 变体。

  1. mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator Linux 容器映像从容器注册表拉取到本地 Docker 主机。

    docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
    
  2. 检查以确保模拟器映像已拉取到本地 Docker 主机。

    docker images
    

要开始使用,请从 Microsoft 容器注册表 (MCR) 获取容器映像的 Linux 变体。

  1. 使用 mongodb 标记将 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator Linux 容器映像从容器注册表拉取到本地 Docker 主机。

    docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:mongodb
    
  2. 检查以确保模拟器映像已拉取到本地 Docker 主机。

    docker images
    

模拟器的 Docker 容器变体(Linux 或 Windows)不支持 API for Apache Cassandra、API for Apache Gremlin 或 API for Table。

启动模拟器

下载后,启用指定的 API 并启动模拟器。

模拟器的 Docker 容器变体不支持 API for Apache Cassandra。

模拟器的 Docker 容器变体不支持 API for Apache Gremlin。

模拟器的 Docker 容器变体不支持 API for Table。

  1. 使用容器映像和以下配置来运行新容器:

    说明
    (可选)AZURE_COSMOS_EMULATOR_PARTITION_COUNT 指定要使用的分区数。
    (可选)AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE 在模拟器运行间隙启用数据持久性。
    (可选)AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE 替代模拟器的默认 IP 地址。
    docker run \
        --publish 8081:8081 \
        --publish 10250-10255:10250-10255 \
        --interactive \
        --tty \
        mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest    
    
  2. 导航到 https://localhost:8081/_explorer/index.html 以访问数据资源管理器。

  1. 使用容器映像和以下配置来运行新容器:

    说明
    AZURE_COSMOS_EMULATOR_ENABLE_MONGODB_ENDPOINT 指定要使用的 MongoDB 终结点版本。 支持的终结点包括:3.23.64.0
    (可选)AZURE_COSMOS_EMULATOR_PARTITION_COUNT 指定要使用的分区数。
    (可选)AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE 在模拟器运行间隙启用数据持久性。
    (可选)AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE 替代模拟器的默认 IP 地址。
    docker run \
        --publish 8081:8081 \
        --publish 10250:10250 \
        --env AZURE_COSMOS_EMULATOR_ENABLE_MONGODB_ENDPOINT=4.0 \
        --interactive \
        --tty \
        mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:mongodb
    
  2. 导航到 https://localhost:8081/_explorer/index.html 以访问数据资源管理器。

导入模拟器的 TLS/SSL 证书

导入模拟器的 TLS/SSL 证书,以便在客户端不禁用 TLS/SSL的情况下将模拟器与首选开发人员 SDK 一起使用。

模拟器的 Docker 容器变体(Linux 或 Windows)不支持 API for Apache Cassandra、API for Apache Gremlin 或 API for Table。

模拟器的证书位于正在运行的容器上的 _explorer/emulator.pem 路径中。 使用 curl 可将证书从正在运行的容器下载到本地计算机。

curl -k https://localhost:8081/_explorer/emulator.pem > ~/emulatorcert.crt

模拟器的证书位于正在运行的容器上的 _explorer/emulator.pem 路径中。

  1. 使用 curl 可将证书从正在运行的容器下载到本地计算机。

    curl -k https://localhost:8081/_explorer/emulator.pem > ~/emulatorcert.crt
    

    注意

    如果以前修改过主机(或 IP 地址)和端口号,则可能需要更改这些值。

  2. 按照通常用于操作系统的过程安装证书。 例如,在 Linux 中,将证书复制到 /usr/local/share/ca-certificates/ 路径。

    cp ~/emulatorcert.crt /usr/local/share/ca-certificates/
    
  3. 使用适用于 Linux 发行版的相应命令更新 CA 证书并重新生成证书捆绑包。

    对于基于 Debian 的系统(例如 Ubuntu),请使用

    sudo update-ca-certificates
    

    对于基于 CentOS 的系统(例如 CentOS、Fedora),请使用

    sudo update-ca-trust
    

    有关详细说明,请参阅特定于 Linux 发行版的文档。

从 SDK 连接到仿真器

每个 SDK 都包含一个客户端类,通常用于将 SDK 连接到 Azure Cosmos DB 帐户。 使用模拟器的凭据,可以改为将 SDK 连接到模拟器实例。

使用 Azure Cosmos DB API for NoSQL .NET SDK 从 .NET 应用程序连接到模拟器。

  1. 从空文件夹开始。

  2. 创建新的 .NET 控制台应用程序

    dotnet new console
    
  3. 从 NuGet 添加 Microsoft.Azure.Cosmos 包。

    dotnet add package Microsoft.Azure.Cosmos
    
  4. 打开 Program.cs 文件。

  5. 删除文件中的任何现有内容。

  6. Microsoft.Azure.Cosmos 命名空间添加一个 using 块。

// <imports>
using Microsoft.Azure.Cosmos;
// </imports>

// <client>
using CosmosClient client = new(
    accountEndpoint: "https://localhost:8081/",
    authKeyOrResourceToken: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);
// </client>

// <resources>
Database database = await client.CreateDatabaseIfNotExistsAsync(
    id: "cosmicworks",
    throughput: 400
);

Container container = await database.CreateContainerIfNotExistsAsync(
    id: "products",
    partitionKeyPath: "/id"
);
// </resources>

// <upsert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

await container.UpsertItemAsync(item);
// </upsert>
  1. 使用仿真器的凭据创建 CosmosClient 的新实例。
// <imports>
using Microsoft.Azure.Cosmos;
// </imports>

// <client>
using CosmosClient client = new(
    accountEndpoint: "https://localhost:8081/",
    authKeyOrResourceToken: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);
// </client>

// <resources>
Database database = await client.CreateDatabaseIfNotExistsAsync(
    id: "cosmicworks",
    throughput: 400
);

Container container = await database.CreateContainerIfNotExistsAsync(
    id: "products",
    partitionKeyPath: "/id"
);
// </resources>

// <upsert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

await container.UpsertItemAsync(item);
// </upsert>
  1. 使用 CreateDatabaseIfNotExistsAsyncCreateContainerIfNotExistsAsync 创建新的数据库和容器。
// <imports>
using Microsoft.Azure.Cosmos;
// </imports>

// <client>
using CosmosClient client = new(
    accountEndpoint: "https://localhost:8081/",
    authKeyOrResourceToken: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);
// </client>

// <resources>
Database database = await client.CreateDatabaseIfNotExistsAsync(
    id: "cosmicworks",
    throughput: 400
);

Container container = await database.CreateContainerIfNotExistsAsync(
    id: "products",
    partitionKeyPath: "/id"
);
// </resources>

// <upsert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

await container.UpsertItemAsync(item);
// </upsert>
  1. 使用 UpsertItemAsync 在容器中创建新项。
// <imports>
using Microsoft.Azure.Cosmos;
// </imports>

// <client>
using CosmosClient client = new(
    accountEndpoint: "https://localhost:8081/",
    authKeyOrResourceToken: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);
// </client>

// <resources>
Database database = await client.CreateDatabaseIfNotExistsAsync(
    id: "cosmicworks",
    throughput: 400
);

Container container = await database.CreateContainerIfNotExistsAsync(
    id: "products",
    partitionKeyPath: "/id"
);
// </resources>

// <upsert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

await container.UpsertItemAsync(item);
// </upsert>
  1. 运行 .NET 应用程序。

    dotnet run
    

    警告

    如果收到 SSL 错误,可能需要为应用程序禁用 TLS/SSL。 如果在本地计算机上进行开发,在容器中使用 Azure Cosmos DB 模拟器,并且尚未导入容器的 SSL 证书,则通常会发生这种情况。 要解决此问题,请在创建客户端之前配置客户端选项,禁用 TLS/SSL 验证:

    CosmosClientOptions options = new ()
    {
        HttpClientFactory = () => new HttpClient(new HttpClientHandler()
        {
            ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
        }),
        ConnectionMode = ConnectionMode.Gateway,
    };
    
    using CosmosClient client = new(
      ...,
      ...,
      clientOptions: options
    );
    

提示

有关可使用 .NET SDK 执行的更多操作,请参阅 .NET 开发人员指南

使用 MongoDB .NET 驱动程序 从 .NET 应用程序连接到模拟器。

  1. 从空文件夹开始。

  2. 创建新的 .NET 控制台应用程序

    dotnet new console
    
  3. 从 NuGet 添加 MongoDB.Driver 包。

    dotnet add package MongoDB.Driver
    
  4. 打开 Program.cs 文件。

  5. 删除文件中的任何现有内容。

  6. MongoDB.Driver 命名空间添加一个 using 块。

// <imports>
using MongoDB.Driver;
// </imports>

// <client>
var client = new MongoClient(
    "mongodb://localhost:C2y6yDjf5%2FR%2Bob0N8A7Cgv30VRDJIWEHLM%2B4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw%2FJw%3D%3D@localhost:10255/admin?ssl=true&retrywrites=false"
);
// </client>

// <resources>
var database = client.GetDatabase("cosmicworks");

var collection = database.GetCollection<dynamic>("products");
// </resources>

// <insert>
var item = new
{
    name = "Kiama classic surfboard"
};

await collection.InsertOneAsync(item);
// </insert>
  1. 使用模拟器的凭据创建 MongoClient 的新实例。
// <imports>
using MongoDB.Driver;
// </imports>

// <client>
var client = new MongoClient(
    "mongodb://localhost:C2y6yDjf5%2FR%2Bob0N8A7Cgv30VRDJIWEHLM%2B4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw%2FJw%3D%3D@localhost:10255/admin?ssl=true&retrywrites=false"
);
// </client>

// <resources>
var database = client.GetDatabase("cosmicworks");

var collection = database.GetCollection<dynamic>("products");
// </resources>

// <insert>
var item = new
{
    name = "Kiama classic surfboard"
};

await collection.InsertOneAsync(item);
// </insert>
  1. 使用 GetDatabaseGetCollection<> 获取数据库和容器。
// <imports>
using MongoDB.Driver;
// </imports>

// <client>
var client = new MongoClient(
    "mongodb://localhost:C2y6yDjf5%2FR%2Bob0N8A7Cgv30VRDJIWEHLM%2B4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw%2FJw%3D%3D@localhost:10255/admin?ssl=true&retrywrites=false"
);
// </client>

// <resources>
var database = client.GetDatabase("cosmicworks");

var collection = database.GetCollection<dynamic>("products");
// </resources>

// <insert>
var item = new
{
    name = "Kiama classic surfboard"
};

await collection.InsertOneAsync(item);
// </insert>
  1. 使用 InsertOneAsync 在 XXX 中创建新项。
// <imports>
using MongoDB.Driver;
// </imports>

// <client>
var client = new MongoClient(
    "mongodb://localhost:C2y6yDjf5%2FR%2Bob0N8A7Cgv30VRDJIWEHLM%2B4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw%2FJw%3D%3D@localhost:10255/admin?ssl=true&retrywrites=false"
);
// </client>

// <resources>
var database = client.GetDatabase("cosmicworks");

var collection = database.GetCollection<dynamic>("products");
// </resources>

// <insert>
var item = new
{
    name = "Kiama classic surfboard"
};

await collection.InsertOneAsync(item);
// </insert>
  1. 运行 .NET 应用程序。

    dotnet run
    

使用 Apache Cassandra .NET 驱动程序 从 .NET 应用程序连接到模拟器。

  1. 从空文件夹开始。

  2. 创建新的 .NET 控制台应用程序

    dotnet new console
    
  3. 从 NuGet 添加 CassandraCSharpDriver 包。

    dotnet add package CassandraCSharpDriver
    
  4. 打开 Program.cs 文件。

  5. 删除文件中的任何现有内容。

  6. Cassandra 命名空间添加一个 using 块。

// <imports>
using Cassandra;
// </imports>

// <client>
var options = new SSLOptions(
    sslProtocol: System.Security.Authentication.SslProtocols.Tls12,
    checkCertificateRevocation: true,
    remoteCertValidationCallback: (_, _, _, policyErrors) => policyErrors == System.Net.Security.SslPolicyErrors.None);

using var cluster = Cluster.Builder()
    .WithCredentials(
        username: "localhost",
        password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
    )
    .WithPort(
        port: 10350
    )
    .AddContactPoint(
        address: "localhost"
    )
    .WithSSL(
        sslOptions: options
    )
    .Build();

using var session = cluster.Connect();
// </client>

// <resources>
var createKeyspace = await session.PrepareAsync("CREATE KEYSPACE IF NOT EXISTS cosmicworks WITH replication = {'class':'basicclass', 'replication_factor': 1};");
await session.ExecuteAsync(createKeyspace.Bind());

var createTable = await session.PrepareAsync("CREATE TABLE IF NOT EXISTS cosmicworks.products (id text PRIMARY KEY, name text)");
await session.ExecuteAsync(createTable.Bind());
// </resources>

// <insert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

var createItem = await session.PrepareAsync("INSERT INTO cosmicworks.products (id, name) VALUES (?, ?)");

var createItemStatement = createItem.Bind(item.id, item.name);

await session.ExecuteAsync(createItemStatement);
// </insert>
  1. 使用模拟器的凭据创建 Cluster 的新实例。 使用 Connect 新建会话。
// <imports>
using Cassandra;
// </imports>

// <client>
var options = new SSLOptions(
    sslProtocol: System.Security.Authentication.SslProtocols.Tls12,
    checkCertificateRevocation: true,
    remoteCertValidationCallback: (_, _, _, policyErrors) => policyErrors == System.Net.Security.SslPolicyErrors.None);

using var cluster = Cluster.Builder()
    .WithCredentials(
        username: "localhost",
        password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
    )
    .WithPort(
        port: 10350
    )
    .AddContactPoint(
        address: "localhost"
    )
    .WithSSL(
        sslOptions: options
    )
    .Build();

using var session = cluster.Connect();
// </client>

// <resources>
var createKeyspace = await session.PrepareAsync("CREATE KEYSPACE IF NOT EXISTS cosmicworks WITH replication = {'class':'basicclass', 'replication_factor': 1};");
await session.ExecuteAsync(createKeyspace.Bind());

var createTable = await session.PrepareAsync("CREATE TABLE IF NOT EXISTS cosmicworks.products (id text PRIMARY KEY, name text)");
await session.ExecuteAsync(createTable.Bind());
// </resources>

// <insert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

var createItem = await session.PrepareAsync("INSERT INTO cosmicworks.products (id, name) VALUES (?, ?)");

var createItemStatement = createItem.Bind(item.id, item.name);

await session.ExecuteAsync(createItemStatement);
// </insert>
  1. 使用 PrepareAsyncExecuteAsync 创建新的数据库和容器。
// <imports>
using Cassandra;
// </imports>

// <client>
var options = new SSLOptions(
    sslProtocol: System.Security.Authentication.SslProtocols.Tls12,
    checkCertificateRevocation: true,
    remoteCertValidationCallback: (_, _, _, policyErrors) => policyErrors == System.Net.Security.SslPolicyErrors.None);

using var cluster = Cluster.Builder()
    .WithCredentials(
        username: "localhost",
        password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
    )
    .WithPort(
        port: 10350
    )
    .AddContactPoint(
        address: "localhost"
    )
    .WithSSL(
        sslOptions: options
    )
    .Build();

using var session = cluster.Connect();
// </client>

// <resources>
var createKeyspace = await session.PrepareAsync("CREATE KEYSPACE IF NOT EXISTS cosmicworks WITH replication = {'class':'basicclass', 'replication_factor': 1};");
await session.ExecuteAsync(createKeyspace.Bind());

var createTable = await session.PrepareAsync("CREATE TABLE IF NOT EXISTS cosmicworks.products (id text PRIMARY KEY, name text)");
await session.ExecuteAsync(createTable.Bind());
// </resources>

// <insert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

var createItem = await session.PrepareAsync("INSERT INTO cosmicworks.products (id, name) VALUES (?, ?)");

var createItemStatement = createItem.Bind(item.id, item.name);

await session.ExecuteAsync(createItemStatement);
// </insert>
  1. 使用 ExecuteAsync 在表中创建新项。 使用 Bind 为项分配属性。
// <imports>
using Cassandra;
// </imports>

// <client>
var options = new SSLOptions(
    sslProtocol: System.Security.Authentication.SslProtocols.Tls12,
    checkCertificateRevocation: true,
    remoteCertValidationCallback: (_, _, _, policyErrors) => policyErrors == System.Net.Security.SslPolicyErrors.None);

using var cluster = Cluster.Builder()
    .WithCredentials(
        username: "localhost",
        password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
    )
    .WithPort(
        port: 10350
    )
    .AddContactPoint(
        address: "localhost"
    )
    .WithSSL(
        sslOptions: options
    )
    .Build();

using var session = cluster.Connect();
// </client>

// <resources>
var createKeyspace = await session.PrepareAsync("CREATE KEYSPACE IF NOT EXISTS cosmicworks WITH replication = {'class':'basicclass', 'replication_factor': 1};");
await session.ExecuteAsync(createKeyspace.Bind());

var createTable = await session.PrepareAsync("CREATE TABLE IF NOT EXISTS cosmicworks.products (id text PRIMARY KEY, name text)");
await session.ExecuteAsync(createTable.Bind());
// </resources>

// <insert>
var item = new
{
    id = "68719518371",
    name = "Kiama classic surfboard"
};

var createItem = await session.PrepareAsync("INSERT INTO cosmicworks.products (id, name) VALUES (?, ?)");

var createItemStatement = createItem.Bind(item.id, item.name);

await session.ExecuteAsync(createItemStatement);
// </insert>
  1. 运行 .NET 应用程序。

    dotnet run
    

重要

在启动之前,API for Apache Gremlin 要求你在模拟器中创建资源。 创建名为 db1 的数据库和名为 coll1 的容器。 吞吐量设置与本指南无关,可以随意设置。

使用 Apache Gremlin .NET 驱动程序 从 .NET 应用程序连接到模拟器。

  1. 从空文件夹开始。

  2. 创建新的 .NET 控制台应用程序

    dotnet new console
    
  3. 从 NuGet 添加 Gremlin.Net 包。

    dotnet add package Gremlin.Net 
    
  4. 打开 Program.cs 文件。

  5. 删除文件中的任何现有内容。

  6. Gremlin.Net.Driver 命名空间添加一个 using 块。

// <imports>
using Gremlin.Net.Driver;
// </imports>

// <client>
var server = new GremlinServer(
    hostname: "localhost",
    port: 8901,
    username: "/dbs/db1/colls/coll1",
    password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);

using var client = new GremlinClient(
    gremlinServer: server,
    messageSerializer: new Gremlin.Net.Structure.IO.GraphSON.GraphSON2MessageSerializer()
);
// </client>

// <graph>
await client.SubmitAsync(
    requestScript: "g.V().drop()"
);
// </graph>

// <insert>
await client.SubmitAsync(
    requestScript: "g.addV('product').property('id', prop_id).property('name', prop_name)",
    bindings: new Dictionary<string, object>
    {
        { "prop_id", "68719518371" },
        { "prop_name", "Kiama classic surfboard" }
    }
);
// </insert>
  1. 使用模拟器的凭据创建 GremlinServerGremlinClient 的新实例。
// <imports>
using Gremlin.Net.Driver;
// </imports>

// <client>
var server = new GremlinServer(
    hostname: "localhost",
    port: 8901,
    username: "/dbs/db1/colls/coll1",
    password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);

using var client = new GremlinClient(
    gremlinServer: server,
    messageSerializer: new Gremlin.Net.Structure.IO.GraphSON.GraphSON2MessageSerializer()
);
// </client>

// <graph>
await client.SubmitAsync(
    requestScript: "g.V().drop()"
);
// </graph>

// <insert>
await client.SubmitAsync(
    requestScript: "g.addV('product').property('id', prop_id).property('name', prop_name)",
    bindings: new Dictionary<string, object>
    {
        { "prop_id", "68719518371" },
        { "prop_name", "Kiama classic surfboard" }
    }
);
// </insert>
  1. 使用 SubmitAsync 清理图形。
// <imports>
using Gremlin.Net.Driver;
// </imports>

// <client>
var server = new GremlinServer(
    hostname: "localhost",
    port: 8901,
    username: "/dbs/db1/colls/coll1",
    password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);

using var client = new GremlinClient(
    gremlinServer: server,
    messageSerializer: new Gremlin.Net.Structure.IO.GraphSON.GraphSON2MessageSerializer()
);
// </client>

// <graph>
await client.SubmitAsync(
    requestScript: "g.V().drop()"
);
// </graph>

// <insert>
await client.SubmitAsync(
    requestScript: "g.addV('product').property('id', prop_id).property('name', prop_name)",
    bindings: new Dictionary<string, object>
    {
        { "prop_id", "68719518371" },
        { "prop_name", "Kiama classic surfboard" }
    }
);
// </insert>
  1. 再次使用 SubmitAsync,可使用指定参数向图形添加新项。
// <imports>
using Gremlin.Net.Driver;
// </imports>

// <client>
var server = new GremlinServer(
    hostname: "localhost",
    port: 8901,
    username: "/dbs/db1/colls/coll1",
    password: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
);

using var client = new GremlinClient(
    gremlinServer: server,
    messageSerializer: new Gremlin.Net.Structure.IO.GraphSON.GraphSON2MessageSerializer()
);
// </client>

// <graph>
await client.SubmitAsync(
    requestScript: "g.V().drop()"
);
// </graph>

// <insert>
await client.SubmitAsync(
    requestScript: "g.addV('product').property('id', prop_id).property('name', prop_name)",
    bindings: new Dictionary<string, object>
    {
        { "prop_id", "68719518371" },
        { "prop_name", "Kiama classic surfboard" }
    }
);
// </insert>
  1. 运行 .NET 应用程序。

    dotnet run
    

使用 适用于 .NET 的 Azure Tables SDK 从 .NET 应用程序连接到模拟器。

  1. 从空文件夹开始。

  2. 创建新的 .NET 控制台应用程序

    dotnet new console
    
  3. 从 NuGet 添加 Azure.Data.Tables 包。

    dotnet add package Azure.Data.Tables
    
  4. 打开 Program.cs 文件。

  5. 删除文件中的任何现有内容。

  6. Azure.Data.Tables 命名空间添加一个 using 块。

// <imports>
using Azure.Data.Tables;
// </imports>

// <client>
var serviceClient = new TableServiceClient(
    connectionString: "DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;TableEndpoint=http://localhost:8902/;"
);
// </client>

// <resources>
var client = serviceClient.GetTableClient(
    tableName: "cosmicworksproducts"
);

await client.CreateIfNotExistsAsync();
// </resources>

// <upsert>
var item = new Product
{
    RowKey = "68719518371",
    PartitionKey = "Surfboards",
    Name = "Kiama classic surfboard",
    Timestamp = DateTimeOffset.Now
};

await client.UpsertEntityAsync(
    entity: item,
    mode: TableUpdateMode.Replace
);
// </upsert>
  1. 使用模拟器的凭据创建 TableServiceClient 的新实例。
// <imports>
using Azure.Data.Tables;
// </imports>

// <client>
var serviceClient = new TableServiceClient(
    connectionString: "DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;TableEndpoint=http://localhost:8902/;"
);
// </client>

// <resources>
var client = serviceClient.GetTableClient(
    tableName: "cosmicworksproducts"
);

await client.CreateIfNotExistsAsync();
// </resources>

// <upsert>
var item = new Product
{
    RowKey = "68719518371",
    PartitionKey = "Surfboards",
    Name = "Kiama classic surfboard",
    Timestamp = DateTimeOffset.Now
};

await client.UpsertEntityAsync(
    entity: item,
    mode: TableUpdateMode.Replace
);
// </upsert>
  1. 使用 GetTableClient 创建带有表名称的 TableClient 的新实例。 然后使用 CreateIfNotExistsAsync 确保表存在。
// <imports>
using Azure.Data.Tables;
// </imports>

// <client>
var serviceClient = new TableServiceClient(
    connectionString: "DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;TableEndpoint=http://localhost:8902/;"
);
// </client>

// <resources>
var client = serviceClient.GetTableClient(
    tableName: "cosmicworksproducts"
);

await client.CreateIfNotExistsAsync();
// </resources>

// <upsert>
var item = new Product
{
    RowKey = "68719518371",
    PartitionKey = "Surfboards",
    Name = "Kiama classic surfboard",
    Timestamp = DateTimeOffset.Now
};

await client.UpsertEntityAsync(
    entity: item,
    mode: TableUpdateMode.Replace
);
// </upsert>
  1. 为项创建新 record 类型。
// <entity>
public record Product : Azure.Data.Tables.ITableEntity
{
    public required string RowKey { get; set; }

    public required string PartitionKey { get; set; }

    public required string Name { get; init; }

    public Azure.ETag ETag { get; set; }

    public DateTimeOffset? Timestamp { get; set; }
}
// </entity>
  1. 使用 UpsertEntityAsyncReplace 模式在表中创建新项。
// <imports>
using Azure.Data.Tables;
// </imports>

// <client>
var serviceClient = new TableServiceClient(
    connectionString: "DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;TableEndpoint=http://localhost:8902/;"
);
// </client>

// <resources>
var client = serviceClient.GetTableClient(
    tableName: "cosmicworksproducts"
);

await client.CreateIfNotExistsAsync();
// </resources>

// <upsert>
var item = new Product
{
    RowKey = "68719518371",
    PartitionKey = "Surfboards",
    Name = "Kiama classic surfboard",
    Timestamp = DateTimeOffset.Now
};

await client.UpsertEntityAsync(
    entity: item,
    mode: TableUpdateMode.Replace
);
// </upsert>
  1. 运行 .NET 应用程序。

    dotnet run
    

在 GitHub Actions CI 工作流中使用模拟器

将 Azure Cosmos DB 模拟器与所选框架的测试套件配合使用,以运行可自动验证应用程序的持续集成工作负载。 GitHub Action 的托管运行器的 windows-latest 变体中预装了Azure Cosmos DB 模拟器。

使用 .NET 内置测试驱动程序和测试框架(如 MSTest、 NUnit 或 XUnit)来运行测试套件。

  1. 验证应用程序的单元测试套件是否按预期运行。

    dotnet test
    
  2. 在 GitHub 存储库中创建新工作流,文件名为 .github/workflows/ci.yml

  3. 将作业添加到工作流,以便使用 PowerShell 启动 Azure Cosmos DB 模拟器并运行单元测试套件。

    name: Continuous Integration
    on:
      push:
        branches:
          - main
    jobs:
      unit_tests:
        name: Run .NET unit tests
        runs-on: windows-latest
        steps:
          - name: Checkout (GitHub)
            uses: actions/checkout@v3
          - name: Start Azure Cosmos DB emulator
            run: >-
              Write-Host "Launching Cosmos DB Emulator"
              Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator"
              Start-CosmosDbEmulator
          - name: Run .NET tests
            run: dotnet test
    

    注意

    使用各种参数或 PowerShell 命令从命令行启动模拟器。 有关详细信息,请参阅 模拟器命令行参数

后续步骤