Skip to content

Commit

Permalink
Update IResult implementation to support TypedResults properly (#68)
Browse files Browse the repository at this point in the history
* Update IResult implementation to support TypedResults properly

Fixes #64

* Delete IRazorSliceHttpResult.cs

* Update IResultExtensions.cs
  • Loading branch information
DamianEdwards authored Dec 13, 2024
1 parent d5e7d7a commit d0bb85f
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 65 deletions.
7 changes: 4 additions & 3 deletions samples/RazorSlices.Samples.WebApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Models = RazorSlices.Samples.WebApp.Models;
using Slices = RazorSlices.Samples.WebApp.Slices;
using LibrarySlices = RazorSlices.Samples.RazorClassLibrary.Slices;
using Microsoft.AspNetCore.Http.HttpResults;

var builder = WebApplication.CreateBuilder(args);

Expand Down Expand Up @@ -59,12 +60,12 @@
});

app.MapGet("/", () => Results.Extensions.RazorSlice<Slices.Todos, Models.Todo[]>(Models.Todos.AllTodos));
app.MapGet("/{id:int}", (int id) =>
app.MapGet("/{id:int}", Results<RazorSliceHttpResult<Models.Todo>, NotFound> (int id) =>
{
var todo = Models.Todos.AllTodos.FirstOrDefault(t => t.Id == id);
return todo is not null
? Results.Extensions.RazorSlice<Slices.Todo, Models.Todo>(todo)
: Results.NotFound();
? TypedResults.Extensions.RazorSlice<Slices.Todo, Models.Todo>(todo)
: TypedResults.NotFound();
});

Console.WriteLine($"RuntimeFeature.IsDynamicCodeSupported = {RuntimeFeature.IsDynamicCodeSupported}");
Expand Down
36 changes: 0 additions & 36 deletions src/RazorSlices/IRazorSliceHttpResult.cs

This file was deleted.

24 changes: 15 additions & 9 deletions src/RazorSlices/IResultExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Http.HttpResults;
using RazorSlices;

namespace Microsoft.AspNetCore.Http;
Expand All @@ -14,15 +15,15 @@ public static class RazorSlicesExtensions
/// <typeparam name="TSliceProxy"></typeparam>
/// <param name="_"></param>
/// <param name="statusCode"></param>
/// <returns>An <see cref="IRazorSliceHttpResult"/> that can be rendered to the response.</returns>
public static IRazorSliceHttpResult RazorSlice<TSliceProxy>(this IResultExtensions _, int statusCode = StatusCodes.Status200OK)
/// <returns>An <see cref="RazorSliceHttpResult"/> that can be rendered to the response.</returns>
public static RazorSliceHttpResult RazorSlice<TSliceProxy>(this IResultExtensions _, int statusCode = StatusCodes.Status200OK)
where TSliceProxy : IRazorSliceProxy
{
#pragma warning disable CA2000 // Dispose objects before losing scope: IResult will get disposed by ASP.NET Core
var razorSlice = TSliceProxy.CreateSlice();
#pragma warning restore CA2000 // Dispose objects before losing scope

if (razorSlice is IRazorSliceHttpResult razorSliceHttpResult)
if (razorSlice is RazorSliceHttpResult razorSliceHttpResult)
{
// Set the default HtmlEncoder if it's not set to avoid looking it up from the DI container and paying the cost of the request services scope.
razorSliceHttpResult.HtmlEncoder ??= HtmlEncoder.Default;
Expand All @@ -41,15 +42,15 @@ public static IRazorSliceHttpResult RazorSlice<TSliceProxy>(this IResultExtensio
/// <param name="_"></param>
/// <param name="model"></param>
/// <param name="statusCode"></param>
/// <returns>An <see cref="IRazorSliceHttpResult"/> that can be rendered to the response.</returns>
public static IRazorSliceHttpResult RazorSlice<TSliceProxy, TModel>(this IResultExtensions _, TModel model, int statusCode = StatusCodes.Status200OK)
/// <returns>An <see cref="RazorSliceHttpResult{TModel}"/> that can be rendered to the response.</returns>
public static RazorSliceHttpResult<TModel> RazorSlice<TSliceProxy, TModel>(this IResultExtensions _, TModel model, int statusCode = StatusCodes.Status200OK)
where TSliceProxy : IRazorSliceProxy
{
#pragma warning disable CA2000 // Dispose objects before losing scope: IResult will get disposed by ASP.NET Core
var razorSlice = TSliceProxy.CreateSlice(model);
#pragma warning restore CA2000 // Dispose objects before losing scope

if (razorSlice is IRazorSliceHttpResult razorSliceHttpResult)
if (razorSlice is RazorSliceHttpResult<TModel> razorSliceHttpResult)
{
// Set the default HtmlEncoder if it's not set to avoid looking it up from the DI container and paying the cost of the request services scope.
razorSliceHttpResult.HtmlEncoder ??= HtmlEncoder.Default;
Expand All @@ -61,10 +62,15 @@ public static IRazorSliceHttpResult RazorSlice<TSliceProxy, TModel>(this IResult
}

private static RazorSliceHttpResultWrapper WrapRazorSliceWithHttpResult(RazorSlice razorSlice, int statusCode)
{
return new RazorSliceHttpResultWrapper(razorSlice)
=> new(razorSlice)
{
StatusCode = statusCode
};
}

private static RazorSliceHttpResultWrapper<TModel> WrapRazorSliceWithHttpResult<TModel>(RazorSlice<TModel> razorSlice, int statusCode)
=> new(razorSlice)
{
Model = razorSlice.Model,
StatusCode = statusCode
};
}
4 changes: 2 additions & 2 deletions src/RazorSlices/RazorSliceHttpResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults;
/// A <see cref="RazorSlice" /> template that is also an <see cref="IResult" /> so it can be directly returned from
/// a route handler delegate. When executed it will render the template to the response.
/// </summary>
public abstract class RazorSliceHttpResult : RazorSlice, IRazorSliceHttpResult
public abstract class RazorSliceHttpResult : RazorSlice, IResult, IStatusCodeHttpResult, IContentTypeHttpResult
{
/// <summary>
/// Gets or sets the HTTP status code. Defaults to <see cref="StatusCodes.Status200OK"/>
/// </summary>
public int StatusCode { get; set; } = StatusCodes.Status200OK;

int? IRazorSliceHttpResult.StatusCode { get => StatusCode; set => StatusCode = value ?? StatusCodes.Status200OK; }
int? IStatusCodeHttpResult.StatusCode { get => StatusCode; }

/// <summary>
/// Gets the content type: <c>text/html; charset=utf-8</c>
Expand Down
4 changes: 2 additions & 2 deletions src/RazorSlices/RazorSliceHttpResultOfTModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults;
/// A <see cref="RazorSlice{TModel}" /> template that is also an <see cref="IResult" /> so it can be directly returned from
/// a route handler delegate. When executed it will render the template to the response.
/// </summary>
public abstract class RazorSliceHttpResult<TModel> : RazorSlice<TModel>, IRazorSliceHttpResult
public abstract class RazorSliceHttpResult<TModel> : RazorSlice<TModel>, IResult, IStatusCodeHttpResult, IContentTypeHttpResult
{
/// <summary>
/// Gets or sets the HTTP status code. Defaults to <see cref="StatusCodes.Status200OK"/>
/// </summary>
public int StatusCode { get; set; } = StatusCodes.Status200OK;

int? IRazorSliceHttpResult.StatusCode { get => StatusCode; set => StatusCode = value ?? StatusCodes.Status200OK; }
int? IStatusCodeHttpResult.StatusCode { get => StatusCode; }

/// <summary>
/// Gets the content type: <c>text/html; charset=utf-8</c>
Expand Down
27 changes: 14 additions & 13 deletions src/RazorSlices/RazorSliceHttpResultWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;

namespace RazorSlices;

internal sealed class RazorSliceHttpResultWrapper(RazorSlice razorSlice) : IRazorSliceHttpResult, IDisposable
internal sealed class RazorSliceHttpResultWrapper(RazorSlice razorSlice) : RazorSliceHttpResult, IResult
{
public int? StatusCode { get; set; } = StatusCodes.Status200OK;

int? IStatusCodeHttpResult.StatusCode => StatusCode;

public string ContentType => "text/html; charset=utf-8";

public HtmlEncoder? HtmlEncoder { get; set; }
public override Task ExecuteAsync() => razorSlice.ExecuteAsync();

/// <inheritdoc />
Task IResult.ExecuteAsync(HttpContext httpContext)
{
razorSlice.HttpContext = httpContext;
return RazorSliceHttpResultHelpers.ExecuteAsync(razorSlice, httpContext, HtmlEncoder, StatusCode ?? StatusCodes.Status200OK, ContentType);
return RazorSliceHttpResultHelpers.ExecuteAsync(razorSlice, httpContext, HtmlEncoder, StatusCode, ContentType);
}
}

public void Dispose()
internal sealed class RazorSliceHttpResultWrapper<TModel>(RazorSlice<TModel> razorSlice) : RazorSliceHttpResult<TModel>, IResult
{
public override Task ExecuteAsync() => razorSlice.ExecuteAsync();

/// <inheritdoc />
Task IResult.ExecuteAsync(HttpContext httpContext)
{
razorSlice.Dispose();
razorSlice.HttpContext = httpContext;
return RazorSliceHttpResultHelpers.ExecuteAsync(razorSlice, httpContext, HtmlEncoder, StatusCode, ContentType);
}
}

0 comments on commit d0bb85f

Please sign in to comment.