diff --git a/src/HyperSharp.Responders/ResponderCompiler.cs b/src/HyperSharp.Responders/ResponderCompiler.cs index deb06ad..06bf7a3 100644 --- a/src/HyperSharp.Responders/ResponderCompiler.cs +++ b/src/HyperSharp.Responders/ResponderCompiler.cs @@ -143,10 +143,12 @@ public ResponderDelegate CompileResponders IEnumerable rootResponders = _builders.Where(builder => builder.RequiredBy.Count == 0); if (!rootResponders.Any()) { + _logger.LogWarning("No responders were found, returning an empty responder."); return (context, cancellationToken) => Result.Success(); } // Compile the root responders + _logger.LogInformation("Compiling {Count:N0} top-level responders.", rootResponders.Count()); List> rootRespondersDelegates = []; foreach (ResponderBuilder builder in rootResponders) { @@ -160,13 +162,15 @@ public ResponderDelegate CompileResponders foreach (ResponderDelegate responder in rootRespondersDelegates) { Result result = responder(context, cancellationToken); - if (!result.IsSuccess || result.HasValue) + if (result.HasValue) { + _logger.LogTrace("Returning result: {Result}", result); return result; } } - return Result.Success(); + _logger.LogTrace("None of the {Count:N0} top-level responders returned a value.", rootRespondersDelegates.Count); + return Result.Failure(); } catch (Exception error) { @@ -246,10 +250,12 @@ public ValueTaskResponderDelegate CompileAsyncResponders rootResponders = _builders.Where(builder => builder.RequiredBy.Count == 0); if (!rootResponders.Any()) { + _logger.LogWarning("No responders were found, returning an empty responder."); return (context, cancellationToken) => ValueTask.FromResult(Result.Success()); } // Compile the root responders + _logger.LogInformation("Compiling {Count:N0} top-level responders.", rootResponders.Count()); List> rootRespondersDelegates = []; foreach (ResponderBuilder builder in rootResponders) { @@ -263,12 +269,15 @@ public ValueTaskResponderDelegate CompileAsyncResponders responder in rootRespondersDelegates) { Result result = await responder(context, cancellationToken); - if (!result.IsSuccess || result.HasValue) + if (result.HasValue) { + _logger.LogTrace("Returning result: {Result}", result); return result; } + } + _logger.LogTrace("None of the {Count:N0} top-level responders returned a value.", rootRespondersDelegates.Count); return Result.Success(); } catch (Exception error) diff --git a/src/HyperSharp.Results/Result.cs b/src/HyperSharp.Results/Result.cs index 8a13ec1..30d7036 100644 --- a/src/HyperSharp.Results/Result.cs +++ b/src/HyperSharp.Results/Result.cs @@ -48,6 +48,13 @@ public Result() Status = ResultStatus.IsSuccess; } + internal Result(ResultStatus status) + { + Value = null; + Errors = _emptyErrors; + Status = status; + } + internal Result(object? value) { Value = value; @@ -94,6 +101,11 @@ internal Result(object? value, IEnumerable errors) /// The value of the result. public static Result Success(object? value) => new(value); + /// + /// Returns a failed result with no error. + /// + public static Result Failure() => new(ResultStatus.None); + /// /// Creates a failed result with an error. /// @@ -128,6 +140,9 @@ internal Result(object? value, IEnumerable errors) /// public static Result Success(T value) => new(value); + /// + public static Result Failure() => new(ResultStatus.None); + /// public static Result Failure(string error) => new(new Error(error)); diff --git a/src/HyperSharp.Results/ResultStatus.cs b/src/HyperSharp.Results/ResultStatus.cs index a2e62d5..ef9d5a1 100644 --- a/src/HyperSharp.Results/ResultStatus.cs +++ b/src/HyperSharp.Results/ResultStatus.cs @@ -11,7 +11,7 @@ public enum ResultStatus /// /// The result has failed and has no value. /// - None = 0 << 0, + None = 0, /// /// The result has succeeded. @@ -21,6 +21,6 @@ public enum ResultStatus /// /// The result does not contain a value. /// - HasValue = 1 << 1, + HasValue = 1 << 1 } } diff --git a/src/HyperSharp.Results/Result`1.cs b/src/HyperSharp.Results/Result`1.cs index 339af8d..f227522 100644 --- a/src/HyperSharp.Results/Result`1.cs +++ b/src/HyperSharp.Results/Result`1.cs @@ -46,6 +46,13 @@ public Result() Status = ResultStatus.IsSuccess; } + internal Result(ResultStatus status) + { + Value = default; + Errors = Result._emptyErrors; + Status = status; + } + internal Result(T? value) { Value = value; diff --git a/src/HyperSharp/HyperConfiguration.cs b/src/HyperSharp/HyperConfiguration.cs index 270b77c..acde9e5 100644 --- a/src/HyperSharp/HyperConfiguration.cs +++ b/src/HyperSharp/HyperConfiguration.cs @@ -78,8 +78,8 @@ public HyperConfiguration(IServiceCollection serviceDescriptors, HyperConfigurat { ArgumentNullException.ThrowIfNull(serviceDescriptors, nameof(serviceDescriptors)); ArgumentNullException.ThrowIfNull(builder, nameof(builder)); - IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); + IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); if (!Uri.TryCreate($"http://{builder.ListeningEndpoint}/", UriKind.Absolute, out Uri? host)) { throw new ArgumentException("The listening endpoint is invalid.", nameof(builder)); diff --git a/src/HyperSharp/Protocol/HyperSerializers/JsonAsync.cs b/src/HyperSharp/Protocol/HyperSerializers/JsonAsync.cs index 3390e82..fe19171 100644 --- a/src/HyperSharp/Protocol/HyperSerializers/JsonAsync.cs +++ b/src/HyperSharp/Protocol/HyperSerializers/JsonAsync.cs @@ -25,7 +25,7 @@ public static ValueTask JsonAsync(HyperContext context, HyperStatus status // Write Content-Type header and beginning of Content-Length header context.Connection.StreamWriter.Write(_contentTypeJsonEncodingHeader); - byte[] body = JsonSerializer.SerializeToUtf8Bytes(status.Body, context.Connection.Server.Configuration.JsonSerializerOptions); + byte[] body = JsonSerializer.SerializeToUtf8Bytes(status.Body ?? new object(), context.Connection.Server.Configuration.JsonSerializerOptions); // Finish the Content-Length header context.Connection.StreamWriter.Write(Encoding.ASCII.GetBytes(body.Length.ToString()));