using EmbedIO.Utilities;
using Swan.Formatters;
using System;
using System.Threading.Tasks;
namespace EmbedIO
{
///
/// Provides standard response serializer callbacks.
///
///
public static class ResponseSerializer
{
///
/// The default response serializer callback used by EmbedIO.
/// Equivalent to Json.
///
public static readonly ResponseSerializerCallback Default = Json;
private static readonly ResponseSerializerCallback ChunkedEncodingBaseSerializer = GetBaseSerializer(false);
private static readonly ResponseSerializerCallback BufferingBaseSerializer = GetBaseSerializer(true);
///
/// Serializes data in JSON format to a HTTP response,
/// using the utility class.
///
/// The HTTP context of the request.
/// The data to serialize.
/// A representing the ongoing operation.
public static async Task Json(IHttpContext context, object? data)
{
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data)).ConfigureAwait(false);
}
///
/// Serializes data in JSON format with the specified
/// to a HTTP response, using the utility class.
///
/// The JSON serializer case.
/// A that can be used to serialize
/// data to a HTTP response.
public static ResponseSerializerCallback Json(JsonSerializerCase jsonSerializerCase)
=> async (context, data) => {
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data, jsonSerializerCase))
.ConfigureAwait(false);
};
///
/// Serializes data in JSON format with the specified
/// to a HTTP response, using the utility class.
///
/// The JSON serializer options.
/// A that can be used to serialize
/// data to a HTTP response.
///
/// is .
///
public static ResponseSerializerCallback Json(SerializerOptions serializerOptions)
{
_ = Validate.NotNull(nameof(serializerOptions), serializerOptions);
return async (context, data) => {
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data, serializerOptions))
.ConfigureAwait(false);
};
}
///
/// Serializes data in JSON format to a HTTP response, using the utility class.
///
/// to write the response body to a memory buffer first,
/// then send it all together with a Content-Length header; to use chunked
/// transfer encoding.
/// A that can be used to serialize
/// data to a HTTP response.
public static ResponseSerializerCallback Json(bool bufferResponse)
=> async (context, data) => {
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
var baseSerializer = None(bufferResponse);
await baseSerializer(context, Swan.Formatters.Json.Serialize(data))
.ConfigureAwait(false);
};
///
/// Serializes data in JSON format with the specified
/// to a HTTP response, using the utility class.
///
/// to write the response body to a memory buffer first,
/// then send it all together with a Content-Length header; to use chunked
/// transfer encoding.
/// The JSON serializer case.
/// A that can be used to serialize
/// data to a HTTP response.
public static ResponseSerializerCallback Json(bool bufferResponse, JsonSerializerCase jsonSerializerCase)
=> async (context, data) => {
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
var baseSerializer = None(bufferResponse);
await baseSerializer(context, Swan.Formatters.Json.Serialize(data, jsonSerializerCase))
.ConfigureAwait(false);
};
///
/// Serializes data in JSON format with the specified
/// to a HTTP response, using the utility class.
///
/// to write the response body to a memory buffer first,
/// then send it all together with a Content-Length header; to use chunked
/// transfer encoding.
/// The JSON serializer options.
/// A that can be used to serialize
/// data to a HTTP response.
///
/// is .
///
public static ResponseSerializerCallback Json(bool bufferResponse, SerializerOptions serializerOptions)
{
_ = Validate.NotNull(nameof(serializerOptions), serializerOptions);
return async (context, data) => {
context.Response.ContentType = MimeType.Json;
context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
var baseSerializer = None(bufferResponse);
await baseSerializer(context, Swan.Formatters.Json.Serialize(data, serializerOptions))
.ConfigureAwait(false);
};
}
///
/// Sends data in a HTTP response without serialization.
///
/// to write the response body to a memory buffer first,
/// then send it all together with a Content-Length header; to use chunked
/// transfer encoding.
/// A that can be used to serialize data to a HTTP response.
///
/// s and one-dimensional arrays of s
/// are sent to the client unchanged; every other type is converted to a string.
/// The ContentType set on the response is used to negotiate
/// a compression method, according to request headers.
/// Strings (and other types converted to strings) are sent with the encoding specified by .
///
public static ResponseSerializerCallback None(bool bufferResponse)
=> bufferResponse ? BufferingBaseSerializer : ChunkedEncodingBaseSerializer;
private static ResponseSerializerCallback GetBaseSerializer(bool bufferResponse)
=> async (context, data) => {
if (data is null)
{
return;
}
var isBinaryResponse = data is byte[];
if (!context.TryDetermineCompression(context.Response.ContentType, out var preferCompression))
{
preferCompression = true;
}
if (isBinaryResponse)
{
var responseBytes = (byte[])data;
using var stream = context.OpenResponseStream(bufferResponse, preferCompression);
await stream.WriteAsync(responseBytes, 0, responseBytes.Length).ConfigureAwait(false);
}
else
{
var responseString = data is string stringData ? stringData : data.ToString() ?? string.Empty;
using var text = context.OpenResponseText(context.Response.ContentEncoding, bufferResponse, preferCompression);
await text.WriteAsync(responseString).ConfigureAwait(false);
}
};
}
}