성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Azure Functions를 사용한 간단한 실습</h1> <p> 오늘은 부담없이, ^^ 간단하게 Azure Function을 실습해 볼까요?<br /> <br /> 사실 Visual Studio 환경에서는 매우 쉽게 테스트해 볼 수 있습니다. 우선, 프로젝트 자체를 "Azure Functions"로 시작해,<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_func_1.png' src='/SysWebRes/bbs/azure_func_1.png' /><br /> <br /> 중간에 선택하는 응용 프로그램 유형에서 (이번 실습은 웹 요청에 반응할 것이므로) "Http trigger"를 선택하면,<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_func_2.png' src='/SysWebRes/bbs/azure_func_2.png' /><br /> <br /> 기본적으로 다음과 같은 코드를 포함하는 프로젝트가 열립니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace FunctionApp1 { public static class Function1 { [FunctionName("Function1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); string name = req.Query["name"]; string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody); name = name ?? data?.name; string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $"Hello, {name}. This HTTP triggered function executed successfully."; return new OkObjectResult(responseMessage); } } } </pre> <br /> 제가 원하는 기능은 클라이언트의 공용 IP를 출력하는 것이므로 Function1을 다음과 같이 수정하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [FunctionName("Function1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); string userHostAddress = req.HttpContext.Connection.RemoteIpAddress.ToString(); string ip = req.Headers["HTTP_X_FORWARDED_FOR"]; if (string.IsNullOrEmpty(ip) == false) { userHostAddress = ip; } return new OkObjectResult(userHostAddress); } </pre> <br /> 이렇게 바꾸고 곧바로 F5 키를 눌러 디버깅을 실행하면 Local PC에서 Emulator가 구동되면서 다음과 같은 출력의 콘솔 창이 뜹니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Azure Functions Core Tools Core Tools Version: 4.0.4483 Commit hash: N/A (64-bit) Function Runtime Version: 4.1.3.17473 [2022-04-18T04:33:25.113Z] Found C:\temp\FunctionApp1\FunctionApp1\FunctionApp1.csproj. Using for user secrets file configuration. Functions: Function1: [GET,POST] http://localhost:7071/api/Function1 For detailed output, run func with --verbose flag. </pre> <br /> 따라서 웹 브라우저를 이용해 "http://localhost:7071/api/Function1" URL로 요청을 보내면, 콘솔에는 다음과 같은 식의 디버깅 로그가 찍히고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [2022-04-18T04:54:04.785Z] Executing 'Function1' (Reason='This function was programmatically called via the host APIs.', Id=f13d0c90-2f8e-4424-ad94-eeca81759aa3) [2022-04-18T04:54:06.632Z] C# HTTP trigger function processed a request. [2022-04-18T04:54:06.646Z] Executed 'Function1' (Succeeded, Id=f13d0c90-2f8e-4424-ad94-eeca81759aa3, Duration=1871ms </pre> <br /> 화면에는 (로컬에서 테스트했으므로) "127.0.0.1"이 찍히는 것을 확인할 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이렇게 로컬에서도 실행 및 테스트를 할 수 있으므로 개발이 어렵지 않습니다. 이후, Azure로의 배포는 솔루션 탐색기의 프로젝트 노드를 우 클릭해 나오는 "Publish" 메뉴를 선택, Azure에서 준비한 다양한 환경을 대상으로 배포할 수 있습니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_func_3.png' src='/SysWebRes/bbs/azure_func_3.png' /><br /> <br /> Azure 측에 미리 Function App 서비스를 하나 만들어 두거나, 위의 배포 창에서 제공하는 기능을 이용해 즉석에서 만들어도 됩니다.<br /> <br /> Azure Function App 서비스는 겉으로는 별도의 서비스인 듯하지만, 내부적으로는 결국 <a target='tab' href='https://azure.microsoft.com/en-us/services/app-service/web/'>Azure Web App Services</a>와 다를 바가 없습니다. 실제로 호스팅되는 기본 URL도 사용자가 지정한 이름 외에 "azurewebsites.net"가 붙기도 합니다. 그러니까 전체적인 서비스 형태는 기존의 App Services를 Function App 유형으로 확장한 것에 불과합니다.<br /> <br /> 배포 후 사용법을 볼까요?<br /> <br /> 가령 사용자의 Function App URL이 다음과 같이 정해진 경우라면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > https://publicipfuncapp.azurewebsites.net/ </pre> <br /> 이 글의 예제에서 작성한 코드는 다음과 같은 경로로 호출할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > https://publicipfuncapp.azurewebsites.net/<span style='color: blue; font-weight: bold'>api/Function1</span> </pre> <br /> 그런데, 실제로 저렇게 호출하면 "HTTP ERROR 401" 오류가 발생합니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > This page isn’t working right now If the problem continues, contact the site owner. HTTP ERROR 401 </pre> <br /> 왜냐하면, 해당 Function1에 대해 소스 코드에서 보면 AuthorizationLevel이 Function으로 되어 있기 때문입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [FunctionName("Function1")] public static async Task&lt;IActionResult&gt; Run( [HttpTrigger(<span style='color: blue; font-weight: bold'>AuthorizationLevel.Function</span>, "get", "post", Route = null)] HttpRequest req, ILogger log) </pre> <br /> 저 값을 "AuthorizationLevel.Anonymous"로 바꾸고 다시 시도하면 이제는 정상적으로 Function1 코드가 수행되는 것을 확인할 수 있습니다.<br /> <br /> 반면, AuthorizationLevelFunction이 Function으로 지정돼 있다면 이를 호출하기 위해 (일반적인 REST API 서비스 측에서 요구하는 App Key처럼) 미리 정해진 Key 값을 함께 명시를 해야 합니다. 이 Key 값은 Azure Portal에서 Function App 화면을 통해 "Get Function Url"로 알아낼 수 있습니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_func_4.png' src='/SysWebRes/bbs/azure_func_4.png' /><br /> <br /> 저 위의 모든 키 값은 Function App 서비스가 생성되는 시점에 함께 만들어지지만, 원한다면 언제든 새롭게 키를 바꿀 수 있습니다. 위의 목록을 보면 3가지 유형의 키가 나오는데,<br /> <br /> <ol> <li>default (function key)</li> <li>default (host key)</li> <li>masterKey (host key)</li> </ol> <br /> function key는 해당 Function마다 달라지는 key입니다. 그래서 또 다른 Function을 하나 더 추가하면 그 Function은 그것에 고유하게 생성되는 Function Key를 또 알아내서 호출을 해야 합니다.<br /> <br /> 반면, host key는 모든 Function을 호출할 수 있는 기능을 합니다. 따라서, Function1과 Funciton2를 만들었고 host key가 "6vkrc/7BLZVHc2AXkeG"라면, 다음과 같은 식으로 2개의 Function 모두를 호출할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > https://publicipfuncapp.azurewebsites.net/api/Function1?<span style='color: blue; font-weight: bold'>code=6vkrc/7BLZVHc2AXkeG</span> https://publicipfuncapp.azurewebsites.net/api/Function2?<span style='color: blue; font-weight: bold'>code=6vkrc/7BLZVHc2AXkeG</span> </pre> <br /> 또한 같은 host key이면서, default와 masterKey로 나뉘는데 masterKey는 일종의 관리자 권한을 더한다고 보시면 됩니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Master Key ; <a target='tab' href='https://learn.microsoft.com/en-us/azure/azure-functions/security-concepts?tabs=v4#master-key-admin-level'>https://learn.microsoft.com/en-us/azure/azure-functions/security-concepts?tabs=v4#master-key-admin-level</a> </pre> <br /> 일례로, AuthorizationLevel을 Admin으로 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [HttpTrigger(<span style='color: blue; font-weight: bold'>AuthorizationLevel.Admin</span>, "get", "post", Route = null)] HttpRequest req, ILogger log) </pre> <br /> 이 Function은 오직 masterKey로만 호출할 수 있고, 일반적인 다른 host key로는 호출할 수 없습니다.<br /> <br /> 참고로, host key는 Azure Portal의 "Function App" 서비스 화면에서 제어할 수 있고, function key는 개별 Function 화면에서 제어할 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 비주얼 스튜디오 환경 내에서, 로컬로 실행하는 Function App의 응용 프로그램은 다음의 위치에서 실행되는 func.exe가 대체합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > %USERPROFILE%\AppData\Local\AzureFunctionsTools\Releases\4.13.0\cli_x64 </pre> <br /> 그리고 iisexpress.exe처럼, 이것 역시 비주얼 스튜디오가 아닌 그냥 단순하게 다음과 같은 식의 명령어를 이용해 실행하는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Function App 프로젝트가 빌드된 경로로 이동하고, c:\temp> <span style='color: blue; font-weight: bold'>cd c:\temp\FunctionApp1\FunctionApp1\bin\Debug\net6.0\</span> // 그 경로를 Current Directory로 해서 func.exe를 수행 c:\temp\FunctionApp1\FunctionApp1\bin\Debug\net6.0> <span style='color: blue; font-weight: bold'>"%USERPROFILE%\AppData\Local\AzureFunctionsTools\Releases\4.13.0\cli_x64\func.exe" host start --port 7071 --pause-on-error</span> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 대충 어떤 식인지 이 정도면 쉽게 파악이 되셨을 것입니다. <br /> <br /> 참고로, Azure Functions는 무료 범위가 있다는 점! ^^<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> // <a target='tab' href='https://azure.microsoft.com/ko-kr/pricing/details/functions/'>https://azure.microsoft.com/ko-kr/pricing/details/functions/</a><br /> <br /> Azure Functions 사용량 과금제는 초당 리소스 사용량과 실행 횟수에 따라 비용이 청구됩니다. 사용량 플랜 가격에는 종량제 가격 체제로 구독 내의 모든 함수 앱에 대해 구독별로 매월 1백만 건의 요청 및 매월 400,000GB의 리소스 사용이 무료로 부여됩니다.<br /> </div><br /> <br /> <hr style='width: 50%' /><br /> <br /> (2024-04-04: 업데이트)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET Conf 2023 (Day 1) - Leveraging the power of the .NET platform in Azure Functions ; <a target='tab' href='https://youtu.be/vU-iZcxbDUk?t=14791'>https://youtu.be/vU-iZcxbDUk?t=14791</a> </pre> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_func_net8_1.png' src='/SysWebRes/bbs/azure_func_net8_1.png' /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
7525
(왼쪽의 숫자를 입력해야 합니다.)