ASP.NET Core - Add Custom Property to HttpRequest

Viewed 1694

I have some ASP.NET Middleware that analyzes a request as it comes in. Based on what's available in that HttpRequest, I would like to add a custom property that I can use in my code. My question is, is there a way for me to add a property to HttpRequest so that I can access it in my controller? For example, in my Controller, I would like to do something like this:

namespace MyWebsite.Controllers
{
  public class MyController : Controller

  public IActionResult Index()
  {
    if (this.Request.MyProperty == null)
    {
      return View("~/Views/NoExist.cshtml");
    }
    return View ("/Views/Index.cshtml");
  }
}

MyProperty represents the custom property that I would like to inject, or add, via my custom middleware. Is this possible? If so, how? If not, what is the recommended approach?

Thank you!

2 Answers

The traditional way of achieving what you want is sharing everything via HttpContext.Items. That way you should manage the keys yourself or even can declare your extension methods for conveniently setting & getting the values.

However here I'd like to introduce a new way associated with a new concept request feature in asp.net core. The features associated with each request can be added by different middlewares along the pipeline and can be consumed by any (if available). That looks like neater and more organized, although may not be very convenient compared to the old way.

Suppose you're in the context of your middleware, the following code will add a feature which exposes your property:

//declare the feature interface first
public interface IMyFeature {
    string MyProperty {get;}
}

//the concrete type for the feature
public class MyFeature : IMyFeature {
    public MyFeature(string myProperty){
        MyProperty = myProperty;
    }
    public string MyProperty {get;}
}

//the context is in your middleware
//add the feature
var myFeature = new MyFeature("value of your choice");
//context here is the HttpContext
context.Features.Set<IMyFeature>(myFeature);

Now anywhere later in the pipeline, you can consume the feature added like this:

//context here is the HttpContext
var myFeature = context.Features.Get<IMyFeature>();
if(myFeature != null){
    //consume your feature
}

One point I think the request features concept is good about is its clear definition of feature interfaces which can be learned, referenced and managed easily by your code. Even porting it to some library for reusing makes more sense than depending on some constant key for accessing the shared data (as achieved by using HttpContext.Items). Of course for some simple data sharing, you can just use HttpContext.Items, the request feature should be used when it may evolve later, has a clear cool concept around it and may contain more data.

  1. Create a singleton that has a readonly ConcurrentDictionary property. Alternatively, create a static class with a readonly static property of type ConcurrentDictionary.

  2. Add a readonly Queue property to your global class.

  3. Use the HttpContext.TraceIdentifier as a unique key and add the data to the ConcurrentDictionary as the value. Also add the HttpContext.TraceIdentifier and DateTime.Now to the Queue property.

  4. Create a clean-up method that removes old data from the Queue and ConcurrentDictionary by pulling data off the Queue until it is under a particular age, say 90 seconds.

  5. Create a background worker that runs periodically and calls the cleanup method. There are libraries that do this. You can also spin off a thread at startup, but this lacks redundancy unless you code it.

  6. Access your data from any called code using the key HttpContext.TraceIdentifier.

Happy Coding!

Related