VS Installer를 통한 설치 과정에서 호출되는 Commit() 함수에서의 동작 실패에 대한 문의드립니다.

제가 고민하는 것들이 독특한 것인지 모르겠지만, 관련 자료를 찾을 수 없어서 문의드립니다. Visual Studio Installer Project를 이용해서 아래와 같이 설치 파일을 만들려고 합니다.

하지만 설치 과정에서 호출되는 Commit() 에서 신규 폴더를 생성하고 그 안에 외부 URI 경로를 통해 해당 파일을 다운로드 시키는 로직을 추가하였습니다.

처음에는 async/await으로 작성하였지만, 혹시나 몰라서 동기식/WebClient로 아래와 같이 수정하였습니다.

namespace IntialSetupApp
{
    [RunInstaller(true)]
    public partial class IntialInstallApp : System.Configuration.Install.Installer
    {
        private readonly string temp = @"C:\Windows\Temp\Folder\";
        private readonly string url = @"downloadfilepath";

        public IntialInstallApp()
        {
            InitializeComponent();
        }

        public override void Commit(IDictionary savedState)
        {
            //Debugger.Launch();
            base.Commit(savedState);

            Directory.CreateDirectory(temp);
            _ = DownloadFileToFolder();

        }
        public Task<bool> DownloadFileToFolder()
        {
            try
            {
                string fileName = Path.Combine(temp, "download.zip");
                Uri uri = new Uri(url);

                using (WebClient client = new WebClient())
                {
                    client.DownloadFile(uri, fileName);
                }

            }
            catch (Exception e)
            {

                Console.WriteLine(e.Message);
            }
            return Task.FromResult(true);
        }    
    }
}

그리고 아래와 같이 적용 하였습니다.

20220426_180904

20220426_180914

설치 결과, 폴더는 정상적으로 생성이 되지만 파일은 다운로드 하지 못하는 상황입니다. 하지만 동일한 함수를 별도의 Console 프로젝트로 동작하면 정상으로 동작합니다. Installer 자체에서 제한되는 부분이 있는걸까요? 아니면 제가 잘못 사용하는 것일까요?

1개의 좋아요

권한 문제로 보입니다. C:\Windows\Temp 경로를 사용하지 마시고 Path.GetTempPath()를 사용하세요.

2개의 좋아요

말씀하신 Path.GetTempPath() 경우에는 공식 문서에도 나와 있는 것처럼 Returns the path of the current user's temporary folder.를 반환한다고 합니다.
그래서 경로 자체도 C:\Windows\Temp 경로가 아닌, C:\\Users\\user\\AppData\\Local\\Temp\로 변경되는 것 같습니다.

해당 경로를 얻기 위해서는 Environment.GetEnvironmentVariable("temp", EnvironmentVariableTarget.Machine)로 호출되어야 하는 것 같습니다. 덕분에 System의 Temp를 사용하는 구조를 지양해야 하는 것도 이해하게 되었습니다.

두 경우 모두 별도의 Console 프로젝트에서는 정상으로 동작합니다. 하지만 Installer에서 적용할 경우, 이와 무관하게 다운로드가 수행되지 않았습니다. 아마도 Installer를 통해서 동작하는 경우에는 폴더 경로에 대한 변경을 제한하는 것 같은데… 확실치 않습니다.

1개의 좋아요

설치를 하는 중에 인스톨러에서 어떤 프로그램을 실행해서 미리 환경 설정을
한다는 건가요?
그런 경우 설치 도중의 파일은 임시 폴더에 있기 때문에 폴더 접근이 꼬일 수 있습니다.
그 외에도 다양하게 문제가 발생할 수 있을 것이고 지금 계속 비슷한 질문을 하시게 되는
원인이 거기에 있는 것 같은데요.

2개의 좋아요

혹시 이미 temp 디렉토리가 있어서 발생하지는 않을까요? 소스상으로 봤을 때는 경로가 고정이라서요. 확인해보시겠어요?

2개의 좋아요

저도 이부분을 염두해두고 매번 설치 프로그램 실행 시에는 사전에 해당 폴더를 삭제해두고 진행하였습니다.

1개의 좋아요

흠. 일단, 예외가 발생했을 때 기록을 파일로 해서 예외 내용을 기록해보시겠어요?

2개의 좋아요

조언주신대로 로깅을 적용하여 시도하였습니다. C:\Users\user\Desktop>msiexec /i ./SetupApp.msi /L*V "everylog.log"로 실행하였지만, 역시 인증서로 self-sign하지 않은 프로그램이라 그런지 로깅을 할 수 없는 것 같습니다.
20220426_195956

1개의 좋아요

catch 예외지점에 ‘File.WriteAllText()’ 등으로 예외를 파일로 기록해보세요.

catch (Exception e)
{
    Console.WriteLine(e.Message); // 이곳!
}
2개의 좋아요

로그를 얻었습니다. 흠… The request was aborted: Could not create SSL/TLS secure channel.

2개의 좋아요

관련 문서를 참조하여 정상 동작 확인하였습니다. 오늘도 많은 것을 배우게 되었습니다. 정말 감사드립니다!!

참고로 추가한 구문은 아래와 같습니다.

// using System.Net;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
2개의 좋아요

해결 방법의 기록도 중요하고, 또 콘솔에서는 정상 실행되었는데 Commit()에서는 해당 예외가 발생했는지 그 이유를 확인하는 것도 중요합니다. 왜일까요?

1개의 좋아요

저도 이부분이 너무 궁금해서 계속 자료를 찾고 있는 중입니다. 찾게 되면 공유드리겠습니다.

2개의 좋아요

혹시 .net framework 4.5 이하의 버전일까요?

위 공유해주신 관련 문서에 보면
프레임워크 버전에 따른 지원 수준이 차이나는 것으로 보입니다.

Framework Version Default Protocols
4.5 and earlier SSL 3.0, TLS 1.0
4.6.x TLS 1.0, 1.1, 1.2, 1.3
4.7+ System (OS) Defaults

For the older versions, your mileage may vary somewhat based on which .NET runtimes are installed on the system. For example, there could be a situation where you are using a very old framework and TLS 1.0 is not supported, or using 4.6.x and TLS 1.3 is not supported.

We recommend that you:

  • Target .NET Framework 4.7 or later versions on your apps. Target .NET Framework 4.7.1 or >later versions on your WCF apps.
  • Do not specify the TLS version. Configure your code to let the OS decide on the TLS version.
  • Perform a thorough code audit to verify you’re not specifying a TLS or SSL version.

제가 하려는 말은 코드추가로 해결이 됐지만
혹 target framework를 .net 4.7로 올려도 해결되지 않을까해서 글 남겨봅니다

괜히 지나가다 글남기네요;
즐코하십시요!!

3개의 좋아요

참고로 현재 프로젝트는 .NET Framework 4.8입니다.

2개의 좋아요

참고로… Visual Studio Installer Project에서 어떤 프레임워크를 사용하는지는 아마 다를 것입니다. 그것이 힌트가 될 것 같네요.

1개의 좋아요

말씀하신대로 현 IntialSetupApp는 Class Library로 생성하였습니다. 기본적으로 Class Library 경우에도 System.Web.Services를 지원해주는 것으로 알고 있는데, ServicePointManager처럼 세부 설정이 지원이 안되는 건 가요?

1개의 좋아요