I have created an AmbientDataProvider
that is intended to be to access query params that are set in a lot of my requests. In a few cases, I would like to set it manually, e.g.
[HttpGet]
public IHttpActionResult SomeAction()
{
_ambientDataProvider.SetRequestId("123");
return Ok();
}
Is there any point of keeping it as AsyncLocal
below? Since the class has a scoped lifestyle, I guess I might as well use a private string?
public class AmbientDataProvider : IAmbientDataProvider
{
private readonly AsyncLocal<string> _requestId = new AsyncLocal<string>();
public string RequestId => _requestId.Value ?? HttpContext.Current?.Request.QueryString["requestId"];
public void SetRequestId(string requestId)
{
_requestId.Value = requestId;
}
}
My container configuration
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IAmbientDataProvider, AmbientDataProvider>(Lifestyle.Scoped);
When it comes to pushing runtime data through an object graph, there are two DI Composition Models to choose from: Ambient Composition Model and Closure Composition Model.
You seem to mixing the two models. With the Closure Composition Model you store runtime data (your request id) in a (private) field inside a component, whereas with the Ambient Composition Model, you store that runtime data as ambient state (for instance using AsyncLocal<T>
).
When using the Ambient Composition Model, you can make your AmbientDataProvider
singleton, because the AsyncLocal<T>
already ensures isolation of runtime data per request. When your data provider is a Scoped component, however, you can also store the data in a private field.