Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.x] Add custom JSON serializer #27

Open
wants to merge 3 commits into
base: v1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion InertiaCore/Extensions/Configure.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.IO.Abstractions;
using System.Net;
using InertiaCore.Models;
using InertiaCore.Ssr;
Expand All @@ -8,6 +7,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace InertiaCore.Extensions;

Expand Down Expand Up @@ -45,6 +45,7 @@ public static IServiceCollection AddInertia(this IServiceCollection services,

services.AddSingleton<IResponseFactory, ResponseFactory>();
services.AddSingleton<IGateway, Gateway>();
services.AddSingleton<IInertiaSerializer, DefaultInertiaSerializer>();

services.Configure<MvcOptions>(mvcOptions => { mvcOptions.Filters.Add<InertiaActionFilter>(); });

Expand All @@ -53,6 +54,16 @@ public static IServiceCollection AddInertia(this IServiceCollection services,
return services;
}

public static IServiceCollection UseInertiaSerializer<TImplementation>(this IServiceCollection services)
where TImplementation : IInertiaSerializer
{
services.Replace(
new ServiceDescriptor(typeof(IInertiaSerializer), typeof(TImplementation), ServiceLifetime.Singleton)
);

return services;
}

public static IServiceCollection AddViteHelper(this IServiceCollection services,
Action<ViteOptions>? options = null)
{
Expand Down
13 changes: 4 additions & 9 deletions InertiaCore/Response.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using InertiaCore.Extensions;
using InertiaCore.Models;
using InertiaCore.Utils;
Expand All @@ -15,13 +13,14 @@ public class Response : IActionResult
private readonly object _props;
private readonly string _rootView;
private readonly string? _version;
private readonly IInertiaSerializer _serializer;

private ActionContext? _context;
private Page? _page;
private IDictionary<string, object>? _viewData;

public Response(string component, object props, string rootView, string? version)
=> (_component, _props, _rootView, _version) = (component, props, rootView, version);
public Response(string component, object props, string rootView, string? version, IInertiaSerializer serializer)
=> (_component, _props, _rootView, _version, _serializer) = (component, props, rootView, version, serializer);

public async Task ExecuteResultAsync(ActionContext context)
{
Expand Down Expand Up @@ -85,11 +84,7 @@ protected internal JsonResult GetJson()
_context!.HttpContext.Response.Headers.Override("Vary", "Accept");
_context!.HttpContext.Response.StatusCode = 200;

return new JsonResult(_page, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles
});
return _serializer.SerializeResult(_page);
}

private ViewResult GetView()
Expand Down
19 changes: 6 additions & 13 deletions InertiaCore/ResponseFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
using InertiaCore.Extensions;
using InertiaCore.Models;
using InertiaCore.Ssr;
using InertiaCore.Utils;
Expand Down Expand Up @@ -29,18 +26,20 @@ internal class ResponseFactory : IResponseFactory
{
private readonly IHttpContextAccessor _contextAccessor;
private readonly IGateway _gateway;
private readonly IInertiaSerializer _serializer;
private readonly IOptions<InertiaOptions> _options;

private object? _version;

public ResponseFactory(IHttpContextAccessor contextAccessor, IGateway gateway, IOptions<InertiaOptions> options) =>
(_contextAccessor, _gateway, _options) = (contextAccessor, gateway, options);
public ResponseFactory(IHttpContextAccessor contextAccessor, IGateway gateway, IInertiaSerializer serializer,
IOptions<InertiaOptions> options)
=> (_contextAccessor, _gateway, _serializer, _options) = (contextAccessor, gateway, serializer, options);

public Response Render(string component, object? props = null)
{
props ??= new { };

return new Response(component, props, _options.Value.RootView, GetVersion());
return new Response(component, props, _options.Value.RootView, GetVersion(), _serializer);
}

public async Task<IHtmlContent> Head(dynamic model)
Expand Down Expand Up @@ -74,13 +73,7 @@ public async Task<IHtmlContent> Html(dynamic model)
}
}

var data = JsonSerializer.Serialize(model,
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles
});

var data = _serializer.Serialize(model);
var encoded = WebUtility.HtmlEncode(data);

return new HtmlString($"<div id=\"app\" data-page=\"{encoded}\"></div>");
Expand Down
14 changes: 5 additions & 9 deletions InertiaCore/Ssr/Gateway.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using InertiaCore.Utils;

