성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
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 Web App 확장 예제 제작</h1> <p> 사실 지난번에 소개한 글만 봐도,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Azure Web App 확장 예제 - Simple WebSite Extension ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11505'>http://www.sysnet.pe.kr/2/0/11505</a> </pre> <br /> 확장 프로그램을 만들 기본이 마련됩니다. 그래도 다시 정리하는 의미에서 바닥부터 만들어 보겠습니다.<br /> <br /> 우선 웹 사이트 하나를 만듭니다. (여기서는 ASP.NET WebForms 프로젝트로 시작합니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 유형: ASP.NET Web Application - Empty - Web Forms 이름: MyAppExtension </pre> <br /> 그다음 default.aspx를 추가하고 다음과 같이 환경 변수를 출력하는 코드만 넣어두겠습니다. (따라서, 이 확장이 설치되면 App Service가 운영 중인 가상 머신의 환경 변수를 모두 확인할 수 있습니다. 참고로, AppService의 환경 변수는 Kudu에서 기본 출력해 줍니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MyAppExtension.Default" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> Ver 1.0<br /> <form id="form1" runat="server"> <div> <table> <% foreach (System.Collections.DictionaryEntry entry in Environment.GetEnvironmentVariables()) { %> <tr> <td><%=entry.Key.ToString()%></td> <td><%=entry.Value.ToString()%></td> </tr> <% } %> </table> </div> </form> </body> </html> </pre> <br /> 그다음, 웹 사이트 프로젝트의 루트에 applicationHost.xdt 파일을 다음의 내용으로 생성합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.applicationHost> <sites> <span style='color: blue; font-weight: bold'><site name="%XDT_SCMSITENAME%" xdt:Locator="Match(name)"> <application path="/MyAppExtension" xdt:Locator="Match(path)" xdt:Transform="Remove" /> <application path="/MyAppExtension" applicationPool="%XDT_APPPOOLNAME%" xdt:Transform="Insert"> <virtualDirectory path="/" physicalPath="%XDT_EXTENSIONPATH%" /> </application> </site></span> </sites> </system.applicationHost> </configuration> </pre> <br /> (위의 path 부분은 여러분의 상황에 맞는 이름으로 바꿔도 됩니다.)<br /> <br /> 이제 비주얼 스튜디오의 솔루션 탐색기에서 프로젝트 노드를 우 클릭해 "Publish" 메뉴로 "Folder"에 배포합니다. 이렇게 만들어진 확장을 배포하기 위해 폴더의 내용을 하나의 .zip 파일로 압축하고 이 파일을 (Windows 10 1803 빌드부터 기본 포함되어 있기도 한) curl.exe를 이용해 <a target='tab' href='http://www.sysnet.pe.kr/2/0/11505'>Azure Portal의 "Deployment Trigger Url(배포 트리거 URL)"</a>로 배포하면 됩니다.<br /> <br /> 여기서 한 가지, 고려 사항이 있는데요. zip 파일은 반드시 내부에 "/SiteExtensions/...[extension_name]..."의 디렉터리 구조를 포함해야 합니다. 즉, 해당 zip 파일을 압축을 풀었을 때 다음과 같은 구조로 나와야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /SiteExtensions /MyAppExtension /app.config /...[이하 생략]... </pre> <br /> 따라서 Publish 메뉴에서 Folder 설정을 "bin\Release\Publish"에서 "bin\Release\Publish\SiteExtensions\MyAppExtension"으로 바꿔야 하고 zip 파일 생성은 ""bin\Release\Publish" 폴더를 기준으로 압축해야 합니다. 참고로, 다음의 글에 따라 FolderProfile.pubxml 파일을 변경하면 비주얼 스튜디오에서 배포(Publish) 시 압축 파일까지 함께 생성할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > MSBuild를 이용해 프로젝트 배포 후 결과물을 zip 파일로 압축하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11508'>http://www.sysnet.pe.kr/2/0/11508</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="utf-8"?> <!-- This file is used by the publish/package process of your Web project. You can customize the behavior of this process by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. --> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> ...[생략]... </PropertyGroup> <PropertyGroup> <MyZipFilePath>$(publishUrl)\..\..\..\$(TargetName).zip</MyZipFilePath> <MyPublishFolderPath>$(publishUrl)\..\..</MyPublishFolderPath> </PropertyGroup> <Target Name="MyPublish" AfterTargets="GatherAllFilesToPublish"> <Delete Files="$(MyZipFilePath)" /> <Exec Command="powershell.exe -nologo -noprofile -command &quot;&amp; { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('$(MyPublishFolderPath)', '$(MyZipFilePath)'); }&quot;" /> </Target> </Project> </pre> <br /> 생성된 (이 글에서는 MyWebAppExtension.zip) zip 파일은 (Windows 10 1803 빌드부터 기본 포함되어 있기도 한) curl.exe를 이용해 <a target='tab' href='http://www.sysnet.pe.kr/2/0/11505'>Azure Portal의 "Deployment Trigger Url(배포 트리거 URL)"로 배포</a>할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > curl.exe -k -v -T "E:\...\MyAppExtension.zip" "https://....scm.azurewebsites.net/zip" </pre> <br /> 정상적으로 배포가 되었으면 다음의 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://[app_service_name].scm.azurewebsites.net/MyAppExtension/ </pre> <br /> (일부 변경은 Azure Portal이나 Kudu Site Extensions 화면을 통해 재시작해줘야 반영됩니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 다음은 AppService 웹 사이트가 Azure VM 내 위치하는 폴더의 경로입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\home\site\wwwroot\ </pre> <br /> 그리고 그 AppService의 확장들은 다음의 폴더에 배포됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\home\SiteExtensions\...[your_extension]... </pre> <br /> 확장들이 포함한 applicationHost.xdt 파일은 대충 다음과 같은 식의 경로에 있는 applicationHost.config 파일과 병합됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\DWASFiles\Sites\...app_service...\Temp\applicationhost.config </pre> <br /> 위의 applicationHost.config 파일에 각각의 Extensions들에 의해 어떤 변경이 이뤄졌는지에 대한 로그를 다음의 경로에서 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\home\LogFiles \*_SCM.log (예: RD0004FFE3003C_2018-05-28_06-53-21_SCM.log) </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;' > Making changes to the applicationHost.config on Azure App Service ; <a target='tab' href='https://www.thebestcsharpprogrammerintheworld.com/2015/01/19/making-changes-to-the-applicationhost-config-on-azure-app-service/'>https://www.thebestcsharpprogrammerintheworld.com/2015/01/19/making-changes-to-the-applicationhost-config-on-azure-app-service/</a> </pre> <br /> d:/home/site 폴더에만 있으면 xdt 파일이 적용됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 개발 팁을 하나 소개하면, App Service 확장은 로컬에서 개발하고 Azure로 올릴 텐데요, 이때 환경에 따른 코드 수행을 제어할 필요가 있습니다. 이에 대해 다음의 글에도 나오지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Writing a Site Extension for Azure Websites ; <a target='tab' href='https://azure.microsoft.com/en-us/blog/writing-a-site-extension-for-azure-websites/'>https://azure.microsoft.com/en-us/blog/writing-a-site-extension-for-azure-websites/</a> </pre> <br /> 그럴 때 "home" 환경 변수 여부를 이용하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > if (Environment.GetEnvironmentVariable("home") != null) { // in Azure } else { // Allows us to run locally. } </pre> <br /> 물론, 여러분의 로컬 PC에 'home' 환경 변수를 정의해 두었다면 다음의 변수들이 후보가 될 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > WEBSITE_HOME_STAMPNAME WEBSITE_PROACTIVE_AUTOHEAL_ENABLED ScmType APPSETTING_WEBSITE_AUTH_ENABLED WEBSITE_SCM_ALWAYS_ON_ENABLED REGION_NAME WEBSITE_SCM_SEPARATE_STATUS WEBSITE_SITE_NAME WEBSITE_AUTH_AUTO_AAD WEBSITE_CURRENT_STAMPNAME APPSETTING_ScmType WEBSITE_COMPUTE_MODE WEBSITE_HOSTNAME WEBSITE_IIS_SITE_NAME HOME_EXPANDED WEBSITE_RESOURCE_GROUP WEBSITE_AUTH_LOGOUT_PATH WEBSITE_LOCALCACHE_ENABLED WEBSITE_INSTANCE_ID WEBSITE_SKU WEBSITE_OWNER_NAME WEBSITE_RELAYS </pre> <br /> <hr style='width: 50%' /><br /> <br /> curl.exe로 배포 시 다음과 같은 오류가 발생한다면?<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'> {"Message":"An error has occurred.","ExceptionMessage":"Access to the path 'D:\\home\\app.config' is denied.","ExceptionType":"System.UnauthorizedAccessException","StackTrace":" at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)\r\n at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)\r\n at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)\r\n at System.IO.FileInfo.Open(FileMode mode, FileAccess access)\r\n at System.IO.Abstractions.FileInfoWrapper.Open(FileMode mode, FileAccess access)\r\n at Kudu.Core.Infrastructure.ZipArchiveExtensions.Extract(ZipArchive archive, String directoryName) in C:\\Kudu Files\\Private\\src\\master\\Kudu.Core\\Infrastructure\\ZipArchiveExtensions.cs:line 130\r\n <br /> ...[생략]...at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}* Connection #0 to host jpublic.scm.azurewebsites.net left intact<br /> </div><br /> <br /> 확장 모듈을 담은 .zip 파일에 "/SiteExtensions/...[extension name]..."과 같은 디렉터리 구조를 담지 않고 있기 때문입니다. 따라서 그 디렉터리를 고려해 다시 압축한 후 업로드하면 정상적으로 설치가 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이 글을 실습하면서 zip 파일 압축 단계에서 다음과 같은 오류가 발생할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 2>Transformed Web.config using E:\TestWebApp\Web.Release.config into obj\Release\TransformWebConfig\transformed\Web.config. 2>Copying all files to temporary location below for package/publish: 2>obj\Release\Package\PackageTmp. 2>7zipping files... 2>powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('...', '...'); }" 2>Exception calling "CreateFromDirectory" with "2" argument(s): "The process cannot access the file 'E:\TestWebApp\bin\Release\Publish\TestWebApp.zip' because it is being used by another process." 2>At line:1 char:53 2>+ ... ileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('E:\... 2>+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2> + CategoryInfo : NotSpecified: (:) [], MethodInvocationException 2> + FullyQualifiedErrorId : IOException 2> 2>Publishing folder /... 2>Publishing folder bin... 2>Publishing folder bin/roslyn... 2>Publishing folder Content... 2>Publishing folder fonts... 2>Publishing folder Scripts... 2>Publishing folder Views... 2>Publishing folder Views/Home... 2>Publishing folder Views/Shared... 2>Web App was published successfully file:///E:/TestWebApp/bin/Release/Publish/SiteExtensions/TestWebApp 2> </pre> <br /> 이건 zip 파일이 생성되는 폴더가 압축을 하려는 폴더와 같은 경우에 발생합니다. 즉, 다음과 같은 식으로 설정하고 빌드하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <PropertyGroup> <MyZipFilePath><span style='color: blue; font-weight: bold'>$(ProjectDir)$(PublishUrl)\..\..\</span>$(TargetName).zip</MyZipFilePath> <MyPublishFolderPath><span style='color: blue; font-weight: bold'>$(ProjectDir)$(PublishUrl)\..\..</span></MyPublishFolderPath> </PropertyGroup> <Target Name="MyPublish" AfterTargets="GatherAllFilesToPublish"> <Delete Files="$(MyZipFilePath)" /> <Exec Command="powershell.exe -nologo -noprofile -command &quot;&amp; { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('$(MyPublishFolderPath)', '$(MyZipFilePath)'); }&quot;"/> </Target> </pre> <br /> 압축 대상 및 그것의 zip 파일이 "$(ProjectDir)$(PublishUrl)\..\.." 폴더를 대상으로 했기 때문에 "The process cannot access the file..." 오류가 발생하는 것입니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1331
(왼쪽의 숫자를 입력해야 합니다.)