diff --git a/samples/AzureFunctionsApp/Entities/Counter.cs b/samples/AzureFunctionsApp/Entities/Counter.cs index b960d386..72e9f003 100644 --- a/samples/AzureFunctionsApp/Entities/Counter.cs +++ b/samples/AzureFunctionsApp/Entities/Counter.cs @@ -30,18 +30,11 @@ namespace AzureFunctionsApp.Entities; /// the added benefit of being able to use DI. When using TaskEntity, state is deserialized to the "State" /// property. No other properties on this type will be serialized/deserialized. /// -public class Counter : TaskEntity +public class Counter(ILogger logger) : TaskEntity { - readonly ILogger logger; - - public Counter(ILogger logger) - { - this.logger = logger; - } - public int Add(int input) { - this.logger.LogInformation("Adding {Input} to {State}", input, this.State); + logger.LogInformation("Adding {Input} to {State}", input, this.State); return this.State += input; } diff --git a/samples/AzureFunctionsApp/Entities/Lifetime.cs b/samples/AzureFunctionsApp/Entities/Lifetime.cs index ed6c1b09..08612f82 100644 --- a/samples/AzureFunctionsApp/Entities/Lifetime.cs +++ b/samples/AzureFunctionsApp/Entities/Lifetime.cs @@ -17,15 +17,8 @@ namespace AzureFunctionsApp.Entities; /// is also possible to design an entity which remains stateless by always returning null from /// and never assigning a non-null state. /// -public class Lifetime : TaskEntity +public class Lifetime(ILogger logger) : TaskEntity { - readonly ILogger logger; - - public Lifetime(ILogger logger) - { - this.logger = logger; - } - /// /// Optional property to override. When 'true', this will allow dispatching of operations to the /// object if there is no matching method on the entity. Default is 'false'. @@ -39,7 +32,7 @@ public Lifetime(ILogger logger) [Function(nameof(Lifetime))] public Task DispatchAsync([EntityTrigger] TaskEntityDispatcher dispatcher) { - this.logger.LogInformation("Dispatching entity"); + logger.LogInformation("Dispatching entity"); return dispatcher.DispatchAsync(this); } diff --git a/samples/AzureFunctionsApp/Entities/User.cs b/samples/AzureFunctionsApp/Entities/User.cs index c66630a9..7106492b 100644 --- a/samples/AzureFunctionsApp/Entities/User.cs +++ b/samples/AzureFunctionsApp/Entities/User.cs @@ -19,20 +19,13 @@ public record UserUpdate(string? Name, int? Age); /// /// This sample demonstrates how to bind to as well as dispatch to orchestrations. /// -public class UserEntity : TaskEntity +public class UserEntity(ILogger logger) : TaskEntity { - readonly ILogger logger; - - public UserEntity(ILogger logger) - { - this.logger = logger; - } - public void Set(User user) { User previous = this.State; this.State = user; - this.logger.LogInformation("User {Id} set {Old} -> {New}", this.Context.Id.Key, previous, this.State); + logger.LogInformation("User {Id} set {Old} -> {New}", this.Context.Id.Key, previous, this.State); } public void Update(UserUpdate update) @@ -40,8 +33,7 @@ public void Update(UserUpdate update) (string n, int a) = (update.Name ?? this.State.Name, update.Age ?? this.State.Age); User previous = this.State; this.State = previous with { Name = n, Age = a }; - - this.logger.LogInformation("User {Id} updated {Old} -> {New}", this.Context.Id.Key, previous, this.State); + logger.LogInformation("User {Id} updated {Old} -> {New}", this.Context.Id.Key, previous, this.State); } /// @@ -55,7 +47,7 @@ public void Greet(TaskEntityContext context, string? message = null) { if (this.State.Name is null) { - this.logger.LogError("User is not in a valid state for a greet operation."); + logger.LogError("User is not in a valid state for a greet operation."); throw new InvalidOperationException("User has not been initialized."); } diff --git a/samples/AzureFunctionsApp/HelloCitiesTyped.cs b/samples/AzureFunctionsApp/HelloCitiesTyped.cs index ce603aac..4ec11dec 100644 --- a/samples/AzureFunctionsApp/HelloCitiesTyped.cs +++ b/samples/AzureFunctionsApp/HelloCitiesTyped.cs @@ -63,28 +63,19 @@ public async override Task RunAsync(TaskOrchestrationContext context, st /// Class-based activity function implementation. Source generators are used to a generate an activity function /// definition that creates an instance of this class and invokes its method. /// +/// +/// This class is initialized once for every activity execution. +/// Activity class constructors support constructor-based dependency injection. +/// The injected services are provided by the function's property. +/// +/// The logger injected by the Azure Functions runtime. [DurableTask(nameof(SayHelloTyped))] -public class SayHelloTyped : TaskActivity +public class SayHelloTyped(ILogger logger) + : TaskActivity { - readonly ILogger logger; - - /// - /// Initializes a new instance of the class. - /// This class is initialized once for every activity execution. - /// - /// - /// Activity class constructors support constructor-based dependency injection. - /// The injected services are provided by the function's property. - /// - /// The logger injected by the Azure Functions runtime. - public SayHelloTyped(ILogger logger) - { - this.logger = logger; - } - public override Task RunAsync(TaskActivityContext context, string cityName) { - this.logger.LogInformation("Saying hello to {name}", cityName); + logger.LogInformation("Saying hello to {name}", cityName); return Task.FromResult($"Hello, {cityName}!"); } } diff --git a/samples/AzureFunctionsApp/Program.cs b/samples/AzureFunctionsApp/Program.cs index 3ec7a407..2947f5eb 100644 --- a/samples/AzureFunctionsApp/Program.cs +++ b/samples/AzureFunctionsApp/Program.cs @@ -2,16 +2,9 @@ // Licensed under the MIT License. using Microsoft.Extensions.Hosting; -namespace AzureFunctionsApp; -public class Program -{ - public static void Main() - { - IHost host = new HostBuilder() - .ConfigureFunctionsWorkerDefaults() - .Build(); +IHost host = new HostBuilder() + .ConfigureFunctionsWorkerDefaults() + .Build(); - host.Run(); - } -} \ No newline at end of file +host.Run(); diff --git a/samples/WebAPI/Controllers/OrderProcessingController.cs b/samples/WebAPI/Controllers/OrderProcessingController.cs index 314e91f5..1756e2c3 100644 --- a/samples/WebAPI/Controllers/OrderProcessingController.cs +++ b/samples/WebAPI/Controllers/OrderProcessingController.cs @@ -10,15 +10,8 @@ namespace WebAPI.Controllers; [Route("orders")] [ApiController] -public class OrderProcessingController : ControllerBase +public class OrderProcessingController(DurableTaskClient durableTaskClient) : ControllerBase { - readonly DurableTaskClient durableTaskClient; - - public OrderProcessingController(DurableTaskClient durableTaskClient) - { - this.durableTaskClient = durableTaskClient; - } - // HTTPie command: // http POST http://localhost:8080/orders/new Item=catfood Quantity=5 Price=600 [HttpPost("new")] @@ -31,7 +24,7 @@ public async Task CreateOrder([FromBody] OrderInfo orderInfo) // Generate an order ID and start the order processing workflow orchestration string orderId = $"{orderInfo.Item}-{Guid.NewGuid().ToString()[..4]}"; - await this.durableTaskClient.ScheduleNewProcessOrderOrchestratorInstanceAsync( + await durableTaskClient.ScheduleNewProcessOrderOrchestratorInstanceAsync( orderInfo, new StartOrchestrationOptions() { InstanceId = orderId }); // Return 202 with a link to the GetOrderStatus API @@ -45,7 +38,7 @@ await this.durableTaskClient.ScheduleNewProcessOrderOrchestratorInstanceAsync( [HttpGet("{orderId}")] public async Task GetOrderStatus(string orderId) { - OrchestrationMetadata? metadata = await this.durableTaskClient.GetInstancesAsync( + OrchestrationMetadata? metadata = await durableTaskClient.GetInstancesAsync( instanceId: orderId, getInputsAndOutputs: true); diff --git a/samples/WebAPI/Orchestrations/ChargeCustomerActivity.cs b/samples/WebAPI/Orchestrations/ChargeCustomerActivity.cs index 768d1b96..a193b615 100644 --- a/samples/WebAPI/Orchestrations/ChargeCustomerActivity.cs +++ b/samples/WebAPI/Orchestrations/ChargeCustomerActivity.cs @@ -7,19 +7,11 @@ namespace WebAPI.Orchestrations; [DurableTask("ChargeCustomer")] -public class ChargeCustomerActivity : TaskActivity +public class ChargeCustomerActivity(ILogger logger) : TaskActivity { - readonly ILogger logger; - - // Dependencies are injected from ASP.NET host service container - public ChargeCustomerActivity(ILogger logger) - { - this.logger = logger; - } - public override async Task RunAsync(TaskActivityContext context, OrderInfo orderInfo) { - this.logger.LogInformation( + logger.LogInformation( "{instanceId}: Charging customer {price:C}'...", context.InstanceId, orderInfo?.Price ?? 0.0); diff --git a/samples/WebAPI/Orchestrations/CheckInventoryActivity.cs b/samples/WebAPI/Orchestrations/CheckInventoryActivity.cs index 198575f4..eb49ab01 100644 --- a/samples/WebAPI/Orchestrations/CheckInventoryActivity.cs +++ b/samples/WebAPI/Orchestrations/CheckInventoryActivity.cs @@ -4,31 +4,19 @@ using Microsoft.DurableTask; using WebAPI.Models; -namespace WebAPI.Orchestrations +namespace WebAPI.Orchestrations; + +[DurableTask("CheckInventory")] +public class CheckInventoryActivity(ILogger logger) + : TaskActivity { - [DurableTask("CheckInventory")] - public class CheckInventoryActivity : TaskActivity + public override Task RunAsync(TaskActivityContext context, OrderInfo orderInfo) { - readonly ILogger logger; - - // Dependencies are injected from ASP.NET host service container - public CheckInventoryActivity(ILogger logger) - { - this.logger = logger; - } - - public override Task RunAsync(TaskActivityContext context, OrderInfo orderInfo) - { - if (orderInfo == null) - { - throw new ArgumentException("Failed to read order info!"); - } - - this.logger.LogInformation( - "{instanceId}: Checking inventory for '{item}'...found some!", - context.InstanceId, - orderInfo.Item); - return Task.FromResult(true); - } + ArgumentNullException.ThrowIfNull(context); + logger.LogInformation( + "{instanceId}: Checking inventory for '{item}'...found some!", + context.InstanceId, + orderInfo.Item); + return Task.FromResult(true); } } diff --git a/samples/WebAPI/Orchestrations/CreateShipmentActivity.cs b/samples/WebAPI/Orchestrations/CreateShipmentActivity.cs index e1cc8a7c..cb4c8dd0 100644 --- a/samples/WebAPI/Orchestrations/CreateShipmentActivity.cs +++ b/samples/WebAPI/Orchestrations/CreateShipmentActivity.cs @@ -7,19 +7,12 @@ namespace WebAPI.Orchestrations; [DurableTask("CreateShipment")] -public class CreateShipmentActivity : TaskActivity +public class CreateShipmentActivity(ILogger logger) + : TaskActivity { - readonly ILogger logger; - - // Dependencies are injected from ASP.NET host service container - public CreateShipmentActivity(ILogger logger) - { - this.logger = logger; - } - public override async Task RunAsync(TaskActivityContext context, OrderInfo orderInfo) { - this.logger.LogInformation( + logger.LogInformation( "{instanceId}: Shipping customer order of {quantity} {item}(s)...", context.InstanceId, orderInfo?.Quantity ?? 0, diff --git a/src/Abstractions/Converters/JsonDataConverter.cs b/src/Abstractions/Converters/JsonDataConverter.cs index eeca67a3..7df20b5f 100644 --- a/src/Abstractions/Converters/JsonDataConverter.cs +++ b/src/Abstractions/Converters/JsonDataConverter.cs @@ -8,7 +8,8 @@ namespace Microsoft.DurableTask.Converters; /// /// An implementation of that uses System.Text.Json APIs for data serialization. /// -public class JsonDataConverter : DataConverter +/// The serializer options. +public class JsonDataConverter(JsonSerializerOptions? options = null) : DataConverter { // WARNING: Changing default serialization options could potentially be breaking for in-flight orchestrations. static readonly JsonSerializerOptions DefaultOptions = new() @@ -16,16 +17,7 @@ public class JsonDataConverter : DataConverter IncludeFields = true, }; - readonly JsonSerializerOptions? options; - - /// - /// Initializes a new instance of the class. - /// - /// The serializer options. - public JsonDataConverter(JsonSerializerOptions? options = null) - { - this.options = options ?? DefaultOptions; - } + readonly JsonSerializerOptions? options = options ?? DefaultOptions; /// /// Gets an instance of the with default configuration. diff --git a/src/Abstractions/DurableTaskAttribute.cs b/src/Abstractions/DurableTaskAttribute.cs index c7a6edce..4d0e41ce 100644 --- a/src/Abstractions/DurableTaskAttribute.cs +++ b/src/Abstractions/DurableTaskAttribute.cs @@ -12,23 +12,14 @@ namespace Microsoft.DurableTask; /// It is used specifically by build-time source generators to generate type-safe methods for invoking /// orchestrations or activities. /// +/// +/// The name of the durable task. If not specified, the class name is used as the implied name of the durable task. +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -public sealed class DurableTaskAttribute : Attribute +public sealed class DurableTaskAttribute(string? name = null) : Attribute { - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the durable task. If not specified, the class name is used as the implied name of the durable task. - /// - public DurableTaskAttribute(string? name = null) - { - // This logic cannot become too complex as code-generator relies on examining the constructor arguments. - this.Name = string.IsNullOrEmpty(name) ? default : new TaskName(name!); - } - /// /// Gets the name of the durable task. /// - public TaskName Name { get; } + public TaskName Name { get; } = string.IsNullOrEmpty(name) ? default : new TaskName(name!); } diff --git a/src/Abstractions/Entities/EntityOperationFailedException.cs b/src/Abstractions/Entities/EntityOperationFailedException.cs index 02a6c15c..86387411 100644 --- a/src/Abstractions/Entities/EntityOperationFailedException.cs +++ b/src/Abstractions/Entities/EntityOperationFailedException.cs @@ -10,36 +10,27 @@ namespace Microsoft.DurableTask.Entities; /// Detailed information associated with a particular operation failure, including exception details, can be found in the /// property. /// -public sealed class EntityOperationFailedException : Exception +/// The operation name. +/// The entity ID. +/// The failure details. +public sealed class EntityOperationFailedException( + EntityInstanceId entityId, string operationName, TaskFailureDetails failureDetails) + : Exception(GetExceptionMessage(operationName, entityId, failureDetails)) { - /// - /// Initializes a new instance of the class. - /// - /// The operation name. - /// The entity ID. - /// The failure details. - public EntityOperationFailedException(EntityInstanceId entityId, string operationName, TaskFailureDetails failureDetails) - : base(GetExceptionMessage(operationName, entityId, failureDetails)) - { - this.EntityId = entityId; - this.OperationName = operationName; - this.FailureDetails = failureDetails; - } - /// /// Gets the ID of the entity. /// - public EntityInstanceId EntityId { get; } + public EntityInstanceId EntityId { get; } = entityId; /// /// Gets the name of the operation. /// - public string OperationName { get; } + public string OperationName { get; } = operationName; - /// + /// /// Gets the details of the task failure, including exception information. /// - public TaskFailureDetails FailureDetails { get; } + public TaskFailureDetails FailureDetails { get; } = failureDetails; static string GetExceptionMessage(string operationName, EntityInstanceId entityId, TaskFailureDetails failureDetails) { diff --git a/src/Abstractions/FuncTaskActivity.cs b/src/Abstractions/FuncTaskActivity.cs index cac12705..678b75a5 100644 --- a/src/Abstractions/FuncTaskActivity.cs +++ b/src/Abstractions/FuncTaskActivity.cs @@ -29,23 +29,17 @@ public static TaskActivity Create( /// /// The Activity input type. /// The Activity output type. - class Implementation : TaskActivity + /// + /// Initializes a new instance of the class. + /// + /// The Activity function. + class Implementation(Func> implementation) + : TaskActivity { - readonly Func> implementation; - - /// - /// Initializes a new instance of the class. - /// - /// The Activity function. - public Implementation(Func> implementation) - { - this.implementation = implementation; - } - /// public override Task RunAsync(TaskActivityContext context, TInput input) { - return this.implementation(context, input); + return implementation(context, input); } } } diff --git a/src/Abstractions/FuncTaskOrchestrator.cs b/src/Abstractions/FuncTaskOrchestrator.cs index a464f01b..b99c2594 100644 --- a/src/Abstractions/FuncTaskOrchestrator.cs +++ b/src/Abstractions/FuncTaskOrchestrator.cs @@ -29,23 +29,14 @@ public static TaskOrchestrator Create( /// /// The orchestrator input type. /// The orchestrator output type. - class Implementation : TaskOrchestrator + /// The orchestrator function. + class Implementation(Func> implementation) + : TaskOrchestrator { - readonly Func> implementation; - - /// - /// Initializes a new instance of the class. - /// - /// The orchestrator function. - public Implementation(Func> implementation) - { - this.implementation = implementation; - } - /// public override Task RunAsync(TaskOrchestrationContext context, TInput input) { - return this.implementation(context, input); + return implementation(context, input); } } } diff --git a/src/Abstractions/Page.cs b/src/Abstractions/Page.cs index 528603b3..542ee9ad 100644 --- a/src/Abstractions/Page.cs +++ b/src/Abstractions/Page.cs @@ -7,30 +7,18 @@ namespace Microsoft.DurableTask; /// Represents a single page of results. /// /// The type of values held by the page. -public sealed class Page +/// The values this holds. +/// The continuation token. +public sealed class Page(IReadOnlyList values, string? continuationToken = null) where T : notnull { - // This code was adopted from Azure SDK Page. - // https://github.com/Azure/azure-sdk-for-net/blob/e811f016a3655e4b29a23c71f84d59f34fe01233/sdk/core/Azure.Core/src/Page.cs - - /// - /// Initializes a new instance of the class. - /// - /// The values this holds. - /// The continuation token. - public Page(IReadOnlyList values, string? continuationToken = null) - { - this.Values = Check.NotNull(values); - this.ContinuationToken = continuationToken; - } - /// /// Gets the values contained in this page. /// - public IReadOnlyList Values { get; } + public IReadOnlyList Values { get; } = Check.NotNull(values); /// /// Gets the continuation token or null if there are no more items. /// - public string? ContinuationToken { get; } + public string? ContinuationToken { get; } = continuationToken; } diff --git a/src/Abstractions/Pageable.cs b/src/Abstractions/Pageable.cs index c2c9c097..ba75379e 100644 --- a/src/Abstractions/Pageable.cs +++ b/src/Abstractions/Pageable.cs @@ -41,16 +41,9 @@ public static AsyncPageable Create(Func(pageFunc); } - class FuncAsyncPageable : AsyncPageable + class FuncAsyncPageable(Func>> pageFunc) : AsyncPageable where T : notnull { - readonly Func>> pageFunc; - - public FuncAsyncPageable(Func>> pageFunc) - { - this.pageFunc = pageFunc; - } - public override IAsyncEnumerable> AsPages( string? continuationToken = default, int? pageSizeHint = default) => this.AsPagesCore(continuationToken, pageSizeHint); @@ -64,7 +57,7 @@ async IAsyncEnumerable> AsPagesCore( { // TODO: Do we need to support customizing ConfigureAwait(bool) here? // ConfigureAwait(false) makes this unusable in orchestrations. - Page page = await this.pageFunc(continuationToken, pageSizeHint, cancellation); + Page page = await pageFunc(continuationToken, pageSizeHint, cancellation); yield return page; continuationToken = page.ContinuationToken; } diff --git a/src/Client/Core/DependencyInjection/DefaultDurableTaskClientBuilder.cs b/src/Client/Core/DependencyInjection/DefaultDurableTaskClientBuilder.cs index c08b2003..4891a28d 100644 --- a/src/Client/Core/DependencyInjection/DefaultDurableTaskClientBuilder.cs +++ b/src/Client/Core/DependencyInjection/DefaultDurableTaskClientBuilder.cs @@ -9,26 +9,17 @@ namespace Microsoft.DurableTask.Client; /// /// Default builder for . /// -public class DefaultDurableTaskClientBuilder : IDurableTaskClientBuilder +/// The name of the builder. +/// The service collection. +public class DefaultDurableTaskClientBuilder(string? name, IServiceCollection services) : IDurableTaskClientBuilder { Type? buildTarget; - /// - /// Initializes a new instance of the class. - /// - /// The name of the builder. - /// The service collection. - public DefaultDurableTaskClientBuilder(string? name, IServiceCollection services) - { - this.Name = name ?? Options.DefaultName; - this.Services = services; - } - /// - public string Name { get; } + public string Name { get; } = name ?? Options.DefaultName; /// - public IServiceCollection Services { get; } + public IServiceCollection Services { get; } = services; /// public Type? BuildTarget diff --git a/src/Client/Core/DependencyInjection/DefaultDurableTaskClientProvider.cs b/src/Client/Core/DependencyInjection/DefaultDurableTaskClientProvider.cs index 42fa59a2..ce3340aa 100644 --- a/src/Client/Core/DependencyInjection/DefaultDurableTaskClientProvider.cs +++ b/src/Client/Core/DependencyInjection/DefaultDurableTaskClientProvider.cs @@ -8,18 +8,11 @@ namespace Microsoft.DurableTask.Client; /// /// Default implementation of . /// -class DefaultDurableTaskClientProvider : IDurableTaskClientProvider +/// The set of clients. +class DefaultDurableTaskClientProvider(IEnumerable clients) + : IDurableTaskClientProvider { - readonly IEnumerable clients; - - /// - /// Initializes a new instance of the class. - /// - /// The set of clients. - public DefaultDurableTaskClientProvider(IEnumerable clients) - { - this.clients = clients; - } + readonly IEnumerable clients = Check.NotNull(clients); /// public DurableTaskClient GetClient(string? name = null) @@ -41,17 +34,9 @@ public DurableTaskClient GetClient(string? name = null) /// /// Container for holding a client in memory. /// - internal class ClientContainer : IAsyncDisposable + /// The client. + internal class ClientContainer(DurableTaskClient client) : IAsyncDisposable { - /// - /// Initializes a new instance of the class. - /// - /// The client. - public ClientContainer(DurableTaskClient client) - { - this.Client = Check.NotNull(client); - } - /// /// Gets the client name. /// @@ -60,7 +45,7 @@ public ClientContainer(DurableTaskClient client) /// /// Gets the client. /// - public DurableTaskClient Client { get; } + public DurableTaskClient Client { get; } = Check.NotNull(client); /// public ValueTask DisposeAsync() => this.Client.DisposeAsync(); diff --git a/src/Client/Core/DependencyInjection/ServiceCollectionExtensions.cs b/src/Client/Core/DependencyInjection/ServiceCollectionExtensions.cs index db1eca95..36bedd3a 100644 --- a/src/Client/Core/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Client/Core/DependencyInjection/ServiceCollectionExtensions.cs @@ -92,22 +92,16 @@ static IDurableTaskClientBuilder GetBuilder(IServiceCollection services, string /// /// A container which is used to store and retrieve builders from within the . /// - class BuilderContainer + class BuilderContainer(IServiceCollection services) { readonly Dictionary builders = new(); - readonly IServiceCollection services; - - public BuilderContainer(IServiceCollection services) - { - this.services = services; - } public IDurableTaskClientBuilder GetOrAdd(string name, out bool added) { added = false; if (!this.builders.TryGetValue(name, out IDurableTaskClientBuilder builder)) { - builder = new DefaultDurableTaskClientBuilder(name, this.services); + builder = new DefaultDurableTaskClientBuilder(name, services); this.builders[name] = builder; added = true; } diff --git a/src/Client/Core/Entities/EntityMetadata.cs b/src/Client/Core/Entities/EntityMetadata.cs index 9eaf5671..3758b7cf 100644 --- a/src/Client/Core/Entities/EntityMetadata.cs +++ b/src/Client/Core/Entities/EntityMetadata.cs @@ -11,21 +11,12 @@ namespace Microsoft.DurableTask.Client.Entities; /// Represents entity metadata. /// /// The type of state held by the metadata. +/// The ID of the entity. [JsonConverter(typeof(EntityMetadataConverter))] -public class EntityMetadata +public class EntityMetadata(EntityInstanceId id) { readonly TState? state; - /// - /// Initializes a new instance of the class. - /// - /// The ID of the entity. - public EntityMetadata(EntityInstanceId id) - { - this.Id = Check.NotDefault(id); - this.IncludesState = false; - } - /// /// Initializes a new instance of the class. /// @@ -41,7 +32,7 @@ public EntityMetadata(EntityInstanceId id, TState? state) /// /// Gets the ID for this entity. /// - public EntityInstanceId Id { get; } + public EntityInstanceId Id { get; } = Check.NotDefault(id); /// /// Gets the time the entity was last modified. @@ -64,9 +55,9 @@ public EntityMetadata(EntityInstanceId id, TState? state) /// /// Queries can exclude the state of the entity from the metadata that is retrieved. /// - [MemberNotNullWhen(true, "State")] - [MemberNotNullWhen(true, "state")] - public bool IncludesState { get; } + [MemberNotNullWhen(true, nameof(State))] + [MemberNotNullWhen(true, nameof(state))] + public bool IncludesState { get; } = false; /// /// Gets the state for this entity. @@ -96,16 +87,10 @@ public TState State /// /// Represents the metadata for a durable entity instance. /// +/// The ID of the entity. +/// The state of this entity. [JsonConverter(typeof(EntityMetadataConverter))] -public sealed class EntityMetadata : EntityMetadata +public sealed class EntityMetadata(EntityInstanceId id, SerializedData? state = null) + : EntityMetadata(id, state) { - /// - /// Initializes a new instance of the class. - /// - /// The ID of the entity. - /// The state of this entity. - public EntityMetadata(EntityInstanceId id, SerializedData? state = null) - : base(id, state) - { - } } diff --git a/src/Client/Core/OrchestrationMetadata.cs b/src/Client/Core/OrchestrationMetadata.cs index 3fc43b0a..e34be7bb 100644 --- a/src/Client/Core/OrchestrationMetadata.cs +++ b/src/Client/Core/OrchestrationMetadata.cs @@ -15,26 +15,17 @@ namespace Microsoft.DurableTask.Client; /// and /// . /// -public sealed class OrchestrationMetadata +/// The name of the orchestration. +/// The instance ID of the orchestration. +public sealed class OrchestrationMetadata(string name, string instanceId) { - /// - /// Initializes a new instance of the class. - /// - /// The name of the orchestration. - /// The instance ID of the orchestration. - public OrchestrationMetadata(string name, string instanceId) - { - this.Name = name; - this.InstanceId = instanceId; - } - /// Gets the name of the orchestration. /// The name of the orchestration. - public string Name { get; } + public string Name { get; } = name; /// Gets the unique ID of the orchestration instance. /// The unique ID of the orchestration instance. - public string InstanceId { get; } + public string InstanceId { get; } = instanceId; /// /// Gets the data converter used to deserialized the serialized data on this instance. diff --git a/src/Client/Core/SerializedData.cs b/src/Client/Core/SerializedData.cs index 6a777680..fd1b4ef6 100644 --- a/src/Client/Core/SerializedData.cs +++ b/src/Client/Core/SerializedData.cs @@ -8,28 +8,19 @@ namespace Microsoft.DurableTask.Client; /// /// Gets a type representing serialized data. /// -public sealed class SerializedData +/// The serialized data. +/// The data converter. +public sealed class SerializedData(string data, DataConverter? converter = null) { - /// - /// Initializes a new instance of the class. - /// - /// The serialized data. - /// The data converter. - public SerializedData(string data, DataConverter? converter = null) - { - this.Value = Check.NotNull(data); - this.Converter = converter ?? JsonDataConverter.Default; - } - /// /// Gets the serialized value. /// - public string Value { get; } + public string Value { get; } = Check.NotNull(data); /// /// Gets the data converter. /// - public DataConverter Converter { get; } + public DataConverter Converter { get; } = converter ?? JsonDataConverter.Default; /// /// Deserializes the data into . diff --git a/src/Client/Grpc/GrpcDurableEntityClient.cs b/src/Client/Grpc/GrpcDurableEntityClient.cs index b5e3371d..e5fc07ec 100644 --- a/src/Client/Grpc/GrpcDurableEntityClient.cs +++ b/src/Client/Grpc/GrpcDurableEntityClient.cs @@ -13,27 +13,15 @@ namespace Microsoft.DurableTask.Client.Grpc; /// /// The client for entities. /// -class GrpcDurableEntityClient : DurableEntityClient +/// The name of the client. +/// The data converter. +/// The client for the GRPC connection to the sidecar. +class GrpcDurableEntityClient( + string name, DataConverter dataConverter, TaskHubSidecarServiceClient sidecarClient) + : DurableEntityClient(name) { - readonly TaskHubSidecarServiceClient sidecarClient; - readonly DataConverter dataConverter; - readonly ILogger logger; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the client. - /// The data converter. - /// The client for the GRPC connection to the sidecar. - /// The logger for logging client requests. - public GrpcDurableEntityClient( - string name, DataConverter dataConverter, TaskHubSidecarServiceClient sidecarClient, ILogger logger) - : base(name) - { - this.dataConverter = dataConverter; - this.sidecarClient = sidecarClient; - this.logger = logger; - } + readonly TaskHubSidecarServiceClient sidecarClient = Check.NotNull(sidecarClient); + readonly DataConverter dataConverter = Check.NotNull(dataConverter); /// public override async Task SignalEntityAsync( @@ -72,20 +60,20 @@ public override async Task SignalEntityAsync( /// public override Task GetEntityAsync( EntityInstanceId id, bool includeState = false, CancellationToken cancellation = default) - => this.GetEntityCoreAsync(id, includeState, (e, s) => this.ToEntityMetadata(e, s), cancellation); + => this.GetEntityCoreAsync(id, includeState, this.ToEntityMetadata, cancellation); /// public override Task?> GetEntityAsync( EntityInstanceId id, bool includeState = false, CancellationToken cancellation = default) - => this.GetEntityCoreAsync(id, includeState, (e, s) => this.ToEntityMetadata(e, s), cancellation); + => this.GetEntityCoreAsync(id, includeState, this.ToEntityMetadata, cancellation); /// public override AsyncPageable GetAllEntitiesAsync(EntityQuery? filter = null) - => this.GetAllEntitiesCoreAsync(filter, (x, s) => this.ToEntityMetadata(x, s)); + => this.GetAllEntitiesCoreAsync(filter, this.ToEntityMetadata); /// public override AsyncPageable> GetAllEntitiesAsync(EntityQuery? filter = null) - => this.GetAllEntitiesCoreAsync(filter, (x, s) => this.ToEntityMetadata(x, s)); + => this.GetAllEntitiesCoreAsync(filter, this.ToEntityMetadata); /// public override async Task CleanEntityStorageAsync( diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs index f0d6e6e8..6f478820 100644 --- a/src/Client/Grpc/GrpcDurableTaskClient.cs +++ b/src/Client/Grpc/GrpcDurableTaskClient.cs @@ -52,7 +52,7 @@ public GrpcDurableTaskClient(string name, GrpcDurableTaskClientOptions options, if (this.options.EnableEntitySupport) { - this.entityClient = new GrpcDurableEntityClient(this.Name, this.DataConverter, this.sidecarClient, logger); + this.entityClient = new GrpcDurableEntityClient(this.Name, this.DataConverter, this.sidecarClient); } } diff --git a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs index 3f3c5211..6e1bb6b3 100644 --- a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs +++ b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs @@ -15,9 +15,11 @@ namespace Microsoft.DurableTask.Client.OrchestrationServiceClientShim; /// /// A shim client for interacting with the backend via . /// -class ShimDurableTaskClient : DurableTaskClient +/// The name of the client. +/// The client options. +class ShimDurableTaskClient(string name, ShimDurableTaskClientOptions options) : DurableTaskClient(name) { - readonly ShimDurableTaskClientOptions options; + readonly ShimDurableTaskClientOptions options = Check.NotNull(options); /// /// Initializes a new instance of the class. @@ -31,17 +33,6 @@ public ShimDurableTaskClient( { } - /// - /// Initializes a new instance of the class. - /// - /// The name of the client. - /// The client options. - public ShimDurableTaskClient(string name, ShimDurableTaskClientOptions options) - : base(name) - { - this.options = Check.NotNull(options); - } - DataConverter DataConverter => this.options.DataConverter; IOrchestrationServiceClient Client => this.options.Client!; diff --git a/src/Generators/AzureFunctions/DurableFunction.cs b/src/Generators/AzureFunctions/DurableFunction.cs index 94925ff8..ecab4311 100644 --- a/src/Generators/AzureFunctions/DurableFunction.cs +++ b/src/Generators/AzureFunctions/DurableFunction.cs @@ -13,30 +13,25 @@ public enum DurableFunctionKind Activity } - public class DurableFunction + public class DurableFunction( + string fullTypeName, + string name, + DurableFunctionKind kind, + TypedParameter parameter, + ITypeSymbol returnType, + HashSet requiredNamespaces) { - public string FullTypeName { get; } - public HashSet RequiredNamespaces { get; } - public string Name { get; } - public DurableFunctionKind Kind { get; } - public TypedParameter Parameter { get; } - public string ReturnType { get; } - - public DurableFunction( - string fullTypeName, - string name, - DurableFunctionKind kind, - TypedParameter parameter, - ITypeSymbol returnType, - HashSet requiredNamespaces) - { - this.FullTypeName = fullTypeName; - this.RequiredNamespaces = requiredNamespaces; - this.Name = name; - this.Kind = kind; - this.Parameter = parameter; - this.ReturnType = SyntaxNodeUtility.GetRenderedTypeExpression(returnType, false); - } + public string FullTypeName { get; } = fullTypeName; + + public HashSet RequiredNamespaces { get; } = requiredNamespaces; + + public string Name { get; } = name; + + public DurableFunctionKind Kind { get; } = kind; + + public TypedParameter Parameter { get; } = parameter; + + public string ReturnType { get; } = SyntaxNodeUtility.GetRenderedTypeExpression(returnType, false); public static bool TryParse(SemanticModel model, MethodDeclarationSyntax method, out DurableFunction? function) { diff --git a/src/Generators/AzureFunctions/TypedParameter.cs b/src/Generators/AzureFunctions/TypedParameter.cs index f6bc7ed8..b0ebe439 100644 --- a/src/Generators/AzureFunctions/TypedParameter.cs +++ b/src/Generators/AzureFunctions/TypedParameter.cs @@ -6,16 +6,10 @@ namespace Microsoft.DurableTask.Generators.AzureFunctions { - public class TypedParameter + public class TypedParameter(INamedTypeSymbol type, string name) { - public INamedTypeSymbol Type { get; } - public string Name { get; } - - public TypedParameter(INamedTypeSymbol type, string name) - { - this.Type = type; - this.Name = name; - } + public INamedTypeSymbol Type { get; } = type; + public string Name { get; } = name; public override string ToString() { diff --git a/src/Shared/Core/AsyncDisposable.cs b/src/Shared/Core/AsyncDisposable.cs index 30ee9038..2773c514 100644 --- a/src/Shared/Core/AsyncDisposable.cs +++ b/src/Shared/Core/AsyncDisposable.cs @@ -6,18 +6,10 @@ namespace Microsoft.DurableTask; /// /// A struct for calling a simple delegate on dispose. /// -struct AsyncDisposable : IAsyncDisposable +/// The callback to invoke on disposal. +struct AsyncDisposable(Func callback) : IAsyncDisposable { - Func? callback; - - /// - /// Initializes a new instance of the struct. - /// - /// The callback to invoke on disposal. - public AsyncDisposable(Func callback) - { - this.callback = callback; - } + Func? callback = callback; /// public ValueTask DisposeAsync() diff --git a/src/Shared/Shared.csproj b/src/Shared/Shared.csproj index ae3d8491..1490a69a 100644 --- a/src/Shared/Shared.csproj +++ b/src/Shared/Shared.csproj @@ -20,4 +20,8 @@ + + + + diff --git a/src/Worker/Core/DependencyInjection/DefaultDurableTaskWorkerBuilder.cs b/src/Worker/Core/DependencyInjection/DefaultDurableTaskWorkerBuilder.cs index 7e70990b..cdc26cb2 100644 --- a/src/Worker/Core/DependencyInjection/DefaultDurableTaskWorkerBuilder.cs +++ b/src/Worker/Core/DependencyInjection/DefaultDurableTaskWorkerBuilder.cs @@ -10,26 +10,17 @@ namespace Microsoft.DurableTask.Worker; /// /// The default builder for durable task. /// -public class DefaultDurableTaskWorkerBuilder : IDurableTaskWorkerBuilder +/// The service collection for this builder. +/// The name for this builder. +public class DefaultDurableTaskWorkerBuilder(string? name, IServiceCollection services) : IDurableTaskWorkerBuilder { Type? buildTarget; - /// - /// Initializes a new instance of the class. - /// - /// The service collection for this builder. - /// The name for this builder. - public DefaultDurableTaskWorkerBuilder(string? name, IServiceCollection services) - { - this.Name = name ?? Extensions.Options.Options.DefaultName; - this.Services = Check.NotNull(services); - } - /// - public string Name { get; } + public string Name { get; } = name ?? Extensions.Options.Options.DefaultName; /// - public IServiceCollection Services { get; } + public IServiceCollection Services { get; } = Check.NotNull(services); /// public Type? BuildTarget diff --git a/src/Worker/Core/DependencyInjection/ServiceCollectionExtensions.cs b/src/Worker/Core/DependencyInjection/ServiceCollectionExtensions.cs index 8a9ef74c..f581b945 100644 --- a/src/Worker/Core/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Worker/Core/DependencyInjection/ServiceCollectionExtensions.cs @@ -87,22 +87,16 @@ static IDurableTaskWorkerBuilder GetBuilder(IServiceCollection services, string /// /// A container which is used to store and retrieve builders from within the . /// - class BuilderContainer + class BuilderContainer(IServiceCollection services) { readonly Dictionary builders = new(); - readonly IServiceCollection services; - - public BuilderContainer(IServiceCollection services) - { - this.services = services; - } public IDurableTaskWorkerBuilder GetOrAdd(string name, out bool added) { added = false; if (!this.builders.TryGetValue(name, out IDurableTaskWorkerBuilder builder)) { - builder = new DefaultDurableTaskWorkerBuilder(name, this.services); + builder = new DefaultDurableTaskWorkerBuilder(name, services); this.builders[name] = builder; added = true; } diff --git a/src/Worker/Core/Shims/DurableTaskShimFactory.cs b/src/Worker/Core/Shims/DurableTaskShimFactory.cs index c8182be3..f6c66f47 100644 --- a/src/Worker/Core/Shims/DurableTaskShimFactory.cs +++ b/src/Worker/Core/Shims/DurableTaskShimFactory.cs @@ -16,22 +16,13 @@ namespace Microsoft.DurableTask.Worker.Shims; /// This class is intended for use with alternate .NET-based durable task runtimes. It's not intended for use /// in application code. /// -public class DurableTaskShimFactory +/// The data converter. +/// The logger factory. +public class DurableTaskShimFactory( + DurableTaskWorkerOptions? options = null, ILoggerFactory? loggerFactory = null) { - readonly DurableTaskWorkerOptions options; - readonly ILoggerFactory loggerFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The data converter. - /// The logger factory. - public DurableTaskShimFactory( - DurableTaskWorkerOptions? options = null, ILoggerFactory? loggerFactory = null) - { - this.options = options ?? new(); - this.loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; - } + readonly DurableTaskWorkerOptions options = options ?? new(); + readonly ILoggerFactory loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; /// /// Gets the default with default values. diff --git a/src/Worker/Core/Shims/JsonDataConverterShim.cs b/src/Worker/Core/Shims/JsonDataConverterShim.cs index d64de603..c1264e63 100644 --- a/src/Worker/Core/Shims/JsonDataConverterShim.cs +++ b/src/Worker/Core/Shims/JsonDataConverterShim.cs @@ -8,18 +8,10 @@ namespace Microsoft.DurableTask.Worker.Shims; /// /// A shim to go from to . /// -sealed class JsonDataConverterShim : CoreJsonDataConverter +/// The converter to wrap. +sealed class JsonDataConverterShim(DataConverter innerConverter) : CoreJsonDataConverter { - readonly DataConverter innerConverter; - - /// - /// Initializes a new instance of the class. - /// - /// The converter to wrap. - public JsonDataConverterShim(DataConverter innerConverter) - { - this.innerConverter = Check.NotNull(innerConverter); - } + readonly DataConverter innerConverter = Check.NotNull(innerConverter); /// public override string Serialize(object value) diff --git a/src/Worker/Core/Shims/TaskActivityShim.cs b/src/Worker/Core/Shims/TaskActivityShim.cs index f0a09c30..a2aa5a02 100644 --- a/src/Worker/Core/Shims/TaskActivityShim.cs +++ b/src/Worker/Core/Shims/TaskActivityShim.cs @@ -8,24 +8,14 @@ namespace Microsoft.DurableTask.Worker.Shims; /// /// Shims a to a . /// -class TaskActivityShim : TaskActivity +/// The data converter. +/// The name of the activity. +/// The activity implementation to wrap. +class TaskActivityShim(DataConverter dataConverter, TaskName name, ITaskActivity implementation) : TaskActivity { - readonly ITaskActivity implementation; - readonly DataConverter dataConverter; - readonly TaskName name; - - /// - /// Initializes a new instance of the class. - /// - /// The data converter. - /// The name of the activity. - /// The activity implementation to wrap. - public TaskActivityShim(DataConverter dataConverter, TaskName name, ITaskActivity implementation) - { - this.dataConverter = Check.NotNull(dataConverter); - this.name = Check.NotDefault(name); - this.implementation = Check.NotNull(implementation); - } + readonly ITaskActivity implementation = Check.NotNull(implementation); + readonly DataConverter dataConverter = Check.NotNull(dataConverter); + readonly TaskName name = Check.NotDefault(name); /// public override async Task RunAsync(TaskContext coreContext, string? rawInput) @@ -56,19 +46,10 @@ public TaskActivityShim(DataConverter dataConverter, TaskName name, ITaskActivit return input; } - sealed class TaskActivityContextWrapper : TaskActivityContext + sealed class TaskActivityContextWrapper(TaskContext taskContext, TaskName name) : TaskActivityContext { - readonly TaskContext innerContext; - readonly TaskName name; - - public TaskActivityContextWrapper(TaskContext taskContext, TaskName name) - { - this.innerContext = taskContext; - this.name = name; - } - - public override TaskName Name => this.name; + public override TaskName Name => name; - public override string InstanceId => this.innerContext.OrchestrationInstance.InstanceId; + public override string InstanceId => taskContext.OrchestrationInstance.InstanceId; } } diff --git a/src/Worker/Core/Shims/TaskEntityShim.cs b/src/Worker/Core/Shims/TaskEntityShim.cs index 800b42bb..74a332ac 100644 --- a/src/Worker/Core/Shims/TaskEntityShim.cs +++ b/src/Worker/Core/Shims/TaskEntityShim.cs @@ -99,19 +99,12 @@ public override async Task ExecuteOperationBatchAsync(EntityB return batchResult; } - class StateShim : TaskEntityState + class StateShim(DataConverter dataConverter) : TaskEntityState { - readonly DataConverter dataConverter; - string? value; object? cachedValue; string? checkpointValue; - public StateShim(DataConverter dataConverter) - { - this.dataConverter = dataConverter; - } - /// public override bool HasState => this.value != null; @@ -152,37 +145,27 @@ public void Reset() return this.cachedValue; } - this.cachedValue = this.dataConverter.Deserialize(this.value, type); + this.cachedValue = dataConverter.Deserialize(this.value, type); return this.cachedValue; } public override void SetState(object? state) { - this.value = this.dataConverter.Serialize(state); + this.value = dataConverter.Serialize(state); this.cachedValue = state; } } - class ContextShim : TaskEntityContext + class ContextShim(EntityInstanceId entityInstanceId, DataConverter dataConverter) : TaskEntityContext { - readonly EntityInstanceId entityInstanceId; - readonly DataConverter dataConverter; - - List operationActions; + List operationActions = new List(); int checkpointPosition; - public ContextShim(EntityInstanceId entityInstanceId, DataConverter dataConverter) - { - this.entityInstanceId = entityInstanceId; - this.dataConverter = dataConverter; - this.operationActions = new List(); - } - public List Actions => this.operationActions; public int CurrentPosition => this.operationActions.Count; - public override EntityInstanceId Id => this.entityInstanceId; + public override EntityInstanceId Id { get; } = entityInstanceId; public void Commit() { @@ -208,7 +191,7 @@ public override void SignalEntity(EntityInstanceId id, string operationName, obj { InstanceId = id.ToString(), Name = operationName, - Input = this.dataConverter.Serialize(input), + Input = dataConverter.Serialize(input), ScheduledTime = options?.SignalTime?.UtcDateTime, }); } @@ -223,36 +206,29 @@ public override string ScheduleNewOrchestration(TaskName name, object? input = n Name = name.Name, Version = name.Version, InstanceId = instanceId, - Input = this.dataConverter.Serialize(input), + Input = dataConverter.Serialize(input), ScheduledStartTime = options?.StartAt?.UtcDateTime, }); return instanceId; } } - class OperationShim : TaskEntityOperation + class OperationShim(TaskEntityShim taskEntityShim) : TaskEntityOperation { - readonly TaskEntityShim taskEntityShim; - string? name; string? input; - public OperationShim(TaskEntityShim taskEntityShim) - { - this.taskEntityShim = taskEntityShim; - } - public override string Name => this.name!; // name is always set before user code can access this property - public override TaskEntityContext Context => this.taskEntityShim.context; + public override TaskEntityContext Context => taskEntityShim.context; - public override TaskEntityState State => this.taskEntityShim.state; + public override TaskEntityState State => taskEntityShim.state; public override bool HasInput => this.input != null; public override object? GetInput(Type inputType) { - return this.taskEntityShim.dataConverter.Deserialize(this.input, inputType); + return taskEntityShim.dataConverter.Deserialize(this.input, inputType); } public void SetNameAndInput(string name, string? input) diff --git a/src/Worker/Core/Shims/TaskOrchestrationEntityContext.cs b/src/Worker/Core/Shims/TaskOrchestrationEntityContext.cs index 35ad033c..3c34ed4e 100644 --- a/src/Worker/Core/Shims/TaskOrchestrationEntityContext.cs +++ b/src/Worker/Core/Shims/TaskOrchestrationEntityContext.cs @@ -220,20 +220,11 @@ Guid SendOperationMessage(string instanceId, string operationName, object? input return guid; } - class LockReleaser : IAsyncDisposable + class LockReleaser(TaskOrchestrationEntityContext context, Guid criticalSectionId) : IAsyncDisposable { - readonly TaskOrchestrationEntityContext context; - readonly Guid criticalSectionId; - - public LockReleaser(TaskOrchestrationEntityContext context, Guid criticalSectionId) - { - this.context = context; - this.criticalSectionId = criticalSectionId; - } - public ValueTask DisposeAsync() { - this.context.ExitCriticalSection(this.criticalSectionId); + context.ExitCriticalSection(criticalSectionId); return default; } } diff --git a/src/Worker/Core/Shims/TaskOrchestrationShim.cs b/src/Worker/Core/Shims/TaskOrchestrationShim.cs index e5957d7d..78af58f8 100644 --- a/src/Worker/Core/Shims/TaskOrchestrationShim.cs +++ b/src/Worker/Core/Shims/TaskOrchestrationShim.cs @@ -13,29 +13,18 @@ namespace Microsoft.DurableTask.Worker.Shims; /// This class is intended for use with alternate .NET-based durable task runtimes. It's not intended for use /// in application code. /// -partial class TaskOrchestrationShim : TaskOrchestration +/// The invocation context for this orchestration. +/// The orchestration's implementation. +partial class TaskOrchestrationShim( + OrchestrationInvocationContext invocationContext, + ITaskOrchestrator implementation) : TaskOrchestration { - readonly ITaskOrchestrator implementation; - readonly OrchestrationInvocationContext invocationContext; + readonly ITaskOrchestrator implementation = Check.NotNull(implementation); + readonly OrchestrationInvocationContext invocationContext = Check.NotNull(invocationContext); TaskOrchestrationContextWrapper? wrapperContext; - /// - /// Initializes a new instance of the class. - /// - /// The invocation context for this orchestration. - /// The orchestration's implementation. - public TaskOrchestrationShim( - OrchestrationInvocationContext invocationContext, - ITaskOrchestrator implementation) - { - this.invocationContext = Check.NotNull(invocationContext); - this.implementation = Check.NotNull(implementation); - } - DataConverter DataConverter => this.invocationContext.Options.DataConverter; - ILoggerFactory LoggerFactory => this.invocationContext.LoggerFactory; - /// public override async Task Execute(OrchestrationContext innerContext, string rawInput) { diff --git a/src/Worker/Grpc/GrpcDurableTaskWorker.cs b/src/Worker/Grpc/GrpcDurableTaskWorker.cs index b9604b14..5cf47e5d 100644 --- a/src/Worker/Grpc/GrpcDurableTaskWorker.cs +++ b/src/Worker/Grpc/GrpcDurableTaskWorker.cs @@ -10,34 +10,23 @@ namespace Microsoft.DurableTask.Worker.Grpc; /// /// The gRPC Durable Task worker. /// -sealed partial class GrpcDurableTaskWorker : DurableTaskWorker +/// The name of the worker. +/// The task factory. +/// The gRPC worker options. +/// The service provider. +/// The logger. +sealed partial class GrpcDurableTaskWorker( + string name, + IDurableTaskFactory factory, + IOptionsMonitor options, + IServiceProvider services, + ILoggerFactory loggerFactory) + : DurableTaskWorker(name, factory) { - readonly GrpcDurableTaskWorkerOptions options; - readonly IServiceProvider services; - readonly ILoggerFactory loggerFactory; - readonly ILogger logger; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the worker. - /// The task factory. - /// The gRPC worker options. - /// The service provider. - /// The logger. - public GrpcDurableTaskWorker( - string name, - IDurableTaskFactory factory, - IOptionsMonitor options, - IServiceProvider services, - ILoggerFactory loggerFactory) - : base(name, factory) - { - this.options = Check.NotNull(options).Get(name); - this.services = Check.NotNull(services); - this.loggerFactory = Check.NotNull(loggerFactory); - this.logger = loggerFactory.CreateLogger("Microsoft.DurableTask"); // TODO: use better category name. - } + readonly GrpcDurableTaskWorkerOptions options = Check.NotNull(options).Get(name); + readonly IServiceProvider services = Check.NotNull(services); + readonly ILoggerFactory loggerFactory = Check.NotNull(loggerFactory); + readonly ILogger logger = loggerFactory.CreateLogger("Microsoft.DurableTask"); /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) diff --git a/src/Worker/Grpc/GrpcExtensions.cs b/src/Worker/Grpc/GrpcExtensions.cs index 8bfd8e42..164510b4 100644 --- a/src/Worker/Grpc/GrpcExtensions.cs +++ b/src/Worker/Grpc/GrpcExtensions.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Runtime.CompilerServices; -using Grpc.Core; namespace Microsoft.DurableTask; diff --git a/test/Abstractions.Tests/Entities/Mocks/TestEntityOperation.cs b/test/Abstractions.Tests/Entities/Mocks/TestEntityOperation.cs index 64372d80..18d2b27f 100644 --- a/test/Abstractions.Tests/Entities/Mocks/TestEntityOperation.cs +++ b/test/Abstractions.Tests/Entities/Mocks/TestEntityOperation.cs @@ -5,10 +5,9 @@ namespace Microsoft.DurableTask.Entities.Tests; -public class TestEntityOperation : TaskEntityOperation +public class TestEntityOperation(string name, TaskEntityState state, Optional input) + : TaskEntityOperation { - readonly Optional input; - public TestEntityOperation(string name, Optional input) : this(name, new TestEntityState(null), input) { @@ -19,39 +18,31 @@ public TestEntityOperation(string name, object? state, Optional input) { } - public TestEntityOperation(string name, TaskEntityState state, Optional input) - { - this.Name = name; - this.State = state; - this.input = input; - this.Context = Mock.Of(); - } - - public override string Name { get; } + public override string Name { get; } = name; - public override TaskEntityContext Context { get; } + public override TaskEntityContext Context { get; } = Mock.Of(); - public override TaskEntityState State { get; } + public override TaskEntityState State { get; } = state; - public override bool HasInput => this.input.HasValue; + public override bool HasInput => input.HasValue; public override object? GetInput(Type inputType) { - if (this.input.IsUndefined) + if (input.IsUndefined) { throw new InvalidOperationException("No input available."); } - if (this.input.IsNull) + if (input.IsNull) { return null; } - if (!inputType.IsAssignableFrom(this.input.Value!.GetType())) + if (!inputType.IsAssignableFrom(input.Value!.GetType())) { throw new InvalidCastException("Cannot convert input type."); } - return this.input.Value; + return input.Value; } } diff --git a/test/Abstractions.Tests/Entities/Mocks/TestEntityState.cs b/test/Abstractions.Tests/Entities/Mocks/TestEntityState.cs index 0477f15c..b0ffe036 100644 --- a/test/Abstractions.Tests/Entities/Mocks/TestEntityState.cs +++ b/test/Abstractions.Tests/Entities/Mocks/TestEntityState.cs @@ -3,16 +3,11 @@ namespace Microsoft.DurableTask.Entities.Tests; -public class TestEntityState : TaskEntityState +public class TestEntityState(object? state) : TaskEntityState { - public TestEntityState(object? state) - { - this.State = state; - } - public override bool HasState => this.State != null; - public object? State { get; private set; } + public object? State { get; private set; } = state; public override object? GetState(Type type) { diff --git a/test/Abstractions.Tests/Entities/StateTaskEntityTests.cs b/test/Abstractions.Tests/Entities/StateTaskEntityTests.cs index 06d16a4f..db996186 100644 --- a/test/Abstractions.Tests/Entities/StateTaskEntityTests.cs +++ b/test/Abstractions.Tests/Entities/StateTaskEntityTests.cs @@ -179,16 +179,9 @@ class NullStateEntity : TestEntity protected override TestState InitializeState(TaskEntityOperation entityOperation) => null!; } - class TestEntity : TaskEntity + class TestEntity(bool allowStateDispatch = true) : TaskEntity { - readonly bool allowStateDispatch; - - public TestEntity(bool allowStateDispatch = true) - { - this.allowStateDispatch = allowStateDispatch; - } - - protected override bool AllowStateDispatch => this.allowStateDispatch; + protected override bool AllowStateDispatch { get; } = allowStateDispatch; public int Precedence() => this.State!.Precedence() * 2; } diff --git a/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientBuilderTests.cs b/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientBuilderTests.cs index b2b184ca..8d7cf2c0 100644 --- a/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientBuilderTests.cs +++ b/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientBuilderTests.cs @@ -60,17 +60,11 @@ class BadBuildTarget { } - class GoodBuildTarget : DurableTaskClient + class GoodBuildTarget(string name, IOptionsMonitor options) : DurableTaskClient(name) { - public GoodBuildTarget(string name, IOptionsMonitor options) - : base(name) - { - this.Options = options.Get(name); - } - public new string Name => base.Name; - public DurableTaskClientOptions Options { get; } + public DurableTaskClientOptions Options { get; } = options.Get(name); public override ValueTask DisposeAsync() { diff --git a/test/Client/Core.Tests/DependencyInjection/DurableTaskClientBuilderExtensionsTests.cs b/test/Client/Core.Tests/DependencyInjection/DurableTaskClientBuilderExtensionsTests.cs index 9af6469e..a426d974 100644 --- a/test/Client/Core.Tests/DependencyInjection/DurableTaskClientBuilderExtensionsTests.cs +++ b/test/Client/Core.Tests/DependencyInjection/DurableTaskClientBuilderExtensionsTests.cs @@ -90,17 +90,11 @@ class BadBuildTarget { } - class GoodBuildTarget : DurableTaskClient + class GoodBuildTarget(string name, IOptionsMonitor options) : DurableTaskClient(name) { - public GoodBuildTarget(string name, IOptionsMonitor options) - : base(name) - { - this.Options = options.Get(name); - } - public new string Name => base.Name; - public GoodBuildTargetOptions Options { get; } + public GoodBuildTargetOptions Options { get; } = options.Get(name); public override ValueTask DisposeAsync() { diff --git a/test/Grpc.IntegrationTests/GrpcDurableTaskClientIntegrationTests.cs b/test/Grpc.IntegrationTests/GrpcDurableTaskClientIntegrationTests.cs index a208671f..25117c8d 100644 --- a/test/Grpc.IntegrationTests/GrpcDurableTaskClientIntegrationTests.cs +++ b/test/Grpc.IntegrationTests/GrpcDurableTaskClientIntegrationTests.cs @@ -10,15 +10,11 @@ namespace Microsoft.DurableTask.Grpc.Tests; -public class DurableTaskGrpcClientIntegrationTests : IntegrationTestBase +public class DurableTaskGrpcClientIntegrationTests(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) + : IntegrationTestBase(output, sidecarFixture) { const string OrchestrationName = "TestOrchestration"; - public DurableTaskGrpcClientIntegrationTests(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) - : base(output, sidecarFixture) - { - } - [Theory] [InlineData(false)] [InlineData(true)] diff --git a/test/Grpc.IntegrationTests/IntegrationTestBase.cs b/test/Grpc.IntegrationTests/IntegrationTestBase.cs index fd63613f..4137471e 100644 --- a/test/Grpc.IntegrationTests/IntegrationTestBase.cs +++ b/test/Grpc.IntegrationTests/IntegrationTestBase.cs @@ -15,21 +15,16 @@ namespace Microsoft.DurableTask.Grpc.Tests; /// /// Base class for integration tests that use a in-process sidecar for executing orchestrations. /// -public class IntegrationTestBase : IClassFixture, IDisposable +/// +/// Documentation on xunit test fixtures: https://xunit.net/docs/shared-context. +/// +public class IntegrationTestBase(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) + : IClassFixture, IDisposable { readonly CancellationTokenSource testTimeoutSource = new(Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(10)); - readonly TestLogProvider logProvider; - - // Documentation on xunit test fixtures: https://xunit.net/docs/shared-context - readonly GrpcSidecarFixture sidecarFixture; - - public IntegrationTestBase(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) - { - this.logProvider = new(output); - this.sidecarFixture = sidecarFixture; - } + readonly TestLogProvider logProvider = new(output); /// /// Gets a that triggers after a default test timeout period. @@ -67,13 +62,13 @@ protected IHostBuilder CreateHostBuilder(Action confi { services.AddDurableTaskWorker(b => { - b.UseGrpc(this.sidecarFixture.Channel); + b.UseGrpc(sidecarFixture.Channel); configure(b); }); services.AddDurableTaskClient(b => { - b.UseGrpc(this.sidecarFixture.Channel); + b.UseGrpc(sidecarFixture.Channel); b.RegisterDirectly(); }); }); @@ -88,19 +83,12 @@ protected IReadOnlyCollection GetLogs() return logs; } - protected struct HostTestLifetime : IAsyncDisposable + protected readonly struct HostTestLifetime(IHost host, CancellationToken cancellation) : IAsyncDisposable { - readonly IHost host; - readonly CancellationToken cancellation; - - public HostTestLifetime(IHost host, CancellationToken cancellation) - { - this.host = host; - this.cancellation = cancellation; - this.Client = host.Services.GetRequiredService(); - } + readonly IHost host = host; + readonly CancellationToken cancellation = cancellation; - public DurableTaskClient Client { get; } + public DurableTaskClient Client { get; } = host.Services.GetRequiredService(); public async ValueTask DisposeAsync() { diff --git a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs index f1281e9f..11dd4093 100644 --- a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs +++ b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs @@ -12,7 +12,8 @@ namespace Microsoft.DurableTask.Grpc.Tests; /// Integration tests that are designed to exercise the error handling and retry functionality /// of the Durable Task SDK. /// -public class OrchestrationErrorHandling(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) : IntegrationTestBase(output, sidecarFixture) +public class OrchestrationErrorHandling(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) + : IntegrationTestBase(output, sidecarFixture) { /// @@ -366,7 +367,7 @@ public async Task TaskNotFoundErrorsAreNotRetried(bool activity) static Exception MakeException(Type exceptionType, string message) { - // We assume the contructor of the exception type takes a single string argument + // We assume the constructor of the exception type takes a single string argument return (Exception)Activator.CreateInstance(exceptionType, message)!; } diff --git a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs index 071dbad5..c95768c7 100644 --- a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs +++ b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs @@ -11,12 +11,9 @@ namespace Microsoft.DurableTask.Grpc.Tests; -public class OrchestrationPatterns : IntegrationTestBase +public class OrchestrationPatterns(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) + : IntegrationTestBase(output, sidecarFixture) { - public OrchestrationPatterns(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) - : base(output, sidecarFixture) - { } - [Fact] public async Task EmptyOrchestration() { diff --git a/test/Grpc.IntegrationTests/PageableIntegrationTests.cs b/test/Grpc.IntegrationTests/PageableIntegrationTests.cs index 6d8d0727..a8a698a8 100644 --- a/test/Grpc.IntegrationTests/PageableIntegrationTests.cs +++ b/test/Grpc.IntegrationTests/PageableIntegrationTests.cs @@ -8,13 +8,9 @@ namespace Microsoft.DurableTask.Grpc.Tests; -public class PageableIntegrationTests : IntegrationTestBase +public class PageableIntegrationTests(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) + : IntegrationTestBase(output, sidecarFixture) { - public PageableIntegrationTests(ITestOutputHelper output, GrpcSidecarFixture sidecarFixture) - : base(output, sidecarFixture) - { - } - [Fact] public async Task PageableActivity_Enumerates() { diff --git a/test/TestHelpers/Logging/LogEntry.cs b/test/TestHelpers/Logging/LogEntry.cs index e0ca5760..ea3e5fa0 100644 --- a/test/TestHelpers/Logging/LogEntry.cs +++ b/test/TestHelpers/Logging/LogEntry.cs @@ -5,38 +5,27 @@ namespace Microsoft.DurableTask.Tests.Logging; -public class LogEntry +public class LogEntry( + string category, + LogLevel level, + EventId eventId, + Exception? exception, + string message, + object? state) { - public LogEntry( - string category, - LogLevel level, - EventId eventId, - Exception? exception, - string message, - object? state) - { - this.Category = category; - this.LogLevel = level; - this.EventId = eventId; - this.Exception = exception; - this.Message = message; - this.Timestamp = DateTime.Now; - this.State = state; - } - - public string Category { get; } + public string Category { get; } = category; - public DateTime Timestamp { get; } + public DateTime Timestamp { get; } = DateTime.Now; - public EventId EventId { get; } + public EventId EventId { get; } = eventId; - public LogLevel LogLevel { get; } + public LogLevel LogLevel { get; } = level; - public Exception? Exception { get; } + public Exception? Exception { get; } = exception; - public string Message { get; } + public string Message { get; } = message; - public object? State { get; } + public object? State { get; } = state; public override string ToString() { diff --git a/test/TestHelpers/Logging/TestLogProvider.cs b/test/TestHelpers/Logging/TestLogProvider.cs index 287c6817..be64192c 100644 --- a/test/TestHelpers/Logging/TestLogProvider.cs +++ b/test/TestHelpers/Logging/TestLogProvider.cs @@ -7,16 +7,11 @@ namespace Microsoft.DurableTask.Tests.Logging; -public sealed class TestLogProvider : ILoggerProvider +public sealed class TestLogProvider(ITestOutputHelper output) : ILoggerProvider { - readonly ITestOutputHelper output; - readonly ConcurrentDictionary loggers; - - public TestLogProvider(ITestOutputHelper output) - { - this.output = output ?? throw new ArgumentNullException(nameof(output)); - this.loggers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - } + readonly ITestOutputHelper output = output ?? throw new ArgumentNullException(nameof(output)); + readonly ConcurrentDictionary loggers + = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); public bool TryGetLogs(string category, out IReadOnlyCollection logs) { @@ -48,18 +43,9 @@ void IDisposable.Dispose() // no-op } - class TestLogger : ILogger + class TestLogger(string category, ITestOutputHelper output) : ILogger { - readonly string category; - readonly ITestOutputHelper output; - readonly List entries; - - public TestLogger(string category, ITestOutputHelper output) - { - this.category = category; - this.output = output; - this.entries = new List(); - } + readonly List entries = new List(); public IReadOnlyCollection GetLogs() => this.entries.AsReadOnly(); @@ -77,7 +63,7 @@ void ILogger.Log( Func formatter) { var entry = new LogEntry( - this.category, + category, level, eventId, exception, @@ -87,7 +73,7 @@ void ILogger.Log( try { - this.output.WriteLine(entry.ToString()); + output.WriteLine(entry.ToString()); } catch (InvalidOperationException) { diff --git a/test/Worker/Core.Tests/DependencyInjection/DefaultDurableTaskWorkerBuilderTests.cs b/test/Worker/Core.Tests/DependencyInjection/DefaultDurableTaskWorkerBuilderTests.cs index e510da34..4b4c6793 100644 --- a/test/Worker/Core.Tests/DependencyInjection/DefaultDurableTaskWorkerBuilderTests.cs +++ b/test/Worker/Core.Tests/DependencyInjection/DefaultDurableTaskWorkerBuilderTests.cs @@ -93,20 +93,15 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) } } - class GoodBuildTarget : DurableTaskWorker + class GoodBuildTarget( + string name, DurableTaskFactory factory, IOptionsMonitor options) + : DurableTaskWorker(name, factory) { - public GoodBuildTarget( - string name, DurableTaskFactory factory, IOptionsMonitor options) - : base(name, factory) - { - this.Options = options.Get(name); - } - public new string Name => base.Name; public new IDurableTaskFactory Factory => base.Factory; - public DurableTaskWorkerOptions Options { get; } + public DurableTaskWorkerOptions Options { get; } = options.Get(name); protected override Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/test/Worker/Core.Tests/DependencyInjection/DurableTaskWorkerBuilderExtensionsTests.cs b/test/Worker/Core.Tests/DependencyInjection/DurableTaskWorkerBuilderExtensionsTests.cs index a1bd0785..1dbdbbc8 100644 --- a/test/Worker/Core.Tests/DependencyInjection/DurableTaskWorkerBuilderExtensionsTests.cs +++ b/test/Worker/Core.Tests/DependencyInjection/DurableTaskWorkerBuilderExtensionsTests.cs @@ -70,20 +70,15 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) } } - class GoodBuildTarget : DurableTaskWorker + class GoodBuildTarget( + string name, DurableTaskFactory factory, IOptions options) + : DurableTaskWorker(name, factory) { - public GoodBuildTarget( - string name, DurableTaskFactory factory, IOptions options) - : base(name, factory) - { - this.Options = options.Value; - } - public new string Name => base.Name; public new IDurableTaskFactory Factory => base.Factory; - public DurableTaskWorkerOptions Options { get; } + public DurableTaskWorkerOptions Options { get; } = options.Value; protected override Task ExecuteAsync(CancellationToken stoppingToken) {