diff --git a/Directory.Build.props b/Directory.Build.props
index 644af0ec2..bf96d72ee 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,6 +7,11 @@
enable
+
+ true
+ false
+
+
Microsoft.DurableTask
diff --git a/samples/AzureFunctionsUnitTests/SampleUnitTests.cs b/samples/AzureFunctionsUnitTests/SampleUnitTests.cs
index 85d3a5b7d..9f31d791e 100644
--- a/samples/AzureFunctionsUnitTests/SampleUnitTests.cs
+++ b/samples/AzureFunctionsUnitTests/SampleUnitTests.cs
@@ -200,9 +200,9 @@ public TestResponse(FunctionContext functionContext) : base(functionContext)
public class TestLogger : ILogger
{
// list of all logs emitted, for validation
- public IList CapturedLogs {get; set;} = new List();
+ public IList CapturedLogs { get; set; } = new List();
- public IDisposable BeginScope(TState state) => Mock.Of();
+ public IDisposable BeginScope(TState state) where TState : notnull => Mock.Of();
public bool IsEnabled(LogLevel logLevel)
{
diff --git a/samples/LargePayloadConsoleApp/Program.cs b/samples/LargePayloadConsoleApp/Program.cs
index 1591d8c04..eb2c22e99 100644
--- a/samples/LargePayloadConsoleApp/Program.cs
+++ b/samples/LargePayloadConsoleApp/Program.cs
@@ -27,7 +27,7 @@
// Keep threshold small to force externalization for demo purposes
opts.ExternalizeThresholdBytes = 1024; // 1KB
opts.ConnectionString = builder.Configuration.GetValue("DURABLETASK_STORAGE") ?? "UseDevelopmentStorage=true";
- opts.ContainerName = builder.Configuration.GetValue("DURABLETASK_PAYLOAD_CONTAINER");
+ opts.ContainerName = builder.Configuration.GetValue("DURABLETASK_PAYLOAD_CONTAINER") ?? "payloads";
});
// 2) Configure Durable Task client
diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs
index efc6d765c..422f15060 100644
--- a/src/Client/Grpc/GrpcDurableTaskClient.cs
+++ b/src/Client/Grpc/GrpcDurableTaskClient.cs
@@ -110,7 +110,7 @@ public override async Task ScheduleNewOrchestrationInstanceAsync(
DateTimeOffset? startAt = options?.StartAt;
this.logger.SchedulingOrchestration(
- request.InstanceId,
+ request.InstanceId ?? string.Empty,
orchestratorName,
sizeInBytes: request.Input != null ? Encoding.UTF8.GetByteCount(request.Input) : 0,
startAt.GetValueOrDefault(DateTimeOffset.UtcNow));
diff --git a/src/Extensions/AzureBlobPayloads/Options/LargePayloadStorageOptions.cs b/src/Extensions/AzureBlobPayloads/Options/LargePayloadStorageOptions.cs
index 7bd47bfc6..2a8b1995b 100644
--- a/src/Extensions/AzureBlobPayloads/Options/LargePayloadStorageOptions.cs
+++ b/src/Extensions/AzureBlobPayloads/Options/LargePayloadStorageOptions.cs
@@ -63,7 +63,6 @@ public LargePayloadStorageOptions(Uri accountUri, TokenCredential credential)
/// Gets or sets the threshold in bytes at which payloads are externalized. Default is 900_000 bytes.
/// Value must not exceed 1 MiB (1,048,576 bytes).
///
-
public int ExternalizeThresholdBytes
{
get => this.externalizeThresholdBytes;
diff --git a/src/Extensions/AzureBlobPayloads/PayloadStore/BlobPayloadStore.cs b/src/Extensions/AzureBlobPayloads/PayloadStore/BlobPayloadStore.cs
index 06294f5f7..9edced26d 100644
--- a/src/Extensions/AzureBlobPayloads/PayloadStore/BlobPayloadStore.cs
+++ b/src/Extensions/AzureBlobPayloads/PayloadStore/BlobPayloadStore.cs
@@ -89,7 +89,7 @@ public override async Task UploadAsync(string payLoad, CancellationToken
// using MemoryStream payloadStream = new(payloadBuffer, writable: false);
// await payloadStream.CopyToAsync(compressedBlobStream, bufferSize: DefaultCopyBufferSize, cancellationToken);
- await compressedBlobStream.WriteAsync(payloadBuffer, 0, payloadBuffer.Length, cancellationToken);
+ await WritePayloadAsync(payloadBuffer, compressedBlobStream, cancellationToken);
await compressedBlobStream.FlushAsync(cancellationToken);
await blobStream.FlushAsync(cancellationToken);
}
@@ -99,7 +99,7 @@ public override async Task UploadAsync(string payLoad, CancellationToken
// using MemoryStream payloadStream = new(payloadBuffer, writable: false);
// await payloadStream.CopyToAsync(blobStream, bufferSize: DefaultCopyBufferSize, cancellationToken);
- await blobStream.WriteAsync(payloadBuffer, 0, payloadBuffer.Length, cancellationToken);
+ await WritePayloadAsync(payloadBuffer, blobStream, cancellationToken);
await blobStream.FlushAsync(cancellationToken);
}
@@ -126,11 +126,11 @@ public override async Task DownloadAsync(string token, CancellationToken
{
using GZipStream decompressed = new(contentStream, CompressionMode.Decompress);
using StreamReader reader = new(decompressed, Encoding.UTF8);
- return await reader.ReadToEndAsync();
+ return await ReadToEndAsync(reader, cancellationToken);
}
using StreamReader uncompressedReader = new(contentStream, Encoding.UTF8);
- return await uncompressedReader.ReadToEndAsync();
+ return await ReadToEndAsync(uncompressedReader, cancellationToken);
}
///
@@ -144,6 +144,27 @@ public override bool IsKnownPayloadToken(string value)
return value.StartsWith(TokenPrefix, StringComparison.Ordinal);
}
+ static async Task WritePayloadAsync(byte[] payloadBuffer, Stream target, CancellationToken cancellationToken)
+ {
+#if NETSTANDARD2_0
+ await target.WriteAsync(payloadBuffer, 0, payloadBuffer.Length, cancellationToken).ConfigureAwait(false);
+#else
+ await target.WriteAsync(payloadBuffer.AsMemory(0, payloadBuffer.Length), cancellationToken).ConfigureAwait(false);
+#endif
+ }
+
+ static async Task ReadToEndAsync(StreamReader reader, CancellationToken cancellationToken)
+ {
+#if NETSTANDARD2_0
+ cancellationToken.ThrowIfCancellationRequested();
+ return await reader.ReadToEndAsync().ConfigureAwait(false);
+#elif NET8_0_OR_GREATER
+ return await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
+#else
+ return await reader.ReadToEndAsync().WaitAsync(cancellationToken).ConfigureAwait(false);
+#endif
+ }
+
static string EncodeToken(string container, string name) => $"blob:v1:{container}:{name}";
static (string Container, string Name) DecodeToken(string token)
diff --git a/src/InProcessTestHost/DurableTaskTestHost.cs b/src/InProcessTestHost/DurableTaskTestHost.cs
index ec075b945..931912eff 100644
--- a/src/InProcessTestHost/DurableTaskTestHost.cs
+++ b/src/InProcessTestHost/DurableTaskTestHost.cs
@@ -22,7 +22,7 @@ namespace Microsoft.DurableTask.Testing;
///
public sealed class DurableTaskTestHost : IAsyncDisposable
{
- readonly IWebHost sidecarHost;
+ readonly IHost sidecarHost;
readonly IHost workerHost;
readonly GrpcChannel grpcChannel;
@@ -33,7 +33,7 @@ public sealed class DurableTaskTestHost : IAsyncDisposable
/// The worker host.
/// The gRPC channel.
/// The durable task client.
- public DurableTaskTestHost(IWebHost sidecarHost, IHost workerHost, GrpcChannel grpcChannel, DurableTaskClient client)
+ public DurableTaskTestHost(IHost sidecarHost, IHost workerHost, GrpcChannel grpcChannel, DurableTaskClient client)
{
this.sidecarHost = sidecarHost;
this.workerHost = workerHost;
@@ -68,32 +68,37 @@ public static async Task StartAsync(
? $"http://localhost:{options.Port.Value}"
: $"http://localhost:{Random.Shared.Next(30000, 40000)}";
- var sidecarHost = new WebHostBuilder()
- .UseKestrel(kestrelOptions =>
+ IHost sidecarHost = Host.CreateDefaultBuilder()
+ .ConfigureWebHostDefaults(webBuilder =>
{
- // Configure for HTTP/2 (required for gRPC)
- kestrelOptions.ConfigureEndpointDefaults(listenOptions =>
- listenOptions.Protocols = HttpProtocols.Http2);
- })
- .UseUrls(address)
- .ConfigureServices(services =>
- {
- services.AddGrpc();
- services.AddSingleton(orchestrationService);
- services.AddSingleton(orchestrationService);
- services.AddSingleton();
- })
- .Configure(app =>
- {
- app.UseRouting();
- app.UseEndpoints(endpoints =>
+ webBuilder.UseUrls(address);
+ webBuilder.ConfigureKestrel(kestrelOptions =>
+ {
+ // Configure for HTTP/2 (required for gRPC)
+ kestrelOptions.ConfigureEndpointDefaults(listenOptions =>
+ listenOptions.Protocols = HttpProtocols.Http2);
+ });
+
+ webBuilder.ConfigureServices(services =>
+ {
+ services.AddGrpc();
+ services.AddSingleton(orchestrationService);
+ services.AddSingleton(orchestrationService);
+ services.AddSingleton();
+ });
+
+ webBuilder.Configure(app =>
{
- endpoints.MapGrpcService();
+ app.UseRouting();
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapGrpcService();
+ });
});
})
.Build();
- sidecarHost.Start();
+ await sidecarHost.StartAsync(cancellationToken);
var grpcChannel = GrpcChannel.ForAddress(address);
// Create worker host with user's orchestrators and activities
diff --git a/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs b/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs
index b25177ae9..15f65dd84 100644
--- a/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs
+++ b/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs
@@ -471,20 +471,20 @@ static P.GetInstanceResponse CreateGetInstanceResponse(OrchestrationState state,
{
// Get the original orchestration state
IList states = await this.client.GetOrchestrationStateAsync(request.InstanceId, false);
-
+
if (states == null || states.Count == 0)
{
throw new RpcException(new Status(StatusCode.NotFound, $"An orchestration with the instanceId {request.InstanceId} was not found."));
}
OrchestrationState state = states[0];
-
+
// Check if the state is null
if (state == null)
{
throw new RpcException(new Status(StatusCode.NotFound, $"An orchestration with the instanceId {request.InstanceId} was not found."));
}
-
+
string newInstanceId = request.RestartWithNewInstanceId ? Guid.NewGuid().ToString("N") : request.InstanceId;
// Create a new orchestration instance
@@ -646,6 +646,13 @@ public override async Task GetWorkItems(P.GetWorkItemsRequest request, IServerSt
}
}
+ ///
+ /// Streams the instance history for a given orchestration instance to the client in chunked form.
+ ///
+ /// The history request that identifies the instance.
+ /// The response stream used to write history chunks.
+ /// The server call context for the streaming operation.
+ /// A task that completes when streaming finishes.
public override async Task StreamInstanceHistory(P.StreamInstanceHistoryRequest request, IServerStreamWriter responseStream, ServerCallContext context)
{
if (this.streamingPastEvents.TryGetValue(request.InstanceId, out List? pastEvents))
diff --git a/src/Shared/AzureManaged/DurableTaskVersionUtil.cs b/src/Shared/AzureManaged/DurableTaskVersionUtil.cs
index 7ad3bc47c..873931292 100644
--- a/src/Shared/AzureManaged/DurableTaskVersionUtil.cs
+++ b/src/Shared/AzureManaged/DurableTaskVersionUtil.cs
@@ -3,6 +3,8 @@
using System.Diagnostics;
+#pragma warning disable CS0436
+
namespace Microsoft.DurableTask;
///
@@ -18,7 +20,7 @@ public static class DurableTaskUserAgentUtil
///
/// The version of the SDK used in the user agent string.
///
- static readonly string PackageVersion = FileVersionInfo.GetVersionInfo(typeof(DurableTaskUserAgentUtil).Assembly.Location).FileVersion;
+ static readonly string PackageVersion = FileVersionInfo.GetVersionInfo(typeof(DurableTaskUserAgentUtil).Assembly.Location).FileVersion ?? "unknown";
///
/// Generates the user agent string for the Durable Task SDK based on a fixed name, the package version, and the caller type.
@@ -29,4 +31,5 @@ public static string GetUserAgent(string callerType)
{
return $"{SdkName}/{PackageVersion?.ToString() ?? "unknown"} ({callerType})";
}
-}
\ No newline at end of file
+}
+#pragma warning restore CS0436
\ No newline at end of file
diff --git a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs
index 7aad801c3..3c760ddf6 100644
--- a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs
+++ b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs
@@ -95,7 +95,7 @@ public void UseDurableTaskScheduler_WithLocalhostConnectionString_ShouldConfigur
[Theory]
[InlineData(null, "testhub")]
[InlineData("myaccount.westus3.durabletask.io", null)]
- public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string endpoint, string taskHub)
+ public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string? endpoint, string? taskHub)
{
// Arrange
ServiceCollection services = new ServiceCollection();
@@ -104,7 +104,7 @@ public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidat
DefaultAzureCredential credential = new DefaultAzureCredential();
// Act
- mockBuilder.Object.UseDurableTaskScheduler(endpoint, taskHub, credential);
+ mockBuilder.Object.UseDurableTaskScheduler(endpoint!, taskHub!, credential);
ServiceProvider provider = services.BuildServiceProvider();
// Assert
@@ -157,7 +157,7 @@ public void UseDurableTaskScheduler_WithInvalidConnectionString_ShouldThrowArgum
[Theory]
[InlineData("")]
[InlineData(null)]
- public void UseDurableTaskScheduler_WithNullOrEmptyConnectionString_ShouldThrowArgumentException(string connectionString)
+ public void UseDurableTaskScheduler_WithNullOrEmptyConnectionString_ShouldThrowArgumentException(string? connectionString)
{
// Arrange
ServiceCollection services = new ServiceCollection();
@@ -165,7 +165,7 @@ public void UseDurableTaskScheduler_WithNullOrEmptyConnectionString_ShouldThrowA
mockBuilder.Setup(b => b.Services).Returns(services);
// Act & Assert
- Action action = () => mockBuilder.Object.UseDurableTaskScheduler(connectionString);
+ Action action = () => mockBuilder.Object.UseDurableTaskScheduler(connectionString!);
action.Should().Throw();
}
diff --git a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs
index 0d14b3961..fa65cc42a 100644
--- a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs
+++ b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs
@@ -94,7 +94,7 @@ public void Ctor_EntitiesConfigured_GetClientSuccess()
[Theory]
[InlineData(false)]
[InlineData(true)]
- public async void GetInstanceMetadata_EmptyList_Null(bool isNull)
+ public async Task GetInstanceMetadata_EmptyList_Null(bool isNull)
{
// arrange
List? states = isNull ? null : new();
diff --git a/test/Grpc.IntegrationTests/ExternalEventStackTests.cs b/test/Grpc.IntegrationTests/ExternalEventStackTests.cs
index dcd79b65d..bd028a2fd 100644
--- a/test/Grpc.IntegrationTests/ExternalEventStackTests.cs
+++ b/test/Grpc.IntegrationTests/ExternalEventStackTests.cs
@@ -36,39 +36,39 @@ public async Task StackBehavior_LIFO_NewestWaiterReceivesEventFirst()
{
// First waiter
Task firstWaiter = ctx.WaitForExternalEvent(EventName);
-
+
// Second waiter (newer, should receive event first)
Task secondWaiter = ctx.WaitForExternalEvent(EventName);
-
+
// Wait for both events to arrive from external client
string secondResult = await secondWaiter; // Should receive first event (stack top)
string firstResult = await firstWaiter; // Should receive second event
-
+
// Return which waiter received which event
return $"{firstResult}:{secondResult}";
}));
});
string instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync(orchestratorName);
-
+
// Wait for orchestration to start and set up waiters
OrchestrationMetadata metadata = await server.Client.WaitForInstanceStartAsync(
- instanceId, this.TimeoutToken);
-
+ instanceId, this.TimeoutToken)
+ ?? throw new InvalidOperationException("Orchestration did not start.");
+
// Send first event - should be received by second waiter (stack top)
await server.Client.RaiseEventAsync(instanceId, EventName, SecondEventPayload);
-
+
// Send second event - should be received by first waiter
await server.Client.RaiseEventAsync(instanceId, EventName, FirstEventPayload);
metadata = await server.Client.WaitForInstanceCompletionAsync(
- instanceId, getInputsAndOutputs: true, this.TimeoutToken);
-
- Assert.NotNull(metadata);
+ instanceId, getInputsAndOutputs: true, this.TimeoutToken)
+ ?? throw new InvalidOperationException("Orchestration did not complete.");
Assert.Equal(OrchestrationRuntimeStatus.Completed, metadata.RuntimeStatus);
-
+
// Verify the output: second waiter should have received "second-event", first waiter "first-event"
- string result = metadata.ReadOutputAs();
+ string result = metadata.ReadOutputAs() ?? throw new InvalidOperationException("Missing orchestration output.");
Assert.Equal($"{FirstEventPayload}:{SecondEventPayload}", result);
}
@@ -110,7 +110,7 @@ public async Task Issue508_FirstWaiterCancelled_SecondWaiterReceivesEvent()
{
Task waitForEvent = ctx.WaitForExternalEvent(EventName, cts.Token);
Task timeout = ctx.CreateTimer(ctx.CurrentUtcDateTime.AddSeconds(2), CancellationToken.None);
-
+
Task winner = await Task.WhenAny(waitForEvent, timeout);
if (winner == timeout)
{
@@ -125,21 +125,20 @@ public async Task Issue508_FirstWaiterCancelled_SecondWaiterReceivesEvent()
});
string instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync(orchestratorName);
-
+
// Wait for orchestration to start and cancel first waiter
await server.Client.WaitForInstanceStartAsync(
instanceId, this.TimeoutToken);
-
+
// Send event - should be received by second waiter (stack top), not the cancelled first waiter
await server.Client.RaiseEventAsync(instanceId, EventName, EventPayload);
OrchestrationMetadata metadata = await server.Client.WaitForInstanceCompletionAsync(
- instanceId, getInputsAndOutputs: true, this.TimeoutToken);
-
- Assert.NotNull(metadata);
+ instanceId, getInputsAndOutputs: true, this.TimeoutToken)
+ ?? throw new InvalidOperationException("Orchestration did not complete.");
Assert.Equal(OrchestrationRuntimeStatus.Completed, metadata.RuntimeStatus);
-
- string result = metadata.ReadOutputAs();
+
+ string result = metadata.ReadOutputAs() ?? throw new InvalidOperationException("Missing orchestration output.");
Assert.Equal(EventPayload, result);
}
@@ -173,24 +172,23 @@ public async Task MultipleEvents_MultipleWaiters_LIFOOrder()
});
string instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync(orchestratorName);
-
+
// Wait for orchestration to start and set up waiters
await server.Client.WaitForInstanceStartAsync(
instanceId, this.TimeoutToken);
-
+
// Send three events - should be received in LIFO order
await server.Client.RaiseEventAsync(instanceId, EventName, "event-1");
await server.Client.RaiseEventAsync(instanceId, EventName, "event-2");
await server.Client.RaiseEventAsync(instanceId, EventName, "event-3");
OrchestrationMetadata metadata = await server.Client.WaitForInstanceCompletionAsync(
- instanceId, getInputsAndOutputs: true, this.TimeoutToken);
-
- Assert.NotNull(metadata);
+ instanceId, getInputsAndOutputs: true, this.TimeoutToken)
+ ?? throw new InvalidOperationException("Orchestration did not complete.");
Assert.Equal(OrchestrationRuntimeStatus.Completed, metadata.RuntimeStatus);
-
+
// Verify LIFO order: waiter3 (newest) gets event-1, waiter2 gets event-2, waiter1 gets event-3
- string result = metadata.ReadOutputAs();
+ string result = metadata.ReadOutputAs() ?? throw new InvalidOperationException("Missing orchestration output.");
Assert.Equal("event-3,event-2,event-1", result);
}
@@ -215,7 +213,7 @@ public async Task EventBuffering_EventArrivesBeforeWaiter_FirstWaiterReceivesBuf
// Now create waiter - should immediately receive the buffered event
Task waiter = ctx.WaitForExternalEvent(EventName);
Task timeout = ctx.CreateTimer(ctx.CurrentUtcDateTime.AddSeconds(1), CancellationToken.None);
-
+
Task winner = await Task.WhenAny(waiter, timeout);
if (winner == timeout)
{
@@ -228,17 +226,16 @@ public async Task EventBuffering_EventArrivesBeforeWaiter_FirstWaiterReceivesBuf
});
string instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync(orchestratorName);
-
+
// Send event before waiter is created
await server.Client.RaiseEventAsync(instanceId, EventName, EventPayload);
OrchestrationMetadata metadata = await server.Client.WaitForInstanceCompletionAsync(
- instanceId, getInputsAndOutputs: true, this.TimeoutToken);
-
- Assert.NotNull(metadata);
+ instanceId, getInputsAndOutputs: true, this.TimeoutToken)
+ ?? throw new InvalidOperationException("Orchestration did not complete.");
Assert.Equal(OrchestrationRuntimeStatus.Completed, metadata.RuntimeStatus);
-
- string result = metadata.ReadOutputAs();
+
+ string result = metadata.ReadOutputAs() ?? throw new InvalidOperationException("Missing orchestration output.");
Assert.Equal(EventPayload, result);
}
}
diff --git a/test/Grpc.IntegrationTests/GrpcSidecarFixture.cs b/test/Grpc.IntegrationTests/GrpcSidecarFixture.cs
index 2408d3d27..cfefcd4d3 100644
--- a/test/Grpc.IntegrationTests/GrpcSidecarFixture.cs
+++ b/test/Grpc.IntegrationTests/GrpcSidecarFixture.cs
@@ -11,6 +11,7 @@
using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Hosting;
namespace Microsoft.DurableTask.Grpc.Tests;
@@ -18,7 +19,7 @@ public sealed class GrpcSidecarFixture : IDisposable
{
const string ListenHost = "localhost";
- readonly IWebHost host;
+ readonly IHost host;
public GrpcSidecarFixture()
{
@@ -26,28 +27,32 @@ public GrpcSidecarFixture()
// Use a random port number to allow multiple instances to run in parallel
string address = $"http://{ListenHost}:{Random.Shared.Next(30000, 40000)}";
- this.host = new WebHostBuilder()
- .UseKestrel(options =>
+ this.host = Host.CreateDefaultBuilder()
+ .ConfigureWebHostDefaults(webBuilder =>
{
- // Need to force Http2 in Kestrel in unencrypted scenarios
- // https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0
- options.ConfigureEndpointDefaults(listenOptions => listenOptions.Protocols = HttpProtocols.Http2);
- })
- .UseUrls(address)
- .ConfigureServices(services =>
- {
- services.AddGrpc();
- services.AddSingleton(service);
- services.AddSingleton(service);
- services.AddSingleton();
- })
- .Configure(app =>
- {
- app.UseRouting();
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGrpcService();
- });
+ webBuilder
+ .UseKestrel(options =>
+ {
+ // Need to force Http2 in Kestrel in unencrypted scenarios
+ // https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0
+ options.ConfigureEndpointDefaults(listenOptions => listenOptions.Protocols = HttpProtocols.Http2);
+ })
+ .UseUrls(address)
+ .ConfigureServices(services =>
+ {
+ services.AddGrpc();
+ services.AddSingleton(service);
+ services.AddSingleton(service);
+ services.AddSingleton();
+ })
+ .Configure(app =>
+ {
+ app.UseRouting();
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapGrpcService();
+ });
+ });
})
.Build();
diff --git a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs
index 84c2f1e49..423dbb2f4 100644
--- a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs
+++ b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs
@@ -262,8 +262,8 @@ public async Task RetryActivityFailuresCustomLogic(int expectedNumberOfAttempts,
[Theory]
[InlineData(10, typeof(ApplicationException), false, int.MaxValue, 2, 1, OrchestrationRuntimeStatus.Failed)] // 1 attempt since retry timeout expired.
[InlineData(2, typeof(ApplicationException), false, int.MaxValue, null, 1, OrchestrationRuntimeStatus.Failed)] // 1 attempt since handler specifies no retry.
- [InlineData(2, typeof(CustomException),true, int.MaxValue, null, 2, OrchestrationRuntimeStatus.Failed)] // 2 attempts, custom exception type
- [InlineData(10, typeof(XunitException),true, 4, null, 5, OrchestrationRuntimeStatus.Completed)] // 10 attempts, 3rd party exception type
+ [InlineData(2, typeof(CustomException), true, int.MaxValue, null, 2, OrchestrationRuntimeStatus.Failed)] // 2 attempts, custom exception type
+ [InlineData(10, typeof(XunitException), true, 4, null, 5, OrchestrationRuntimeStatus.Completed)] // 10 attempts, 3rd party exception type
public async Task RetryActivityFailuresCustomLogicAndPolicy(
int maxNumberOfAttempts,
Type exceptionType,
@@ -665,7 +665,7 @@ void MyActivityImpl(TaskActivityContext ctx) =>
{
// Register the custom exception properties provider
b.Services.AddSingleton();
-
+
b.AddTasks(tasks => tasks
.AddOrchestratorFunc(orchestratorName, MyOrchestrationImpl)
.AddActivityFunc(activityName, MyActivityImpl));
@@ -753,7 +753,7 @@ void MyOrchestrationImpl(TaskOrchestrationContext ctx) =>
{
// Register the custom exception properties provider
b.Services.AddSingleton();
-
+
b.AddTasks(tasks => tasks
.AddOrchestratorFunc(orchestratorName, MyOrchestrationImpl));
});
@@ -814,7 +814,7 @@ void ActivityImpl(TaskActivityContext ctx) =>
{
// Register the custom exception properties provider
b.Services.AddSingleton();
-
+
b.AddTasks(tasks => tasks
.AddOrchestratorFunc(parentOrchestratorName, ParentOrchestrationImpl)
.AddOrchestratorFunc(subOrchestratorName, SubOrchestrationImpl)
@@ -831,7 +831,7 @@ void ActivityImpl(TaskActivityContext ctx) =>
Assert.NotNull(metadata.FailureDetails);
TaskFailureDetails failureDetails = metadata.FailureDetails!;
-
+
// The parent orchestration failed due to a TaskFailedException from the sub-orchestration
Assert.Equal(typeof(TaskFailedException).FullName, failureDetails.ErrorType);
Assert.Contains(subOrchestratorName, failureDetails.ErrorMessage);
@@ -879,10 +879,12 @@ public CustomException(string message, Exception innerException)
{
}
+#pragma warning disable SYSLIB0051
protected CustomException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
+#pragma warning restore SYSLIB0051
}
///
@@ -891,7 +893,7 @@ protected CustomException(SerializationInfo info, StreamingContext context)
[Serializable]
class BusinessValidationException : Exception
{
- public BusinessValidationException(string message,
+ public BusinessValidationException(string message,
string stringProperty,
int intProperty,
long longProperty,
@@ -917,10 +919,12 @@ public BusinessValidationException(string message,
public IList