Closed Zaicon closed 4 years ago
Hello and welcome back @Zaicon!
Since EmbedIO version 3, both SendStringAsync
and SendDataAsync
use chunked transfer encoding. The rationale is that they can be called more than once for the same response, hence it is not possible to determine the content length in advance.
May I know why the Content-Length
header is so important to you? A better knowledge of your use case might help @geoperez and me to either figure out a workaround, or devise additional extension methods to IHttpContext
that do set the content length.
Hey, I was talking to @geoperez about this. I am using EmbedIO with a Slack application. When I used v2 and sent string responses via return await Ok("Some message here.");
, everything worked perfectly. When I upgraded to v3, Slack now shows an error every time I try to respond to an incoming web request.
It looks like the response payload is exactly the same (at least on Postman); the only difference is the headers returned. Geo noticed that the content-length header is missing and asked me to open this issue.
So, apparently Slack can't handle chunked responses, possibly along with other clients. Not all of them are browsers after all.
@Zaicon, can you put the class below in your app, use SendStringContentAsync
instead of SendStringAsync
, and report your results? If it works, it's going to be an addition to EmbedIO v4.0, along with similar methods for binary and serialized data.
using System;
using System.Text;
using System.Threading.Tasks;
using EmbedIO;
using EmbedIO.Utilities;
namespace YOUR_NAMESPACE_HERE
{
/// <summary>
/// Provides extension methods for types implementing <see cref="IHttpContext"/>.
/// </summary>
public static class HttpContextExtensions
{
/// <summary>
/// <para>Asynchronously sends a string as response.</para>
/// <para>This method differs from <seealso cref="EmbedIO.HttpContextExtensions.SendStringAsync"/>
/// in that it sets the <c>Content-Length</c> header in the response, thus preventing
/// any further output to the response stream.</para>
/// </summary>
/// <param name="this">The <see cref="IHttpResponse"/> interface on which this method is called.</param>
/// <param name="content">The response content.</param>
/// <param name="contentType">The MIME type of the content.
/// If this parameter is <see langword="null"/> or the empty string, the content type will not be set.</param>
/// <param name="encoding">The <see cref="Encoding"/> to use.</param>
/// <returns>A <see cref="Task"/> representing the ongoing operation.</returns>
/// <exception cref="NullReferenceException"><paramref name="this"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="content"/> is <see langword="null"/>.</para>
/// <para>- or -</para>
/// <para><paramref name="encoding"/> is <see langword="null"/>.</para>
/// </exception>
public static Task SendStringContentAsync(
this IHttpContext @this,
string content,
string? contentType,
Encoding encoding)
{
content = Validate.NotNull(nameof(content), content);
encoding = Validate.NotNull(nameof(encoding), encoding);
if (!string.IsNullOrEmpty(contentType))
{
#pragma warning disable CS8601 // Possible null reference assignment - Tested with string.NotNullOrEmpty
@this.Response.ContentType = contentType;
#pragma warning restore CS8601
@this.Response.ContentEncoding = encoding;
}
var data = encoding.GetBytes(content);
@this.Response.ContentLength64 = data.Length;
return @this.Response.OutputStream.WriteAsync(data, 0, data.Length, @this.CancellationToken);
}
}
}
Ayyy it worked!
Also with Slack?
Yes, Slack accepted the response and handled it as expected.
Great!
In the meantime, I think I've found a better way to support setting Content-Length
, so SendStringContentAsync
will probably not be a part of EmbedIO v4.0.
Although the code above will work with version 4, I'd advise you to use out-of-the-box extension methods as much as possible, as they shield you from having to deal with the HTTP response object directly. This will minimize you code's dependency on HttpListener
, minimizing required changes when EmbedIO eventually parts ways with it.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Describe the bug In EmbedIO v3.3.3, when sending a response to a WebApi request, the content-length header is missing.
As a side note, in EmbedIO v2.9.2, the content-length header is sent as expected.
To Reproduce Steps to reproduce the behavior:
await HttpContext.SendStringAsync("example text here", "application/json; charset=utf-8", Encoding.UTF8);
orawait HttpContext.SendDataAsync(new { blah = "example" });
Expected behavior The content-length header is sent in the response.
Screenshots EmbedIO v2.9.2: EmbedIO v3.3.3: