skip to Main Content

I was working on one of the requirements, where I need to modify result data in middleware (not any MVC Filters due to some other services injected through middleware).

In middleware I was getting data in json format and then deserializing that data then updating that data and finally serializing to JSON and sending it back as a response.

I don’t want to serialize data in MVC pipeline so I tried to remove output formator but that didn’t work for me and throwing error.

services.AddControllers(options =>
        {
            options.OutputFormatters.Clear();
        });

Is there any solution to get the .Net object in the pipeline and modify that object (as we do in MVC filter) and then serialize at last?

4

Answers


  1. I am not sure whether it fits your requirements but you can use HttpContext to store some data in the scope of the request. There is a ‘Items’ key-value collection.

    Login or Signup to reply.
  2. Beside the other suggestion to use Items of HttpContext, I want to note that you can inject services into Action Filters:

    public class ResultFilter : IActionFilter
    {
    
        // Inject anything you want
        IHostEnvironment env;
        public ResultFilter(IHostEnvironment env)
        {
            this.env = env;
        }
    
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Result is OkObjectResult result)
            {
                result.Value = JsonSerializer.Serialize(new
                {
                    Value = result.Value,
                    Environment = this.env.EnvironmentName,
                });
            }
        }
    
        public void OnActionExecuting(ActionExecutingContext context) { }
    }
    
    

    Register to DI Builder:

    services.AddScoped<ResultFilter>();
    

    Apply to action/controller:

        [HttpGet, Route("/test"), ServiceFilter(typeof(ResultFilter))]
        public IActionResult ReturnOk()
        {
            return this.Ok(new
            {
                Value = 1,
            });
        }
    

    Testing by accessing the URL:

    {"Value":{"Value":1},"Environment":"Development"}
    
    Login or Signup to reply.
  3. Another alternative is to use DI service with Scoped lifetime.

    Scoped objects are the same for a given request but differ across each new request.

    Service:

    public interface IMyRequestDataService
    {
        object? MyData { get; set; }
    }
    
    public class MyRequestDataService : IMyRequestDataService
    {
    
        public object? MyData { get; set; }
    
    }
    

    Register to DI:

    services.AddScoped<IMyRequestDataService, MyRequestDataService>();
    

    Set data in Controller:

        readonly IMyRequestDataService dataService;
        public TestController(IMyRequestDataService dataService)
        {
            this.dataService = dataService;
        }
    
        [HttpGet, Route("/test-scoped")]
        public IActionResult ReturnObj()
        {
            this.dataService.MyData = new
            {
                Value = 1,
            };
    
            return this.Ok();
        }
    

    Your middleware that consumes it:

    class CustomMiddleware
    {
        readonly RequestDelegate next;
        public CustomMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
    
        // Add DI Services here
        public async Task InvokeAsync(HttpContext httpContext, IMyRequestDataService dataService, IHostEnvironment env)
        {
            await this.next(httpContext);
    
            // Data should be here
            if (dataService.MyData != null)
            {
                // Do something with it
                await httpContext.Response.WriteAsJsonAsync(new
                {
                    Data = dataService.MyData,
                    Env = env.EnvironmentName,
                });
            }
        }
    
    }
    
    // Register it:
    app.UseMiddleware<CustomMiddleware>();
    
    // Make sure it's before the Controller middleware since we wrap it around the next()
    // ...
    
    app.MapControllers();
    

    Test with the URL:

    {"data":{"value":1},"env":"Development"}
    
    Login or Signup to reply.
  4. You can store data in HTTP context items.

    In controller action:

    Request.HttpContext.Items.Add("SomeKey", data);
    

    In middleware:

    object data = httpContext.Items["SomeKey"];
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search