Azure / Azure/azure-functions-dotnet-worker
Make FunctionContext available as a Dependency Type ( Like IHttpContextAccessor)
- Dominant language
- C#
- Stars
- 466
- Forks
- 215
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 7
Description
### Enhancement Introduction
Currently current FunctionContext available as a input parameter to Function.
```
[Function("HelloWorld")]
public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "send")] HttpRequestData req
,FunctionContext functionContext)
```
Now if there is any dependency that called as part of above function implementation then It required explicit pass of FunctionContext. If compare is with asp.net core web api structure then we have IHttpContextAccessor. In can be available to access in downstream call. For example if there is to create HttpClient from IHttpClientFactory and It has custom message handler which required FunctionContext.
```
services.AddHttpClient("Call", client =>
{
client.BaseAddress = new Uri("http://localhost");
}).AddHttpMessageHandler();
```
ExampleMessageHandler looks like following.
```
public class ExampleHttpMessageHandler : DelegatingHandler
{
private readonly FunctionContext functionContext;
public ExampleHttpMessageHandler(FunctionContext functionContext)
{
this.functionContext = functionContext;
}
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken);
}
}
```
Currently above will not work as FunctionContext is not available as dependency.
### Possible Solution
- Create Contract
```
public interface IFunctionContextAccessor
{
public FunctionContext? FunctionContext { get; set; }
}
```
- Implementation
```
internal sealed class DefaultFunctionContextAccessor
: IFunctionContextAccessor
{
private static readonly AsyncLocal _functionContextCurrent = new AsyncLocal();
public FunctionContext? FunctionContext
{
get
{
return _functionContextCurrent.Value?.Context;
}
set
{
var holder = _functionContextCurrent.Value;
if (holder != null)
{
holder.Context = null;
}
if (value != null)
{
_functionContextCurrent.Value = new FunctionContextHolder { Context = value };
}
}
}
private class FunctionContextHolder
{
public FunctionContext? Context;
}
}
```
Current Approach ( As Middleware is only approach )
```
public class FunctionContextMiddleware : IFunctionsWorkerMiddleware
{
public Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
{
var _functionContextAccessor = context.InstanceServices.GetService();
if (_functionContextAccessor != null)
{
_functionContextAccessor.FunctionContext = context;
}
return next(context);
}
}
```
This is how it is being used.
```
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(worker =>
{
worker.UseMiddleware();
})
.ConfigureServices(services =>
{
services.AddSingleton();
})
.Build();
host.Run();
```
### Suggestion
- If this has been taken as an enhancement then it required to integrate in `GrpcWorker.cs` . In this when FunctionContext is being created and we can inject invocation feature so IFunctionContextAccessor available.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.