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
10 changes: 10 additions & 0 deletions samples/isolated-entities/Chirper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Build output
bin/
obj/

# User-specific files
*.user
*.suo

# Visual Studio cache
.vs/
30 changes: 30 additions & 0 deletions samples/isolated-entities/Chirper/Chirper.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Content Include="local.settings.json" />
</ItemGroup>

<ItemGroup>
Comment thread
bachuv marked this conversation as resolved.
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" VersionOverride="2.23.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" VersionOverride="2.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Core" VersionOverride="2.2.0" />
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

The Microsoft.Azure.Functions.Worker.Core package reference is redundant. It's already included as a transitive dependency of Microsoft.Azure.Functions.Worker. Consider removing this explicit reference to avoid potential version conflicts.

Suggested change
<PackageReference Include="Microsoft.Azure.Functions.Worker.Core" VersionOverride="2.2.0" />

Copilot uses AI. Check for mistakes.
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" VersionOverride="2.0.0" />
<ProjectReference Include="..\..\..\src\Worker.Extensions.DurableTask\Worker.Extensions.DurableTask.csproj" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" VersionOverride="2.0.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" VersionOverride="2.0.5" />
</ItemGroup>

<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions samples/isolated-entities/Chirper/Entities/IUserChirps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
Comment thread
bachuv marked this conversation as resolved.
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

The using directives System.Text and System.Collections.Generic are not used in this file. Consider removing them to keep the code clean.

Suggested change
using System.Text;

Copilot uses AI. Check for mistakes.
using System.Threading.Tasks;

namespace Chirper
{
public interface IUserChirps
{
void Add(Chirp chirp);

void Remove(DateTime timestamp);

Task<List<Chirp>> Get();
}
}
16 changes: 16 additions & 0 deletions samples/isolated-entities/Chirper/Entities/IUserFollows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
Comment thread
bachuv marked this conversation as resolved.
Comment on lines +1 to +3
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

The using directives System, System.Text, and System.Collections.Generic are not used in this file. Consider removing them to keep the code clean.

Suggested change
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Generic;

Copilot uses AI. Check for mistakes.
using System.Threading.Tasks;

namespace Chirper
{
public interface IUserFollows
{
void Add(string user);

void Remove(string user);

Task<List<string>> Get();
}
}
40 changes: 40 additions & 0 deletions samples/isolated-entities/Chirper/Entities/UserChirps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Newtonsoft.Json;

namespace Chirper
{
// The UserChirps entity stores all the chirps by ONE user.
// The entity key is the userId.

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class UserChirps : IUserChirps
{
[JsonProperty]
public List<Chirp> Chirps { get; set; } = new List<Chirp>();

public void Add(Chirp chirp)
{
Chirps.Add(chirp);
}

public void Remove(DateTime timestamp)
{
Chirps.RemoveAll(chirp => chirp.Timestamp == timestamp);
}

public Task<List<Chirp>> Get()
{
return Task.FromResult(Chirps);
}

// Boilerplate (entry point for the functions runtime)
[Function(nameof(UserChirps))]
public static Task HandleEntityOperation([EntityTrigger] TaskEntityDispatcher context)
{
return context.DispatchAsync<UserChirps>();
Comment thread
bachuv marked this conversation as resolved.
}
}
}
40 changes: 40 additions & 0 deletions samples/isolated-entities/Chirper/Entities/UserFollows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Newtonsoft.Json;

namespace Chirper
{
// The UserFollows entity stores all the follows of ONE user.
// The entity key is the userId.

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class UserFollows : IUserFollows
{
[JsonProperty]
public List<string> FollowedUsers { get; set; } = new List<string>();

public void Add(string user)
{
FollowedUsers.Add(user);
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

The Add method allows adding duplicate users to the followed users list. Consider checking if the user is already in the list before adding to prevent duplicates, or use a HashSet instead of a List for the FollowedUsers property.

Suggested change
FollowedUsers.Add(user);
if (!FollowedUsers.Contains(user))
{
FollowedUsers.Add(user);
}

Copilot uses AI. Check for mistakes.
}

public void Remove(string user)
{
FollowedUsers.Remove(user);
}

public Task<List<string>> Get()
{
return Task.FromResult(FollowedUsers);
}

// Boilerplate (entry point for the functions runtime)
[Function(nameof(UserFollows))]
public static Task HandleEntityOperation([EntityTrigger] TaskEntityDispatcher context)
{
return context.DispatchAsync<UserFollows>();
Comment thread
bachuv marked this conversation as resolved.
}
}
}
44 changes: 44 additions & 0 deletions samples/isolated-entities/Chirper/Orchestrations/GetTimeline.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Entities;

namespace Chirper
{
// The GetTimeline orchestration collects all chirps by followed users,
// and returns it as a list sorted by timestamp.
public static class GetTimeline
{
[Function(nameof(GetTimeline))]
public static async Task<Chirp[]> RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var userId = context.GetInput<string>();

// call the UserFollows entity to figure out whose chirps should be included
var userFollowsId = new EntityInstanceId(nameof(UserFollows), userId);
var followedUsers = await context.Entities.CallEntityAsync<List<string>>(userFollowsId, "Get");


// in parallel, collect all the chirps
var tasks = followedUsers
.Select(id =>
{
var userChirpsId = new EntityInstanceId(nameof(UserChirps), id);
return context.Entities.CallEntityAsync<List<Chirp>>(userChirpsId, "Get");
})
.ToList();
Comment on lines +22 to +32
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

If followedUsers is null (which can happen if the entity doesn't exist), this will throw a NullReferenceException when calling .Select(). Consider adding a null check and returning an empty array if the followed users list is null.

Copilot uses AI. Check for mistakes.

await Task.WhenAll(tasks);

// combine and sort the returned lists of chirps
var sortedResults = tasks
.SelectMany(task => task.Result)
.OrderBy(chirp => chirp.Timestamp);

return sortedResults.ToArray();
}
}
}
14 changes: 14 additions & 0 deletions samples/isolated-entities/Chirper/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services
.AddApplicationInsightsTelemetryWorkerService()
.ConfigureFunctionsApplicationInsights();

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"dependencies": {
"appInsights1": {
"type": "appInsights"
},
"storage1": {
"type": "storage",
"connectionId": "AzureWebJobsStorage"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"dependencies": {
"appInsights1": {
"type": "appInsights.sdk"
},
"storage1": {
"type": "storage.emulator",
"connectionId": "AzureWebJobsStorage"
}
}
}
24 changes: 24 additions & 0 deletions samples/isolated-entities/Chirper/PublicRest/Chirp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.Collections.Generic;
using System.Text;
Comment thread
bachuv marked this conversation as resolved.
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
Comment thread
bachuv marked this conversation as resolved.

namespace Chirper
{
/// <summary>
/// A data structure representing a chirp.
/// </summary>
[JsonObject(MemberSerialization.OptOut)]
public struct Chirp
{
public string UserId { get; set; }

public DateTime Timestamp { get; set; }

public string Content { get; set; }
}
}
Loading
Loading