[{"data":1,"prerenderedAt":4862},["Reactive",2],{"navigation":3,"aAII9Cz3yR":204,"tags-Azure Functions":397},[4,192,200],{"title":5,"_path":6,"children":7,"icon":191},"Blog","/posts",[8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,98,101,104,107,110,113,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,167,170,173,176,179,182,185,188],{"title":9,"_path":10},"Testing your API with REST Client","/posts/testing-your-api-with-rest-client",{"title":12,"_path":13},"HTML templating in Xamarin","/posts/html-templating-in-xamarin",{"title":15,"_path":16},"Goodbye Azure Portal, Welcome Azure CLI","/posts/welcome-azure-cli",{"title":18,"_path":19},"Coming across Gitpod","/posts/gitpod",{"title":21,"_path":22},"Handle token retrieval while querying an API","/posts/delegating-handler",{"title":24,"_path":25},"Clean up your local git branches.","/posts/cleaning-git-branches",{"title":27,"_path":28},"Automate configuration of Teams Tab SSO with PowerShell.","/posts/teams-sso-powershell",{"title":30,"_path":31},"How to do a technology watch? - Part 1","/posts/technology-watch-part1",{"title":33,"_path":34},"How to do a technology watch? - Part 2","/posts/technology-watch-part2",{"title":36,"_path":37},"You almost no longer need Key Vault references for Azure Functions.","/posts/azure-functions-custom-configuration",{"title":39,"_path":40},"How to do a technology watch? - Part 3","/posts/technology-watch-part3",{"title":42,"_path":43},"Forget DevOps, the future is already here!","/posts/devops-future",{"title":45,"_path":46},"Week 9, 2021 - Tips I learned this week","/posts/w09-2021-tips-learned-this-week",{"title":48,"_path":49},"Week 12, 2021 - Tips I learned this week","/posts/w12-2021-tips-learned-this-week",{"title":51,"_path":52},"Week 14, 2021 - Tips I learned this week","/posts/w14-2021-tips-learned-this-week",{"title":54,"_path":55},"Once upon a time in .NET","/posts/once-upon-a-time-in-dotnet",{"title":57,"_path":58},"Install your applications with winget","/posts/winget-import",{"title":60,"_path":61},"Customize your applications when installing them with winget","/posts/winget-override",{"title":63,"_path":64},"Week 22, 2021 - Tips I learned this week","/posts/w22-2021-tips-learned-this-week",{"title":66,"_path":67},"How to connect to an Azure SQL Database from C# using Azure AD","/posts/sqlclient-active-directory-authent",{"title":69,"_path":70},"Producing packages for Windows Package Manager","/posts/wingetcreate",{"title":72,"_path":73},"4 tips about GitHub Actions environment variables and contexts","/posts/github-actions-var-and-context",{"title":75,"_path":76},"AzureWebJobsStorage, the secret you don't need in your Function App.","/posts/azure-functions-without-azurewebjobsstorage",{"title":78,"_path":79},"ASP.NET Core - Lost in configuration","/posts/lost-in-configuration",{"title":81,"_path":82},"Week 39, 2021 - Tips I learned this week","/posts/w39-2021-tips-learned-this-week",{"title":84,"_path":85},"Week 41, 2021 - Tips I learned this week","/posts/w41-2021-tips-learned-this-week",{"title":87,"_path":88},"Migrating and open-sourcing my blog","/posts/migrating-blog",{"title":90,"_path":91},"Week 45, 2021 - Tips I learned this week","/posts/w45-2021-tips-learned-this-week",{"title":93,"_path":94},"Organize your GitHub stars with Astral","/posts/astral",{"title":96,"_path":97},"Pulumi with an Azure Blob Storage backend","/posts/pulumi-azure-backend",{"title":99,"_path":100},"IaC Hot Reload with Pulumi Watch","/posts/pulumi-watch",{"title":102,"_path":103},"Week 2, 2022 - Tips I learned this week","/posts/w02-2022-tips-learned-this-week",{"title":105,"_path":106},"Week 3, 2022 - Tips I learned this week","/posts/w03-2022-tips-learned-this-week",{"title":108,"_path":109},"Week 5, 2022 - Tips I learned this week","/posts/w05-2022-tips-learned-this-week",{"title":111,"_path":112},"How to provision an Azure SQL Database with Active Directory authentication","/posts/sqldatabase-active-directory-authent",{"title":114,"_path":115},"Why will I choose Pulumi over Terraform for my next project?","/posts/pulumi-vs-terraform",{"title":117,"_path":118},"Week 19, 2022 - Tips I learned this week","/posts/w19-2022-tips-learned-this-week",{"title":120,"_path":121},"Week 20, 2022 - Tips I learned this week","/posts/w20-2022-tips-learned-this-week",{"title":123,"_path":124},"Keeping secrets secure when using API Clients","/posts/http-clients-secrets",{"title":126,"_path":127},"What made me want to be a developer?","/posts/be-a-developer",{"title":129,"_path":130},"What can we do when stuck with a programming problem?","/posts/get-unstuck",{"title":132,"_path":133},"How did I automate the setup of my developer Windows laptop?","/posts/automate-developer-machine",{"title":135,"_path":136},"Discussion about API clients","/posts/http-clients",{"title":138,"_path":139},"Week 46, 2022 - Tips I learned this week","/posts/w46-2022-tips-learned-this-week",{"title":141,"_path":142},"When Pulumi met Nuke: a .NET love story","/posts/when-pulumi-met-nuke",{"title":144,"_path":145},"A year of learning and sharing - Dev Retro 2022","/posts/2022-retro",{"title":147,"_path":148},"Perform Dynamic Execution of an npm Package","/posts/pnpm-dlx",{"title":150,"_path":151},"Manage multiple Node.js versions","/posts/pnpm-env",{"title":153,"_path":154},"Introducing the Vue.js CI/CD series","/posts/vuecicd-introduction",{"title":156,"_path":157},"Execute commands using your project dependencies","/posts/pnpm-exec",{"title":159,"_path":160},"Vue.js CI/CD: Continuous Integration","/posts/vuecicd-ci",{"title":162,"_path":163},"Who is using pnpm?","/posts/pnpm-who-is-using",{"title":165,"_path":166},"Create an Azure-Ready GitHub Repository using Pulumi","/posts/azure-ready-github-repository",{"title":168,"_path":169},"Deploying to Azure from Azure DevOps without secrets","/posts/ado-workload-identity-federation",{"title":171,"_path":172},"Effortlessly Configure GitHub Repositories for Azure Deployment via OIDC","/posts/scripting-azure-ready-github-repository",{"title":174,"_path":175},"Playing with the .NET 8 Web API template","/posts/playing-with-dotnet8",{"title":177,"_path":178},"Another year of sharing and learning - Dev Retro 2023","/posts/2023-retro",{"title":180,"_path":181},"Week 4, 2024 - Tips I learned this week","/posts/w04-2024-tips-learned-this-week",{"title":183,"_path":184},"Using dependency injection with Azure .NET SDK","/posts/azure-sdk-di",{"title":186,"_path":187},"Having Fun With IT Event Calendars","/posts/it-event-calendars",{"title":189,"_path":190},"Call your Azure AD B2C protected API with authenticated HTTP requests from your JetBrains IDE","/posts/http-clients-oauth2","i-heroicons-newspaper",{"title":193,"_path":194,"children":195,"icon":199},"Goodies","/goodies",[196],{"title":197,"_path":198},"My Git Cheat Sheet","/goodies/gitcheatsheet","i-heroicons-gift-solid",{"title":201,"_path":202,"icon":203},"About","/about","i-heroicons-user-circle-solid",[205,207,209,211,214,217,220,223,226,229,231,234,237,240,242,244,247,250,253,255,258,261,264,267,270,273,276,279,282,285,287,289,292,294,297,300,303,305,308,310,313,316,319,322,325,327,329,332,335,338,341,344,347,350,353,356,359,361,363,366,369,372,375,377,380,383,385,388,391,394],[206,206],"tooling",[208,208],"vscode",[210,210],"rest",[212,213],"http","HTTP",[215,216],"razor","Razor",[218,219],"xamarin","Xamarin",[221,222],"templating","Templating",[224,225],"azure-cli","Azure CLI",[227,228],"azure","Azure",[230,230],"shell",[232,233],"github","GitHub",[235,236],"asp-net-core","ASP.NET Core",[238,239],"net",".NET",[241,241],"git",[243,243],"nushell",[245,246],"microsoft-teams","Microsoft Teams",[248,249],"powershell","PowerShell",[251,252],"azure-active-directory","Azure Active Directory",[254,254],"learning",[256,257],"azure-functions","Azure Functions",[259,260],"azure-key-vault","Azure Key Vault",[262,263],"configuration","Configuration",[265,266],"devops","DevOps",[268,269],"it","IT",[271,272],"tips-learned-this-week","tips learned this week",[274,275],"windows-terminal","Windows Terminal",[277,278],"azure-pipelines","Azure Pipelines",[280,281],"application-insights","Application Insights",[283,284],"azure-iot","Azure IoT",[286,286],"records",[288,288],"refit",[290,291],"development-box-setup","development box setup",[293,293],"winget",[295,296],"package-manager","package manager",[298,299],"azure-sql-database","Azure SQL Database",[301,302],"azure-sdk","Azure SDK",[304,304],"wingetcreate",[306,307],"github-actions","GitHub Actions",[309,309],"jq",[311,312],"pulumi","Pulumi",[314,315],"iac","IaC",[317,318],"azure-storage","Azure Storage",[320,321],"azure-signalr","Azure SignalR",[323,324],"visio","Visio",[326,326],"csharp",[328,328],"jest",[330,331],"statiq","Statiq",[333,334],"open-source","open source",[336,337],"visual-studio","Visual Studio",[339,340],"vue-js","Vue.js",[342,343],"azure-devops","Azure DevOps",[345,346],"vite","Vite",[348,349],"code-analysis","Code analysis",[351,352],"diagram","Diagram",[354,355],"terraform","Terraform",[357,358],"typescript","TypeScript",[360,360],"thoughts",[362,362],"pnpm",[364,365],"nuke","Nuke",[367,368],"pipelines","Pipelines",[370,371],"cicd","CI/CD",[373,374],"openid-connect","OpenID Connect",[376,376],"security",[378,379],"github-cli","GitHub CLI",[381,382],"microsoft-entra-id","Microsoft Entra ID",[384,384],"advent",[386,387],"finops","FinOps",[389,390],"anglesharp","AngleSharp",[392,393],"oauth2","OAuth2",[395,396],"azure-ad-b2c","Azure AD B2C",[398,1280,2462,4465],{"_path":181,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":180,"description":402,"lead":402,"date":403,"image":404,"badge":406,"tags":408,"ImageAttribution":409,"body":410,"_type":1275,"_id":1276,"_source":1277,"_file":1278,"_extension":1279},"posts",false,"","Some tips about Azure and Azure DevOps.","2024-01-29T00:00:00.000Z",{"src":405},"/images/surface_1.jpg",{"label":407},"Tips",[272,257,387,343],"Picture of \u003Ca href=\"https://unsplash.com/fr/@surface?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash\">Surface\u003C/a> on \u003Ca href=\"https://unsplash.com/fr/photos/appareil-surface-sur-la-table-taHYzvApW1o?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash\">Unsplash\u003C/a>",{"type":411,"children":412,"toc":1270},"root",[413,422,428,433,883,899,911,916,921,941,950,955,1140,1151,1161,1167,1172,1201,1206,1215,1221,1226,1231,1245,1254,1259,1264],{"type":414,"tag":415,"props":416,"children":418},"element","h2",{"id":417},"easily-debug-a-non-http-triggered-azure-function",[419],{"type":420,"value":421},"text","Easily debug a non-HTTP-triggered Azure Function",{"type":414,"tag":423,"props":424,"children":425},"p",{},[426],{"type":420,"value":427},"The other day, I wanted to locally debug a Queue-triggered function without manually adding a queue message to my local storage.",{"type":414,"tag":423,"props":429,"children":430},{},[431],{"type":420,"value":432},"My Azure Function looked like that:",{"type":414,"tag":434,"props":435,"children":438},"pre",{"className":436,"code":437,"language":326,"meta":401,"style":401},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","public record Order(string Product,int Count);\n\npublic class ProcessOrder\n{\n    private readonly ILogger\u003CProcessOrder> _logger;\n\n    public ProcessOrder(ILogger\u003CProcessOrder> logger)\n    {\n        _logger = logger;\n    }\n\n    [Function(nameof(ProcessOrder))]\n    public void Run([QueueTrigger(\"orders\")] Order sentOrder)\n    {\n        _logger.LogInformation($\"Order contains {sentOrder.Count} {sentOrder.Product}\");\n    }\n}\n",[439],{"type":414,"tag":440,"props":441,"children":442},"code",{"__ignoreMap":401},[443,497,507,525,534,578,586,632,641,664,673,681,709,774,782,866,874],{"type":414,"tag":444,"props":445,"children":448},"span",{"class":446,"line":447},"line",1,[449,455,461,466,472,477,482,487,492],{"type":414,"tag":444,"props":450,"children":452},{"style":451},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[453],{"type":420,"value":454},"public",{"type":414,"tag":444,"props":456,"children":458},{"style":457},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[459],{"type":420,"value":460}," record",{"type":414,"tag":444,"props":462,"children":463},{"style":457},[464],{"type":420,"value":465}," Order",{"type":414,"tag":444,"props":467,"children":469},{"style":468},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[470],{"type":420,"value":471},"(",{"type":414,"tag":444,"props":473,"children":474},{"style":468},[475],{"type":420,"value":476},"string",{"type":414,"tag":444,"props":478,"children":479},{"style":457},[480],{"type":420,"value":481}," Product",{"type":414,"tag":444,"props":483,"children":484},{"style":468},[485],{"type":420,"value":486},",int",{"type":414,"tag":444,"props":488,"children":489},{"style":457},[490],{"type":420,"value":491}," Count",{"type":414,"tag":444,"props":493,"children":494},{"style":468},[495],{"type":420,"value":496},");\n",{"type":414,"tag":444,"props":498,"children":500},{"class":446,"line":499},2,[501],{"type":414,"tag":444,"props":502,"children":504},{"emptyLinePlaceholder":503},true,[505],{"type":420,"value":506},"\n",{"type":414,"tag":444,"props":508,"children":510},{"class":446,"line":509},3,[511,515,520],{"type":414,"tag":444,"props":512,"children":513},{"style":451},[514],{"type":420,"value":454},{"type":414,"tag":444,"props":516,"children":517},{"style":457},[518],{"type":420,"value":519}," class",{"type":414,"tag":444,"props":521,"children":522},{"style":457},[523],{"type":420,"value":524}," ProcessOrder\n",{"type":414,"tag":444,"props":526,"children":528},{"class":446,"line":527},4,[529],{"type":414,"tag":444,"props":530,"children":531},{"style":468},[532],{"type":420,"value":533},"{\n",{"type":414,"tag":444,"props":535,"children":537},{"class":446,"line":536},5,[538,543,548,553,558,563,568,573],{"type":414,"tag":444,"props":539,"children":540},{"style":451},[541],{"type":420,"value":542},"    private",{"type":414,"tag":444,"props":544,"children":545},{"style":451},[546],{"type":420,"value":547}," readonly",{"type":414,"tag":444,"props":549,"children":550},{"style":457},[551],{"type":420,"value":552}," ILogger",{"type":414,"tag":444,"props":554,"children":555},{"style":468},[556],{"type":420,"value":557},"\u003C",{"type":414,"tag":444,"props":559,"children":560},{"style":457},[561],{"type":420,"value":562},"ProcessOrder",{"type":414,"tag":444,"props":564,"children":565},{"style":468},[566],{"type":420,"value":567},">",{"type":414,"tag":444,"props":569,"children":570},{"style":457},[571],{"type":420,"value":572}," _logger",{"type":414,"tag":444,"props":574,"children":575},{"style":468},[576],{"type":420,"value":577},";\n",{"type":414,"tag":444,"props":579,"children":581},{"class":446,"line":580},6,[582],{"type":414,"tag":444,"props":583,"children":584},{"emptyLinePlaceholder":503},[585],{"type":420,"value":506},{"type":414,"tag":444,"props":587,"children":589},{"class":446,"line":588},7,[590,595,601,605,610,614,618,622,627],{"type":414,"tag":444,"props":591,"children":592},{"style":451},[593],{"type":420,"value":594},"    public",{"type":414,"tag":444,"props":596,"children":598},{"style":597},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[599],{"type":420,"value":600}," ProcessOrder",{"type":414,"tag":444,"props":602,"children":603},{"style":468},[604],{"type":420,"value":471},{"type":414,"tag":444,"props":606,"children":607},{"style":457},[608],{"type":420,"value":609},"ILogger",{"type":414,"tag":444,"props":611,"children":612},{"style":468},[613],{"type":420,"value":557},{"type":414,"tag":444,"props":615,"children":616},{"style":457},[617],{"type":420,"value":562},{"type":414,"tag":444,"props":619,"children":620},{"style":468},[621],{"type":420,"value":567},{"type":414,"tag":444,"props":623,"children":624},{"style":457},[625],{"type":420,"value":626}," logger",{"type":414,"tag":444,"props":628,"children":629},{"style":468},[630],{"type":420,"value":631},")\n",{"type":414,"tag":444,"props":633,"children":635},{"class":446,"line":634},8,[636],{"type":414,"tag":444,"props":637,"children":638},{"style":468},[639],{"type":420,"value":640},"    {\n",{"type":414,"tag":444,"props":642,"children":644},{"class":446,"line":643},9,[645,651,656,660],{"type":414,"tag":444,"props":646,"children":648},{"style":647},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[649],{"type":420,"value":650},"        _logger ",{"type":414,"tag":444,"props":652,"children":653},{"style":468},[654],{"type":420,"value":655},"=",{"type":414,"tag":444,"props":657,"children":658},{"style":647},[659],{"type":420,"value":626},{"type":414,"tag":444,"props":661,"children":662},{"style":468},[663],{"type":420,"value":577},{"type":414,"tag":444,"props":665,"children":667},{"class":446,"line":666},10,[668],{"type":414,"tag":444,"props":669,"children":670},{"style":468},[671],{"type":420,"value":672},"    }\n",{"type":414,"tag":444,"props":674,"children":676},{"class":446,"line":675},11,[677],{"type":414,"tag":444,"props":678,"children":679},{"emptyLinePlaceholder":503},[680],{"type":420,"value":506},{"type":414,"tag":444,"props":682,"children":684},{"class":446,"line":683},12,[685,690,695,700,704],{"type":414,"tag":444,"props":686,"children":687},{"style":468},[688],{"type":420,"value":689},"    [",{"type":414,"tag":444,"props":691,"children":692},{"style":457},[693],{"type":420,"value":694},"Function",{"type":414,"tag":444,"props":696,"children":697},{"style":468},[698],{"type":420,"value":699},"(nameof(",{"type":414,"tag":444,"props":701,"children":702},{"style":647},[703],{"type":420,"value":562},{"type":414,"tag":444,"props":705,"children":706},{"style":468},[707],{"type":420,"value":708},"))]\n",{"type":414,"tag":444,"props":710,"children":712},{"class":446,"line":711},13,[713,717,722,727,732,737,741,746,752,756,761,765,770],{"type":414,"tag":444,"props":714,"children":715},{"style":451},[716],{"type":420,"value":594},{"type":414,"tag":444,"props":718,"children":719},{"style":468},[720],{"type":420,"value":721}," void",{"type":414,"tag":444,"props":723,"children":724},{"style":597},[725],{"type":420,"value":726}," Run",{"type":414,"tag":444,"props":728,"children":729},{"style":468},[730],{"type":420,"value":731},"([",{"type":414,"tag":444,"props":733,"children":734},{"style":457},[735],{"type":420,"value":736},"QueueTrigger",{"type":414,"tag":444,"props":738,"children":739},{"style":468},[740],{"type":420,"value":471},{"type":414,"tag":444,"props":742,"children":743},{"style":468},[744],{"type":420,"value":745},"\"",{"type":414,"tag":444,"props":747,"children":749},{"style":748},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[750],{"type":420,"value":751},"orders",{"type":414,"tag":444,"props":753,"children":754},{"style":468},[755],{"type":420,"value":745},{"type":414,"tag":444,"props":757,"children":758},{"style":468},[759],{"type":420,"value":760},")]",{"type":414,"tag":444,"props":762,"children":763},{"style":457},[764],{"type":420,"value":465},{"type":414,"tag":444,"props":766,"children":767},{"style":457},[768],{"type":420,"value":769}," sentOrder",{"type":414,"tag":444,"props":771,"children":772},{"style":468},[773],{"type":420,"value":631},{"type":414,"tag":444,"props":775,"children":777},{"class":446,"line":776},14,[778],{"type":414,"tag":444,"props":779,"children":780},{"style":468},[781],{"type":420,"value":640},{"type":414,"tag":444,"props":783,"children":785},{"class":446,"line":784},15,[786,791,796,801,805,810,815,820,825,829,834,839,844,848,852,857,862],{"type":414,"tag":444,"props":787,"children":788},{"style":647},[789],{"type":420,"value":790},"        _logger",{"type":414,"tag":444,"props":792,"children":793},{"style":468},[794],{"type":420,"value":795},".",{"type":414,"tag":444,"props":797,"children":798},{"style":597},[799],{"type":420,"value":800},"LogInformation",{"type":414,"tag":444,"props":802,"children":803},{"style":468},[804],{"type":420,"value":471},{"type":414,"tag":444,"props":806,"children":807},{"style":468},[808],{"type":420,"value":809},"$\"",{"type":414,"tag":444,"props":811,"children":812},{"style":748},[813],{"type":420,"value":814},"Order contains ",{"type":414,"tag":444,"props":816,"children":817},{"style":468},[818],{"type":420,"value":819},"{",{"type":414,"tag":444,"props":821,"children":822},{"style":647},[823],{"type":420,"value":824},"sentOrder",{"type":414,"tag":444,"props":826,"children":827},{"style":468},[828],{"type":420,"value":795},{"type":414,"tag":444,"props":830,"children":831},{"style":647},[832],{"type":420,"value":833},"Count",{"type":414,"tag":444,"props":835,"children":836},{"style":468},[837],{"type":420,"value":838},"}",{"type":414,"tag":444,"props":840,"children":841},{"style":468},[842],{"type":420,"value":843}," {",{"type":414,"tag":444,"props":845,"children":846},{"style":647},[847],{"type":420,"value":824},{"type":414,"tag":444,"props":849,"children":850},{"style":468},[851],{"type":420,"value":795},{"type":414,"tag":444,"props":853,"children":854},{"style":647},[855],{"type":420,"value":856},"Product",{"type":414,"tag":444,"props":858,"children":859},{"style":468},[860],{"type":420,"value":861},"}\"",{"type":414,"tag":444,"props":863,"children":864},{"style":468},[865],{"type":420,"value":496},{"type":414,"tag":444,"props":867,"children":869},{"class":446,"line":868},16,[870],{"type":414,"tag":444,"props":871,"children":872},{"style":468},[873],{"type":420,"value":672},{"type":414,"tag":444,"props":875,"children":877},{"class":446,"line":876},17,[878],{"type":414,"tag":444,"props":879,"children":880},{"style":468},[881],{"type":420,"value":882},"}\n",{"type":414,"tag":423,"props":884,"children":885},{},[886,888,897],{"type":420,"value":887},"To trigger it, I could simply add a message in the order queue of my ",{"type":414,"tag":889,"props":890,"children":894},"a",{"href":891,"rel":892},"https://github.com/Azure/Azurite",[893],"nofollow",[895],{"type":420,"value":896},"storage emulator",{"type":420,"value":898}," like this:",{"type":414,"tag":423,"props":900,"children":901},{},[902],{"type":414,"tag":903,"props":904,"children":910},"img",{"alt":905,"className":906,"src":909},"Queue message in Azure Storage Explorer.",[907,908],"rounded-lg","mx-auto","/posts/images/w042024tips_storage.webp",[],{"type":414,"tag":423,"props":912,"children":913},{},[914],{"type":420,"value":915},"You may notice that I don't even have to go to the Azure Storage Explorer to add the message, I can do it directly in the IDE. However, call me lazy but I wanted to execute the function just by making an HTTP call, like we do for HTTP-triggered functions.",{"type":414,"tag":423,"props":917,"children":918},{},[919],{"type":420,"value":920},"This way, I could write the HTTP request in an HTTP file, commit it, and push it to my repository to share it with my colleagues, so they don't have to guess what message they should put in the queue to trigger the function.",{"type":414,"tag":423,"props":922,"children":923},{},[924,926,939],{"type":420,"value":925},"Fortunately, the ",{"type":414,"tag":889,"props":927,"children":930},{"href":928,"rel":929},"https://learn.microsoft.com/en-us/azure/azure-functions/functions-manually-run-non-http?tabs=azure-portal#define-the-request-location",[893],[931,937],{"type":414,"tag":932,"props":933,"children":934},"strong",{},[935],{"type":420,"value":936},"documentation",{"type":420,"value":938}," explains",{"type":420,"value":940}," how to do this.",{"type":414,"tag":423,"props":942,"children":943},{},[944],{"type":414,"tag":903,"props":945,"children":949},{"alt":946,"className":947,"src":948},"Define the request location: host name + folder path + function name.",[907,908],"/posts/images/w042024tips_function.webp",[],{"type":414,"tag":423,"props":951,"children":952},{},[953],{"type":420,"value":954},"Thus, for my use case, the resulting request is as follows:",{"type":414,"tag":434,"props":956,"children":959},{"className":957,"code":958,"language":212,"meta":401,"style":401},"language-http shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","POST http://localhost:7071/admin/functions/ProcessOrder HTTP/1.1\nContent-Type: application/json\n\n{\n  \"input\": \"{\\n  \\\"product\\\": \\\"laptop\\\",\\n  \\\"count\\\": 3\\n}\"\n}\n",[960],{"type":414,"tag":440,"props":961,"children":962},{"__ignoreMap":401},[963,992,1011,1018,1025,1133],{"type":414,"tag":444,"props":964,"children":965},{"class":446,"line":447},[966,972,977,982,987],{"type":414,"tag":444,"props":967,"children":969},{"style":968},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[970],{"type":420,"value":971},"POST",{"type":414,"tag":444,"props":973,"children":974},{"style":647},[975],{"type":420,"value":976}," http://localhost:7071/admin/functions/ProcessOrder ",{"type":414,"tag":444,"props":978,"children":980},{"style":979},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[981],{"type":420,"value":213},{"type":414,"tag":444,"props":983,"children":984},{"style":647},[985],{"type":420,"value":986},"/",{"type":414,"tag":444,"props":988,"children":989},{"style":979},[990],{"type":420,"value":991},"1.1\n",{"type":414,"tag":444,"props":993,"children":994},{"class":446,"line":499},[995,1001,1006],{"type":414,"tag":444,"props":996,"children":998},{"style":997},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[999],{"type":420,"value":1000},"Content-Type",{"type":414,"tag":444,"props":1002,"children":1003},{"style":979},[1004],{"type":420,"value":1005},":",{"type":414,"tag":444,"props":1007,"children":1008},{"style":748},[1009],{"type":420,"value":1010}," application/json\n",{"type":414,"tag":444,"props":1012,"children":1013},{"class":446,"line":509},[1014],{"type":414,"tag":444,"props":1015,"children":1016},{"emptyLinePlaceholder":503},[1017],{"type":420,"value":506},{"type":414,"tag":444,"props":1019,"children":1020},{"class":446,"line":527},[1021],{"type":414,"tag":444,"props":1022,"children":1023},{"style":468},[1024],{"type":420,"value":533},{"type":414,"tag":444,"props":1026,"children":1027},{"class":446,"line":536},[1028,1033,1038,1042,1046,1051,1055,1060,1065,1070,1075,1080,1084,1089,1093,1098,1102,1106,1111,1115,1120,1124,1128],{"type":414,"tag":444,"props":1029,"children":1030},{"style":468},[1031],{"type":420,"value":1032},"  \"",{"type":414,"tag":444,"props":1034,"children":1035},{"style":451},[1036],{"type":420,"value":1037},"input",{"type":414,"tag":444,"props":1039,"children":1040},{"style":468},[1041],{"type":420,"value":745},{"type":414,"tag":444,"props":1043,"children":1044},{"style":468},[1045],{"type":420,"value":1005},{"type":414,"tag":444,"props":1047,"children":1048},{"style":468},[1049],{"type":420,"value":1050}," \"",{"type":414,"tag":444,"props":1052,"children":1053},{"style":748},[1054],{"type":420,"value":819},{"type":414,"tag":444,"props":1056,"children":1057},{"style":647},[1058],{"type":420,"value":1059},"\\n",{"type":414,"tag":444,"props":1061,"children":1062},{"style":647},[1063],{"type":420,"value":1064},"  \\\"",{"type":414,"tag":444,"props":1066,"children":1067},{"style":748},[1068],{"type":420,"value":1069},"product",{"type":414,"tag":444,"props":1071,"children":1072},{"style":647},[1073],{"type":420,"value":1074},"\\\"",{"type":414,"tag":444,"props":1076,"children":1077},{"style":748},[1078],{"type":420,"value":1079},": ",{"type":414,"tag":444,"props":1081,"children":1082},{"style":647},[1083],{"type":420,"value":1074},{"type":414,"tag":444,"props":1085,"children":1086},{"style":748},[1087],{"type":420,"value":1088},"laptop",{"type":414,"tag":444,"props":1090,"children":1091},{"style":647},[1092],{"type":420,"value":1074},{"type":414,"tag":444,"props":1094,"children":1095},{"style":748},[1096],{"type":420,"value":1097},",",{"type":414,"tag":444,"props":1099,"children":1100},{"style":647},[1101],{"type":420,"value":1059},{"type":414,"tag":444,"props":1103,"children":1104},{"style":647},[1105],{"type":420,"value":1064},{"type":414,"tag":444,"props":1107,"children":1108},{"style":748},[1109],{"type":420,"value":1110},"count",{"type":414,"tag":444,"props":1112,"children":1113},{"style":647},[1114],{"type":420,"value":1074},{"type":414,"tag":444,"props":1116,"children":1117},{"style":748},[1118],{"type":420,"value":1119},": 3",{"type":414,"tag":444,"props":1121,"children":1122},{"style":647},[1123],{"type":420,"value":1059},{"type":414,"tag":444,"props":1125,"children":1126},{"style":748},[1127],{"type":420,"value":838},{"type":414,"tag":444,"props":1129,"children":1130},{"style":468},[1131],{"type":420,"value":1132},"\"\n",{"type":414,"tag":444,"props":1134,"children":1135},{"class":446,"line":580},[1136],{"type":414,"tag":444,"props":1137,"children":1138},{"style":468},[1139],{"type":420,"value":882},{"type":414,"tag":423,"props":1141,"children":1142},{},[1143,1145,1150],{"type":420,"value":1144},"The content of your queue message goes in the value of the key \"input\" and ",{"type":414,"tag":932,"props":1146,"children":1147},{},[1148],{"type":420,"value":1149},"must be escaped",{"type":420,"value":795},{"type":414,"tag":1152,"props":1153,"children":1155},"callout",{"icon":1154},"i-fluent-emoji-flat-construction",[1156],{"type":414,"tag":423,"props":1157,"children":1158},{},[1159],{"type":420,"value":1160},"If like me, you skim through the documentation, you might miss the \"escape\" requirement and your request will fail so be sure to properly escape your content.",{"type":414,"tag":415,"props":1162,"children":1164},{"id":1163},"the-azure-devops-tip-you-did-not-know-about-azure-pipelines-tasks-name-conflicts",[1165],{"type":420,"value":1166},"The Azure DevOps tip you did not know about: Azure Pipelines tasks name conflicts",{"type":414,"tag":423,"props":1168,"children":1169},{},[1170],{"type":420,"value":1171},"I recently discovered that when you install extensions from the Azure DevOps marketplace, several Azure Pipelines tasks can have the same name. And if you use that name in your pipelines, Azure Pipelines won't know which task you are referring to and will prevent your pipeline from running.",{"type":414,"tag":423,"props":1173,"children":1174},{},[1175,1177,1184,1186,1192,1194,1200],{"type":420,"value":1176},"This can easily occur if you install multiple extensions for Terraform in your Azure DevOps organization. For instance, the extensions ",{"type":414,"tag":889,"props":1178,"children":1181},{"href":1179,"rel":1180},"https://marketplace.visualstudio.com/items?itemName=JasonBJohnson.azure-pipelines-tasks-terraform",[893],[1182],{"type":420,"value":1183},"Azure Pipelines Terraform Tasks",{"type":420,"value":1185}," from Jason Johnson and ",{"type":414,"tag":889,"props":1187,"children":1190},{"href":1188,"rel":1189},"https://marketplace.visualstudio.com/items?itemName=ms-devlabs.custom-terraform-tasks",[893],[1191],{"type":420,"value":355},{"type":420,"value":1193}," from Microsoft Dev Labs both have a task named the same way: ",{"type":414,"tag":440,"props":1195,"children":1197},{"className":1196},[],[1198],{"type":420,"value":1199},"TerraformInstaller",{"type":420,"value":795},{"type":414,"tag":423,"props":1202,"children":1203},{},[1204],{"type":420,"value":1205},"To avoid these conflicts, you must use the full name of the tasks in your pipelines. You can find their full names in the GitHub repository of the extensions. Another way is to use these tasks in a test Release and click on the \"View YAML\" button to see the full name of the task you added.",{"type":414,"tag":423,"props":1207,"children":1208},{},[1209],{"type":414,"tag":903,"props":1210,"children":1214},{"alt":1211,"className":1212,"src":1213},"Screenshot of a release in Azure DevOps.",[907,908],"/posts/images/w042024tips_ado_release.webp",[],{"type":414,"tag":415,"props":1216,"children":1218},{"id":1217},"using-metrics-to-understand-your-usage-of-azure-resources",[1219],{"type":420,"value":1220},"Using metrics to understand your usage of Azure resources",{"type":414,"tag":423,"props":1222,"children":1223},{},[1224],{"type":420,"value":1225},"I don't often use all my monthly free credits of my Azure subscription, but this month my spending limit was quickly reached and my subscription was disabled!",{"type":414,"tag":423,"props":1227,"children":1228},{},[1229],{"type":420,"value":1230},"The cost analysis tab of my subscription showed me that an Azure Maps Account resource was responsible for consuming most of my credits but didn't provide more details.",{"type":414,"tag":423,"props":1232,"children":1233},{},[1234,1236,1243],{"type":420,"value":1235},"So, I went to the Metrics tab of my resource and discovered that I could split the Usage metric by API name to determine exactly which Azure Maps API was heavily used by my applications. Combined with the ",{"type":414,"tag":889,"props":1237,"children":1240},{"href":1238,"rel":1239},"https://azure.microsoft.com/en-us/pricing/details/azure-maps/",[893],[1241],{"type":420,"value":1242},"pricing page",{"type":420,"value":1244},", I can deduce which API requests I'm making too frequently and, therefore how to optimize costs.",{"type":414,"tag":423,"props":1246,"children":1247},{},[1248],{"type":414,"tag":903,"props":1249,"children":1253},{"alt":1250,"className":1251,"src":1252},"Azure Maps usage metrics by API name.",[907,908],"/posts/images/w042024tips_azuremaps_metrics.webp",[],{"type":414,"tag":423,"props":1255,"children":1256},{},[1257],{"type":420,"value":1258},"Depending on the type of resource, you will use different metrics and split on different properties. Regardless, metrics can help you comprehend your resource usage and its associated cost.",{"type":414,"tag":423,"props":1260,"children":1261},{},[1262],{"type":420,"value":1263},"And that's it for this week, happy learning!",{"type":414,"tag":1265,"props":1266,"children":1267},"style",{},[1268],{"type":420,"value":1269},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":401,"searchDepth":499,"depth":499,"links":1271},[1272,1273,1274],{"id":417,"depth":499,"text":421},{"id":1163,"depth":499,"text":1166},{"id":1217,"depth":499,"text":1220},"markdown","content:1.posts:58.w04-2024-tips-learned-this-week.md","content","1.posts/58.w04-2024-tips-learned-this-week.md","md",{"_path":121,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":120,"description":1281,"lead":1281,"date":1282,"image":1283,"badge":1284,"tags":1285,"body":1286,"_type":1275,"_id":2460,"_source":1277,"_file":2461,"_extension":1279},"The \"this\" in TypeScript, a must-have tool for Durable Functions, and a new git alias.","2022-05-23T00:00:00.000Z",{"src":405},{"label":407},[272,358,241,257,206],{"type":411,"children":1287,"toc":2454},[1288,1300,1321,1326,1551,1586,1612,1719,1728,1748,1861,1894,2297,2303,2317,2326,2338,2347,2353,2367,2411,2446,2450],{"type":414,"tag":415,"props":1289,"children":1291},{"id":1290},"reminder-for-my-future-self-dont-forget-about-this-in-ts",[1292,1294],{"type":420,"value":1293},"Reminder for my future self: don't forget about \"this\" in ",{"type":414,"tag":440,"props":1295,"children":1297},{"className":1296},[],[1298],{"type":420,"value":1299},"ts",{"type":414,"tag":423,"props":1301,"children":1302},{},[1303,1305,1311,1313,1319],{"type":420,"value":1304},"Once again, I found myself forgetting that ",{"type":414,"tag":440,"props":1306,"children":1308},{"className":1307},[],[1309],{"type":420,"value":1310},"this",{"type":420,"value":1312}," can lose context in JavaScript/TypeScript which results in exceptions because ",{"type":414,"tag":440,"props":1314,"children":1316},{"className":1315},[],[1317],{"type":420,"value":1318},"this ",{"type":420,"value":1320}," is undefined. This is probably obvious for most developers but this is not a case I come across often so it's better to write it down so that I have something to refer to next time.",{"type":414,"tag":423,"props":1322,"children":1323},{},[1324],{"type":420,"value":1325},"Let's take an example:",{"type":414,"tag":434,"props":1327,"children":1330},{"className":1328,"code":1329,"language":1299,"meta":401,"style":401},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","class AudioBook {\n    private isStarted = false;\n\n    constructor(public title: string) {\n    }\n    \n    play() {\n        this.isStarted = true;\n    }\n\n    stop() {\n        this.isStarted = false;\n    }\n}\n",[1331],{"type":414,"tag":440,"props":1332,"children":1333},{"__ignoreMap":401},[1334,1352,1379,1386,1426,1433,1441,1458,1484,1491,1498,1514,1537,1544],{"type":414,"tag":444,"props":1335,"children":1336},{"class":446,"line":447},[1337,1342,1347],{"type":414,"tag":444,"props":1338,"children":1339},{"style":451},[1340],{"type":420,"value":1341},"class",{"type":414,"tag":444,"props":1343,"children":1344},{"style":457},[1345],{"type":420,"value":1346}," AudioBook",{"type":414,"tag":444,"props":1348,"children":1349},{"style":468},[1350],{"type":420,"value":1351}," {\n",{"type":414,"tag":444,"props":1353,"children":1354},{"class":446,"line":499},[1355,1359,1364,1369,1375],{"type":414,"tag":444,"props":1356,"children":1357},{"style":451},[1358],{"type":420,"value":542},{"type":414,"tag":444,"props":1360,"children":1361},{"style":997},[1362],{"type":420,"value":1363}," isStarted",{"type":414,"tag":444,"props":1365,"children":1366},{"style":468},[1367],{"type":420,"value":1368}," =",{"type":414,"tag":444,"props":1370,"children":1372},{"style":1371},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[1373],{"type":420,"value":1374}," false",{"type":414,"tag":444,"props":1376,"children":1377},{"style":468},[1378],{"type":420,"value":577},{"type":414,"tag":444,"props":1380,"children":1381},{"class":446,"line":509},[1382],{"type":414,"tag":444,"props":1383,"children":1384},{"emptyLinePlaceholder":503},[1385],{"type":420,"value":506},{"type":414,"tag":444,"props":1387,"children":1388},{"class":446,"line":527},[1389,1394,1398,1402,1408,1412,1417,1422],{"type":414,"tag":444,"props":1390,"children":1391},{"style":451},[1392],{"type":420,"value":1393},"    constructor",{"type":414,"tag":444,"props":1395,"children":1396},{"style":468},[1397],{"type":420,"value":471},{"type":414,"tag":444,"props":1399,"children":1400},{"style":451},[1401],{"type":420,"value":454},{"type":414,"tag":444,"props":1403,"children":1405},{"style":1404},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[1406],{"type":420,"value":1407}," title",{"type":414,"tag":444,"props":1409,"children":1410},{"style":468},[1411],{"type":420,"value":1005},{"type":414,"tag":444,"props":1413,"children":1414},{"style":457},[1415],{"type":420,"value":1416}," string",{"type":414,"tag":444,"props":1418,"children":1419},{"style":468},[1420],{"type":420,"value":1421},")",{"type":414,"tag":444,"props":1423,"children":1424},{"style":468},[1425],{"type":420,"value":1351},{"type":414,"tag":444,"props":1427,"children":1428},{"class":446,"line":536},[1429],{"type":414,"tag":444,"props":1430,"children":1431},{"style":468},[1432],{"type":420,"value":672},{"type":414,"tag":444,"props":1434,"children":1435},{"class":446,"line":580},[1436],{"type":414,"tag":444,"props":1437,"children":1438},{"style":647},[1439],{"type":420,"value":1440},"    \n",{"type":414,"tag":444,"props":1442,"children":1443},{"class":446,"line":588},[1444,1449,1454],{"type":414,"tag":444,"props":1445,"children":1446},{"style":997},[1447],{"type":420,"value":1448},"    play",{"type":414,"tag":444,"props":1450,"children":1451},{"style":468},[1452],{"type":420,"value":1453},"()",{"type":414,"tag":444,"props":1455,"children":1456},{"style":468},[1457],{"type":420,"value":1351},{"type":414,"tag":444,"props":1459,"children":1460},{"class":446,"line":634},[1461,1466,1471,1475,1480],{"type":414,"tag":444,"props":1462,"children":1463},{"style":468},[1464],{"type":420,"value":1465},"        this.",{"type":414,"tag":444,"props":1467,"children":1468},{"style":647},[1469],{"type":420,"value":1470},"isStarted",{"type":414,"tag":444,"props":1472,"children":1473},{"style":468},[1474],{"type":420,"value":1368},{"type":414,"tag":444,"props":1476,"children":1477},{"style":1371},[1478],{"type":420,"value":1479}," true",{"type":414,"tag":444,"props":1481,"children":1482},{"style":468},[1483],{"type":420,"value":577},{"type":414,"tag":444,"props":1485,"children":1486},{"class":446,"line":643},[1487],{"type":414,"tag":444,"props":1488,"children":1489},{"style":468},[1490],{"type":420,"value":672},{"type":414,"tag":444,"props":1492,"children":1493},{"class":446,"line":666},[1494],{"type":414,"tag":444,"props":1495,"children":1496},{"emptyLinePlaceholder":503},[1497],{"type":420,"value":506},{"type":414,"tag":444,"props":1499,"children":1500},{"class":446,"line":675},[1501,1506,1510],{"type":414,"tag":444,"props":1502,"children":1503},{"style":997},[1504],{"type":420,"value":1505},"    stop",{"type":414,"tag":444,"props":1507,"children":1508},{"style":468},[1509],{"type":420,"value":1453},{"type":414,"tag":444,"props":1511,"children":1512},{"style":468},[1513],{"type":420,"value":1351},{"type":414,"tag":444,"props":1515,"children":1516},{"class":446,"line":683},[1517,1521,1525,1529,1533],{"type":414,"tag":444,"props":1518,"children":1519},{"style":468},[1520],{"type":420,"value":1465},{"type":414,"tag":444,"props":1522,"children":1523},{"style":647},[1524],{"type":420,"value":1470},{"type":414,"tag":444,"props":1526,"children":1527},{"style":468},[1528],{"type":420,"value":1368},{"type":414,"tag":444,"props":1530,"children":1531},{"style":1371},[1532],{"type":420,"value":1374},{"type":414,"tag":444,"props":1534,"children":1535},{"style":468},[1536],{"type":420,"value":577},{"type":414,"tag":444,"props":1538,"children":1539},{"class":446,"line":711},[1540],{"type":414,"tag":444,"props":1541,"children":1542},{"style":468},[1543],{"type":420,"value":672},{"type":414,"tag":444,"props":1545,"children":1546},{"class":446,"line":776},[1547],{"type":414,"tag":444,"props":1548,"children":1549},{"style":468},[1550],{"type":420,"value":882},{"type":414,"tag":423,"props":1552,"children":1553},{},[1554,1556,1562,1564,1569,1571,1577,1579,1585],{"type":420,"value":1555},"This is a class ",{"type":414,"tag":440,"props":1557,"children":1559},{"className":1558},[],[1560],{"type":420,"value":1561},"AudioBook",{"type":420,"value":1563}," that has a private boolean field ",{"type":414,"tag":440,"props":1565,"children":1567},{"className":1566},[],[1568],{"type":420,"value":1470},{"type":420,"value":1570}," that is modified by the two methods ",{"type":414,"tag":440,"props":1572,"children":1574},{"className":1573},[],[1575],{"type":420,"value":1576},"play",{"type":420,"value":1578}," and ",{"type":414,"tag":440,"props":1580,"children":1582},{"className":1581},[],[1583],{"type":420,"value":1584},"stop",{"type":420,"value":795},{"type":414,"tag":423,"props":1587,"children":1588},{},[1589,1591,1596,1598,1603,1605,1610],{"type":420,"value":1590},"If I create an instance of ",{"type":414,"tag":440,"props":1592,"children":1594},{"className":1593},[],[1595],{"type":420,"value":1561},{"type":420,"value":1597}," and I want to assign the ",{"type":414,"tag":440,"props":1599,"children":1601},{"className":1600},[],[1602],{"type":420,"value":1576},{"type":420,"value":1604}," function to a variable, an exception will occur when the function is run because ",{"type":414,"tag":440,"props":1606,"children":1608},{"className":1607},[],[1609],{"type":420,"value":1310},{"type":420,"value":1611}," will be undefined.",{"type":414,"tag":434,"props":1613,"children":1615},{"className":1328,"code":1614,"language":1299,"meta":401,"style":401},"const audioBook = new AudioBook(\"The Unicorn Project\");\nconst listenDevOpsBook = audioBook.play;\nlistenDevOpsBook();\n",[1616],{"type":414,"tag":440,"props":1617,"children":1618},{"__ignoreMap":401},[1619,1670,1703],{"type":414,"tag":444,"props":1620,"children":1621},{"class":446,"line":447},[1622,1627,1632,1636,1641,1645,1649,1653,1658,1662,1666],{"type":414,"tag":444,"props":1623,"children":1624},{"style":451},[1625],{"type":420,"value":1626},"const",{"type":414,"tag":444,"props":1628,"children":1629},{"style":647},[1630],{"type":420,"value":1631}," audioBook ",{"type":414,"tag":444,"props":1633,"children":1634},{"style":468},[1635],{"type":420,"value":655},{"type":414,"tag":444,"props":1637,"children":1638},{"style":468},[1639],{"type":420,"value":1640}," new",{"type":414,"tag":444,"props":1642,"children":1643},{"style":597},[1644],{"type":420,"value":1346},{"type":414,"tag":444,"props":1646,"children":1647},{"style":647},[1648],{"type":420,"value":471},{"type":414,"tag":444,"props":1650,"children":1651},{"style":468},[1652],{"type":420,"value":745},{"type":414,"tag":444,"props":1654,"children":1655},{"style":748},[1656],{"type":420,"value":1657},"The Unicorn Project",{"type":414,"tag":444,"props":1659,"children":1660},{"style":468},[1661],{"type":420,"value":745},{"type":414,"tag":444,"props":1663,"children":1664},{"style":647},[1665],{"type":420,"value":1421},{"type":414,"tag":444,"props":1667,"children":1668},{"style":468},[1669],{"type":420,"value":577},{"type":414,"tag":444,"props":1671,"children":1672},{"class":446,"line":499},[1673,1677,1682,1686,1691,1695,1699],{"type":414,"tag":444,"props":1674,"children":1675},{"style":451},[1676],{"type":420,"value":1626},{"type":414,"tag":444,"props":1678,"children":1679},{"style":647},[1680],{"type":420,"value":1681}," listenDevOpsBook ",{"type":414,"tag":444,"props":1683,"children":1684},{"style":468},[1685],{"type":420,"value":655},{"type":414,"tag":444,"props":1687,"children":1688},{"style":647},[1689],{"type":420,"value":1690}," audioBook",{"type":414,"tag":444,"props":1692,"children":1693},{"style":468},[1694],{"type":420,"value":795},{"type":414,"tag":444,"props":1696,"children":1697},{"style":647},[1698],{"type":420,"value":1576},{"type":414,"tag":444,"props":1700,"children":1701},{"style":468},[1702],{"type":420,"value":577},{"type":414,"tag":444,"props":1704,"children":1705},{"class":446,"line":509},[1706,1711,1715],{"type":414,"tag":444,"props":1707,"children":1708},{"style":597},[1709],{"type":420,"value":1710},"listenDevOpsBook",{"type":414,"tag":444,"props":1712,"children":1713},{"style":647},[1714],{"type":420,"value":1453},{"type":414,"tag":444,"props":1716,"children":1717},{"style":468},[1718],{"type":420,"value":577},{"type":414,"tag":423,"props":1720,"children":1721},{},[1722],{"type":414,"tag":903,"props":1723,"children":1727},{"alt":1724,"className":1725,"src":1726},"JavaScript Failed error in console output.",[907,908],"/posts/images/w202022tips_this_1.png",[],{"type":414,"tag":423,"props":1729,"children":1730},{},[1731,1733,1740,1742,1747],{"type":420,"value":1732},"The solution to avoid that is to use the ",{"type":414,"tag":889,"props":1734,"children":1737},{"href":1735,"rel":1736},"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind",[893],[1738],{"type":420,"value":1739},"bind",{"type":420,"value":1741}," function to specify the object to use as ",{"type":414,"tag":440,"props":1743,"children":1745},{"className":1744},[],[1746],{"type":420,"value":1310},{"type":420,"value":795},{"type":414,"tag":434,"props":1749,"children":1751},{"className":1328,"code":1750,"language":1299,"meta":401,"style":401},"const audioBook = new AudioBook(\"The Unicorn Project\");\nconst listenDevOpsBook = audioBook.play.bind(audioBook);\nlistenDevOpsBook();\n",[1752],{"type":414,"tag":440,"props":1753,"children":1754},{"__ignoreMap":401},[1755,1802,1846],{"type":414,"tag":444,"props":1756,"children":1757},{"class":446,"line":447},[1758,1762,1766,1770,1774,1778,1782,1786,1790,1794,1798],{"type":414,"tag":444,"props":1759,"children":1760},{"style":451},[1761],{"type":420,"value":1626},{"type":414,"tag":444,"props":1763,"children":1764},{"style":647},[1765],{"type":420,"value":1631},{"type":414,"tag":444,"props":1767,"children":1768},{"style":468},[1769],{"type":420,"value":655},{"type":414,"tag":444,"props":1771,"children":1772},{"style":468},[1773],{"type":420,"value":1640},{"type":414,"tag":444,"props":1775,"children":1776},{"style":597},[1777],{"type":420,"value":1346},{"type":414,"tag":444,"props":1779,"children":1780},{"style":647},[1781],{"type":420,"value":471},{"type":414,"tag":444,"props":1783,"children":1784},{"style":468},[1785],{"type":420,"value":745},{"type":414,"tag":444,"props":1787,"children":1788},{"style":748},[1789],{"type":420,"value":1657},{"type":414,"tag":444,"props":1791,"children":1792},{"style":468},[1793],{"type":420,"value":745},{"type":414,"tag":444,"props":1795,"children":1796},{"style":647},[1797],{"type":420,"value":1421},{"type":414,"tag":444,"props":1799,"children":1800},{"style":468},[1801],{"type":420,"value":577},{"type":414,"tag":444,"props":1803,"children":1804},{"class":446,"line":499},[1805,1809,1813,1817,1821,1825,1829,1833,1837,1842],{"type":414,"tag":444,"props":1806,"children":1807},{"style":451},[1808],{"type":420,"value":1626},{"type":414,"tag":444,"props":1810,"children":1811},{"style":647},[1812],{"type":420,"value":1681},{"type":414,"tag":444,"props":1814,"children":1815},{"style":468},[1816],{"type":420,"value":655},{"type":414,"tag":444,"props":1818,"children":1819},{"style":647},[1820],{"type":420,"value":1690},{"type":414,"tag":444,"props":1822,"children":1823},{"style":468},[1824],{"type":420,"value":795},{"type":414,"tag":444,"props":1826,"children":1827},{"style":647},[1828],{"type":420,"value":1576},{"type":414,"tag":444,"props":1830,"children":1831},{"style":468},[1832],{"type":420,"value":795},{"type":414,"tag":444,"props":1834,"children":1835},{"style":597},[1836],{"type":420,"value":1739},{"type":414,"tag":444,"props":1838,"children":1839},{"style":647},[1840],{"type":420,"value":1841},"(audioBook)",{"type":414,"tag":444,"props":1843,"children":1844},{"style":468},[1845],{"type":420,"value":577},{"type":414,"tag":444,"props":1847,"children":1848},{"class":446,"line":509},[1849,1853,1857],{"type":414,"tag":444,"props":1850,"children":1851},{"style":597},[1852],{"type":420,"value":1710},{"type":414,"tag":444,"props":1854,"children":1855},{"style":647},[1856],{"type":420,"value":1453},{"type":414,"tag":444,"props":1858,"children":1859},{"style":468},[1860],{"type":420,"value":577},{"type":414,"tag":423,"props":1862,"children":1863},{},[1864,1866,1871,1873,1878,1880,1885,1887,1892],{"type":420,"value":1865},"To avoid having to use bind everywhere the ",{"type":414,"tag":440,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":420,"value":1576},{"type":420,"value":1872}," or the ",{"type":414,"tag":440,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":420,"value":1584},{"type":420,"value":1879}," methods are used, we can do the ",{"type":414,"tag":440,"props":1881,"children":1883},{"className":1882},[],[1884],{"type":420,"value":1739},{"type":420,"value":1886}," thing directly in the constructor of the ",{"type":414,"tag":440,"props":1888,"children":1890},{"className":1889},[],[1891],{"type":420,"value":1561},{"type":420,"value":1893}," class.",{"type":414,"tag":434,"props":1895,"children":1897},{"className":1328,"code":1896,"language":1299,"meta":401,"style":401},"class AudioBook {\n    private isStarted = false;\n\n    constructor(public title: string) {\n        this.play = this.play.bind(this);\n        this.stop = this.stop.bind(this);\n    }\n    \n    play() {\n        this.isStarted = true;\n    }\n\n    stop() {\n        this.isStarted = false;\n    }\n}\n\nconst audioBook = new AudioBook(\"The Unicorn Project\");\nconst listenDevOpsBook = audioBook.play;\nlistenDevOpsBook();\n",[1898],{"type":414,"tag":440,"props":1899,"children":1900},{"__ignoreMap":401},[1901,1916,1939,1946,1981,2029,2076,2083,2090,2105,2128,2135,2142,2157,2180,2187,2194,2201,2249,2281],{"type":414,"tag":444,"props":1902,"children":1903},{"class":446,"line":447},[1904,1908,1912],{"type":414,"tag":444,"props":1905,"children":1906},{"style":451},[1907],{"type":420,"value":1341},{"type":414,"tag":444,"props":1909,"children":1910},{"style":457},[1911],{"type":420,"value":1346},{"type":414,"tag":444,"props":1913,"children":1914},{"style":468},[1915],{"type":420,"value":1351},{"type":414,"tag":444,"props":1917,"children":1918},{"class":446,"line":499},[1919,1923,1927,1931,1935],{"type":414,"tag":444,"props":1920,"children":1921},{"style":451},[1922],{"type":420,"value":542},{"type":414,"tag":444,"props":1924,"children":1925},{"style":997},[1926],{"type":420,"value":1363},{"type":414,"tag":444,"props":1928,"children":1929},{"style":468},[1930],{"type":420,"value":1368},{"type":414,"tag":444,"props":1932,"children":1933},{"style":1371},[1934],{"type":420,"value":1374},{"type":414,"tag":444,"props":1936,"children":1937},{"style":468},[1938],{"type":420,"value":577},{"type":414,"tag":444,"props":1940,"children":1941},{"class":446,"line":509},[1942],{"type":414,"tag":444,"props":1943,"children":1944},{"emptyLinePlaceholder":503},[1945],{"type":420,"value":506},{"type":414,"tag":444,"props":1947,"children":1948},{"class":446,"line":527},[1949,1953,1957,1961,1965,1969,1973,1977],{"type":414,"tag":444,"props":1950,"children":1951},{"style":451},[1952],{"type":420,"value":1393},{"type":414,"tag":444,"props":1954,"children":1955},{"style":468},[1956],{"type":420,"value":471},{"type":414,"tag":444,"props":1958,"children":1959},{"style":451},[1960],{"type":420,"value":454},{"type":414,"tag":444,"props":1962,"children":1963},{"style":1404},[1964],{"type":420,"value":1407},{"type":414,"tag":444,"props":1966,"children":1967},{"style":468},[1968],{"type":420,"value":1005},{"type":414,"tag":444,"props":1970,"children":1971},{"style":457},[1972],{"type":420,"value":1416},{"type":414,"tag":444,"props":1974,"children":1975},{"style":468},[1976],{"type":420,"value":1421},{"type":414,"tag":444,"props":1978,"children":1979},{"style":468},[1980],{"type":420,"value":1351},{"type":414,"tag":444,"props":1982,"children":1983},{"class":446,"line":536},[1984,1988,1992,1996,2001,2005,2009,2013,2017,2021,2025],{"type":414,"tag":444,"props":1985,"children":1986},{"style":468},[1987],{"type":420,"value":1465},{"type":414,"tag":444,"props":1989,"children":1990},{"style":647},[1991],{"type":420,"value":1576},{"type":414,"tag":444,"props":1993,"children":1994},{"style":468},[1995],{"type":420,"value":1368},{"type":414,"tag":444,"props":1997,"children":1998},{"style":468},[1999],{"type":420,"value":2000}," this.",{"type":414,"tag":444,"props":2002,"children":2003},{"style":647},[2004],{"type":420,"value":1576},{"type":414,"tag":444,"props":2006,"children":2007},{"style":468},[2008],{"type":420,"value":795},{"type":414,"tag":444,"props":2010,"children":2011},{"style":597},[2012],{"type":420,"value":1739},{"type":414,"tag":444,"props":2014,"children":2015},{"style":997},[2016],{"type":420,"value":471},{"type":414,"tag":444,"props":2018,"children":2019},{"style":468},[2020],{"type":420,"value":1310},{"type":414,"tag":444,"props":2022,"children":2023},{"style":997},[2024],{"type":420,"value":1421},{"type":414,"tag":444,"props":2026,"children":2027},{"style":468},[2028],{"type":420,"value":577},{"type":414,"tag":444,"props":2030,"children":2031},{"class":446,"line":580},[2032,2036,2040,2044,2048,2052,2056,2060,2064,2068,2072],{"type":414,"tag":444,"props":2033,"children":2034},{"style":468},[2035],{"type":420,"value":1465},{"type":414,"tag":444,"props":2037,"children":2038},{"style":647},[2039],{"type":420,"value":1584},{"type":414,"tag":444,"props":2041,"children":2042},{"style":468},[2043],{"type":420,"value":1368},{"type":414,"tag":444,"props":2045,"children":2046},{"style":468},[2047],{"type":420,"value":2000},{"type":414,"tag":444,"props":2049,"children":2050},{"style":647},[2051],{"type":420,"value":1584},{"type":414,"tag":444,"props":2053,"children":2054},{"style":468},[2055],{"type":420,"value":795},{"type":414,"tag":444,"props":2057,"children":2058},{"style":597},[2059],{"type":420,"value":1739},{"type":414,"tag":444,"props":2061,"children":2062},{"style":997},[2063],{"type":420,"value":471},{"type":414,"tag":444,"props":2065,"children":2066},{"style":468},[2067],{"type":420,"value":1310},{"type":414,"tag":444,"props":2069,"children":2070},{"style":997},[2071],{"type":420,"value":1421},{"type":414,"tag":444,"props":2073,"children":2074},{"style":468},[2075],{"type":420,"value":577},{"type":414,"tag":444,"props":2077,"children":2078},{"class":446,"line":588},[2079],{"type":414,"tag":444,"props":2080,"children":2081},{"style":468},[2082],{"type":420,"value":672},{"type":414,"tag":444,"props":2084,"children":2085},{"class":446,"line":634},[2086],{"type":414,"tag":444,"props":2087,"children":2088},{"style":647},[2089],{"type":420,"value":1440},{"type":414,"tag":444,"props":2091,"children":2092},{"class":446,"line":643},[2093,2097,2101],{"type":414,"tag":444,"props":2094,"children":2095},{"style":997},[2096],{"type":420,"value":1448},{"type":414,"tag":444,"props":2098,"children":2099},{"style":468},[2100],{"type":420,"value":1453},{"type":414,"tag":444,"props":2102,"children":2103},{"style":468},[2104],{"type":420,"value":1351},{"type":414,"tag":444,"props":2106,"children":2107},{"class":446,"line":666},[2108,2112,2116,2120,2124],{"type":414,"tag":444,"props":2109,"children":2110},{"style":468},[2111],{"type":420,"value":1465},{"type":414,"tag":444,"props":2113,"children":2114},{"style":647},[2115],{"type":420,"value":1470},{"type":414,"tag":444,"props":2117,"children":2118},{"style":468},[2119],{"type":420,"value":1368},{"type":414,"tag":444,"props":2121,"children":2122},{"style":1371},[2123],{"type":420,"value":1479},{"type":414,"tag":444,"props":2125,"children":2126},{"style":468},[2127],{"type":420,"value":577},{"type":414,"tag":444,"props":2129,"children":2130},{"class":446,"line":675},[2131],{"type":414,"tag":444,"props":2132,"children":2133},{"style":468},[2134],{"type":420,"value":672},{"type":414,"tag":444,"props":2136,"children":2137},{"class":446,"line":683},[2138],{"type":414,"tag":444,"props":2139,"children":2140},{"emptyLinePlaceholder":503},[2141],{"type":420,"value":506},{"type":414,"tag":444,"props":2143,"children":2144},{"class":446,"line":711},[2145,2149,2153],{"type":414,"tag":444,"props":2146,"children":2147},{"style":997},[2148],{"type":420,"value":1505},{"type":414,"tag":444,"props":2150,"children":2151},{"style":468},[2152],{"type":420,"value":1453},{"type":414,"tag":444,"props":2154,"children":2155},{"style":468},[2156],{"type":420,"value":1351},{"type":414,"tag":444,"props":2158,"children":2159},{"class":446,"line":776},[2160,2164,2168,2172,2176],{"type":414,"tag":444,"props":2161,"children":2162},{"style":468},[2163],{"type":420,"value":1465},{"type":414,"tag":444,"props":2165,"children":2166},{"style":647},[2167],{"type":420,"value":1470},{"type":414,"tag":444,"props":2169,"children":2170},{"style":468},[2171],{"type":420,"value":1368},{"type":414,"tag":444,"props":2173,"children":2174},{"style":1371},[2175],{"type":420,"value":1374},{"type":414,"tag":444,"props":2177,"children":2178},{"style":468},[2179],{"type":420,"value":577},{"type":414,"tag":444,"props":2181,"children":2182},{"class":446,"line":784},[2183],{"type":414,"tag":444,"props":2184,"children":2185},{"style":468},[2186],{"type":420,"value":672},{"type":414,"tag":444,"props":2188,"children":2189},{"class":446,"line":868},[2190],{"type":414,"tag":444,"props":2191,"children":2192},{"style":468},[2193],{"type":420,"value":882},{"type":414,"tag":444,"props":2195,"children":2196},{"class":446,"line":876},[2197],{"type":414,"tag":444,"props":2198,"children":2199},{"emptyLinePlaceholder":503},[2200],{"type":420,"value":506},{"type":414,"tag":444,"props":2202,"children":2204},{"class":446,"line":2203},18,[2205,2209,2213,2217,2221,2225,2229,2233,2237,2241,2245],{"type":414,"tag":444,"props":2206,"children":2207},{"style":451},[2208],{"type":420,"value":1626},{"type":414,"tag":444,"props":2210,"children":2211},{"style":647},[2212],{"type":420,"value":1631},{"type":414,"tag":444,"props":2214,"children":2215},{"style":468},[2216],{"type":420,"value":655},{"type":414,"tag":444,"props":2218,"children":2219},{"style":468},[2220],{"type":420,"value":1640},{"type":414,"tag":444,"props":2222,"children":2223},{"style":597},[2224],{"type":420,"value":1346},{"type":414,"tag":444,"props":2226,"children":2227},{"style":647},[2228],{"type":420,"value":471},{"type":414,"tag":444,"props":2230,"children":2231},{"style":468},[2232],{"type":420,"value":745},{"type":414,"tag":444,"props":2234,"children":2235},{"style":748},[2236],{"type":420,"value":1657},{"type":414,"tag":444,"props":2238,"children":2239},{"style":468},[2240],{"type":420,"value":745},{"type":414,"tag":444,"props":2242,"children":2243},{"style":647},[2244],{"type":420,"value":1421},{"type":414,"tag":444,"props":2246,"children":2247},{"style":468},[2248],{"type":420,"value":577},{"type":414,"tag":444,"props":2250,"children":2252},{"class":446,"line":2251},19,[2253,2257,2261,2265,2269,2273,2277],{"type":414,"tag":444,"props":2254,"children":2255},{"style":451},[2256],{"type":420,"value":1626},{"type":414,"tag":444,"props":2258,"children":2259},{"style":647},[2260],{"type":420,"value":1681},{"type":414,"tag":444,"props":2262,"children":2263},{"style":468},[2264],{"type":420,"value":655},{"type":414,"tag":444,"props":2266,"children":2267},{"style":647},[2268],{"type":420,"value":1690},{"type":414,"tag":444,"props":2270,"children":2271},{"style":468},[2272],{"type":420,"value":795},{"type":414,"tag":444,"props":2274,"children":2275},{"style":647},[2276],{"type":420,"value":1576},{"type":414,"tag":444,"props":2278,"children":2279},{"style":468},[2280],{"type":420,"value":577},{"type":414,"tag":444,"props":2282,"children":2284},{"class":446,"line":2283},20,[2285,2289,2293],{"type":414,"tag":444,"props":2286,"children":2287},{"style":597},[2288],{"type":420,"value":1710},{"type":414,"tag":444,"props":2290,"children":2291},{"style":647},[2292],{"type":420,"value":1453},{"type":414,"tag":444,"props":2294,"children":2295},{"style":468},[2296],{"type":420,"value":577},{"type":414,"tag":415,"props":2298,"children":2300},{"id":2299},"tool-of-the-week-durable-functions-monitor",[2301],{"type":420,"value":2302},"Tool of the week: Durable Functions Monitor ⚡",{"type":414,"tag":423,"props":2304,"children":2305},{},[2306,2308,2315],{"type":420,"value":2307},"If you are an Azure developer, you are probably already familiar with Azure Functions which is one of the solutions to do serverless in Azure. And, you may also have used Durable Functions to build serverless workflows. If I quote ",{"type":414,"tag":889,"props":2309,"children":2312},{"href":2310,"rel":2311},"https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview?tabs=csharp",[893],[2313],{"type":420,"value":2314},"Microsoft documentation",{"type":420,"value":2316},": \"Durable Functions is an extension of Azure Functions that lets you write stateful functions in a serverless compute environment.\" In concrete terms, if you are developing multiple Azure Functions and you want to orchestrate their execution while maintaining a state, Durable Functions are what you need. I like this technology a lot ❤️. When used correctly and for the right purpose, it can solve many issues you would face to implementing manually a workflow. Enough talk, let's go back to the tool of the week!",{"type":414,"tag":423,"props":2318,"children":2319},{},[2320],{"type":414,"tag":903,"props":2321,"children":2325},{"alt":2322,"className":2323,"src":2324},"GitHub README of the Durable Functions Monitor project.",[907,908],"/posts/images/w202022tips_durablemonitor_1.png",[],{"type":414,"tag":423,"props":2327,"children":2328},{},[2329,2336],{"type":414,"tag":889,"props":2330,"children":2333},{"href":2331,"rel":2332},"https://github.com/microsoft/DurableFunctionsMonitor",[893],[2334],{"type":420,"value":2335},"Durable Functions Monitor",{"type":420,"value":2337}," is a UI tool that allows you to monitor, manage and debug your Azure Durable Functions. That's something very valuable because the tooling in Azure Portal is very poor for Durable Functions. Moreover, because a workflow can last for a long time and is often composed of many Azure Functions, it can be quite hard to understand at what stage the workflow is and what functions have already been executed 🤔. Durable Functions can help you with that and offers many other interesting features (functions graph, sequence diagram...). I heard about it a while ago but did not take the time to try it until recently and honestly it's too bad because it's a must-have to work with Azure Durable Functions 🚀!",{"type":414,"tag":1152,"props":2339,"children":2341},{"icon":2340},"i-heroicons-light-bulb",[2342],{"type":414,"tag":423,"props":2343,"children":2344},{},[2345],{"type":420,"value":2346},"It's worth noting that Durable Functions Monitor can be used as a vscode extension, as a Standalone service, or directly in your Function App.",{"type":414,"tag":415,"props":2348,"children":2350},{"id":2349},"git-tip-of-the-week-alias-to-force-push-commits",[2351],{"type":420,"value":2352},"Git tip of the week: alias to force push commits",{"type":414,"tag":423,"props":2354,"children":2355},{},[2356,2358,2365],{"type":420,"value":2357},"I often force push changes on my git branches. Indeed, I try to keep a clean and easy to read the history on my branches by using the ",{"type":414,"tag":889,"props":2359,"children":2362},{"href":2360,"rel":2361},"https://www.techwatching.dev/gitcheatsheet#when-you-want-to-have-a-clean-commit-history-on-your-branch-before-creating-your-pull-request",[893],[2363],{"type":420,"value":2364},"interactive rebase command",{"type":420,"value":2366}," so that it's easier for my colleagues to review my Pull Requests and I can use a rebase merging strategy instead of squashing my changes in a big commit when completing them.",{"type":414,"tag":423,"props":2368,"children":2369},{},[2370,2372,2378,2380,2386,2388,2394,2396,2402,2404,2410],{"type":420,"value":2371},"Before, I was using the ",{"type":414,"tag":440,"props":2373,"children":2375},{"className":2374},[],[2376],{"type":420,"value":2377},"git push --force",{"type":420,"value":2379}," command but reading a few articles on the topic convinced me that I should use the ",{"type":414,"tag":440,"props":2381,"children":2383},{"className":2382},[],[2384],{"type":420,"value":2385},"git push --force-with-lease",{"type":420,"value":2387}," command instead to avoid crushing commits colleagues could have done on my branch (even if there is little risk as I only rewrite the history of already pushed changes when working alone on a branch). You can read more about ",{"type":414,"tag":440,"props":2389,"children":2391},{"className":2390},[],[2392],{"type":420,"value":2393},"--force-with-lease",{"type":420,"value":2395}," on the git ",{"type":414,"tag":889,"props":2397,"children":2400},{"href":2398,"rel":2399},"https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegt",[893],[2401],{"type":420,"value":936},{"type":420,"value":2403},". The only problem with this command is that it's a bit long to write so here is an alias to add to your ",{"type":414,"tag":440,"props":2405,"children":2407},{"className":2406},[],[2408],{"type":420,"value":2409},".gitconfig",{"type":420,"value":1005},{"type":414,"tag":434,"props":2412,"children":2416},{"className":2413,"code":2414,"language":2415,"meta":401,"style":401},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[alias]\n    pf = push origin --force-with-lease\n","yaml",[2417],{"type":414,"tag":440,"props":2418,"children":2419},{"__ignoreMap":401},[2420,2438],{"type":414,"tag":444,"props":2421,"children":2422},{"class":446,"line":447},[2423,2428,2433],{"type":414,"tag":444,"props":2424,"children":2425},{"style":468},[2426],{"type":420,"value":2427},"[",{"type":414,"tag":444,"props":2429,"children":2430},{"style":748},[2431],{"type":420,"value":2432},"alias",{"type":414,"tag":444,"props":2434,"children":2435},{"style":468},[2436],{"type":420,"value":2437},"]\n",{"type":414,"tag":444,"props":2439,"children":2440},{"class":446,"line":499},[2441],{"type":414,"tag":444,"props":2442,"children":2443},{"style":748},[2444],{"type":420,"value":2445},"    pf = push origin --force-with-lease\n",{"type":414,"tag":423,"props":2447,"children":2448},{},[2449],{"type":420,"value":1263},{"type":414,"tag":1265,"props":2451,"children":2452},{},[2453],{"type":420,"value":1269},{"title":401,"searchDepth":499,"depth":499,"links":2455},[2456,2458,2459],{"id":1290,"depth":499,"text":2457},"Reminder for my future self: don't forget about \"this\" in ts",{"id":2299,"depth":499,"text":2302},{"id":2349,"depth":499,"text":2352},"content:1.posts:38.w20-2022-tips-learned-this-week.md","1.posts/38.w20-2022-tips-learned-this-week.md",{"_path":76,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":75,"description":2463,"date":2464,"image":2465,"badge":2467,"tags":2468,"body":2469,"_type":1275,"_id":4463,"_source":1277,"_file":4464,"_extension":1279},"If you are using Azure Functions chances are you are using the setting AzureWebJobsStorage in your Function App configuration. And it is quite likely that the value of this setting which is a secret is stored in a non-secured way directly in your Function App configuration, available to anyone who has access to this configuration. But do not worry, we will see in this article how we can make your Function App more secure by removing this secret.","2021-09-15T00:00:00.000Z",{"src":2466},"/images/lightning_2.jpg",{"label":266},[257,312,315,252,228],{"type":411,"children":2470,"toc":4452},[2471,2484,2489,2495,2508,2520,2529,2535,2540,2549,2554,2560,2574,2583,2596,2610,2628,2634,2647,2654,2659,2679,2684,2690,2704,2709,2824,2837,3056,3061,3335,3347,4024,4046,4273,4281,4300,4314,4320,4325,4362,4371,4384,4389,4419,4424,4432,4438,4443,4448],{"type":414,"tag":423,"props":2472,"children":2473},{},[2474,2476,2482],{"type":420,"value":2475},"If you are using Azure Functions chances are you are using the setting ",{"type":414,"tag":440,"props":2477,"children":2479},{"className":2478},[],[2480],{"type":420,"value":2481},"AzureWebJobsStorage",{"type":420,"value":2483}," in your Function App configuration. And it is quite likely that the value of this setting which is a secret is stored in a non-secured way directly in your Function App configuration, available to anyone who has access to this configuration. But do not worry, we will see in this article how we can make your Function App more secure by removing this secret.",{"type":414,"tag":423,"props":2485,"children":2486},{},[2487],{"type":420,"value":2488},"But first, let's start at the beginning.",{"type":414,"tag":415,"props":2490,"children":2492},{"id":2491},"what-is-this-azurewebjobsstorage-setting",[2493],{"type":420,"value":2494},"What is this AzureWebJobsStorage setting?",{"type":414,"tag":423,"props":2496,"children":2497},{},[2498,2500,2506],{"type":420,"value":2499},"As explained in the ",{"type":414,"tag":889,"props":2501,"children":2504},{"href":2502,"rel":2503},"https://docs.microsoft.com/en-us/azure/azure-functions/storage-considerations#storage-account-requirements",[893],[2505],{"type":420,"value":936},{"type":420,"value":2507},", Azure Functions \"rely on Azure Storage for operations such as managing triggers and logging function executions\" which explains why you must associate a storage account to your Function App when you create one.",{"type":414,"tag":423,"props":2509,"children":2510},{},[2511,2513,2518],{"type":420,"value":2512},"By default when you create a Function App with its storage account from Azure Portal, the setting ",{"type":414,"tag":440,"props":2514,"children":2516},{"className":2515},[],[2517],{"type":420,"value":2481},{"type":420,"value":2519}," is automatically created in the Function App configuration and its value contains the secret connection string of the storage account. Thanks to that it will allow your Function App to have access to this storage and to work properly.",{"type":414,"tag":423,"props":2521,"children":2522},{},[2523],{"type":414,"tag":903,"props":2524,"children":2528},{"alt":2525,"className":2526,"src":2527},"AzureWebJobsStorage setting with a secret value in Function App settings.",[907,908],"/posts/images/functionsidentity_portal_1.png",[],{"type":414,"tag":415,"props":2530,"children":2532},{"id":2531},"why-azurewebjobsstorage-poses-a-security-risk",[2533],{"type":420,"value":2534},"Why AzureWebJobsStorage poses a security risk?",{"type":414,"tag":423,"props":2536,"children":2537},{},[2538],{"type":420,"value":2539},"App settings of your Function App are stored encrypted in Azure so having secrets in a Function App configuration in Azure does not seem a big security threat. Yet,  secrets in Azure application settings will be available to anyone who has access to the configuration screen of your Function App (or to Kudu) which does not seem a great idea. Moreover in the application settings of a Function App, there is no proper access monitoring, alerting, and auditing as you would have in an Azure Key Vault. So your secret is not really \"safe\" there.",{"type":414,"tag":423,"props":2541,"children":2542},{},[2543],{"type":414,"tag":903,"props":2544,"children":2548},{"alt":2545,"className":2546,"src":2547},"Padlock on a keyboard.",[907,908],"/posts/images/functionsidentity_padlock_1.jpgpng",[],{"type":414,"tag":423,"props":2550,"children":2551},{},[2552],{"type":420,"value":2553},"To avoid having someone gaining access to your storage account without you knowing, you probably do not want your storage account connection string to stay in a Function App configuration on Azure Portal.",{"type":414,"tag":415,"props":2555,"children":2557},{"id":2556},"what-can-we-do-about-it",[2558],{"type":420,"value":2559},"What can we do about it?",{"type":414,"tag":423,"props":2561,"children":2562},{},[2563,2565,2572],{"type":420,"value":2564},"A solution could be to store the AzureWebJobsStorage secret value in an Azure Key Vault and use a ",{"type":414,"tag":889,"props":2566,"children":2569},{"href":2567,"rel":2568},"https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references",[893],[2570],{"type":420,"value":2571},"Key Vault reference",{"type":420,"value":2573}," to link the secret in Key Vault to the AzureWebJobsStorage setting like on the example below.",{"type":414,"tag":423,"props":2575,"children":2576},{},[2577],{"type":414,"tag":903,"props":2578,"children":2582},{"alt":2579,"className":2580,"src":2581},"AzureWebJobsStorage setting as a keyvault reference in Function App settings.",[907,908],"/posts/images/functionsidentity_portal_2.png",[],{"type":414,"tag":423,"props":2584,"children":2585},{},[2586,2588,2594],{"type":420,"value":2587},"Another solution that is far more interesting I think (as it does not require any secret) is to assign the Storage Blob Data Owner role to your Function App identity and to replace the AzureWebJobsStorage connection string setting by the setting ",{"type":414,"tag":440,"props":2589,"children":2591},{"className":2590},[],[2592],{"type":420,"value":2593},"AzureWebJobsStorage__accountName",{"type":420,"value":2595}," that only contains the name of the storage account and no secret value at all.",{"type":414,"tag":423,"props":2597,"children":2598},{},[2599,2601,2608],{"type":420,"value":2600},"If you want more details about connecting to the storage with the Function App identity you can find it ",{"type":414,"tag":889,"props":2602,"children":2605},{"href":2603,"rel":2604},"https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference#connecting-to-host-storage-with-an-identity",[893],[2606],{"type":420,"value":2607},"here",{"type":420,"value":2609},". There is no point for me to paraphrase the documentation just to explain how you can set this up. However, I can show you how to implement that using Infrastructure as Code.",{"type":414,"tag":1152,"props":2611,"children":2613},{"icon":2612},"i-heroicons-chat-bubble-left-20-solid",[2614],{"type":414,"tag":423,"props":2615,"children":2616},{},[2617,2619,2626],{"type":420,"value":2618},"If you have read ",{"type":414,"tag":889,"props":2620,"children":2623},{"href":2621,"rel":2622},"https://www.techwatching.dev/posts/sqlclient-active-directory-authent",[893],[2624],{"type":420,"value":2625},"my article",{"type":420,"value":2627}," about connecting to an Azure SQL Database using Azure AD to authenticate instead of a secret connection, you probably know that I am not a big fan of secrets when we can avoid using them. From a security perspective, I think it is always a gain to remove the need for secrets while ensuring a resource can only be accessed by authorized people/applications.",{"type":414,"tag":415,"props":2629,"children":2631},{"id":2630},"how-to-configure-a-function-app-to-work-with-its-storage-account-without-a-secret-connection-string",[2632],{"type":420,"value":2633},"How to configure a Function App to work with its storage account without a secret connection string?",{"type":414,"tag":423,"props":2635,"children":2636},{},[2637,2639,2645],{"type":420,"value":2638},"To do that, I will use ",{"type":414,"tag":889,"props":2640,"children":2643},{"href":2641,"rel":2642},"https://www.pulumi.com/",[893],[2644],{"type":420,"value":312},{"type":420,"value":2646}," which is an Infrastructure as Code platform that uses programming languages instead of DSL to deploy infrastructure. As I am usually programming in C# for my application code, I will use C# as well for my infrastructure code.",{"type":414,"tag":2648,"props":2649,"children":2651},"h3",{"id":2650},"what-resources-do-we-need-to-create",[2652],{"type":420,"value":2653},"What resources do we need to create?",{"type":414,"tag":423,"props":2655,"children":2656},{},[2657],{"type":420,"value":2658},"We need to create 3 different Azure resources:",{"type":414,"tag":2660,"props":2661,"children":2662},"ul",{},[2663,2669,2674],{"type":414,"tag":2664,"props":2665,"children":2666},"li",{},[2667],{"type":420,"value":2668},"a consumption App Service Plan",{"type":414,"tag":2664,"props":2670,"children":2671},{},[2672],{"type":420,"value":2673},"a Function App",{"type":414,"tag":2664,"props":2675,"children":2676},{},[2677],{"type":420,"value":2678},"a Storage Account",{"type":414,"tag":423,"props":2680,"children":2681},{},[2682],{"type":420,"value":2683},"A resource group will also be created to contain these resources.\nAnd we will also need to assign the Storage Blob Data Owner role to the Function App, so to create a Role Assignment \"resource\".",{"type":414,"tag":2648,"props":2685,"children":2687},{"id":2686},"what-the-infrastructure-code-looks-like",[2688],{"type":420,"value":2689},"What the infrastructure code looks like?",{"type":414,"tag":423,"props":2691,"children":2692},{},[2693,2695,2702],{"type":420,"value":2694},"The infrastructure code looks like standard C# code, but it describes the Azure resources we need using the ",{"type":414,"tag":889,"props":2696,"children":2699},{"href":2697,"rel":2698},"https://www.pulumi.com/blog/full-coverage-of-azure-resources-with-azure-native/",[893],[2700],{"type":420,"value":2701},"Azure Native provider",{"type":420,"value":2703}," for Pulumi.",{"type":414,"tag":423,"props":2705,"children":2706},{},[2707],{"type":420,"value":2708},"Declaring a resource group is quite easy. Here we use C# string interpolation to build the resource group name from the project name and the stack name (two Pulumi notions that correspond to the name of the project and the environment):",{"type":414,"tag":434,"props":2710,"children":2712},{"className":436,"code":2711,"language":326,"meta":401,"style":401},"var resourceGroup = new ResourceGroup($\"rg-{Deployment.Instance.ProjectName}-{Deployment.Instance.StackName}\");\n",[2713],{"type":414,"tag":440,"props":2714,"children":2715},{"__ignoreMap":401},[2716],{"type":414,"tag":444,"props":2717,"children":2718},{"class":446,"line":447},[2719,2724,2729,2733,2737,2742,2746,2750,2755,2759,2764,2768,2773,2777,2782,2786,2791,2795,2799,2803,2807,2811,2816,2820],{"type":414,"tag":444,"props":2720,"children":2721},{"style":457},[2722],{"type":420,"value":2723},"var",{"type":414,"tag":444,"props":2725,"children":2726},{"style":457},[2727],{"type":420,"value":2728}," resourceGroup",{"type":414,"tag":444,"props":2730,"children":2731},{"style":468},[2732],{"type":420,"value":1368},{"type":414,"tag":444,"props":2734,"children":2735},{"style":468},[2736],{"type":420,"value":1640},{"type":414,"tag":444,"props":2738,"children":2739},{"style":457},[2740],{"type":420,"value":2741}," ResourceGroup",{"type":414,"tag":444,"props":2743,"children":2744},{"style":468},[2745],{"type":420,"value":471},{"type":414,"tag":444,"props":2747,"children":2748},{"style":468},[2749],{"type":420,"value":809},{"type":414,"tag":444,"props":2751,"children":2752},{"style":748},[2753],{"type":420,"value":2754},"rg-",{"type":414,"tag":444,"props":2756,"children":2757},{"style":468},[2758],{"type":420,"value":819},{"type":414,"tag":444,"props":2760,"children":2761},{"style":647},[2762],{"type":420,"value":2763},"Deployment",{"type":414,"tag":444,"props":2765,"children":2766},{"style":468},[2767],{"type":420,"value":795},{"type":414,"tag":444,"props":2769,"children":2770},{"style":647},[2771],{"type":420,"value":2772},"Instance",{"type":414,"tag":444,"props":2774,"children":2775},{"style":468},[2776],{"type":420,"value":795},{"type":414,"tag":444,"props":2778,"children":2779},{"style":647},[2780],{"type":420,"value":2781},"ProjectName",{"type":414,"tag":444,"props":2783,"children":2784},{"style":468},[2785],{"type":420,"value":838},{"type":414,"tag":444,"props":2787,"children":2788},{"style":748},[2789],{"type":420,"value":2790},"-",{"type":414,"tag":444,"props":2792,"children":2793},{"style":468},[2794],{"type":420,"value":819},{"type":414,"tag":444,"props":2796,"children":2797},{"style":647},[2798],{"type":420,"value":2763},{"type":414,"tag":444,"props":2800,"children":2801},{"style":468},[2802],{"type":420,"value":795},{"type":414,"tag":444,"props":2804,"children":2805},{"style":647},[2806],{"type":420,"value":2772},{"type":414,"tag":444,"props":2808,"children":2809},{"style":468},[2810],{"type":420,"value":795},{"type":414,"tag":444,"props":2812,"children":2813},{"style":647},[2814],{"type":420,"value":2815},"StackName",{"type":414,"tag":444,"props":2817,"children":2818},{"style":468},[2819],{"type":420,"value":861},{"type":414,"tag":444,"props":2821,"children":2822},{"style":468},[2823],{"type":420,"value":496},{"type":414,"tag":423,"props":2825,"children":2826},{},[2827,2829,2835],{"type":420,"value":2828},"To declare the resource group in which we want to create the storage account, we can use the property name of variable ",{"type":414,"tag":440,"props":2830,"children":2832},{"className":2831},[],[2833],{"type":420,"value":2834},"resourceGroup",{"type":420,"value":2836}," previously declared. We can see that for some arguments like the SKU names, Pulumi has types to help us choose between different possible values instead of specifying a magic string. It is not always the case but it is pretty handy when such things are available.",{"type":414,"tag":434,"props":2838,"children":2840},{"className":436,"code":2839,"language":326,"meta":401,"style":401},"var storageAccount = new StorageAccount($\"stnosecretfun{Deployment.Instance.StackName}\", new StorageAccountArgs\n{\n    ResourceGroupName = resourceGroup.Name,\n    Sku = new SkuArgs\n    {\n        Name = SkuName.Standard_LRS\n    },\n    Kind = Kind.StorageV2\n});\n",[2841],{"type":414,"tag":440,"props":2842,"children":2843},{"__ignoreMap":401},[2844,2923,2930,2960,2981,2988,3014,3022,3048],{"type":414,"tag":444,"props":2845,"children":2846},{"class":446,"line":447},[2847,2851,2856,2860,2864,2869,2873,2877,2882,2886,2890,2894,2898,2902,2906,2910,2914,2918],{"type":414,"tag":444,"props":2848,"children":2849},{"style":457},[2850],{"type":420,"value":2723},{"type":414,"tag":444,"props":2852,"children":2853},{"style":457},[2854],{"type":420,"value":2855}," storageAccount",{"type":414,"tag":444,"props":2857,"children":2858},{"style":468},[2859],{"type":420,"value":1368},{"type":414,"tag":444,"props":2861,"children":2862},{"style":468},[2863],{"type":420,"value":1640},{"type":414,"tag":444,"props":2865,"children":2866},{"style":457},[2867],{"type":420,"value":2868}," StorageAccount",{"type":414,"tag":444,"props":2870,"children":2871},{"style":468},[2872],{"type":420,"value":471},{"type":414,"tag":444,"props":2874,"children":2875},{"style":468},[2876],{"type":420,"value":809},{"type":414,"tag":444,"props":2878,"children":2879},{"style":748},[2880],{"type":420,"value":2881},"stnosecretfun",{"type":414,"tag":444,"props":2883,"children":2884},{"style":468},[2885],{"type":420,"value":819},{"type":414,"tag":444,"props":2887,"children":2888},{"style":647},[2889],{"type":420,"value":2763},{"type":414,"tag":444,"props":2891,"children":2892},{"style":468},[2893],{"type":420,"value":795},{"type":414,"tag":444,"props":2895,"children":2896},{"style":647},[2897],{"type":420,"value":2772},{"type":414,"tag":444,"props":2899,"children":2900},{"style":468},[2901],{"type":420,"value":795},{"type":414,"tag":444,"props":2903,"children":2904},{"style":647},[2905],{"type":420,"value":2815},{"type":414,"tag":444,"props":2907,"children":2908},{"style":468},[2909],{"type":420,"value":861},{"type":414,"tag":444,"props":2911,"children":2912},{"style":468},[2913],{"type":420,"value":1097},{"type":414,"tag":444,"props":2915,"children":2916},{"style":468},[2917],{"type":420,"value":1640},{"type":414,"tag":444,"props":2919,"children":2920},{"style":457},[2921],{"type":420,"value":2922}," StorageAccountArgs\n",{"type":414,"tag":444,"props":2924,"children":2925},{"class":446,"line":499},[2926],{"type":414,"tag":444,"props":2927,"children":2928},{"style":468},[2929],{"type":420,"value":533},{"type":414,"tag":444,"props":2931,"children":2932},{"class":446,"line":509},[2933,2938,2942,2946,2950,2955],{"type":414,"tag":444,"props":2934,"children":2935},{"style":647},[2936],{"type":420,"value":2937},"    ResourceGroupName ",{"type":414,"tag":444,"props":2939,"children":2940},{"style":468},[2941],{"type":420,"value":655},{"type":414,"tag":444,"props":2943,"children":2944},{"style":647},[2945],{"type":420,"value":2728},{"type":414,"tag":444,"props":2947,"children":2948},{"style":468},[2949],{"type":420,"value":795},{"type":414,"tag":444,"props":2951,"children":2952},{"style":647},[2953],{"type":420,"value":2954},"Name",{"type":414,"tag":444,"props":2956,"children":2957},{"style":468},[2958],{"type":420,"value":2959},",\n",{"type":414,"tag":444,"props":2961,"children":2962},{"class":446,"line":527},[2963,2968,2972,2976],{"type":414,"tag":444,"props":2964,"children":2965},{"style":647},[2966],{"type":420,"value":2967},"    Sku ",{"type":414,"tag":444,"props":2969,"children":2970},{"style":468},[2971],{"type":420,"value":655},{"type":414,"tag":444,"props":2973,"children":2974},{"style":468},[2975],{"type":420,"value":1640},{"type":414,"tag":444,"props":2977,"children":2978},{"style":457},[2979],{"type":420,"value":2980}," SkuArgs\n",{"type":414,"tag":444,"props":2982,"children":2983},{"class":446,"line":536},[2984],{"type":414,"tag":444,"props":2985,"children":2986},{"style":468},[2987],{"type":420,"value":640},{"type":414,"tag":444,"props":2989,"children":2990},{"class":446,"line":580},[2991,2996,3000,3005,3009],{"type":414,"tag":444,"props":2992,"children":2993},{"style":647},[2994],{"type":420,"value":2995},"        Name ",{"type":414,"tag":444,"props":2997,"children":2998},{"style":468},[2999],{"type":420,"value":655},{"type":414,"tag":444,"props":3001,"children":3002},{"style":647},[3003],{"type":420,"value":3004}," SkuName",{"type":414,"tag":444,"props":3006,"children":3007},{"style":468},[3008],{"type":420,"value":795},{"type":414,"tag":444,"props":3010,"children":3011},{"style":647},[3012],{"type":420,"value":3013},"Standard_LRS\n",{"type":414,"tag":444,"props":3015,"children":3016},{"class":446,"line":588},[3017],{"type":414,"tag":444,"props":3018,"children":3019},{"style":468},[3020],{"type":420,"value":3021},"    },\n",{"type":414,"tag":444,"props":3023,"children":3024},{"class":446,"line":634},[3025,3030,3034,3039,3043],{"type":414,"tag":444,"props":3026,"children":3027},{"style":647},[3028],{"type":420,"value":3029},"    Kind ",{"type":414,"tag":444,"props":3031,"children":3032},{"style":468},[3033],{"type":420,"value":655},{"type":414,"tag":444,"props":3035,"children":3036},{"style":647},[3037],{"type":420,"value":3038}," Kind",{"type":414,"tag":444,"props":3040,"children":3041},{"style":468},[3042],{"type":420,"value":795},{"type":414,"tag":444,"props":3044,"children":3045},{"style":647},[3046],{"type":420,"value":3047},"StorageV2\n",{"type":414,"tag":444,"props":3049,"children":3050},{"class":446,"line":643},[3051],{"type":414,"tag":444,"props":3052,"children":3053},{"style":468},[3054],{"type":420,"value":3055},"});\n",{"type":414,"tag":423,"props":3057,"children":3058},{},[3059],{"type":420,"value":3060},"This is the way of declaring a consumption App Service Plan:",{"type":414,"tag":434,"props":3062,"children":3064},{"className":436,"code":3063,"language":326,"meta":401,"style":401},"var appServicePlan = new AppServicePlan($\"plan-{Deployment.Instance.ProjectName}-{Deployment.Instance.StackName}\", new AppServicePlanArgs\n{\n    ResourceGroupName = resourceGroup.Name,\n    Kind = \"Windows\",\n    Sku = new SkuDescriptionArgs\n    {\n        Tier = \"Dynamic\",\n        Name = \"Y1\"\n    }\n});\n",[3065],{"type":414,"tag":440,"props":3066,"children":3067},{"__ignoreMap":401},[3068,3179,3186,3213,3241,3261,3268,3297,3321,3328],{"type":414,"tag":444,"props":3069,"children":3070},{"class":446,"line":447},[3071,3075,3080,3084,3088,3093,3097,3101,3106,3110,3114,3118,3122,3126,3130,3134,3138,3142,3146,3150,3154,3158,3162,3166,3170,3174],{"type":414,"tag":444,"props":3072,"children":3073},{"style":457},[3074],{"type":420,"value":2723},{"type":414,"tag":444,"props":3076,"children":3077},{"style":457},[3078],{"type":420,"value":3079}," appServicePlan",{"type":414,"tag":444,"props":3081,"children":3082},{"style":468},[3083],{"type":420,"value":1368},{"type":414,"tag":444,"props":3085,"children":3086},{"style":468},[3087],{"type":420,"value":1640},{"type":414,"tag":444,"props":3089,"children":3090},{"style":457},[3091],{"type":420,"value":3092}," AppServicePlan",{"type":414,"tag":444,"props":3094,"children":3095},{"style":468},[3096],{"type":420,"value":471},{"type":414,"tag":444,"props":3098,"children":3099},{"style":468},[3100],{"type":420,"value":809},{"type":414,"tag":444,"props":3102,"children":3103},{"style":748},[3104],{"type":420,"value":3105},"plan-",{"type":414,"tag":444,"props":3107,"children":3108},{"style":468},[3109],{"type":420,"value":819},{"type":414,"tag":444,"props":3111,"children":3112},{"style":647},[3113],{"type":420,"value":2763},{"type":414,"tag":444,"props":3115,"children":3116},{"style":468},[3117],{"type":420,"value":795},{"type":414,"tag":444,"props":3119,"children":3120},{"style":647},[3121],{"type":420,"value":2772},{"type":414,"tag":444,"props":3123,"children":3124},{"style":468},[3125],{"type":420,"value":795},{"type":414,"tag":444,"props":3127,"children":3128},{"style":647},[3129],{"type":420,"value":2781},{"type":414,"tag":444,"props":3131,"children":3132},{"style":468},[3133],{"type":420,"value":838},{"type":414,"tag":444,"props":3135,"children":3136},{"style":748},[3137],{"type":420,"value":2790},{"type":414,"tag":444,"props":3139,"children":3140},{"style":468},[3141],{"type":420,"value":819},{"type":414,"tag":444,"props":3143,"children":3144},{"style":647},[3145],{"type":420,"value":2763},{"type":414,"tag":444,"props":3147,"children":3148},{"style":468},[3149],{"type":420,"value":795},{"type":414,"tag":444,"props":3151,"children":3152},{"style":647},[3153],{"type":420,"value":2772},{"type":414,"tag":444,"props":3155,"children":3156},{"style":468},[3157],{"type":420,"value":795},{"type":414,"tag":444,"props":3159,"children":3160},{"style":647},[3161],{"type":420,"value":2815},{"type":414,"tag":444,"props":3163,"children":3164},{"style":468},[3165],{"type":420,"value":861},{"type":414,"tag":444,"props":3167,"children":3168},{"style":468},[3169],{"type":420,"value":1097},{"type":414,"tag":444,"props":3171,"children":3172},{"style":468},[3173],{"type":420,"value":1640},{"type":414,"tag":444,"props":3175,"children":3176},{"style":457},[3177],{"type":420,"value":3178}," AppServicePlanArgs\n",{"type":414,"tag":444,"props":3180,"children":3181},{"class":446,"line":499},[3182],{"type":414,"tag":444,"props":3183,"children":3184},{"style":468},[3185],{"type":420,"value":533},{"type":414,"tag":444,"props":3187,"children":3188},{"class":446,"line":509},[3189,3193,3197,3201,3205,3209],{"type":414,"tag":444,"props":3190,"children":3191},{"style":647},[3192],{"type":420,"value":2937},{"type":414,"tag":444,"props":3194,"children":3195},{"style":468},[3196],{"type":420,"value":655},{"type":414,"tag":444,"props":3198,"children":3199},{"style":647},[3200],{"type":420,"value":2728},{"type":414,"tag":444,"props":3202,"children":3203},{"style":468},[3204],{"type":420,"value":795},{"type":414,"tag":444,"props":3206,"children":3207},{"style":647},[3208],{"type":420,"value":2954},{"type":414,"tag":444,"props":3210,"children":3211},{"style":468},[3212],{"type":420,"value":2959},{"type":414,"tag":444,"props":3214,"children":3215},{"class":446,"line":527},[3216,3220,3224,3228,3233,3237],{"type":414,"tag":444,"props":3217,"children":3218},{"style":647},[3219],{"type":420,"value":3029},{"type":414,"tag":444,"props":3221,"children":3222},{"style":468},[3223],{"type":420,"value":655},{"type":414,"tag":444,"props":3225,"children":3226},{"style":468},[3227],{"type":420,"value":1050},{"type":414,"tag":444,"props":3229,"children":3230},{"style":748},[3231],{"type":420,"value":3232},"Windows",{"type":414,"tag":444,"props":3234,"children":3235},{"style":468},[3236],{"type":420,"value":745},{"type":414,"tag":444,"props":3238,"children":3239},{"style":468},[3240],{"type":420,"value":2959},{"type":414,"tag":444,"props":3242,"children":3243},{"class":446,"line":536},[3244,3248,3252,3256],{"type":414,"tag":444,"props":3245,"children":3246},{"style":647},[3247],{"type":420,"value":2967},{"type":414,"tag":444,"props":3249,"children":3250},{"style":468},[3251],{"type":420,"value":655},{"type":414,"tag":444,"props":3253,"children":3254},{"style":468},[3255],{"type":420,"value":1640},{"type":414,"tag":444,"props":3257,"children":3258},{"style":457},[3259],{"type":420,"value":3260}," SkuDescriptionArgs\n",{"type":414,"tag":444,"props":3262,"children":3263},{"class":446,"line":580},[3264],{"type":414,"tag":444,"props":3265,"children":3266},{"style":468},[3267],{"type":420,"value":640},{"type":414,"tag":444,"props":3269,"children":3270},{"class":446,"line":588},[3271,3276,3280,3284,3289,3293],{"type":414,"tag":444,"props":3272,"children":3273},{"style":647},[3274],{"type":420,"value":3275},"        Tier ",{"type":414,"tag":444,"props":3277,"children":3278},{"style":468},[3279],{"type":420,"value":655},{"type":414,"tag":444,"props":3281,"children":3282},{"style":468},[3283],{"type":420,"value":1050},{"type":414,"tag":444,"props":3285,"children":3286},{"style":748},[3287],{"type":420,"value":3288},"Dynamic",{"type":414,"tag":444,"props":3290,"children":3291},{"style":468},[3292],{"type":420,"value":745},{"type":414,"tag":444,"props":3294,"children":3295},{"style":468},[3296],{"type":420,"value":2959},{"type":414,"tag":444,"props":3298,"children":3299},{"class":446,"line":634},[3300,3304,3308,3312,3317],{"type":414,"tag":444,"props":3301,"children":3302},{"style":647},[3303],{"type":420,"value":2995},{"type":414,"tag":444,"props":3305,"children":3306},{"style":468},[3307],{"type":420,"value":655},{"type":414,"tag":444,"props":3309,"children":3310},{"style":468},[3311],{"type":420,"value":1050},{"type":414,"tag":444,"props":3313,"children":3314},{"style":748},[3315],{"type":420,"value":3316},"Y1",{"type":414,"tag":444,"props":3318,"children":3319},{"style":468},[3320],{"type":420,"value":1132},{"type":414,"tag":444,"props":3322,"children":3323},{"class":446,"line":643},[3324],{"type":414,"tag":444,"props":3325,"children":3326},{"style":468},[3327],{"type":420,"value":672},{"type":414,"tag":444,"props":3329,"children":3330},{"class":446,"line":666},[3331],{"type":414,"tag":444,"props":3332,"children":3333},{"style":468},[3334],{"type":420,"value":3055},{"type":414,"tag":423,"props":3336,"children":3337},{},[3338,3340,3345],{"type":420,"value":3339},"In Azure APIs, a FunctionApp is just a WebApp of a special kind \"FunctionApp\". You can notice that we enabled the System Managed Identity on the Function App by setting the Identity property. And as expected we added an app setting ",{"type":414,"tag":440,"props":3341,"children":3343},{"className":3342},[],[3344],{"type":420,"value":2593},{"type":420,"value":3346}," whose value is the name of the storage account.",{"type":414,"tag":434,"props":3348,"children":3350},{"className":436,"code":3349,"language":326,"meta":401,"style":401},"var functionApp = new WebApp($\"func-nosecret-{Deployment.Instance.StackName}\", new WebAppArgs\n{\n    Kind = \"FunctionApp\",\n    ResourceGroupName = resourceGroup.Name,\n    ServerFarmId = appServicePlan.Id,\n    Identity = new ManagedServiceIdentityArgs\n    {\n        Type = Pulumi.AzureNative.Web.ManagedServiceIdentityType.SystemAssigned\n    },\n    SiteConfig = new SiteConfigArgs\n    {\n        AppSettings = new[]\n        {\n            new NameValuePairArgs\n            {\n                Name = \"runtime\",\n                Value = \"dotnet\",\n            },\n            new NameValuePairArgs\n            {\n                Name = \"FUNCTIONS_WORKER_RUNTIME\",\n                Value = \"dotnet\",\n            },\n            new NameValuePairArgs\n            {\n                Name = \"FUNCTIONS_EXTENSION_VERSION\",\n                Value = \"~4\"\n            },\n            new NameValuePairArgs\n            {\n                Name = \"AzureWebJobsStorage__accountName\",\n                Value = storageAccount.Name\n            }\n        },\n    },\n});\n",[3351],{"type":414,"tag":440,"props":3352,"children":3353},{"__ignoreMap":401},[3354,3433,3440,3468,3495,3524,3545,3552,3605,3612,3633,3640,3657,3665,3678,3686,3715,3744,3752,3763,3770,3799,3827,3835,3847,3855,3884,3909,3917,3929,3937,3965,3990,3999,4008,4016],{"type":414,"tag":444,"props":3355,"children":3356},{"class":446,"line":447},[3357,3361,3366,3370,3374,3379,3383,3387,3392,3396,3400,3404,3408,3412,3416,3420,3424,3428],{"type":414,"tag":444,"props":3358,"children":3359},{"style":457},[3360],{"type":420,"value":2723},{"type":414,"tag":444,"props":3362,"children":3363},{"style":457},[3364],{"type":420,"value":3365}," functionApp",{"type":414,"tag":444,"props":3367,"children":3368},{"style":468},[3369],{"type":420,"value":1368},{"type":414,"tag":444,"props":3371,"children":3372},{"style":468},[3373],{"type":420,"value":1640},{"type":414,"tag":444,"props":3375,"children":3376},{"style":457},[3377],{"type":420,"value":3378}," WebApp",{"type":414,"tag":444,"props":3380,"children":3381},{"style":468},[3382],{"type":420,"value":471},{"type":414,"tag":444,"props":3384,"children":3385},{"style":468},[3386],{"type":420,"value":809},{"type":414,"tag":444,"props":3388,"children":3389},{"style":748},[3390],{"type":420,"value":3391},"func-nosecret-",{"type":414,"tag":444,"props":3393,"children":3394},{"style":468},[3395],{"type":420,"value":819},{"type":414,"tag":444,"props":3397,"children":3398},{"style":647},[3399],{"type":420,"value":2763},{"type":414,"tag":444,"props":3401,"children":3402},{"style":468},[3403],{"type":420,"value":795},{"type":414,"tag":444,"props":3405,"children":3406},{"style":647},[3407],{"type":420,"value":2772},{"type":414,"tag":444,"props":3409,"children":3410},{"style":468},[3411],{"type":420,"value":795},{"type":414,"tag":444,"props":3413,"children":3414},{"style":647},[3415],{"type":420,"value":2815},{"type":414,"tag":444,"props":3417,"children":3418},{"style":468},[3419],{"type":420,"value":861},{"type":414,"tag":444,"props":3421,"children":3422},{"style":468},[3423],{"type":420,"value":1097},{"type":414,"tag":444,"props":3425,"children":3426},{"style":468},[3427],{"type":420,"value":1640},{"type":414,"tag":444,"props":3429,"children":3430},{"style":457},[3431],{"type":420,"value":3432}," WebAppArgs\n",{"type":414,"tag":444,"props":3434,"children":3435},{"class":446,"line":499},[3436],{"type":414,"tag":444,"props":3437,"children":3438},{"style":468},[3439],{"type":420,"value":533},{"type":414,"tag":444,"props":3441,"children":3442},{"class":446,"line":509},[3443,3447,3451,3455,3460,3464],{"type":414,"tag":444,"props":3444,"children":3445},{"style":647},[3446],{"type":420,"value":3029},{"type":414,"tag":444,"props":3448,"children":3449},{"style":468},[3450],{"type":420,"value":655},{"type":414,"tag":444,"props":3452,"children":3453},{"style":468},[3454],{"type":420,"value":1050},{"type":414,"tag":444,"props":3456,"children":3457},{"style":748},[3458],{"type":420,"value":3459},"FunctionApp",{"type":414,"tag":444,"props":3461,"children":3462},{"style":468},[3463],{"type":420,"value":745},{"type":414,"tag":444,"props":3465,"children":3466},{"style":468},[3467],{"type":420,"value":2959},{"type":414,"tag":444,"props":3469,"children":3470},{"class":446,"line":527},[3471,3475,3479,3483,3487,3491],{"type":414,"tag":444,"props":3472,"children":3473},{"style":647},[3474],{"type":420,"value":2937},{"type":414,"tag":444,"props":3476,"children":3477},{"style":468},[3478],{"type":420,"value":655},{"type":414,"tag":444,"props":3480,"children":3481},{"style":647},[3482],{"type":420,"value":2728},{"type":414,"tag":444,"props":3484,"children":3485},{"style":468},[3486],{"type":420,"value":795},{"type":414,"tag":444,"props":3488,"children":3489},{"style":647},[3490],{"type":420,"value":2954},{"type":414,"tag":444,"props":3492,"children":3493},{"style":468},[3494],{"type":420,"value":2959},{"type":414,"tag":444,"props":3496,"children":3497},{"class":446,"line":536},[3498,3503,3507,3511,3515,3520],{"type":414,"tag":444,"props":3499,"children":3500},{"style":647},[3501],{"type":420,"value":3502},"    ServerFarmId ",{"type":414,"tag":444,"props":3504,"children":3505},{"style":468},[3506],{"type":420,"value":655},{"type":414,"tag":444,"props":3508,"children":3509},{"style":647},[3510],{"type":420,"value":3079},{"type":414,"tag":444,"props":3512,"children":3513},{"style":468},[3514],{"type":420,"value":795},{"type":414,"tag":444,"props":3516,"children":3517},{"style":647},[3518],{"type":420,"value":3519},"Id",{"type":414,"tag":444,"props":3521,"children":3522},{"style":468},[3523],{"type":420,"value":2959},{"type":414,"tag":444,"props":3525,"children":3526},{"class":446,"line":580},[3527,3532,3536,3540],{"type":414,"tag":444,"props":3528,"children":3529},{"style":647},[3530],{"type":420,"value":3531},"    Identity ",{"type":414,"tag":444,"props":3533,"children":3534},{"style":468},[3535],{"type":420,"value":655},{"type":414,"tag":444,"props":3537,"children":3538},{"style":468},[3539],{"type":420,"value":1640},{"type":414,"tag":444,"props":3541,"children":3542},{"style":457},[3543],{"type":420,"value":3544}," ManagedServiceIdentityArgs\n",{"type":414,"tag":444,"props":3546,"children":3547},{"class":446,"line":588},[3548],{"type":414,"tag":444,"props":3549,"children":3550},{"style":468},[3551],{"type":420,"value":640},{"type":414,"tag":444,"props":3553,"children":3554},{"class":446,"line":634},[3555,3560,3564,3569,3573,3578,3582,3587,3591,3596,3600],{"type":414,"tag":444,"props":3556,"children":3557},{"style":647},[3558],{"type":420,"value":3559},"        Type ",{"type":414,"tag":444,"props":3561,"children":3562},{"style":468},[3563],{"type":420,"value":655},{"type":414,"tag":444,"props":3565,"children":3566},{"style":647},[3567],{"type":420,"value":3568}," Pulumi",{"type":414,"tag":444,"props":3570,"children":3571},{"style":468},[3572],{"type":420,"value":795},{"type":414,"tag":444,"props":3574,"children":3575},{"style":647},[3576],{"type":420,"value":3577},"AzureNative",{"type":414,"tag":444,"props":3579,"children":3580},{"style":468},[3581],{"type":420,"value":795},{"type":414,"tag":444,"props":3583,"children":3584},{"style":647},[3585],{"type":420,"value":3586},"Web",{"type":414,"tag":444,"props":3588,"children":3589},{"style":468},[3590],{"type":420,"value":795},{"type":414,"tag":444,"props":3592,"children":3593},{"style":647},[3594],{"type":420,"value":3595},"ManagedServiceIdentityType",{"type":414,"tag":444,"props":3597,"children":3598},{"style":468},[3599],{"type":420,"value":795},{"type":414,"tag":444,"props":3601,"children":3602},{"style":647},[3603],{"type":420,"value":3604},"SystemAssigned\n",{"type":414,"tag":444,"props":3606,"children":3607},{"class":446,"line":643},[3608],{"type":414,"tag":444,"props":3609,"children":3610},{"style":468},[3611],{"type":420,"value":3021},{"type":414,"tag":444,"props":3613,"children":3614},{"class":446,"line":666},[3615,3620,3624,3628],{"type":414,"tag":444,"props":3616,"children":3617},{"style":647},[3618],{"type":420,"value":3619},"    SiteConfig ",{"type":414,"tag":444,"props":3621,"children":3622},{"style":468},[3623],{"type":420,"value":655},{"type":414,"tag":444,"props":3625,"children":3626},{"style":468},[3627],{"type":420,"value":1640},{"type":414,"tag":444,"props":3629,"children":3630},{"style":457},[3631],{"type":420,"value":3632}," SiteConfigArgs\n",{"type":414,"tag":444,"props":3634,"children":3635},{"class":446,"line":675},[3636],{"type":414,"tag":444,"props":3637,"children":3638},{"style":468},[3639],{"type":420,"value":640},{"type":414,"tag":444,"props":3641,"children":3642},{"class":446,"line":683},[3643,3648,3652],{"type":414,"tag":444,"props":3644,"children":3645},{"style":647},[3646],{"type":420,"value":3647},"        AppSettings ",{"type":414,"tag":444,"props":3649,"children":3650},{"style":468},[3651],{"type":420,"value":655},{"type":414,"tag":444,"props":3653,"children":3654},{"style":468},[3655],{"type":420,"value":3656}," new[]\n",{"type":414,"tag":444,"props":3658,"children":3659},{"class":446,"line":711},[3660],{"type":414,"tag":444,"props":3661,"children":3662},{"style":468},[3663],{"type":420,"value":3664},"        {\n",{"type":414,"tag":444,"props":3666,"children":3667},{"class":446,"line":776},[3668,3673],{"type":414,"tag":444,"props":3669,"children":3670},{"style":468},[3671],{"type":420,"value":3672},"            new",{"type":414,"tag":444,"props":3674,"children":3675},{"style":457},[3676],{"type":420,"value":3677}," NameValuePairArgs\n",{"type":414,"tag":444,"props":3679,"children":3680},{"class":446,"line":784},[3681],{"type":414,"tag":444,"props":3682,"children":3683},{"style":468},[3684],{"type":420,"value":3685},"            {\n",{"type":414,"tag":444,"props":3687,"children":3688},{"class":446,"line":868},[3689,3694,3698,3702,3707,3711],{"type":414,"tag":444,"props":3690,"children":3691},{"style":647},[3692],{"type":420,"value":3693},"                Name ",{"type":414,"tag":444,"props":3695,"children":3696},{"style":468},[3697],{"type":420,"value":655},{"type":414,"tag":444,"props":3699,"children":3700},{"style":468},[3701],{"type":420,"value":1050},{"type":414,"tag":444,"props":3703,"children":3704},{"style":748},[3705],{"type":420,"value":3706},"runtime",{"type":414,"tag":444,"props":3708,"children":3709},{"style":468},[3710],{"type":420,"value":745},{"type":414,"tag":444,"props":3712,"children":3713},{"style":468},[3714],{"type":420,"value":2959},{"type":414,"tag":444,"props":3716,"children":3717},{"class":446,"line":876},[3718,3723,3727,3731,3736,3740],{"type":414,"tag":444,"props":3719,"children":3720},{"style":647},[3721],{"type":420,"value":3722},"                Value ",{"type":414,"tag":444,"props":3724,"children":3725},{"style":468},[3726],{"type":420,"value":655},{"type":414,"tag":444,"props":3728,"children":3729},{"style":468},[3730],{"type":420,"value":1050},{"type":414,"tag":444,"props":3732,"children":3733},{"style":748},[3734],{"type":420,"value":3735},"dotnet",{"type":414,"tag":444,"props":3737,"children":3738},{"style":468},[3739],{"type":420,"value":745},{"type":414,"tag":444,"props":3741,"children":3742},{"style":468},[3743],{"type":420,"value":2959},{"type":414,"tag":444,"props":3745,"children":3746},{"class":446,"line":2203},[3747],{"type":414,"tag":444,"props":3748,"children":3749},{"style":468},[3750],{"type":420,"value":3751},"            },\n",{"type":414,"tag":444,"props":3753,"children":3754},{"class":446,"line":2251},[3755,3759],{"type":414,"tag":444,"props":3756,"children":3757},{"style":468},[3758],{"type":420,"value":3672},{"type":414,"tag":444,"props":3760,"children":3761},{"style":457},[3762],{"type":420,"value":3677},{"type":414,"tag":444,"props":3764,"children":3765},{"class":446,"line":2283},[3766],{"type":414,"tag":444,"props":3767,"children":3768},{"style":468},[3769],{"type":420,"value":3685},{"type":414,"tag":444,"props":3771,"children":3773},{"class":446,"line":3772},21,[3774,3778,3782,3786,3791,3795],{"type":414,"tag":444,"props":3775,"children":3776},{"style":647},[3777],{"type":420,"value":3693},{"type":414,"tag":444,"props":3779,"children":3780},{"style":468},[3781],{"type":420,"value":655},{"type":414,"tag":444,"props":3783,"children":3784},{"style":468},[3785],{"type":420,"value":1050},{"type":414,"tag":444,"props":3787,"children":3788},{"style":748},[3789],{"type":420,"value":3790},"FUNCTIONS_WORKER_RUNTIME",{"type":414,"tag":444,"props":3792,"children":3793},{"style":468},[3794],{"type":420,"value":745},{"type":414,"tag":444,"props":3796,"children":3797},{"style":468},[3798],{"type":420,"value":2959},{"type":414,"tag":444,"props":3800,"children":3802},{"class":446,"line":3801},22,[3803,3807,3811,3815,3819,3823],{"type":414,"tag":444,"props":3804,"children":3805},{"style":647},[3806],{"type":420,"value":3722},{"type":414,"tag":444,"props":3808,"children":3809},{"style":468},[3810],{"type":420,"value":655},{"type":414,"tag":444,"props":3812,"children":3813},{"style":468},[3814],{"type":420,"value":1050},{"type":414,"tag":444,"props":3816,"children":3817},{"style":748},[3818],{"type":420,"value":3735},{"type":414,"tag":444,"props":3820,"children":3821},{"style":468},[3822],{"type":420,"value":745},{"type":414,"tag":444,"props":3824,"children":3825},{"style":468},[3826],{"type":420,"value":2959},{"type":414,"tag":444,"props":3828,"children":3830},{"class":446,"line":3829},23,[3831],{"type":414,"tag":444,"props":3832,"children":3833},{"style":468},[3834],{"type":420,"value":3751},{"type":414,"tag":444,"props":3836,"children":3838},{"class":446,"line":3837},24,[3839,3843],{"type":414,"tag":444,"props":3840,"children":3841},{"style":468},[3842],{"type":420,"value":3672},{"type":414,"tag":444,"props":3844,"children":3845},{"style":457},[3846],{"type":420,"value":3677},{"type":414,"tag":444,"props":3848,"children":3850},{"class":446,"line":3849},25,[3851],{"type":414,"tag":444,"props":3852,"children":3853},{"style":468},[3854],{"type":420,"value":3685},{"type":414,"tag":444,"props":3856,"children":3858},{"class":446,"line":3857},26,[3859,3863,3867,3871,3876,3880],{"type":414,"tag":444,"props":3860,"children":3861},{"style":647},[3862],{"type":420,"value":3693},{"type":414,"tag":444,"props":3864,"children":3865},{"style":468},[3866],{"type":420,"value":655},{"type":414,"tag":444,"props":3868,"children":3869},{"style":468},[3870],{"type":420,"value":1050},{"type":414,"tag":444,"props":3872,"children":3873},{"style":748},[3874],{"type":420,"value":3875},"FUNCTIONS_EXTENSION_VERSION",{"type":414,"tag":444,"props":3877,"children":3878},{"style":468},[3879],{"type":420,"value":745},{"type":414,"tag":444,"props":3881,"children":3882},{"style":468},[3883],{"type":420,"value":2959},{"type":414,"tag":444,"props":3885,"children":3887},{"class":446,"line":3886},27,[3888,3892,3896,3900,3905],{"type":414,"tag":444,"props":3889,"children":3890},{"style":647},[3891],{"type":420,"value":3722},{"type":414,"tag":444,"props":3893,"children":3894},{"style":468},[3895],{"type":420,"value":655},{"type":414,"tag":444,"props":3897,"children":3898},{"style":468},[3899],{"type":420,"value":1050},{"type":414,"tag":444,"props":3901,"children":3902},{"style":748},[3903],{"type":420,"value":3904},"~4",{"type":414,"tag":444,"props":3906,"children":3907},{"style":468},[3908],{"type":420,"value":1132},{"type":414,"tag":444,"props":3910,"children":3912},{"class":446,"line":3911},28,[3913],{"type":414,"tag":444,"props":3914,"children":3915},{"style":468},[3916],{"type":420,"value":3751},{"type":414,"tag":444,"props":3918,"children":3920},{"class":446,"line":3919},29,[3921,3925],{"type":414,"tag":444,"props":3922,"children":3923},{"style":468},[3924],{"type":420,"value":3672},{"type":414,"tag":444,"props":3926,"children":3927},{"style":457},[3928],{"type":420,"value":3677},{"type":414,"tag":444,"props":3930,"children":3932},{"class":446,"line":3931},30,[3933],{"type":414,"tag":444,"props":3934,"children":3935},{"style":468},[3936],{"type":420,"value":3685},{"type":414,"tag":444,"props":3938,"children":3940},{"class":446,"line":3939},31,[3941,3945,3949,3953,3957,3961],{"type":414,"tag":444,"props":3942,"children":3943},{"style":647},[3944],{"type":420,"value":3693},{"type":414,"tag":444,"props":3946,"children":3947},{"style":468},[3948],{"type":420,"value":655},{"type":414,"tag":444,"props":3950,"children":3951},{"style":468},[3952],{"type":420,"value":1050},{"type":414,"tag":444,"props":3954,"children":3955},{"style":748},[3956],{"type":420,"value":2593},{"type":414,"tag":444,"props":3958,"children":3959},{"style":468},[3960],{"type":420,"value":745},{"type":414,"tag":444,"props":3962,"children":3963},{"style":468},[3964],{"type":420,"value":2959},{"type":414,"tag":444,"props":3966,"children":3968},{"class":446,"line":3967},32,[3969,3973,3977,3981,3985],{"type":414,"tag":444,"props":3970,"children":3971},{"style":647},[3972],{"type":420,"value":3722},{"type":414,"tag":444,"props":3974,"children":3975},{"style":468},[3976],{"type":420,"value":655},{"type":414,"tag":444,"props":3978,"children":3979},{"style":647},[3980],{"type":420,"value":2855},{"type":414,"tag":444,"props":3982,"children":3983},{"style":468},[3984],{"type":420,"value":795},{"type":414,"tag":444,"props":3986,"children":3987},{"style":647},[3988],{"type":420,"value":3989},"Name\n",{"type":414,"tag":444,"props":3991,"children":3993},{"class":446,"line":3992},33,[3994],{"type":414,"tag":444,"props":3995,"children":3996},{"style":468},[3997],{"type":420,"value":3998},"            }\n",{"type":414,"tag":444,"props":4000,"children":4002},{"class":446,"line":4001},34,[4003],{"type":414,"tag":444,"props":4004,"children":4005},{"style":468},[4006],{"type":420,"value":4007},"        },\n",{"type":414,"tag":444,"props":4009,"children":4011},{"class":446,"line":4010},35,[4012],{"type":414,"tag":444,"props":4013,"children":4014},{"style":468},[4015],{"type":420,"value":3021},{"type":414,"tag":444,"props":4017,"children":4019},{"class":446,"line":4018},36,[4020],{"type":414,"tag":444,"props":4021,"children":4022},{"style":468},[4023],{"type":420,"value":3055},{"type":414,"tag":423,"props":4025,"children":4026},{},[4027,4029,4036,4038,4044],{"type":420,"value":4028},"The last thing to do is to assign the role Storage Blob Data Owner to the Function App. To find the resource id I needed I looked at ",{"type":414,"tag":889,"props":4030,"children":4033},{"href":4031,"rel":4032},"https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles",[893],[4034],{"type":420,"value":4035},"this page of the Microsoft documentation",{"type":420,"value":4037}," but I hope that in the future Pulumi will provide an ",{"type":414,"tag":440,"props":4039,"children":4041},{"className":4040},[],[4042],{"type":420,"value":4043},"enum",{"type":420,"value":4045}," or something like that with the possible values to make that easier to find and assign.",{"type":414,"tag":434,"props":4047,"children":4049},{"className":436,"code":4048,"language":326,"meta":401,"style":401},"var storageBlobDataOwnerRole = new RoleAssignment(\"storageBlobDataOwner\", new RoleAssignmentArgs\n{\n    PrincipalId = functionApp.Identity.Apply(i => i.PrincipalId),\n    PrincipalType = PrincipalType.ServicePrincipal,\n    RoleDefinitionId = \"/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b\",\n    Scope = storageAccount.Id\n});\n",[4050],{"type":414,"tag":440,"props":4051,"children":4052},{"__ignoreMap":401},[4053,4108,4115,4182,4212,4241,4266],{"type":414,"tag":444,"props":4054,"children":4055},{"class":446,"line":447},[4056,4060,4065,4069,4073,4078,4082,4086,4091,4095,4099,4103],{"type":414,"tag":444,"props":4057,"children":4058},{"style":457},[4059],{"type":420,"value":2723},{"type":414,"tag":444,"props":4061,"children":4062},{"style":457},[4063],{"type":420,"value":4064}," storageBlobDataOwnerRole",{"type":414,"tag":444,"props":4066,"children":4067},{"style":468},[4068],{"type":420,"value":1368},{"type":414,"tag":444,"props":4070,"children":4071},{"style":468},[4072],{"type":420,"value":1640},{"type":414,"tag":444,"props":4074,"children":4075},{"style":457},[4076],{"type":420,"value":4077}," RoleAssignment",{"type":414,"tag":444,"props":4079,"children":4080},{"style":468},[4081],{"type":420,"value":471},{"type":414,"tag":444,"props":4083,"children":4084},{"style":468},[4085],{"type":420,"value":745},{"type":414,"tag":444,"props":4087,"children":4088},{"style":748},[4089],{"type":420,"value":4090},"storageBlobDataOwner",{"type":414,"tag":444,"props":4092,"children":4093},{"style":468},[4094],{"type":420,"value":745},{"type":414,"tag":444,"props":4096,"children":4097},{"style":468},[4098],{"type":420,"value":1097},{"type":414,"tag":444,"props":4100,"children":4101},{"style":468},[4102],{"type":420,"value":1640},{"type":414,"tag":444,"props":4104,"children":4105},{"style":457},[4106],{"type":420,"value":4107}," RoleAssignmentArgs\n",{"type":414,"tag":444,"props":4109,"children":4110},{"class":446,"line":499},[4111],{"type":414,"tag":444,"props":4112,"children":4113},{"style":468},[4114],{"type":420,"value":533},{"type":414,"tag":444,"props":4116,"children":4117},{"class":446,"line":509},[4118,4123,4127,4131,4135,4140,4144,4149,4153,4158,4163,4168,4172,4177],{"type":414,"tag":444,"props":4119,"children":4120},{"style":647},[4121],{"type":420,"value":4122},"    PrincipalId ",{"type":414,"tag":444,"props":4124,"children":4125},{"style":468},[4126],{"type":420,"value":655},{"type":414,"tag":444,"props":4128,"children":4129},{"style":647},[4130],{"type":420,"value":3365},{"type":414,"tag":444,"props":4132,"children":4133},{"style":468},[4134],{"type":420,"value":795},{"type":414,"tag":444,"props":4136,"children":4137},{"style":647},[4138],{"type":420,"value":4139},"Identity",{"type":414,"tag":444,"props":4141,"children":4142},{"style":468},[4143],{"type":420,"value":795},{"type":414,"tag":444,"props":4145,"children":4146},{"style":597},[4147],{"type":420,"value":4148},"Apply",{"type":414,"tag":444,"props":4150,"children":4151},{"style":468},[4152],{"type":420,"value":471},{"type":414,"tag":444,"props":4154,"children":4155},{"style":457},[4156],{"type":420,"value":4157},"i",{"type":414,"tag":444,"props":4159,"children":4160},{"style":468},[4161],{"type":420,"value":4162}," =>",{"type":414,"tag":444,"props":4164,"children":4165},{"style":647},[4166],{"type":420,"value":4167}," i",{"type":414,"tag":444,"props":4169,"children":4170},{"style":468},[4171],{"type":420,"value":795},{"type":414,"tag":444,"props":4173,"children":4174},{"style":647},[4175],{"type":420,"value":4176},"PrincipalId",{"type":414,"tag":444,"props":4178,"children":4179},{"style":468},[4180],{"type":420,"value":4181},"),\n",{"type":414,"tag":444,"props":4183,"children":4184},{"class":446,"line":527},[4185,4190,4194,4199,4203,4208],{"type":414,"tag":444,"props":4186,"children":4187},{"style":647},[4188],{"type":420,"value":4189},"    PrincipalType ",{"type":414,"tag":444,"props":4191,"children":4192},{"style":468},[4193],{"type":420,"value":655},{"type":414,"tag":444,"props":4195,"children":4196},{"style":647},[4197],{"type":420,"value":4198}," PrincipalType",{"type":414,"tag":444,"props":4200,"children":4201},{"style":468},[4202],{"type":420,"value":795},{"type":414,"tag":444,"props":4204,"children":4205},{"style":647},[4206],{"type":420,"value":4207},"ServicePrincipal",{"type":414,"tag":444,"props":4209,"children":4210},{"style":468},[4211],{"type":420,"value":2959},{"type":414,"tag":444,"props":4213,"children":4214},{"class":446,"line":536},[4215,4220,4224,4228,4233,4237],{"type":414,"tag":444,"props":4216,"children":4217},{"style":647},[4218],{"type":420,"value":4219},"    RoleDefinitionId ",{"type":414,"tag":444,"props":4221,"children":4222},{"style":468},[4223],{"type":420,"value":655},{"type":414,"tag":444,"props":4225,"children":4226},{"style":468},[4227],{"type":420,"value":1050},{"type":414,"tag":444,"props":4229,"children":4230},{"style":748},[4231],{"type":420,"value":4232},"/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b",{"type":414,"tag":444,"props":4234,"children":4235},{"style":468},[4236],{"type":420,"value":745},{"type":414,"tag":444,"props":4238,"children":4239},{"style":468},[4240],{"type":420,"value":2959},{"type":414,"tag":444,"props":4242,"children":4243},{"class":446,"line":580},[4244,4249,4253,4257,4261],{"type":414,"tag":444,"props":4245,"children":4246},{"style":647},[4247],{"type":420,"value":4248},"    Scope ",{"type":414,"tag":444,"props":4250,"children":4251},{"style":468},[4252],{"type":420,"value":655},{"type":414,"tag":444,"props":4254,"children":4255},{"style":647},[4256],{"type":420,"value":2855},{"type":414,"tag":444,"props":4258,"children":4259},{"style":468},[4260],{"type":420,"value":795},{"type":414,"tag":444,"props":4262,"children":4263},{"style":647},[4264],{"type":420,"value":4265},"Id\n",{"type":414,"tag":444,"props":4267,"children":4268},{"class":446,"line":588},[4269],{"type":414,"tag":444,"props":4270,"children":4271},{"style":468},[4272],{"type":420,"value":3055},{"type":414,"tag":1152,"props":4274,"children":4275},{"icon":2612},[4276],{"type":414,"tag":423,"props":4277,"children":4278},{},[4279],{"type":420,"value":4280},"Because the Azure provider is auto-generated from the Azure Resource Manager APIs, it is not always obvious to figure out what object and properties we should use to implement the infrastructure we want. Hopefully, because we are using a programming language in an IDE (C# in Visual Studio in my case), IntelliSense can help us.",{"type":414,"tag":423,"props":4282,"children":4283},{},[4284,4286,4291,4293,4298],{"type":420,"value":4285},"And that's just it, with this code the Function App will go well without needing the secret connection string of the storage in the AzureWebJobsStorage setting. Everything works fine thanks to the Managed Identity, the assignment of the correct role, and the setting ",{"type":414,"tag":440,"props":4287,"children":4289},{"className":4288},[],[4290],{"type":420,"value":2593},{"type":420,"value":4292},". One thing we could do is to remove the ",{"type":414,"tag":440,"props":4294,"children":4296},{"className":4295},[],[4297],{"type":420,"value":2593},{"type":420,"value":4299}," setting from the configuration to observe that without it, the Function App will not work properly: for instance, we would not be able to create function keys as a storage is needed to store them.",{"type":414,"tag":423,"props":4301,"children":4302},{},[4303,4305,4312],{"type":420,"value":4304},"You can find all this code on ",{"type":414,"tag":889,"props":4306,"children":4309},{"href":4307,"rel":4308},"https://github.com/TechWatching/FunctionAppWithoutSecretConnectionString",[893],[4310],{"type":420,"value":4311},"this GitHub repository",{"type":420,"value":4313}," if you want to test it by yourself. You will also find an HttpTrigger Azure Function created from the templates in Visual Studio that I only used to have something deployed on my Function App.",{"type":414,"tag":415,"props":4315,"children":4317},{"id":4316},"how-can-we-remove-the-azurewebjobsstorage-secret-setting-using-terraform",[4318],{"type":420,"value":4319},"How can we remove the AzureWebJobsStorage secret setting using Terraform?",{"type":414,"tag":423,"props":4321,"children":4322},{},[4323],{"type":420,"value":4324},"I am a big fan of Pulumi's approach to build and deploy infrastructure but as Terraform is pretty popular for doing Infrastructure as Code, I thought it might be a good idea to explain how to solve the same issue using Terraform instead of Pulumi.",{"type":414,"tag":423,"props":4326,"children":4327},{},[4328,4330,4337,4339,4345,4347,4353,4354,4360],{"type":420,"value":4329},"Well, in fact, you can't. 🤔 Currently there is no way to remove AzureWebJobsStorage secret using Terraform. Indeed as you can see in the ",{"type":414,"tag":889,"props":4331,"children":4334},{"href":4332,"rel":4333},"https://www.pulumi.com/blog/pulumiup-native-providers/",[893],[4335],{"type":420,"value":4336},"Terraform documentation of a Function App resource",{"type":420,"value":4338}," ",{"type":414,"tag":440,"props":4340,"children":4342},{"className":4341},[],[4343],{"type":420,"value":4344},"azurerm_function_app",{"type":420,"value":4346},", the AzureWebJobsStorage setting is automatically filled based on the ",{"type":414,"tag":440,"props":4348,"children":4350},{"className":4349},[],[4351],{"type":420,"value":4352},"storage_account_name",{"type":420,"value":1578},{"type":414,"tag":440,"props":4355,"children":4357},{"className":4356},[],[4358],{"type":420,"value":4359},"storage_account_access_key",{"type":420,"value":4361}," parameters which are required. So not only you can't use the Managed Identity access to storage as we did in Pulumi but also you can't use a key vault reference for the AzureWebJobsStorage setting (see the documentation screenshot below).",{"type":414,"tag":423,"props":4363,"children":4364},{},[4365],{"type":414,"tag":903,"props":4366,"children":4370},{"alt":4367,"className":4368,"src":4369},"Azure RM provider for Terraform documentation about AzureWebJobsStorage.",[907,908],"/posts/images/functionsidentity_terraform_1.png",[],{"type":414,"tag":423,"props":4372,"children":4373},{},[4374,4376,4382],{"type":420,"value":4375},"The only possibility right now is to use an ARM template in your Terraform project thanks to the ",{"type":414,"tag":440,"props":4377,"children":4379},{"className":4378},[],[4380],{"type":420,"value":4381},"azurerm_resource_group_template_deployment",{"type":420,"value":4383}," resource but that defeats the whole point of using Terraform especially for a major resource like a Function App.",{"type":414,"tag":423,"props":4385,"children":4386},{},[4387],{"type":420,"value":4388},"In the GitHub repository of the Terraform provider for Azure RM there are 2 issues relative to this problem (do not hesitate to vote for them):",{"type":414,"tag":2660,"props":4390,"children":4391},{},[4392,4406],{"type":414,"tag":2664,"props":4393,"children":4394},{},[4395,4397,4404],{"type":420,"value":4396},"the ",{"type":414,"tag":889,"props":4398,"children":4401},{"href":4399,"rel":4400},"https://github.com/hashicorp/terraform-provider-azurerm/issues/8977",[893],[4402],{"type":420,"value":4403},"8977 issue",{"type":420,"value":4405}," that aims at supporting a KeyVault reference for the AzureWebJobsStorage setting",{"type":414,"tag":2664,"props":4407,"children":4408},{},[4409,4410,4417],{"type":420,"value":4396},{"type":414,"tag":889,"props":4411,"children":4414},{"href":4412,"rel":4413},"https://github.com/hashicorp/terraform-provider-azurerm/issues/13240",[893],[4415],{"type":420,"value":4416},"13240 issue",{"type":420,"value":4418}," that aims at supporting the Managed Identity access to storage",{"type":414,"tag":423,"props":4420,"children":4421},{},[4422],{"type":420,"value":4423},"I guess this will be implemented someday in Terraform provider for Azure RM, so that may not be a big deal but that clearly shows the limitations of Terraform providers.",{"type":414,"tag":1152,"props":4425,"children":4426},{"icon":2612},[4427],{"type":414,"tag":423,"props":4428,"children":4429},{},[4430],{"type":420,"value":4431},"Because Terraform provider for Azure RM is manually implemented using the Azure SDK, it does not match Azure APIs hence not all new resources and features are available (they have to be implemented in the provider as new features in Azure are released and it can take time). It's something that is not a problem with Pulumi Azure Native provider as the SDKs are generated automatically from the Azure API specifications which makes Pulumi Azure Native provider always up-to-date.",{"type":414,"tag":415,"props":4433,"children":4435},{"id":4434},"final-thoughts",[4436],{"type":420,"value":4437},"Final thoughts",{"type":414,"tag":423,"props":4439,"children":4440},{},[4441],{"type":420,"value":4442},"I hope that after reading this article if you are working on a Function App with an AzureWebJobsStorage setting you will take the time to replace it with an access to storage through the Managed Identity of your Function. One question you could ask me is why this is not the default behavior when creating a new Function App instead of using the AzureWebJobsStorage. And that would be an excellent question... for the Azure Functions team 😀.",{"type":414,"tag":423,"props":4444,"children":4445},{},[4446],{"type":420,"value":4447},"If you did not know Pulumi before reading this article, I hope it made you want to give it a try.\nHappy learning.",{"type":414,"tag":1265,"props":4449,"children":4450},{},[4451],{"type":420,"value":1269},{"title":401,"searchDepth":499,"depth":499,"links":4453},[4454,4455,4456,4457,4461,4462],{"id":2491,"depth":499,"text":2494},{"id":2531,"depth":499,"text":2534},{"id":2556,"depth":499,"text":2559},{"id":2630,"depth":499,"text":2633,"children":4458},[4459,4460],{"id":2650,"depth":509,"text":2653},{"id":2686,"depth":509,"text":2689},{"id":4316,"depth":499,"text":4319},{"id":4434,"depth":499,"text":4437},"content:1.posts:23.azure-functions-without-azurewebjobsstorage.md","1.posts/23.azure-functions-without-azurewebjobsstorage.md",{"_path":37,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":36,"description":4466,"lead":4467,"date":4468,"image":4469,"badge":4471,"tags":4473,"body":4474,"_type":1275,"_id":4860,"_source":1277,"_file":4861,"_extension":1279},"The possibility to add configuration sources in Azure Functions has just been released with the latest version of Microsoft.Azure.Functions.Extensions NuGet package. I have been waiting for this feature for a long time (like many people I think) because it brings to Azure Functions all the things we are used to with configuration in ASP.NET Core 😻. But that is not the only reason, it is also because with this feature you almost don't need to use key vault references!","Talking about how to manage configuration secrets in Azure Functions.","2020-09-21T00:00:00.000Z",{"src":4470},"/images/lightning_1.jpg",{"label":4472},"Development",[257,260,228,263],{"type":411,"children":4475,"toc":4852},[4476,4497,4502,4508,4535,4544,4557,4566,4571,4577,4589,4594,4603,4608,4662,4674,4683,4688,4701,4713,4755,4764,4769,4778,4783,4789,4824,4832,4837,4843,4848],{"type":414,"tag":423,"props":4477,"children":4478},{},[4479,4481,4487,4488,4495],{"type":420,"value":4480},"The possibility to add configuration sources in Azure Functions has just been released with the latest version of ",{"type":414,"tag":440,"props":4482,"children":4484},{"className":4483},[],[4485],{"type":420,"value":4486},"Microsoft.Azure.Functions.Extensions",{"type":420,"value":4338},{"type":414,"tag":889,"props":4489,"children":4492},{"href":4490,"rel":4491},"https://www.nuget.org/packages/Microsoft.Azure.Functions.Extensions/1.1.0",[893],[4493],{"type":420,"value":4494},"NuGet package",{"type":420,"value":4496},". I have been waiting for this feature for a long time (like many people I think) because it brings to Azure Functions all the things we are used to with configuration in ASP.NET Core 😻. But that is not the only reason, it is also because with this feature you almost don't need to use key vault references!",{"type":414,"tag":423,"props":4498,"children":4499},{},[4500],{"type":420,"value":4501},"But before deep dive into this topic, let's give a bit of context about configuration and secrets in Azure Functions (just skip the next section if you already are familiar with all that).",{"type":414,"tag":415,"props":4503,"children":4505},{"id":4504},"a-quick-reminder-about-configuration-and-secrets-in-azure-functions",[4506],{"type":420,"value":4507},"A quick reminder about configuration and secrets in Azure Functions",{"type":414,"tag":423,"props":4509,"children":4510},{},[4511,4513,4518,4520,4526,4528,4533],{"type":420,"value":4512},"Configuration used by functions in a Function App is stored in settings that can be set in the ",{"type":414,"tag":440,"props":4514,"children":4516},{"className":4515},[],[4517],{"type":420,"value":263},{"type":420,"value":4519}," section of a Function App in Azure Portal. When developing locally you have to use a ",{"type":414,"tag":440,"props":4521,"children":4523},{"className":4522},[],[4524],{"type":420,"value":4525},"local.settings.json",{"type":420,"value":4527}," file that will contain copies of the settings stored in Azure portal. The settings from ",{"type":414,"tag":440,"props":4529,"children":4531},{"className":4530},[],[4532],{"type":420,"value":4525},{"type":420,"value":4534}," will be loaded as environment variables when debugging locally. But as its name suggests, the purpose of this file is to be used for local development only: its settings are not used when the function runs on Azure. Furthermore, this file should never be committed to avoid putting settings corresponding to secrets in source control.",{"type":414,"tag":423,"props":4536,"children":4537},{},[4538],{"type":414,"tag":903,"props":4539,"children":4543},{"alt":4540,"className":4541,"src":4542},"Azure Function local settings file.",[907,908],"/posts/images/functionssecrets_localsettings_1.png",[],{"type":414,"tag":423,"props":4545,"children":4546},{},[4547,4549,4555],{"type":420,"value":4548},"Speaking of secrets, they should never be directly stored in the application settings of a Function App (the same goes for App Services by the way). Why not? Because secrets would be available to  anyone who has access to the Function App in the Azure Portal. The right way is to use an Azure Key Vault which is the Azure component for securely storing and accessing secrets 🔒. Once your secrets are in the key vault, you have to grant the Key Vault access to the identity of your Function App and you can then reference the secrets you need directly in your application settings. These are called ",{"type":414,"tag":889,"props":4550,"children":4552},{"href":2567,"rel":4551},[893],[4553],{"type":420,"value":4554},"Key Vault references",{"type":420,"value":4556}," because an application setting does not contain directly the value of a secret but a reference to the secret which is stored in Key Vault. When running, your function will automatically have access to the secret and its value as an environment variable, as if it was a normal application setting.",{"type":414,"tag":423,"props":4558,"children":4559},{},[4560],{"type":414,"tag":903,"props":4561,"children":4565},{"alt":4562,"className":4563,"src":4564},"Function App application settings in Azure portal.",[907,908],"/posts/images/functionssecrets_portal_1.png",[],{"type":414,"tag":423,"props":4567,"children":4568},{},[4569],{"type":420,"value":4570},"Key Vault references work for both App Services and Function Apps and are particularly useful for existing applications that have their secrets stored in settings because securing the secrets with Azure Key Vault references does not require any code change.",{"type":414,"tag":415,"props":4572,"children":4574},{"id":4573},"the-downside-of-key-vault-references-the-local-debugging-experience",[4575],{"type":420,"value":4576},"The downside of Key Vault references: the local debugging experience",{"type":414,"tag":423,"props":4578,"children":4579},{},[4580,4582,4587],{"type":420,"value":4581},"Do you remember when I told you that the local settings file should not be committed to your git repository? Well, what you might not have realized is that it means when someone from your team clones the git repository containing your function he won't have this ",{"type":414,"tag":440,"props":4583,"children":4585},{"className":4584},[],[4586],{"type":420,"value":4525},{"type":420,"value":4588}," file which is mandatory to run your function app locally. And even if he creates manually the file, he will not necessarily know which settings to put in it. But we want to avoid him manually copying all the settings from the Azure portal or asking a colleague to send his local settings file by email (which is a really bad practice if it contains secrets). Hopefully, there are some ways to fill or generate this file.",{"type":414,"tag":423,"props":4590,"children":4591},{},[4592],{"type":420,"value":4593},"If you use Visual Studio there is a GUI that will help you compare/modify local settings and Azure settings.",{"type":414,"tag":423,"props":4595,"children":4596},{},[4597],{"type":414,"tag":903,"props":4598,"children":4602},{"alt":4599,"className":4600,"src":4601},"Function App application settings in Visual Studio.",[907,908],"/posts/images/functionssecrets_vs_1.png",[],{"type":414,"tag":423,"props":4604,"children":4605},{},[4606],{"type":420,"value":4607},"And whether or not you are using Visual Studio, you can generate the local settings file filled with Azure settings with a few Azure Functions CLI commands:",{"type":414,"tag":434,"props":4609,"children":4613},{"className":4610,"code":4611,"language":4612,"meta":401,"style":401},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","func azure functionapp fetch-app-settings $FUNCTION_APP_NAME\nfunc settings decrypt\n","bash",[4614],{"type":414,"tag":440,"props":4615,"children":4616},{"__ignoreMap":401},[4617,4645],{"type":414,"tag":444,"props":4618,"children":4619},{"class":446,"line":447},[4620,4625,4630,4635,4640],{"type":414,"tag":444,"props":4621,"children":4622},{"style":457},[4623],{"type":420,"value":4624},"func",{"type":414,"tag":444,"props":4626,"children":4627},{"style":748},[4628],{"type":420,"value":4629}," azure",{"type":414,"tag":444,"props":4631,"children":4632},{"style":748},[4633],{"type":420,"value":4634}," functionapp",{"type":414,"tag":444,"props":4636,"children":4637},{"style":748},[4638],{"type":420,"value":4639}," fetch-app-settings",{"type":414,"tag":444,"props":4641,"children":4642},{"style":647},[4643],{"type":420,"value":4644}," $FUNCTION_APP_NAME\n",{"type":414,"tag":444,"props":4646,"children":4647},{"class":446,"line":499},[4648,4652,4657],{"type":414,"tag":444,"props":4649,"children":4650},{"style":457},[4651],{"type":420,"value":4624},{"type":414,"tag":444,"props":4653,"children":4654},{"style":748},[4655],{"type":420,"value":4656}," settings",{"type":414,"tag":444,"props":4658,"children":4659},{"style":748},[4660],{"type":420,"value":4661}," decrypt\n",{"type":414,"tag":423,"props":4663,"children":4664},{},[4665,4667,4672],{"type":420,"value":4666},"This is an example of a generated ",{"type":414,"tag":440,"props":4668,"children":4670},{"className":4669},[],[4671],{"type":420,"value":4525},{"type":420,"value":4673}," file:",{"type":414,"tag":423,"props":4675,"children":4676},{},[4677],{"type":414,"tag":903,"props":4678,"children":4682},{"alt":4679,"className":4680,"src":4681},"Generated local settings file.",[907,908],"/posts/images/functionssecrets_localsettings_2.png",[],{"type":414,"tag":423,"props":4684,"children":4685},{},[4686],{"type":420,"value":4687},"However, as you can see, the settings corresponding to secrets contain the Key Vault reference values that are used by Azure to link the settings to the secrets. But this is an Azure mechanism, locally the true secrets value won't be loaded into configuration. So you will have to manually retrieve the value of the secrets in your key vault and set them manually in your local settings file. That may be okay for one secret but that gets quickly annoying when you have many secrets. You don't want your team members to constantly lose time copying secret values from the key vault on their local environment. I don't even talk about the loss of time understanding what is wrong when a secret value has changed and you did not realize it or the bad habits it could lead to like sending secrets by email or chat messages.",{"type":414,"tag":423,"props":4689,"children":4690},{},[4691,4693,4700],{"type":420,"value":4692},"This is a terrible local debugging experience and honestly, you don't want that. What you want is that your function code just works when you or one of your colleagues clones or pulls a new version of the function app code. When debugging locally the code of an ASP.NET Core application deployed in an App Service you don't have this kind of problem because usually your code directly loads the secrets from the Key Vault thanks to ",{"type":414,"tag":889,"props":4694,"children":4697},{"href":4695,"rel":4696},"https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-3.1",[893],[4698],{"type":420,"value":4699},"Key Vault configuration provider",{"type":420,"value":795},{"type":414,"tag":415,"props":4702,"children":4704},{"id":4703},"here-comes-ifunctionsconfigurationbuilder",[4705,4707],{"type":420,"value":4706},"Here comes ",{"type":414,"tag":440,"props":4708,"children":4710},{"className":4709},[],[4711],{"type":420,"value":4712},"IFunctionsConfigurationBuilder",{"type":414,"tag":423,"props":4714,"children":4715},{},[4716,4718,4723,4725,4731,4733,4739,4741,4746,4747,4753],{"type":420,"value":4717},"If you are already familiar with dependency injection in Azure Functions, you already know the ",{"type":414,"tag":440,"props":4719,"children":4721},{"className":4720},[],[4722],{"type":420,"value":4486},{"type":420,"value":4724}," NuGet package that allows you to inherit from the ",{"type":414,"tag":440,"props":4726,"children":4728},{"className":4727},[],[4729],{"type":420,"value":4730},"FunctionStartup",{"type":420,"value":4732}," abstract class and register the different services you want to inject into your functions (you can find more about that in the ",{"type":414,"tag":889,"props":4734,"children":4737},{"href":4735,"rel":4736},"https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection",[893],[4738],{"type":420,"value":936},{"type":420,"value":4740},"). In the latest version of this NuGet package, a new virtual method has been added to ",{"type":414,"tag":440,"props":4742,"children":4744},{"className":4743},[],[4745],{"type":420,"value":4730},{"type":420,"value":1079},{"type":414,"tag":440,"props":4748,"children":4750},{"className":4749},[],[4751],{"type":420,"value":4752},"ConfigureAppConfiguration",{"type":420,"value":4754},". It allows you to specify additional configuration sources you would need in your functions.",{"type":414,"tag":423,"props":4756,"children":4757},{},[4758],{"type":414,"tag":903,"props":4759,"children":4763},{"alt":4760,"className":4761,"src":4762},"FunctionsStartup abstract class.",[907,908],"/posts/images/functionssecrets_vs_2.png",[],{"type":414,"tag":423,"props":4765,"children":4766},{},[4767],{"type":420,"value":4768},"What is awesome is that you can use all the configuration providers you are used to in ASP.NET Core and that includes the Key Vault Configuration provider. I think you understand what I am getting at 😉: instead of using key vault references in your function app settings, you can simply retrieve the secrets from your key vault thanks to the configuration provider.",{"type":414,"tag":423,"props":4770,"children":4771},{},[4772],{"type":414,"tag":903,"props":4773,"children":4777},{"alt":4774,"className":4775,"src":4776},"Debugging configuration in Startup file in Visual Studio.",[907,908],"/posts/images/functionssecrets_vs_3.png",[],{"type":414,"tag":423,"props":4779,"children":4780},{},[4781],{"type":420,"value":4782},"This way, no more copying secret, no more storing secrets values locally, no more wondering if you have the latest version of a secret. Say goodbye to key vault references, pull the latest version of your code, press F5 and it will work!",{"type":414,"tag":415,"props":4784,"children":4786},{"id":4785},"the-triggers-case",[4787],{"type":420,"value":4788},"The triggers case",{"type":414,"tag":423,"props":4790,"children":4791},{},[4792,4794,4807,4809,4813,4815,4822],{"type":420,"value":4793},"Well in my title I said ",{"type":414,"tag":4795,"props":4796,"children":4797},"em",{},[4798,4800,4805],{"type":420,"value":4799},"\"you ",{"type":414,"tag":932,"props":4801,"children":4802},{},[4803],{"type":420,"value":4804},"almost",{"type":420,"value":4806}," no longer need key vault references\"",{"type":420,"value":4808}," and the ",{"type":414,"tag":932,"props":4810,"children":4811},{},[4812],{"type":420,"value":4804},{"type":420,"value":4814}," is important. As the ",{"type":414,"tag":889,"props":4816,"children":4819},{"href":4817,"rel":4818},"https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources",[893],[4820],{"type":420,"value":4821},"Azure Functions documentation",{"type":420,"value":4823}," about customizing configuration sources mentions:",{"type":414,"tag":1152,"props":4825,"children":4826},{"icon":2340},[4827],{"type":414,"tag":423,"props":4828,"children":4829},{},[4830],{"type":420,"value":4831},"For function apps running in the Consumption or Premium plans, modifications to configuration values used in triggers can cause scaling errors. Any changes to these properties by the FunctionsStartup class result in a function app startup error.",{"type":414,"tag":423,"props":4833,"children":4834},{},[4835],{"type":420,"value":4836},"Therefore, if you use a trigger that needs a secret (the connection string of an EventHub trigger for instance), you have no other choice than to use a key vault reference. But for everything else you are good to go with Azure Key Vault configuration provider.",{"type":414,"tag":415,"props":4838,"children":4840},{"id":4839},"to-conclude",[4841],{"type":420,"value":4842},"To conclude",{"type":414,"tag":423,"props":4844,"children":4845},{},[4846],{"type":420,"value":4847},"To summarize, after a quick recall of how Azure Functions configuration works we have seen how Key Vault references can help to avoid having secret values in settings. We talked about the downside of this approach for the local development experience and how using the Azure Key Vault configuration provider solved that except when a secret is needed in a trigger.",{"type":414,"tag":1265,"props":4849,"children":4850},{},[4851],{"type":420,"value":1269},{"title":401,"searchDepth":499,"depth":499,"links":4853},[4854,4855,4856,4858,4859],{"id":4504,"depth":499,"text":4507},{"id":4573,"depth":499,"text":4576},{"id":4703,"depth":499,"text":4857},"Here comes IFunctionsConfigurationBuilder",{"id":4785,"depth":499,"text":4788},{"id":4839,"depth":499,"text":4842},"content:1.posts:10.azure-functions-custom-configuration.md","1.posts/10.azure-functions-custom-configuration.md",1716749600668]