namespace InertiaCore.Ssr;

Expand All @@ -13,17 +12,14 @@ internal interface IGateway
internal class Gateway : IGateway
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IInertiaSerializer _serializer;

public Gateway(IHttpClientFactory httpClientFactory) => _httpClientFactory = httpClientFactory;
public Gateway(IHttpClientFactory httpClientFactory, IInertiaSerializer serializer)
=> (_httpClientFactory, _serializer) = (httpClientFactory, serializer);

public async Task<SsrResponse?> Dispatch(dynamic model, string url)
{
var json = JsonSerializer.Serialize(model,
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles
});
var json = _serializer.Serialize(model);
var content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");

var client = _httpClientFactory.CreateClient();
Expand Down
27 changes: 27 additions & 0 deletions InertiaCore/Utils/DefaultInertiaSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;

namespace InertiaCore.Utils;

public class DefaultInertiaSerializer : IInertiaSerializer
{
protected static JsonSerializerOptions GetOptions()
{
return new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles
};
}

public string Serialize(object? obj)
{
return JsonSerializer.Serialize(obj, GetOptions());
}

public JsonResult SerializeResult(object? obj)
{
return new JsonResult(obj, GetOptions());
}
}
10 changes: 10 additions & 0 deletions InertiaCore/Utils/IInertiaSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Mvc;

namespace InertiaCore.Utils;

public interface IInertiaSerializer
{
public string Serialize(object? obj);

public JsonResult SerializeResult(object? obj);
}
5 changes: 3 additions & 2 deletions InertiaCoreTests/Setup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ public void Setup()
var contextAccessor = new Mock<IHttpContextAccessor>();
var httpClientFactory = new Mock<IHttpClientFactory>();

var gateway = new Gateway(httpClientFactory.Object);
var serializer = new DefaultInertiaSerializer();
var gateway = new Gateway(httpClientFactory.Object, serializer);
var options = new Mock<IOptions<InertiaOptions>>();
options.SetupGet(x => x.Value).Returns(new InertiaOptions());

_factory = new ResponseFactory(contextAccessor.Object, gateway, options.Object);
_factory = new ResponseFactory(contextAccessor.Object, gateway, serializer, options.Object);
}

/// <summary>
Expand Down
31 changes: 31 additions & 0 deletions InertiaCoreTests/UnitTestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

namespace InertiaCoreTests;

internal class DummySerializer : DefaultInertiaSerializer
{
}

public partial class Tests
{
[Test]
Expand All @@ -28,6 +32,7 @@ public void TestConfiguration()

Assert.That(builder.Services.Any(s => s.ServiceType == typeof(IResponseFactory)), Is.True);
Assert.That(builder.Services.Any(s => s.ServiceType == typeof(IGateway)), Is.True);
Assert.That(builder.Services.Any(s => s.ServiceType == typeof(IInertiaSerializer)), Is.True);
});

var mvcConfiguration =
Expand All @@ -45,4 +50,30 @@ public void TestConfiguration()

Assert.DoesNotThrow(() => Inertia.GetVersion());
}

[Test]
[Description("Test if the configuration registers properly custom JSON serializer.")]
public void TestSerializerConfiguration()
{
var builder = WebApplication.CreateBuilder();
builder.Services.AddInertia();

Assert.Multiple(() =>
{
Assert.That(builder.Services.Any(s => s.ServiceType == typeof(IInertiaSerializer)), Is.True);

Assert.That(builder.Services.Any(s => s.ImplementationType == typeof(DefaultInertiaSerializer)), Is.True);
Assert.That(builder.Services.Any(s => s.ImplementationType == typeof(DummySerializer)), Is.False);
});

Assert.DoesNotThrow(() => builder.Services.UseInertiaSerializer<DummySerializer>());

Assert.Multiple(() =>
{
Assert.That(builder.Services.Any(s => s.ServiceType == typeof(IInertiaSerializer)), Is.True);

Assert.That(builder.Services.Any(s => s.ImplementationType == typeof(DefaultInertiaSerializer)), Is.False);
Assert.That(builder.Services.Any(s => s.ImplementationType == typeof(DummySerializer)), Is.True);
});
}
}
Loading