Is there an equivalent to "HttpContext.Response.Write" in ASP.NET Core?
Asked Answered
D

4

13

I'm trying to append some HTML and JavaScript content on page using ActionFilter in ASP.NET Core 2.

In ASP.NET MVC, that can be done with:

filterContext.HttpContext.Response.Write(stringBuilder.ToString());

but in ASP.NET Core that's not working.

I tried to implement with this:

filterContext.HttpContext.Response.WriteAsync(stringBuilder.ToString());

But it makes my page completely blank.

I'm looking for a solution compatible with nopCommerce 4.0, which I use with ASP.NET Core.

Dearden answered 17/11, 2017 at 12:10 Comment(0)
H
5

You can try something like this

In a custom implementation of INopStartup.Configure(IApplicationBuilder application):

application.Use(async (context, next) =>    
{
    using (var customStream = new MemoryStream())
    {
        // Create a backup of the original response stream
        var backup = context.Response.Body;

        // Assign readable/writeable stream
        context.Response.Body = customStream;
        
        await next();

        // Restore the response stream
        context.Response.Body = backup;
        
        // Move to start and read response content
        customStream.Seek(0, SeekOrigin.Begin);
        var content = new StreamReader(customStream).ReadToEnd();
        
        // Write custom content to response
        await context.Response.WriteAsync(content);
    }
});

And then in your custom ResultFilterAttribute:

public class MyAttribute : ResultFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext context)
    {
        try
        {
            var bytes = Encoding.UTF8.GetBytes("Foo Bar");
            
            // Seek to end
            context.HttpContext.Response.Body.Seek(context.HttpContext.Response.Body.Length, SeekOrigin.Begin);
            context.HttpContext.Response.Body.Write(bytes, 0, bytes.Length);
        }
        catch
        {
            // ignored
        }

        base.OnResultExecuted(context);
    }
}

And the result

Result HTML

Hornstein answered 18/11, 2017 at 22:15 Comment(1)
If we use this solution in nopCommerce, we are getting issue. In INopStartup.Configure method, If we call await next() first and then restore the response stream, it will not load images and scripts on User side and gives error of Response Content-Length mismatch:too many bytes written. If we first restore the response stream and then call await next() then it will give error in filterContext.HttpContext.Response.Body.Seek() method not found.Dearden
A
20

The static and asynchronous method HttpResponseWritingExtensions.WriteAsync is currently the preferred way of reaching this goal.

You can find it in the assembly Microsoft.AspNetCore.Http.Abstractions.

using Microsoft.AspNetCore.Http;

[HttpGet("test")]
public async Task GetTest()
    => await HttpResponseWritingExtensions.WriteAsync(this.Response, "Hello World");

Using the ASP.NET Core 6.0, you can write a simple response using Minimal API like this:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World");
app.Run();

Source: MSDN

Astronomer answered 2/2, 2019 at 23:24 Comment(1)
How would we put this in, for example, an if statement inside a method on a .cshtml.cs page?Scandic
C
11

Response.Body.Write takes a byte array as an argument.

public void OnGet() {
    var text = "<h1>Hello, Response!</h1>";
    byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
    Response.Body.Write(data, 0, data.Length);
}

or async version:

public async Task OnGetAsync() {
    var text = "<h1>Hello, Async Response!</h1>";
    byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
    await Response.Body.WriteAsync(data, 0, data.Length);
}
Closer answered 18/11, 2017 at 22:4 Comment(1)
Make sure to remove or comment our default content from razor page, since Response.Body.Write takes over page response ` @* @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} } *@`Closer
H
5

You can try something like this

In a custom implementation of INopStartup.Configure(IApplicationBuilder application):

application.Use(async (context, next) =>    
{
    using (var customStream = new MemoryStream())
    {
        // Create a backup of the original response stream
        var backup = context.Response.Body;

        // Assign readable/writeable stream
        context.Response.Body = customStream;
        
        await next();

        // Restore the response stream
        context.Response.Body = backup;
        
        // Move to start and read response content
        customStream.Seek(0, SeekOrigin.Begin);
        var content = new StreamReader(customStream).ReadToEnd();
        
        // Write custom content to response
        await context.Response.WriteAsync(content);
    }
});

And then in your custom ResultFilterAttribute:

public class MyAttribute : ResultFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext context)
    {
        try
        {
            var bytes = Encoding.UTF8.GetBytes("Foo Bar");
            
            // Seek to end
            context.HttpContext.Response.Body.Seek(context.HttpContext.Response.Body.Length, SeekOrigin.Begin);
            context.HttpContext.Response.Body.Write(bytes, 0, bytes.Length);
        }
        catch
        {
            // ignored
        }

        base.OnResultExecuted(context);
    }
}

And the result

Result HTML

Hornstein answered 18/11, 2017 at 22:15 Comment(1)
If we use this solution in nopCommerce, we are getting issue. In INopStartup.Configure method, If we call await next() first and then restore the response stream, it will not load images and scripts on User side and gives error of Response Content-Length mismatch:too many bytes written. If we first restore the response stream and then call await next() then it will give error in filterContext.HttpContext.Response.Body.Seek() method not found.Dearden
M
1

My code was no prepared for async execution, so i used:

Response.WriteAsync("text").Wait();

.Wait() make the execution waits for the Async Method complete execution to continue.

I don't know if the performance is the best, but is already better than .Net Framework solution

.Wait(): https://learn.microsoft.com/pt-br/dotnet/api/system.io.stream.writeasync?view=net-6.0

.WriteAsync(): https://learn.microsoft.com/pt-br/dotnet/api/system.threading.tasks.task.wait?view=net-6.0

Monaural answered 11/3, 2022 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.