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
56 changes: 56 additions & 0 deletions storage/api/Storage.Samples.Tests/GetObjectContextsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using System.Collections.Generic;
using Xunit;

[Collection(nameof(StorageFixture))]
public class GetObjectContextsTest
{
private readonly StorageFixture _fixture;

public GetObjectContextsTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void GetObjectContexts()
{
GetObjectContextsSample getContextsSample = new GetObjectContextsSample();
SetObjectContextsSample setContextsSample = new SetObjectContextsSample();
UploadObjectFromMemorySample uploadObjectSample = new UploadObjectFromMemorySample();

string contextKey = "A\u00F1\u03A9\U0001F680";
string contextValue = "Ab\u00F1\u03A9\U0001F680";

var customContexts = new Dictionary<string, ObjectCustomContextPayload>
{
{ contextKey, new ObjectCustomContextPayload { Value = contextValue } }
};

var bucketName = _fixture.GenerateBucketName();
var objectName = _fixture.GenerateName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: true, registerForDeletion: true);
var content = _fixture.GenerateContent();
uploadObjectSample.UploadObjectFromMemory(bucketName, objectName, content);
var appliedContexts = setContextsSample.SetObjectContexts(bucketName, objectName, customContexts);
var retrievedContexts = getContextsSample.GetObjectContexts(bucketName, objectName);
Assert.Equal(appliedContexts.Custom.Count, retrievedContexts.Custom.Count);
var singleContext = Assert.Single(retrievedContexts.Custom);
Assert.Equal(contextKey, singleContext.Key);
Assert.Equal(contextValue, singleContext.Value.Value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using System.Collections.Generic;
using Xunit;

[Collection(nameof(StorageFixture))]
public class ListObjectsWithContextFilterTest
{
private readonly StorageFixture _fixture;

public ListObjectsWithContextFilterTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void ListObjectsWithContextFilter()
{
ListObjectsWithContextFilterSample listContextsSample = new ListObjectsWithContextFilterSample();
SetObjectContextsSample setContextsSample = new SetObjectContextsSample();
UploadObjectFromMemorySample uploadObjectSample = new UploadObjectFromMemorySample();

string contextKey = "A\u00F1\u03A9\U0001F680";
string contextValue = "Ab\u00F1\u03A9\U0001F680";

var customContexts = new Dictionary<string, ObjectCustomContextPayload>
{
{ contextKey, new ObjectCustomContextPayload { Value = contextValue } }
};

var bucketName = _fixture.GenerateBucketName();
var objectName = _fixture.GenerateName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: true, registerForDeletion: true);
var content = _fixture.GenerateContent();
uploadObjectSample.UploadObjectFromMemory(bucketName, objectName, content);
setContextsSample.SetObjectContexts(bucketName, objectName, customContexts);

string filter = $@"contexts.""{contextKey}""=""{contextValue}""";
var filteredObjects = listContextsSample.ListObjectsWithContextFilter(bucketName, filter);
var obj = Assert.Single(filteredObjects);
var fetchedContext = Assert.Single(obj.Contexts.Custom);
Assert.Equal(contextKey, fetchedContext.Key);
Assert.Equal(contextValue, fetchedContext.Value.Value);
}
}
56 changes: 56 additions & 0 deletions storage/api/Storage.Samples.Tests/SetObjectContextsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using System.Collections.Generic;
using Xunit;

[Collection(nameof(StorageFixture))]
public class SetObjectContextsTest
{
private readonly StorageFixture _fixture;

public SetObjectContextsTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void SetObjectContexts()
{
SetObjectContextsSample contextsSample = new SetObjectContextsSample();
UploadObjectFromMemorySample uploadObjectSample = new UploadObjectFromMemorySample();

string contextKey = "A\u00F1\u03A9\U0001F680";
string contextValue = "Ab\u00F1\u03A9\U0001F680";

var customContexts = new Dictionary<string, ObjectCustomContextPayload>
{
{ contextKey, new ObjectCustomContextPayload { Value = contextValue } }
};

var bucketName = _fixture.GenerateBucketName();
var objectName = _fixture.GenerateName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: true, registerForDeletion: true);

var content = _fixture.GenerateContent();
uploadObjectSample.UploadObjectFromMemory(bucketName, objectName, content);
var appliedContexts = contextsSample.SetObjectContexts(bucketName, objectName, customContexts);
var retrievedObject = _fixture.Client.GetObject(bucketName, objectName);
Assert.Equal(appliedContexts.Custom.Count, retrievedObject.Contexts.Custom.Count);
var singleContext = Assert.Single(retrievedObject.Contexts.Custom);
Assert.Equal(contextKey, singleContext.Key);
Assert.Equal(contextValue, singleContext.Value.Value);
}
}
49 changes: 49 additions & 0 deletions storage/api/Storage.Samples/GetObjectContexts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_get_object_contexts]

using Google.Cloud.Storage.V1;
using System;

public class GetObjectContextsSample
{
/// <summary>
/// Gets the context data associated with the object.
/// </summary>
/// <param name="bucketName">The name of the bucket containing the object.</param>
/// <param name="objectName">The name of the object.</param>
public Google.Apis.Storage.v1.Data.Object.ContextsData GetObjectContexts(
string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name")
{
var storage = StorageClient.Create();
var obj = storage.GetObject(bucketName, objectName);
Google.Apis.Storage.v1.Data.Object.ContextsData contextsData = obj.Contexts;

if (contextsData?.Custom == null || contextsData.Custom.Count == 0)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The condition to check if contextsData.Custom is null or empty can be written more concisely using the null-conditional (?.) and null-coalescing (??) operators. This improves readability and is a common C# idiom.

        if ((contextsData?.Custom?.Count ?? 0) == 0)

{
Console.WriteLine($"No Context Data found for the Object {objectName}");
return contextsData;
}

Console.WriteLine($"Context Data for the Object {objectName} is as follows:");
foreach (var (key, contextPayload) in contextsData.Custom)
{
Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
}
return contextsData;
}
}
// [END storage_get_object_contexts]
51 changes: 51 additions & 0 deletions storage/api/Storage.Samples/ListObjectsWithContextFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_list_object_contexts]

using Google.Cloud.Storage.V1;
using System;
using System.Collections.Generic;
using System.Linq;

public class ListObjectsWithContextFilterSample
{
/// <summary>
/// List objects in the specified bucket that match a context filter.
/// </summary>
/// <param name="bucketName">The name of the bucket.</param>
/// <param name="filter">The metadata context filter (e.g. "contexts.\"KEY\":*", "-contexts.\"KEY\":*", "contexts.\"KEY\"=\"VALUE\"", "-contexts.\"KEY\"=\"VALUE\"").</param>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example filter strings in the documentation contain unnecessary backslashes and are wrapped in quotes, which can be confusing. To improve clarity, please remove the backslashes and the outer quotes from the examples.

    /// <param name="filter">The metadata context filter (e.g. contexts."KEY":*, -contexts."KEY":*, contexts."KEY"="VALUE", -contexts."KEY"="VALUE").</param>

public IEnumerable<Google.Apis.Storage.v1.Data.Object> ListObjectsWithContextFilter(string bucketName = "your-unique-bucket-name",
string filter = "contexts.\"KEY\"=\"VALUE\"")
{
var storage = StorageClient.Create();
var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { Filter = filter, Fields = "items(name,contexts)" }).ToList();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Calling .ToList() materializes the entire collection of objects in memory. For buckets with a large number of objects, this can lead to high memory consumption and performance issues. Since the method returns an IEnumerable<Object> and the subsequent code iterates over it, you can remove .ToList() to take advantage of deferred execution and stream the results from the API. This will make the sample more efficient and scalable.

        var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { Filter = filter, Fields = "items(name,contexts)" });

Console.WriteLine($"The Names and Context Data for the Objects in the {bucketName} with Context Filter {filter} are as follows:");
foreach (var obj in objects)
{
Console.WriteLine($"Object: {obj.Name}");
Console.WriteLine($"Context Data for the Object {obj.Name} is as follows:");

if (obj.Contexts?.Custom is { } customContexts)
{
foreach (var (key, contextPayload) in customContexts)
{
Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
}
}
}
return objects;
}
}
// [END storage_list_object_contexts]
49 changes: 49 additions & 0 deletions storage/api/Storage.Samples/SetObjectContexts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_set_object_contexts]

using Google.Apis.Storage.v1.Data;
using Google.Cloud.Storage.V1;
using System;
using System.Collections.Generic;

public class SetObjectContextsSample
{
/// <summary>
/// Sets the context data associated with the object.
/// </summary>
/// <param name="bucketName">The name of the bucket containing the object.</param>
/// <param name="objectName">The name of the object.</param>
/// <param name="customContexts">The new user-defined contexts to set context data associated with the object.</param>
public Google.Apis.Storage.v1.Data.Object.ContextsData SetObjectContexts(
string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name",
IDictionary<string, ObjectCustomContextPayload> customContexts = null)
{
var storage = StorageClient.Create();
customContexts ??= new Dictionary<string, ObjectCustomContextPayload>();
var contextsData = new Google.Apis.Storage.v1.Data.Object.ContextsData { Custom = customContexts };
var obj = new Google.Apis.Storage.v1.Data.Object
{
Bucket = bucketName,
Name = objectName,
Contexts = contextsData
};
var updatedObject = storage.UpdateObject(obj);
Console.WriteLine($"Updated Context Data for the Object {objectName} in the Bucket {bucketName}");
return updatedObject.Contexts;
}
}
// [END storage_set_object_contexts]
2 changes: 1 addition & 1 deletion storage/api/Storage.Samples/Storage.Samples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<ItemGroup>
<PackageReference Include="Google.Cloud.Storage.Control.V2" Version="1.5.0" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.14.0" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.15.0" />
</ItemGroup>

</Project>