27

I am using ASP.NET Core Web API, where I have Multiple independent web api projects. Before executing any of the controllers' actions, I have to check if the the logged in user is already impersonating other user (which i can get from DB) and can pass the impersonated user Id to the actions.

Since this is a piece of code that gonna be reused, I thought I can use a middleware so:

  • I can get the initial user login from request header
  • Get the impesonated User Id if any
  • Inject that ID in the request pipeline to make it available to the api being called
public class GetImpersonatorMiddleware
{
    private readonly RequestDelegate _next;
    private IImpersonatorRepo _repo { get; set; }

    public GetImpersonatorMiddleware(RequestDelegate next, IImpersonatorRepo imperRepo)
    {
        _next = next;
        _repo = imperRepo;
    }
    public async Task Invoke(HttpContext context)
    {
        //get user id from identity Token
        var userId = 1;

        int impersonatedUserID = _repo.GetImpesonator(userId);

        //how to pass the impersonatedUserID so it can be picked up from controllers
        if (impersonatedUserID > 0 )
            context.Request.Headers.Add("impers_id", impersonatedUserID.ToString());

        await _next.Invoke(context);
    }
}

I found this Question, but that didn't address what I am looking for.

How can I pass a parameter and make it available in the request pipeline? Is it Ok to pass it in the header or there is more elegant way to do this?

ArunPratap
  • 4,816
  • 7
  • 25
  • 43
Hussein Salman
  • 7,806
  • 15
  • 60
  • 98
  • You should change the request context, not the pipeline itself. – Lex Li Mar 14 '17 at 14:08
  • @LexLi, Can you please elaborate by an example, Do you mean adding some information to the request itself and get that from controller? If that what have you meant, I was thinking about that, but again where, querysting, body, wouldn't that affect the called action? – Hussein Salman Mar 14 '17 at 14:37

2 Answers2

28

You can use HttpContext.Items to pass arbitrary values inside the pipeline:

context.Items["some"] = "value";
Ricardo Peres
  • 13,724
  • 5
  • 57
  • 74
13

A better solution would be to use a scoped service. Take a look at this: Per-request middleware dependencies

Your code should look like:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext, IImpersonatorRepo imperRepo)
    {
        imperRepo.MyProperty = 1000;
        await _next(httpContext);
    }
}

And then register your ImpersonatorRepo as:

services.AddScoped<IImpersonatorRepo, ImpersonatorRepo>()
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Motumbo
  • 655
  • 1
  • 8
  • 12
  • 3
    This is not working when you try to use the service per-request outside the middleware. See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1#per-request-middleware-dependencies – Sven Dec 04 '19 at 13:57