.NET Standard 라이브러리를 .NET Framework 앱에서 사용할 때 주의사항

사실 이제 와서 .NET Framework를 쓰는 사람이 있을까 싶긴 하지만…

1. 상황 설명

이런 코드가 있습니다.

화면 캡처 2025-01-09 015501

StandardLibraryStandardClass는 .NET Standard 2.0을 타겟하는 라이브러리에 포함되어 있습니다.

콘솔 프로젝트는 .NET Framework 4.7을 대상으로 하고 있습니다. 이제 이 콘솔 프로젝트를 빌드합니다. 근데 왠걸? 출력 폴더에 이상한 파일들이 있습니다.

필요 없을 것 같은 dll들이 100개 가까이 있습니다. 결국 이러한 dll들을 빼고 배포하기로 결정했습니다.

이제 .NET Framework 4.7만 설치된 환경에서 앱을 실행하려고 합니다.

캡처

파일을 찾을 수 없다는 오류가 발생합니다.

2. 원인 파악

.NET Standard 2.0은 2017년 8월에 발표되었습니다. 그에 반해 .NET Framework 4.7은 동년 4월에 출시되었습니다. 그렇습니다. .NET Framework 4.7이 .NET Standard 2.0보다 먼저 나왔기 때문에 당연히 지원하지 않는 것이 정상입니다. 하지만 추가적으로 dll 파일들을 제공하여 지원하게끔 만든 것입니다.

.NET Standard 2.0은 netstandard.dll이라는 특수한 dll 파일을 사용합니다. 보통 .NET Standard 2.0으로 라이브러리를 만들게 되면 이 dll만 참조하게 됩니다. 이 dll 파일은 TypeForwardedToAttribute로 실제 구현(.NET Framework의 mscorlib.dll, .NET Core의 System.Private.CoreLib.dll 등…)으로 넘겨주는 기능을 가지고 있습니다. .NET Framework 4.7은 .NET Standard 2.0보다 먼저 나왔기 때문에 이 dll이 없어서 오류가 발생한 것입니다.

이후 버전들에 대해서 얘기를 하자면, .NET Framework 4.7.1은 .NET Standard 2.0 출시 이후인 2017년 10월에 출시되었습니다. 하지만 4.7.1 버전에서도 (수는 줄었지만) 여전히 추가 dll들이 포함됩니다.

(2018년 4월 출시된) 4.7.2로 올려야만 비로소 이러한 dll들이 사라집니다.

그 말은 곧 4.7.2는 기본적으로 .NET Standard 2.0을 지원한다는 의미겠죠?

어쨌든 그래서 추가 dll들을 포함한 채로 배포합니다.

캡처2

(당연히) 앱이 정상적으로 실행됩니다.

3. 그래도 최소 배포를 하고 싶다면

그렇기 때문에 보통은 추가 dll들을 포함시킨 채로 배포를 하는 것이 정상입니다. 하지만 용량 문제가 있어서 최대한 줄여야 한다면?

사실 대부분의 상황에서는 (아마도) netstandard.dll만 포함시켜도 별 문제는 없을겁니다. 아래 스샷은 netstandard.dll만 있는데도 앱이 정상 작동하는 모습을 보여줍니다.

하지만 특정 버전의 .NET Framework에 포함된 API는 문제될 수 있습니다. 예를 들어, ValueTuple이 있겠습니다. ValueTuple은 .NET Framework 4.7에 추가되었습니다. 하지만 .NET Standard 2.0에도 포함되어 있습니다.

코드를 아래와 같이 고쳐보겠습니다.

화면 캡처 2025-01-09 022422

위 코드는 편의상 콘솔 프로젝트에다가 적었지만 ValueTuple은 .NET Standard 2.0에도 포함되어 있기 때문에 거기다가 적어도 별 차이는 없을겁니다.

.NET Framework 4.7에서는 ValueTuple 타입이 포함되어 있기 때문에 앱이 정상 작동합니다. 하지만 프레임워크를 살짝 내려서, 4.6.2에서 테스트해 봅시다. netstandard.dll만 포함해서 배포해보겠습니다.

캡처4

오류가 발생합니다. ValueTuple이 없다. 이건데요. 사실 당연합니다. 4.7부터 추가되었으니까요.

근데 4.6.2에서도 ValueTuple을 포함시킨 코드가 정상 작동하는 경우가 있습니다.

위 스샷은 4.6.2에서 실행되었습니다. 그럼에도 불구하고 ValueTuple을 포함시킨 코드가 잘 작동합니다.

그 이유는 패치를 설치했기 때문입니다. 4.5.2부터 4.7.2까지 누적 업데이트는 공유되는데, 때문에 누적 업데이트를 설치하게 되면 일부 4.7.2 dll들이 설치됩니다. 4.7.2의 일부 기능들을 그 이전 버전들로 백포팅했다고 할 수 있겠습니다. 이렇게 백포팅된 dll 덕분에 앱이 정상 작동할 수 있었던 것입니다.

4. 결론

그래서 결론이 뭐냐면… 4.6.1 ~ 4.7.1에서 .NET Standard 라이브러리를 쓰는 짓은 하지맙시다. 제대로된 지원이 아니기 때문입니다. 사실상 진짜 제대로된 지원은 4.7.2부터라고 할 수 있습니다.

만약 해당 프레임워크를 부득이하게 써야만 한다면… 추가되는 dll들을 버리지 맙시다. 특히 netstandard.dll은 무조건 살려야 합니다.

솔직히 말해서, 이러한 문제가 있는데도 왜 .NET Standard 2.0 지원 범위에 4.6.1 ~ 4.7.1을 추가했는지는 모르겠습니다. 4.7.2 이상만 지원하는 것으로 표시해야 한다고 생각하지만 이젠 너무 늦었죠.

7개의 좋아요

dll을 지우지 않으면 잘 동작한다는게 MS가 신경을 많이 썼군요!!

논외의 이야기지만, 이미 출력된 결과물을 보고 추가적으로 가공해서 어떤 해결을 꾀하려는 접근법은 지양하셨으면 좋겠습니다.

필요한것이 있다면 컴파일과정에서 포함되도록 만들어야하는것이고, 필요없다면 컴파일과정에서 배제되야 하는것이고, 위 문제는 당연히 컴파일러가 필요하니까 포함시켰던걸로 처음부터 해석하셨어야 합니다.

3개의 좋아요