Created
December 5, 2023 09:34
-
-
Save martijnlentink/da862d759fe989b8b0e7b6a7c4063104 to your computer and use it in GitHub Desktop.
Get the URL of HTTP triggered Azure Function including path/query parameters. GetUrl(nameof(FunctionClass.Run))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Namespace.Helpers | |
using Microsoft.Azure.Functions.Worker; | |
using Microsoft.AspNetCore.Routing.Template; | |
using System.Reflection; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Microsoft.AspNetCore.Routing; | |
using Microsoft.AspNetCore.Routing.Internal; | |
using Microsoft.Extensions.ObjectPool; | |
using System.Text.Encodings.Web; | |
public class UrlFunctionsHelper | |
{ | |
private static readonly Lazy<(FunctionAttribute? fnAttr, ParameterInfo[] parameters)[]> FunctionNameAttributesLazy = new (() => Assembly | |
.GetExecutingAssembly() | |
.GetTypes() | |
.SelectMany(x => x.GetMethods()) | |
.Select(x => (x.GetCustomAttribute<FunctionAttribute>(), x.GetParameters())) | |
.Where(x => x.Item1 is not null) | |
.ToArray() | |
); | |
public static Uri GetUrl(string functionName, IDictionary<string, string>? routeValues = default) | |
{ | |
var correspondingAttribute = FunctionNameAttributesLazy.Value | |
.FirstOrDefault(x => x.fnAttr?.Name == functionName); | |
if (correspondingAttribute.fnAttr is null) | |
{ | |
throw new InvalidOperationException($"'{functionName}' is not a valid Azure Function, please make sure the {nameof(FunctionAttribute)} was set correctly"); | |
} | |
#if DEBUG | |
const string scheme = "http"; | |
#else | |
const string scheme = "https"; | |
#endif | |
var hostname = Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME"); | |
var httpTrigger = correspondingAttribute.parameters | |
.Select(x => x.GetCustomAttribute<HttpTriggerAttribute>()) | |
.SingleOrDefault(); | |
if (httpTrigger is null) | |
{ | |
throw new InvalidOperationException( | |
$"Provided function had no parameter with attribute of type {nameof(HttpTriggerAttribute)}"); | |
} | |
var preparedRoute = ParseRouteTemplate(httpTrigger?.Route ?? functionName, routeValues); | |
return new Uri($"{scheme}://{hostname}/api{preparedRoute}"); | |
} | |
private static string? ParseRouteTemplate(string route, IDictionary<string, string>? routeValues) | |
{ | |
var templateRoute = TemplateParser.Parse(route); | |
var pool = new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy()); | |
var templateBinder = new TemplateBinder(UrlEncoder.Default, pool, templateRoute, defaults: null); | |
return templateBinder.BindValues(new RouteValueDictionary(routeValues)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment