.NET Framework를 .NET으로 이행하기 전에 확인해야 할 것 - 착수 전에 승부가 결정되는 실천 체크리스트

· 업데이트: · · .NET, .NET Framework, C#, 모더나이제이션, Windows 개발, 이행

수정 이력(1건, 최종 수정 2026년 09월 01일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635142)
최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635141)

이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.

小村 豪 (2026). 「.NET Framework를 .NET으로 이행하기 전에 확인해야 할 것 - 착수 전에 승부가 결정되는 실천 체크리스트」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635141 https://comcomponent.com/ko/blog/2026/03/15/003-dotnet-framework-to-dotnet-premigration-checklist/

DOI(최신 버전)
10.5281/zenodo.21635141
DOI(이 버전)
10.5281/zenodo.22217438

일영 시트 포함 Excel 체크리스트 다운로드

이 파일은 Checklist-jaChecklist-en 2개 시트로 구성되어 있으며, 13개 장의 착수 전 체크리스트를 방침 / 현행 .NET Framework 쪽 정비 / 앱 종류와 기술 선정 / 비대응 기술·요주의 API / Windows 전용 의존 / shared library와 데이터 액세스 / 운영과 build의 7개 카테고리 34개 항목으로 정리한 것입니다. StatusNotes 열은 비어 있으므로 프로젝트별 점검표로 그대로 사용할 수 있습니다. 글을 읽기 전에 훑어보면 13장까지의 흐름을 파악하기 쉬울 것입니다.

.csprojTargetFrameworknet10.0으로 바꾸고, NuGet을 몇 개 업데이트해서 빌드가 통과하면 끝.

……이런 이행이라면 상당히 평화롭습니다. 실제로는 그렇게 되지 않는 경우가 더 많습니다.

.NET Framework 현장에는 System.Web, WCF, Web Forms, 오래된 packages.config, web.config.install.xdt, 네이티브 DLL, COM / ActiveX, 디자인 타임에만 동작하는 서드파티 컨트롤, 암묵적인 x86 전제, 디자이너에 의존하는 ResX, 오래된 시리얼라이저 등 평소에는 의식하지 않는 전제가 여러 곳에 잠들어 있습니다.

그래서 .NET Framework에서 .NET으로의 이행에서 정말 중요한 것은 구현에 들어가기 전의 사전 점검입니다. 착수 전에 논점을 분해할 수 있다면 이행은 「큰 도박」이 아니라 「순서대로 처리해 나가는 작업」이 됩니다.

사전 점검이 이행의 성격을 바꾼다구현에 들어가기 전에 사전 점검을 해서 논점을 분해할 수 있다면, 이행은 큰 도박이 아니라 순서대로 처리해 나가는 작업이 됨을 보여주는 그림.사전 점검을 건너뛰면잠들어 있는 암묵적 전제들착수 전 사전 점검으로 논점을 분해순서대로 처리해 나가는 작업이 된다이행이 큰 도박이 된다

그림 1: 착수 전에 논점을 분해할 수 있는지 여부로, 이행은 도박도 되고 작업도 된다.

이 글에서는 기존의 .NET Framework 4.x 업무 애플리케이션현재의 .NET으로 이행하기 전에 무엇을 확인해야 하는지를 정리합니다. 주된 대상은 다음과 같습니다.

  • 클래스 라이브러리
  • 콘솔 앱
  • Windows 서비스
  • WinForms / WPF
  • ASP.NET Framework(MVC / Web API / Web Forms)
  • WCF를 사용하는 앱
  • EF6을 사용하는 앱

집필 시점은 2026-03-15입니다. 지원 기간이나 공식 도구의 권장 사항은 바뀌므로, 날짜가 지난 뒤에 읽는다면 공식 정보도 함께 확인하기 바랍니다.

1. 먼저 결론

먼저 빗나가기 어려운 결론만 짚어 둡니다.

  • 이행 전에 .NET Framework 쪽을 정리하는 것이 먼저입니다. Microsoft의 공식 가이드에서도 이식 전에 .NET Framework 4.7.2 이상으로 올리고, PackageReference화, SDK 스타일화, 의존 관계 업데이트를 먼저 끝내는 것을 추천합니다.
  • 난이도는 코드량보다 앱 모델로 결정됩니다. 클래스 라이브러리나 콘솔은 비교적 가볍고, ASP.NET Framework, Web Forms, WCF 서버, WF(Workflow Foundation)는 무거워지기 쉽습니다.
  • WinForms / WPF는 .NET으로 이행해도 Windows 전용 그대로입니다. 여기를 착각하면 이행은 했는데 Linux 컨테이너에는 실리지 않는다는, 정석적인 지뢰를 밟게 됩니다.
  • ASP.NET Framework → ASP.NET Core는 실질적인 아키텍처 이행입니다. 소규모 앱이라면 한 번에 갈 수 있는 경우도 있지만, 큰 운영 시스템은 단계적 이행을 전제로 하는 편이 안전합니다.
  • WCF와 EF6은 runtime의 이행과 분리할 수 있는 경우가 있습니다. WCF 클라이언트는 .NET용으로 지원되는 패키지가 있고, EF6은 modern .NET으로 옮긴 뒤에 EF Core로 별도 이행할 수 있습니다.
  • 한편, AppDomain 생성, .NET Remoting, CAS(Code Access Security, 코드 접근 보안), COM+, Workflow Foundation, BinaryFormatter 의존은 빨간불입니다. 먼저 찾아내지 않으면 뒤에서 공수가 폭발합니다.
  • packages.config / install.ps1 / XDT(XML Document Transform, web.config 등을 변환하는 구조) / content 자산 / 네이티브 DLL / COM / ActiveX / x86 전제는 빌드는 통과해도 실행 시나 디자인 타임에 떨어지기 쉬우므로 착수 전에 점검합니다.
  • 2026-03 시점에서는 .NET 10이 LTS입니다. 신규 이행의 착지점은 기본적으로 현행 LTS를 기준으로 생각하는 것이 자연스럽습니다.
  • 테스트, 계측, 롤백 준비가 없는 이행은 위험합니다. 이행은 구현 작업이라기보다 전제 조건을 하나씩 가시화하는 작업입니다.

이 글의 지식 맵

.NET Framework에서 .NET으로의 이행은 구현보다 앞서는 사전 점검이 핵심이며, packages.config의 후속인 PackageReference나 SDK 스타일 프로젝트로의 전환은 이행보다 먼저 끝내 두어야 할 작업으로 여겨집니다. AppDomain의 신규 생성이나 .NET Remoting, COM+, Workflow Foundation은 .NET과 양립하지 않으며, BinaryFormatter도 상황에 따라서는 양립하지 않습니다. WCF는 클라이언트와 서버에서 사정이 다르며, 서버 쪽은 CoreWCF나 gRPC로의 재설계가 필요해집니다. ASP.NET Framework의 후속은 ASP.NET Core지만 Web Forms는 같은 app model이 아니며, EF6에서 EF Core로의 이행은 runtime 이행과 분리해 뒤로 미루는 것이 안전하다고 여겨집니다. WinForms/WPF는 이행할 수 있어도 Windows 전용 그대로이며, Windows 전용 API 의존은 Windows Compatibility Pack으로 완화할 수 있습니다.

.NET Framework에서 .NET으로의 이행 전 체크리스트 지식 맵.NET Framework에서 .NET으로 이행하기 전에 정리해야 할 의존 관계 형식·비대응 기술·WCF나 EF6의 취급·Windows 전용 API 의존의 관계를 보여주는 그림전제로 한다의 후속이용한다의 후속보다 먼저 해야 한다보다 먼저 해야 한다사용은 비권장권장되는 대응이용한다양립하지 않는다양립하지 않는다양립하지 않는다양립하지 않는다양립하지 않는다전제로 한다전제로 한다구현을 담당한다의 후속보다 먼저 해야 한다의 후속양립하지 않는다양립하지 않는다이용한다이용한다이용한다이용한다완화한다이용한다전제로 한다전제로 한다.NET Framework에서 .NET으로 마이그레이션.NET Framework.NET(Core 이후)Windows 호환 팩PackageReferencepackages.configSDK 스타일 프로젝트.NET Upgrade AssistantGitHub Copilot 현대화.NET Standard 2.0AppDomain 생성.NET RemotingCOM+(System.EnterpriseServices)Workflow FoundationBinaryFormatterWCF 서버(WCF 서비스 호스트)CoreWCFgRPCEF CoreEF6(Entity Framework 6)ASP.NET CoreASP.NET Framework(MVC/Web API)ASP.NET Web FormsSystem.Web / HttpContext.CurrentWPFWindows FormsWindows 전용 API 의존WCF 클라이언트

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 30건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. 애초에 “지금 당장 이행해야 하는지”부터 정한다

처음에 정해야 할 것은 “어떻게 이행할 것인가”가 아닙니다. 정말로 지금 이 앱을 이행해야 하는가를 정하는 것입니다.

여기를 애매하게 두면, 기술적으로는 옳지만 사업적으로는 지나치게 무거운 이행이 되거나, 반대로 명백히 이행하는 편이 좋은데도 지나치게 뒤로 미루는 판단이 되기 쉽습니다.

최초에 정해야 할 질문어떻게 이행할 것인가보다 먼저, 정말로 지금 이 앱을 이행해야 하는지를 정해야 하며, 여기가 애매하면 지나치게 무거운 이행이나 지나친 후순위화로 흐르기 쉬움을 보여주는 그림.먼저 정한다애매한 채로 진행하면정말로 지금 이행해야 하는가어떻게 이행할 것인가지나치게 무거운 이행 또는 지나친 후순위화

그림 2: “어떻게 이행할 것인가”보다 먼저 “지금 이행해야 하는가”를 정하지 않으면, 판단이 어느 한쪽으로 치우친다.

2.1 .NET Framework에 남는 판단도 충분히 있을 수 있다

.NET Framework 4.8.1은 지원되는 Windows에 실려 있는 한 계속 지원됩니다. 즉, 지금 당장 전부 modern .NET으로 바꾸지 않으면 즉시 위험하다는 단순한 이야기가 아닙니다.

다만 잔류에는 분명한 제약이 있습니다.

  • Windows 전용에서 벗어날 수 없다
  • ASP.NET Web Forms나 오래된 서버 스택을 계속 안고 가야 한다
  • 새로운 .NET의 성능 개선, 언어 기능, 에코시스템의 혜택을 받기 어렵다
  • 클라우드, 컨테이너, CI/CD의 요즘 전제와 어긋나기 쉽다

반대로 다음과 같은 의존이 강하다면, 당분간은 .NET Framework 4.8.1에 맞춰 안정적으로 운영하면서 별도 라인에서 교체 계획을 세우는 편이 합리적입니다.

잔류라는 합리적인 선택Web Forms나 WCF 서버 호환, COM+ 등 강한 레거시 의존이 있다면, 당분간은 .NET Framework 4.8.1에 맞춰 안정적으로 운영하면서 별도 라인에서 교체 계획을 세우는 것이 합리적임을 보여주는 그림.강한 레거시 의존이 있다당분간 4.8.1에 맞춰 안정 운영별도 라인에서 교체 계획Windows 전용 등의 제약은 남는다

그림 3: 의존이 깊은 경우에는 4.8.1로의 안정 운영과 교체 계획, 두 갈래를 함께 두는 것이 현실적이다.

  • Web Forms 화면 자산이 대량으로 있다
  • WCF 서버 호환을 엄격히 유지해야 한다
  • Workflow Foundation이나 COM+ 의존이 깊다
  • 서드파티 디자인 타임 부품이 modern .NET에 비대응이다
  • 비즈니스적으로 큰 사양 변경이 허용되지 않는다

2.2 선택지별로 무엇이 달라지는가

선택 무엇이 좋아지는가 무엇이 남는가 / 잃는가 어울리는 경우
.NET Framework 4.8.1에 머문다 기존 자산을 무너뜨리지 않고 안정적으로 운영하기 쉽다 Windows 전용, 오래된 앱 모델, 모더나이제이션의 한계 레거시 의존이 강하고, 지금은 사업을 우선하며 안정 운영하고 싶다
modern .NET으로 이행하되 Windows에 머문다 런타임과 툴체인을 modern화할 수 있다. 성능·개발 경험·SDK 스타일의 혜택이 크다 Windows API 의존은 남는다. 크로스 플랫폼이 되지는 않는다 WinForms / WPF, Windows Service, Windows API를 사용하는 업무 앱
modern .NET으로 이행하고, 장래에는 Linux / 컨테이너 / 클라우드도 시야에 넣는다 배포처의 자유도가 올라간다. 운영 모델도 새롭게 하기 쉽다 Windows 전용 API나 app model을 먼저 걷어내야 한다 서버 사이드를 클라우드 쪽으로 옮기고 싶다, 인프라도 함께 쇄신하고 싶다

중요한 것은 이행하고 싶은가가 아니라 이행 후에 어디로 착지하고 싶은가를 먼저 정하는 것입니다.

정해야 할 것은 착지점이행하고 싶은가가 아니라, 이행 후에 어디로 착지하고 싶은가를 먼저 정하는 것이 중요함을 보여주는 그림.질문으로는 불충분이것을 정한다이행하고 싶은가먼저 정해야 할 것이행 후에 어디로 착지하고 싶은가선택지와 봐야 할 논점이 정해진다

그림 4: 질문을 “이행하고 싶은가”에서 “어디로 착지하고 싶은가”로 바꾸면 선택지가 정해진다.

3. 먼저 정해 둬야 할 4가지 방침

3.1 착지점이 될 .NET 버전

집필 시점에는 Microsoft의 지원 정책상 .NET 10이 LTS입니다. 한편 .NET 8 LTS.NET 9 STS는 둘 다 2026-11-10에 지원이 종료될 예정입니다. STS인데도 LTS와 같은 날짜가 되는 이유는 STS의 지원 기간이 18개월에서 24개월로 연장되었기 때문입니다. “STS는 18개월”이라는 예전 전제로 계산하면 .NET 9는 2026-05-12 종료로 보이므로, 날짜를 근거로 삼을 때는 공식 라이프사이클 정보로 확인하기 바랍니다.

그래서 이제부터 새로 .NET Framework에서 이행한다면, 웬만한 사정이 없는 한 현행 LTS를 착지점으로 삼는 것이 자연스럽습니다.

여기서의 실무적인 사고방식은 단순합니다.

  • 짧게 끝내고 싶은 소규모 이행이라면 현행 LTS로 바로 착지
  • 장기 운영을 전제로 한 기간 시스템이라도 역시 현행 LTS를 기본으로 생각한다
  • “기존 라이브러리 사정으로 한 단계 전 LTS로 하고 싶다”는 것도 사정으로는 있을 수 있지만, 언제까지 유지보수되는지를 날짜로 확인하고 판단한다
착지 버전을 정하는 사고방식소규모 이행이든 기간 시스템이든 현행 LTS를 기본으로 하고, 기존 라이브러리 사정으로 한 단계 전 LTS로 하고 싶다면 언제까지 유지보수되는지를 날짜로 확인하고 판단한다는 사고방식을 보여주는 그림.기본기존 라이브러리 사정착지점이 될 .NET을 고른다현행 LTS로 착지한 단계 전 LTS도 검토유지보수 기한을 날짜로 확인하고 판단

그림 5: 착지점은 현행 LTS가 기본이며, 이전 LTS를 고른다면 유지보수 기한의 날짜를 근거로 삼는다.

3.2 Windows 전용으로 갈 것인가, 장래 크로스 플랫폼을 노릴 것인가

이 판단에 따라 봐야 할 논점이 크게 달라집니다.

  • Windows 전용으로 간다면, WPF / WinForms나 Windows Compatibility Pack을 사용해 우선 runtime을 modern화하는 현실적인 노선을 택할 수 있습니다.
  • 장래 Linux / 컨테이너화도 노린다면 System.Drawing.Common, 레지스트리, WMI, EventLog, Windows Service, COM, Office Interop 등 Windows를 전제로 하는 API를 이른 단계에서 점검할 필요가 있습니다.

여기를 정하지 않고 이행을 시작하면, 도중에 “Windows 고정이면 됐던 거 아닌가”, “아니, 컨테이너에 올리려던 거였는데”처럼 이야기가 어긋나기 시작합니다.

Windows 전용인가 크로스 플랫폼인가의 분기Windows 전용으로 간다면 호환 팩을 사용해 우선 runtime을 modern화하는 현실적인 노선을 택할 수 있고, 장래 Linux나 컨테이너화를 노린다면 Windows를 전제로 하는 API를 이른 단계에서 점검할 필요가 있다는 분기를 보여주는 그림.Windows 전용으로장래에는 컨테이너도정하지 않고 시작하면어느 쪽을 노릴 것인가호환 팩으로 runtime을 modern화Windows 전제 API를 조기에 점검도중에 이야기가 어긋난다

그림 6: 이 분기를 먼저 정하지 않으면 봐야 할 논점이 정해지지 않아 도중에 어긋난다.

3.3 한 번에 할 것인가, 단계적으로 이행할 것인가

이행의 형태는 크게 3가지입니다.

  • in-place에 가까운 일괄 이행
  • side-by-side로 신구를 나란히 두는 이행
  • route / library 단위로 조금씩 옮기는 단계적 이행

특히 ASP.NET Framework 앱에서는 Microsoft의 가이드에서도 incremental migration이 명확히 안내되고 있습니다. 운영을 멈추고 싶지 않다, 기능 수가 많다, 주변 의존이 많다는 조건이라면, 처음부터 단계적 이행을 전제로 설계하는 편이 무리가 없습니다.

이행의 3가지 형태이행에는 in-place에 가까운 일괄 이행, side-by-side로 신구를 나란히 두는 이행, route나 library 단위로 조금씩 옮기는 단계적 이행의 3가지 형태가 있으며, 운영을 멈추고 싶지 않은 조건에서는 단계적 이행을 전제로 하는 편이 무리가 없음을 보여주는 그림.이행 형태를 고른다일괄 이행(in-place 방식)side-by-side로 신구 병행route / library 단위의 단계적 이행운영을 멈추고 싶지 않다면 이것이 전제

그림 7: 형태는 3가지이며, 기능이 많고 멈출 수 없는 운영 시스템은 단계적 이행을 전제로 둔다.

3.4 무엇을 “이번 이행 대상에서 제외할지”

이행이 실패하기 쉬운 것은 할 일을 지나치게 많이 담기 때문입니다.

예를 들어 다음을 동시에 하는 것은 무거워지기 쉽습니다.

  • .NET Framework → .NET
  • ASP.NET Framework → ASP.NET Core
  • EF6 → EF Core
  • Windows 서버 → Linux 컨테이너
  • 인증 기반의 변경
  • 로그 / 모니터링 기반의 변경
  • 데이터베이스 이행

물론 전부 언젠가는 필요할지도 모릅니다. 다만 동시에 할 필요가 있는가는 별개의 문제입니다.

현실에서는 다음과 같이 분리하는 편이 잘 진행됩니다.

  1. 먼저 runtime과 프로젝트 구조를 modern화한다
  2. 그 위에서 app model을 옮긴다
  3. 마지막으로 ORM, 인증, 클라우드, 모니터링을 업데이트한다
지나치게 담지 않는 분리 순서먼저 runtime과 프로젝트 구조를 modern화하고, 그 위에서 app model을 옮기고, 마지막으로 ORM, 인증, 클라우드, 모니터링을 업데이트한다는 분리 순서를 보여주는 그림.동시에 담으면runtime과 구조를 modern화app model을 옮긴다ORM·인증·클라우드·모니터링을 업데이트이행이 무거워져 실패하기 쉽다

그림 8: 전부를 동시에 하지 않고 runtime·app model·주변의 순서로 분리하면 무거워지지 않는다.

4. 착수 전에 갖춰 둘 토대

Microsoft의 이식 전 가이드는 상당히 실무적입니다. 요컨대 이행 전에 지금의 .NET Framework 프로젝트를 modern한 입구 쪽으로 맞춰 둔다는 이야기입니다.

4.1 .NET Framework 4.7.2 이상으로 올린다

공식 가이드에서는 이식 전에 .NET Framework 4.7.2 이상을 타겟으로 하는 것을 추천합니다. 이유는 .NET Standard가 기존 API를 그대로 갖고 있지 않을 때에도 더 새로운 API 대체재 쪽으로 옮기기 쉬워지기 때문입니다.

실무에서는 가능하면 4.8.1을 기준으로 생각하는 편이 이해하기 쉽습니다.

  • 지원 관점에서 자연스럽다
  • .NET Framework 쪽의 최종 안정 지점으로 다루기 쉽다
  • “먼저 현행 Framework 쪽에서 정리한다”는 방침을 세우기 쉽다

이 작업을 먼저 하면 무엇이 달라지는가

  • .NET Standard 2.0 공유 라이브러리를 다루는 방식이 안정되기 쉬워진다
  • 오래된 런타임에서 비롯된 노이즈를 먼저 줄일 수 있다
  • 호환성 문제의 원인이 “Framework가 오래된 탓”인지 “modern .NET화 탓”인지 구분하기 쉬워진다

4.2 PackageReference로 전환한다

이식 전 가이드에서는 참조를 PackageReference 형식으로 전환할 것을 추천합니다. 이 작업을 먼저 해 두면 의존 관계 관리의 전망이 훨씬 좋아집니다.

PackageReference로 바꾸면 무엇이 달라지는가

  • 패키지 참조가 csproj에 모인다
  • 추이적 의존 관계를 파악하기 쉬워진다
  • restore의 전제가 modern .NET 쪽과 맞춰진다
  • CLI / CI와의 상성이 좋아진다

다만 여기에는 지뢰가 있습니다.

전형적인 지뢰

NuGet의 공식 문서에는 packages.config에서 PackageReference로의 이행에서 다음과 같은 제약이 명시되어 있습니다.

  • Visual Studio의 built-in 이행 기능은 ASP.NET 프로젝트에서는 사용할 수 없다
  • install.ps1 / uninstall.ps1에 의존하는 패키지는 예상대로 동작하지 않을 수 있다
  • content 폴더의 자산이 무시될 수 있다
  • web.config.install.xdt 등의 XDT 변환은 적용되지 않는다
  • lib 바로 아래의 어셈블리 구성이 오래된 패키지는 제대로 해결되지 않을 수 있다

즉, 패키지 형식만 바꾸면 된다고 생각하지 않는 편이 좋습니다. 특히 classic ASP.NET은 NuGet 패키지 설치 시에 web.config를 고쳐 쓰는 관행이 상당히 있었기 때문에, 이행 시에 암묵적인 전제가 드러나기 쉽습니다.

PackageReference화로 드러나는 암묵적 전제packages.config에서 PackageReference로의 이행에서는 install.ps1이나 XDT 변환, content 폴더의 자산이 적용되지 않을 수 있어, 설치 시에 web.config를 고쳐 쓰던 암묵적 전제가 드러나기 쉬움을 보여주는 그림.PackageReference로 변환install.ps1이 동작하지 않을 수 있다XDT 변환은 적용되지 않는다content 자산이 무시될 수 있다암묵적 전제가 드러난다

그림 9: 형식만 바꾸려는 생각이어도, 설치 시의 장치에 의존하던 전제가 한꺼번에 드러난다.

무엇으로 변환할 것인가

수작업만 있는 것은 아닙니다. 다만 도구마다 다루는 범위가 다릅니다.

도구 할 수 있는 것 전제와 주의점
Visual Studio의 변환 기능 솔루션 탐색기에서 “참조” 또는 packages.config를 오른쪽 클릭하고 Migrate packages.config to PackageReference...를 선택하면 변환된다 Visual Studio 2017 15.7 이상. ASP.NET과 C++ 프로젝트에서는 사용할 수 없다. 메뉴에 나오지 않으면 NuGet 복원이나 패키지 관리자를 한 번 연 뒤 다시 오른쪽 클릭한다
.NET Upgrade Assistant 프로젝트 분석과 업그레이드를 한꺼번에 수행한다 공식 문서상 비권장으로 바뀌었으며, GitHub Copilot 모더나이제이션을 사용하도록 안내되고 있다
GitHub Copilot 모더나이제이션 평가, 계획, 코드 수정, 검증까지 지원한다. 현재 공식 안내의 중심이다 4.5에서 다루는 대로 Visual Studio와 Copilot, C# 코드가 전제다
수작업 SDK 스타일화 csproj를 만들고 필요한 항목만 옮긴다 파일 수가 적은 프로젝트라면 이것이 가장 빠를 수 있다

Visual Studio의 변환 기능은 실행 전에 프로젝트 백업을 만들고, 마지막에 변환 리포트(최상위 의존, 추이적 의존, 검출된 호환성 문제)를 출력합니다. 되돌리고 싶을 때는 백업 폴더에서 csprojpackages.config를 다시 가져오고, 패키지 관리자 콘솔에서 update-package -reinstall을 실행하는 절차가 문서에 나와 있습니다.

즉, 다시 시도할 수 있는 형태로 실험할 수 있다는 뜻입니다. 착수 전 견적에서는 우선 프로젝트 하나만 변환해 리포트를 읽어 보는 것이 빠릅니다.

변환을 다시 시도할 수 있는 형태로 실험한다Visual Studio의 변환 기능은 백업을 만든 뒤 변환하고 변환 리포트를 출력하므로, 우선 프로젝트 하나만 변환해 리포트를 읽고, 필요하면 백업에서 되돌릴 수 있음을 보여주는 그림.문제가 있으면문제가 없으면백업이 만들어진다프로젝트 하나만 변환변환 리포트를 읽는다되돌리고 재설치다른 프로젝트로 확대

그림 10: 변환은 백업과 리포트가 딸려 있어 실험해 볼 수 있으므로, 우선 하나로 가늠해 본다.

4.3 SDK 스타일로 전환한다

이식 전 가이드에서는 SDK 스타일 프로젝트 형식으로의 전환도 추천합니다.

이것은 상당히 효과적입니다.

SDK 스타일로 하면 무엇이 달라지는가

  • csproj가 크게 간결해진다
  • PackageReference와 상성이 좋다
  • multi-targeting하기 쉬워진다
  • dotnet build / dotnet test / dotnet publish를 중심으로 한 CI/CD로 옮기기 쉬워진다
  • modern .NET 쪽 구성에 가까워지므로 후반의 차이가 줄어든다

반대로 말하면 오래된 csproj와 오래된 NuGet 관리 방식 그대로 갑자기 modern .NET으로 건너뛰면 차이가 지나치게 커진다는 뜻입니다.

SDK 스타일화로 차이를 줄인다오래된 csproj와 오래된 NuGet 관리 방식 그대로 갑자기 modern .NET으로 건너뛰면 차이가 지나치게 커지므로, 먼저 SDK 스타일로 전환해 modern .NET 쪽 구성에 가깝게 만들어 후반의 차이를 줄인다는 것을 보여주는 그림.바로 건너뛰면먼저 SDK 스타일화오래된 csproj + 오래된 NuGet 관리차이가 지나치게 커진다modern 쪽 구성에 가까워진다후반의 차이가 줄어든다

그림 11: SDK 스타일화를 거치면 modern .NET으로 건너뛸 때의 차이가 한층 줄어든다.

4.4 의존 관계를 먼저 업데이트한다

이것도 공식 가이드대로지만, 의존 관계는 이용 가능한 최신 버전으로 옮기고, 가능하면 .NET Standard 대응판으로 옮깁니다.

이 작업을 먼저 하는 의미

  • “이 패키지는 modern .NET에서 사용할 수 있는가”를 빨리 알 수 있다
  • 오래된 의존 관계가 노이즈가 되는 것을 막을 수 있다
  • shared library를 netstandard2.0화하기 쉬워진다
  • 이후의 이행 작업을 “코드 이식”에 집중시키기 쉽다
의존 관계를 먼저 업데이트하는 의미의존 관계를 미리 최신 쪽으로 업데이트해 두면 modern .NET에서 사용할 수 있는지 빨리 알 수 있고, 오래된 의존이 만드는 노이즈를 피할 수 있으며, 이후 이행 작업을 코드 이식에 집중시킬 수 있음을 보여주는 그림.의존 관계를 먼저 최신으로modern .NET 대응 여부를 빨리 안다오래된 의존의 노이즈를 줄인다이후는 코드 이식에 집중할 수 있다

그림 12: 의존 관계 업데이트를 먼저 끝낼수록 이행 본체 작업은 이식 그 자체에 집중할 수 있다.

4.5 공식 도구의 전제도 확인해 둔다

2026-03 시점에는 Microsoft 안내의 중심이 GitHub Copilot 모더나이제이션 쪽으로 옮겨져 있습니다. 기존의 이행 지원 도구만을 전제로 하기보다, 평가, 계획, 코드 수정, 검증까지 포함한 일련의 지원 흐름으로 보는 편이 실무에 맞습니다.

다만 현행 문서에서는 Visual Studio 2026 또는 지원 중인 Visual Studio 2022 계열, GitHub Copilot, 그리고 C# 코드가 전제입니다.

이 확인이 필요한 이유

  • 공식 도구에 무엇을 기대할 수 있는지가 달라진다
  • 팀의 IDE / build agent / 확장 기능의 전제를 맞출 수 있다
  • VB.NET 솔루션에서는 자동화에 지나치게 기대하지 않는다는 판단을 할 수 있다

VB.NET이 섞여 있는 현장은 드물지 않습니다. 그래서 “최신 공식 도구가 어디까지 도와주는가”를 처음에 확인해 둘 가치가 있습니다.

공식 도구의 현재 위치와 전제.NET Upgrade Assistant는 비권장이 되고 안내의 중심은 GitHub Copilot 모더나이제이션으로 옮겨졌지만, Visual Studio와 Copilot과 C# 코드가 전제이므로 VB.NET이 섞인 현장에서는 자동화에 지나치게 기대하지 않는 판단이 필요함을 보여주는 그림.비권장·안내처VB.NET이 섞여 있다면.NET Upgrade AssistantGitHub Copilot 모더나이제이션전제: Visual Studio + Copilot + C#자동화에 지나치게 기대하지 않는다

그림 13: 도구의 중심은 Copilot 모더나이제이션으로 옮겨졌으며, 그 전제에 맞지 않는 현장은 별도 대응이 필요하다.

5. 프로젝트 종류별 난이도를 가늠한다

이행은 “.NET Framework에서 .NET으로”라고 한데 묶여 이야기되기 쉽지만, 현실에는 프로젝트 종류별로 전혀 다른 게임입니다.

5.1 대략적인 난이도

종류 난이도 주된 논점
클래스 라이브러리 낮음~중간 API 호환성, 의존 관계, 타겟 분할
콘솔 / 배치 / 일부 Windows Service 낮음~중간 배포 방식, 네이티브 의존, 설정
WinForms / WPF 중간 Windows 전용 그대로, 디자이너, 서드파티 UI, BinaryFormatter 주변
ASP.NET MVC / Web API 중간~높음 ASP.NET Core로의 app model 이행, 인증, 세션, 설정, DI
ASP.NET Web Forms 높음 화면 모델의 차이가 크고, UI 계층 교체 전제
WCF 클라이언트 중간 패키지 교체, 계약, 구성
WCF 서버 높음 CoreWCF인지 gRPC / HTTP API 재설계인지
EF6 → EF Core 동시 진행 높음 ORM이 별개, 동작 차이, 이행 이력

5.2 클래스 라이브러리는 “공유 경계”를 어떻게 자르느냐가 관건

클래스 라이브러리는 비교적 옮기기 쉽습니다. 다만 그것은 정말로 라이브러리가 라이브러리답게 분리되어 있을 때에 한정됩니다.

다음과 같은 의존이 있으면 난이도가 올라갑니다.

  • System.Web을 건드리고 있다
  • HttpContext.Current를 직접 참조하고 있다
  • WPF / WinForms의 타입을 공개 API에 포함하고 있다
  • 레지스트리, WMI, EventLog 등 Windows API에 지나치게 의존하고 있다
  • AppDomain이나 Remoting에 의존하고 있다

비즈니스 로직만 잘라낼 수 있다면 가볍고, 앱 모델까지 안고 있다면 무겁다고 보면 이해하기 쉽습니다.

클래스 라이브러리 무게를 보는 방법비즈니스 로직만 잘라낼 수 있는 클래스 라이브러리는 가볍고, System.Web이나 UI 타입, Windows API, AppDomain 등 앱 모델까지 안고 있으면 무거워짐을 보여주는 그림.로직만 잘라낼 수 있다앱 모델을 안고 있다클래스 라이브러리를 본다이행은 가볍다이행은 무겁다System.Web·UI 타입·Windows API 의존 등

그림 14: 라이브러리의 난이도는 코드 줄 수가 아니라 앱 모델을 얼마나 안고 있는지로 정해진다.

5.3 WinForms / WPF는 이행하기는 쉽지만 Windows 전용 그대로

WinForms와 WPF는 .NET으로 이행할 수 있습니다. 다만 어느 쪽도 Windows 전용 프레임워크 그대로입니다.

여기서 기대치를 잘못 잡으면 위험합니다.

  • 좋아지는 것
    • modern .NET의 런타임, 언어, SDK 스타일에 올라탈 수 있다
    • CI/CD나 package 관리를 요즘 방식으로 옮기기 쉽다
    • 일부 성능·유지보수성 개선을 얻기 쉽다
  • 바뀌지 않는 것
    • Windows 전용이라는 점
    • UI 컨트롤이나 디자인 타임 부품의 상성 문제가 남는다는 점
    • ActiveX / COM / 네이티브 DLL 문제가 사라지지 않는다는 점

또한 WinForms / WPF는 BinaryFormatter의 영향 확인이 필요한 경우가 있습니다. 특히 clipboard, drag & drop, ResX, 디자인 타임의 시리얼라이즈에 custom type이 얽혀 있으면, target을 .NET 9 이후로 올렸을 때 표면화되기 쉽습니다.

WinForms / WPF 이행의 기대치WinForms와 WPF는 .NET으로 이행할 수 있고 modern .NET의 런타임이나 언어, SDK 스타일에는 올라탈 수 있지만, Windows 전용이라는 점은 바뀌지 않으며 BinaryFormatter의 영향 확인이 필요한 경우도 있음을 보여주는 그림.WinForms / WPF를 이행modern .NET의 혜택에 올라탄다Windows 전용 그대로BinaryFormatter 확인이 필요하다

그림 15: 데스크톱 UI는 이행할 수 있지만, Windows 전용이라는 성질은 그대로 이어진다.

5.4 ASP.NET Framework는 “runtime 이행”이 아니라 “app model 이행”

ASP.NET Framework에서 ASP.NET Core로의 이행은 Microsoft의 가이드에서도 non-trivial이라고 명시되어 있습니다. 이것은 단순히 API 이름이 바뀌기 때문이 아니라 전제가 되는 아키텍처가 다르기 때문입니다.

차이가 나기 쉬운 부분은 다음과 같습니다.

  • Hosting model
  • Middleware pipeline
  • Request processing model
  • Session / Cache
  • Authentication / Authorization
  • Configuration
  • Dependency Injection
  • Logging / Monitoring

ASP.NET Framework 앱에서 먼저 확인하고 싶은 것은 다음입니다.

  • 어느 route / endpoint부터 먼저 옮길 수 있는가
  • System.Web 의존을 shared library에서 떼어낼 수 있는가
  • 인증 / 세션 / 예외 처리 / 로그를 어떻게 맞출 것인가
  • 운영을 멈추지 않고 단계적으로 이행할 것인가

특히 규모가 큰 앱은 처음부터 incremental migration을 전제로 생각하는 편이 현실적입니다.

ASP.NET 이행은 app model 이행ASP.NET Framework에서 ASP.NET Core로의 이행은 API 이름 교체가 아니라 hosting, middleware, 인증, 구성, DI 같은 전제 아키텍처가 바뀌는 app model 이행이며, 규모가 큰 앱은 단계적 이행을 전제로 하는 편이 현실적임을 보여주는 그림.규모가 큰 앱ASP.NET Framework → Core전제 아키텍처가 바뀐다hosting·middleware·인증·구성·DIincremental migration을 전제로 계획

그림 16: ASP.NET 이행은 runtime이 아니라 app model의 이행이며, 규모가 클수록 단계적 이행이 전제가 된다.

5.5 Web Forms는 “자산 이행”이 아니라 “책임 분해”부터 시작한다

Web Forms는 ASP.NET Core와 같은 app model이 아닙니다. 그래서 견적을 낼 때는 화면 자산을 그대로 옮길 수 있다는 전제로 생각하지 않는 편이 안전합니다.

실무에서는 먼저 다음과 같은 분해부터 시작하는 경우가 많습니다.

  • 화면 로직과 비즈니스 로직을 나눈다
  • Page / UserControl / ViewState에 묻혀 있는 책임을 분해한다
  • 업무 로직이나 데이터 액세스를 shared library로 옮긴다
  • UI는 Razor Pages / MVC / Blazor 등 다른 모델로 재구성한다

즉 Web Forms 프로젝트는 runtime 이행보다 먼저 책임 분해 계획이 있는지가 중요합니다.

Web Forms는 책임 분해부터 시작한다Web Forms는 ASP.NET Core와 같은 app model이 아니므로, 화면 로직과 비즈니스 로직을 나누고 로직을 shared library로 옮긴 뒤 UI는 다른 모델로 재구성하는 책임 분해부터 시작함을 보여주는 그림.그대로 옮길 수 있다는 전제Web Forms 화면 자산화면 로직과 업무 로직을 나눈다로직을 shared library로 옮긴다UI는 다른 모델로 재구성견적이 틀어진다

그림 17: Web Forms는 자산 이행이 아니라, 책임을 분해한 뒤 다른 모델로 다시 짜는 전제로 본다.

5.6 WCF 클라이언트와 WCF 서버는 나누어 생각한다

여기는 한데 묶지 않는 편이 좋습니다.

WCF 클라이언트

WCF Client에는 modern .NET용의 지원되는 NuGet 패키지가 있습니다. 그래서 WCF를 호출하는 쪽만이라면 보기보다 무겁지 않은 경우가 있습니다.

WCF 서버

한편 WCF 서비스를 호스트하는 쪽은 다릅니다. Microsoft의 가이드에서는 modern화 경로로 크게 다음 2가지가 안내되고 있습니다.

  • CoreWCF를 사용해 기존 클라이언트 호환을 유지하는 방향
  • gRPC 등 modern한 RPC / HTTP 기반으로 옮기는 방향

다만 CoreWCF는 WCF의 모든 것을 그대로 가져오는 것이 아니라 서브셋입니다. 기존 클라이언트와의 호환 유지에는 적합하지만, 코드 변경과 테스트는 전제입니다.

WCF는 클라이언트와 서버에서 평가가 다르다WCF 클라이언트는 modern .NET용의 지원되는 패키지가 있어 보기보다 무겁지 않을 수 있는 반면, 서버 쪽은 호환 유지를 위한 CoreWCF나 gRPC 등으로의 재설계 중에서 경로를 선택해야 함을 보여주는 그림.클라이언트서버호환 유지재설계WCF를 어느 쪽에서 쓰는가지원되는 패키지로 이행경로를 선택CoreWCF(서브셋)gRPC / HTTP API

그림 18: 호출하는 쪽과 호스트하는 쪽은 난이도도 선택지도 다르므로 한데 묶어 가늠하지 않는다.

6. .NET에서 쓸 수 없거나 그대로는 막히기 쉬운 기술을 파악한다

이것은 착수 전에 반드시 해 둬야 할 작업입니다. Microsoft에는 .NET Framework에서는 쓸 수 있었지만 .NET 6+에서는 쓸 수 없는 기술의 목록이 있습니다.

6.1 빨간불이 되기 쉬운 기술

기술 .NET에서의 상태 어떻게 생각해야 하는가
AppDomain.CreateDomain 등 AppDomain 생성 비대응 분리는 별도 프로세스 / 컨테이너 / AssemblyLoadContext로 생각한다
.NET Remoting 비대응 IPC, HTTP, gRPC, Socket, Pipe 등으로 재설계
CAS / Security Transparency 보안 경계로서 비대응 OS / 컨테이너 / 권한 분리로 생각한다
System.EnterpriseServices(COM+) 비대응 COM+ 전제의 설계를 분리·교체한다
Workflow Foundation 비대응 CoreWF 등 대체재를 포함해 별도로 견적한다
WCF server built-in에서는 그대로 되지 않는다 CoreWCF인지 gRPC인지 선택한다
BinaryFormatter .NET 9 이후에는 구현이 항상 예외 시리얼라이저 이행, ResX / clipboard / drag & drop 감사

6.2 AppDomain은 “일부 API가 남아 있어도 생성은 별개 문제”

AppDomain 주변은 다소 까다롭습니다. .NET에서도 일부 API surface는 남아 있지만, 새로운 AppDomain을 만들어 격리하는 사용법은 지원되지 않습니다.

그래서 다음 용도로 AppDomain을 사용하고 있었다면 재설계가 필요합니다.

  • 플러그인 격리
  • 동적 로드의 파기
  • 부분 신뢰 코드의 격리
  • 일시적인 실행 환경의 분리

이행 전에 봐야 할 것은 AppDomain이라는 단어가 나오는지뿐만 아니라, 무엇을 위해 AppDomain을 사용했는지입니다.

AppDomain의 사용 방식에 따라 판단이 달라진다AppDomain은 일부 API가 남아 있어도 새 AppDomain을 만들어 격리하는 사용법은 지원되지 않으므로, 타입을 쓰고 있을 뿐인지 격리 목적인지를 구분하고, 격리 목적이라면 별도 프로세스나 AssemblyLoadContext로 재설계함을 보여주는 그림.타입이나 정보 참조뿐만들어서 격리하고 있었다AppDomain이 등장했다그대로 되는 경우가 많다재설계가 필요하다별도 프로세스 / 컨테이너 / AssemblyLoadContext

그림 19: 단어의 유무가 아니라 “무엇을 위해 사용했는지”로 재설계의 필요 여부가 갈린다.

6.3 Remoting은 “겉보기보다 깊다”

Remoting은 물론이고, delegate의 BeginInvoke() / EndInvoke() 호출과 같은 비동기 delegate도 영향 범위에 들어갈 수 있습니다. 이것은 Remoting 자체는 아니지만 modern .NET에서는 지원되지 않으므로 이행 전에 찾아내야 합니다.

그래서 검색할 때는 이 부분도 함께 확인해 두면 안전합니다.

  • System.Runtime.Remoting
  • MarshalByRefObject
  • RealProxy
  • BeginInvoke( / EndInvoke(

6.4 BinaryFormatter는 target version에서 갑자기 전면에 드러난다

BinaryFormatter는 오래된 코드베이스일수록 “자각 없이 사용하고 있는” 경우가 있습니다.

  • 영속화 데이터
  • 캐시
  • 세션 저장
  • 플러그인 상태
  • clipboard / drag & drop
  • ResX
  • WinForms / WPF 디자이너 주변

.NET 9 이후에는 BinaryFormatter가 runtime에 구현되어 있지 않아, API는 항상 PlatformNotSupportedException을 던집니다. 즉, 이것은 “나중에 생각한다”가 아니라 target version을 정한 시점에 먼저 감사해야 할 논점입니다.

BinaryFormatter가 전면에 드러나는 경로BinaryFormatter는 영속화 데이터나 ResX, clipboard 등에서 자각 없이 쓰이기 쉽고, .NET 9 이후에는 API가 항상 예외를 던지므로, target version을 정한 시점에 먼저 감사해야 할 논점임을 보여주는 그림.자각 없는 사용(ResX·clipboard 등)target을 .NET 9 이후로 정한다API가 항상 예외를 던진다정한 시점에 먼저 감사한다

그림 20: BinaryFormatter는 target을 정한 순간 영향이 나타나므로, 뒤로 미루지 말고 먼저 감사한다.

6.5 우선 grep해 두고 싶은 검색어

착수 전에 솔루션 전체에 다음 단어로 검색을 걸어 보기만 해도 상황이 꽤 달라 보입니다.

System.Web
HttpContext.Current
System.Runtime.Remoting
MarshalByRefObject
AppDomain
BinaryFormatter
ServiceHost
ChannelFactory
System.EnterpriseServices
Workflow
packages.config
web.config.install.xdt
install.ps1
DllImport
AxInterop
Microsoft.Office.Interop

이 중 하나라도 발견되면 즉시 아웃이라는 뜻은 아닙니다. 어디가 표준 경로로 이행할 수 있고, 어디가 별도 트랙이 되는지를 파악하기 위한 지도입니다.

실제 검색 명령

도구는 rg(ripgrep)여도 PowerShell이어도 상관없습니다.

# PowerShell. 솔루션 아래를 한꺼번에 검색한다
Get-ChildItem -Recurse -Include *.cs,*.vb,*.config,*.csproj,*.vbproj |
    Select-String -Pattern 'BinaryFormatter|System\.Runtime\.Remoting|MarshalByRefObject|AppDomain\.CreateDomain' |
    Select-Object Path, LineNumber, Line
# ripgrep. 우선 건수로 가늠하고 싶을 때
rg -n --stats "BinaryFormatter|System\.Runtime\.Remoting|AppDomain\.CreateDomain" --glob "*.cs" --glob "*.vb"

발견되면 다음에 무엇을 할 것인가

검색은 입구일 뿐이고, 그 뒤의 판단이 진짜입니다. 단어마다 다음에 확인할 곳이 정해져 있습니다.

발견된 단어 다음에 확인할 것 정리 방향
System.Web / HttpContext.Current shared library 밖으로 뺄 수 있는가. 호출 쪽에서 DTO로 다시 담을 수 있는가 8.5의 전략으로 떼어낸다
System.Runtime.Remoting / MarshalByRefObject / BeginInvoke 무엇을 위한 원격 호출이었는가. 프로세스 간인지, 머신 간인지, 단순한 비동기 호출인지 IPC, HTTP, gRPC, Task 기반으로 재설계
AppDomain 타입 이름만 쓰고 있는가, CreateDomain으로 격리하고 있는가 격리 목적이라면 별도 프로세스나 AssemblyLoadContext(6.2)
BinaryFormatter 저장한 데이터를 나중에 읽을 필요가 있는가. ResX나 clipboard를 경유해 간접적으로 쓰고 있지는 않은가 다른 시리얼라이저로 이행하고, 기존 데이터를 다시 읽는 계획도 세운다(6.4)
ServiceHost / ChannelFactory 호스트 쪽인가 클라이언트 쪽인가 5.6대로 나누어 평가한다
packages.config / install.ps1 / web.config.install.xdt 설치 시에 무엇을 고쳐 쓰고 있었는가 4.2의 지뢰. 설정을 명시적으로 다시 갖춘다
DllImport / AxInterop / Microsoft.Office.Interop bitness 전제와 실행 시에 필요한 파일 일체 9.4의 bitness 확인으로

여기까지 하면 “이행할 수 있는가”가 아니라 “어느 것이 표준 경로로 이행할 수 있고, 어느 것이 별도 견적인가”의 목록이 됩니다. 착수 전에 원하는 것은 바로 이 형태의 목록입니다.

검색에서 목록으로검색은 입구이며, 발견된 단어마다 다음에 확인할 곳을 따라가면 어느 것이 표준 경로로 이행할 수 있고 어느 것이 별도 견적이 되는지의 목록으로 바뀜을 보여주는 그림.검색어로 솔루션을 훑는다단어마다 다음 확인 지점을 따라간다표준 경로와 별도 견적의 목록이 된다발견되어도 즉시 아웃은 아니다

그림 21: 검색 자체는 입구이며, 판단까지 진행하면 착수 전에 필요한 목록의 형태가 된다.

7. Windows 전용 전제를 어디까지 허용할지 정한다

이행에서 자주 일어나는 오해가 “.NET으로 옮기면 크로스 플랫폼이 된다”는 것입니다. 그런 마법은 없습니다. 앱이 Windows에 깊게 결합되어 있으면 이행 후에도 여느 때처럼 Windows 전용입니다.

7.1 Windows 전용인 채로 옮기는 것도 충분히 현실적이다

Microsoft에는 Windows Compatibility Pack이 있어, 레지스트리, WMI, EventLog, Windows Service, Directory Services 등 많은 Windows 계열 API를 modern .NET에서 쓸 수 있게 해 주는 수단이 있습니다.

이 존재는 실무에서 큽니다.

  • 우선 modern .NET으로 옮기고 싶다
  • 하지만 당분간 Windows에서 벗어나지 않는다
  • 그래서 Windows API 의존은 일단 허용하고 싶다

는 현장에서는 유력한 선택지가 됩니다.

이행의 첫 목표가 반드시 크로스 플랫폼화가 아니어도 되는 것입니다.

7.2 다만 Windows 전용 API는 “나중에 발목을 잡는 빚”이기도 하다

Windows Compatibility Pack이 있다고 해서 무엇이든 안심할 수 있는 것은 아닙니다.

  • Linux 컨테이너에 올리고 싶다
  • Kubernetes를 전제로 동작시키고 싶다
  • macOS / Linux 개발자도 같은 build를 돌리고 싶다
  • 장래에 클라우드에서 Windows VM을 줄이고 싶다

와 같은 목표가 있다면 Windows API 의존을 지금 미리 가시화해 두는 편이 좋습니다.

호환 팩을 쓰는 곳과 그로 인한 빚당분간 Windows에서 벗어나지 않는다면 Windows 호환 팩으로 Windows API 의존을 일단 허용하며 modern .NET으로 옮길 수 있지만, 장래 컨테이너나 클라우드를 노린다면 그 의존은 나중에 발목을 잡는 빚이 되므로 지금 미리 가시화해야 함을 보여주는 그림.당분간 Windows 그대로장래 컨테이너·클라우드를 노린다면우선 modern .NET으로 옮기고 싶다호환 팩으로 의존을 일단 허용의존은 나중에 발목을 잡는 빚지금 미리 가시화해 둔다

그림 22: 호환 팩은 현실적인 다리이지만, 그 의존은 목표에 따라 빚도 될 수 있으므로 미리 가시화해 둔다.

7.3 System.Drawing.Common은 특히 오해하기 쉽다

System.Drawing.Common은 .NET 6 이후에는 Windows 전용 라이브러리입니다. 이미지 처리나 문자 렌더링에 사용하고 있는 코드가 있다면, 먼저 어느 쪽으로 갈지 정할 필요가 있습니다.

  • Windows인 채로 운영할 것인가
  • 장래 Linux / macOS에서도 동작시키고 싶은가

전자라면 당분간 그대로여도 괜찮은 경우가 있습니다. 후자라면 SkiaSharp나 ImageSharp 등으로의 교체를 이행 계획에 처음부터 포함해야 합니다.

System.Drawing.Common의 분기System.Drawing.Common은 .NET 6 이후 Windows 전용 라이브러리이므로, Windows인 채로 운영한다면 당분간 그대로여도 되는 경우가 있고, 장래 Linux나 macOS에서도 동작시키고 싶다면 SkiaSharp나 ImageSharp로의 교체를 계획에 처음부터 포함해야 함을 보여주는 그림.Windows인 채로 운영Linux / macOS에서도 동작System.Drawing.Common을 사용 중당분간 그대로여도 되는 경우가 있다SkiaSharp / ImageSharp로 교체이행 계획에 처음부터 포함

그림 23: System.Drawing.Common은 Windows 전용이므로, 착지점에 따라 다루는 방식이 처음부터 갈린다.

7.4 Windows 고정을 나타내는 대표적인 징후

다음과 같은 참조나 API가 있을 때는 “적어도 처음에는 Windows 전용인 채로 옮긴다”는 전제로 견적하는 편이 안전합니다.

  • Microsoft.Win32.Registry
  • System.Management
  • System.Diagnostics.EventLog
  • System.ServiceProcess
  • System.DirectoryServices
  • System.Drawing
  • DllImport / P/Invoke
  • COM 참조
  • AxInterop.*
  • Microsoft.Office.Interop.*

8. 공유 라이브러리를 어떻게 분리하느냐로 난이도가 달라진다

규모가 큰 솔루션에서는 이행의 성패가 shared library를 자르는 방식으로 결정된다고 해도 과장이 아닙니다.

8.1 먼저 분류한다

라이브러리는 크게 3종류로 나누면 정리하기 쉽습니다.

  1. 순수한 업무 로직 / 도메인 로직
  2. 앱 모델에 약간 의존하는 중간 계층
  3. UI / Web / Windows API에 밀착한 계층

이 중 가장 먼저 옮겨야 할 것은 1입니다.

  • 계산
  • 규칙 판정
  • DTO / 계약
  • 도메인 서비스
  • 단순한 데이터 변환

여기를 깔끔하게 분리해 낼 수 있으면 난이도가 단번에 낮아집니다.

라이브러리의 3가지 분류와 옮기는 순서라이브러리를 순수한 업무 로직, 앱 모델에 약간 의존하는 중간 계층, UI나 Windows API에 밀착한 계층의 3종류로 나누고, 가장 먼저 옮기는 것은 순수한 업무 로직임을 보여주는 그림.가장 먼저 옮긴다그다음마지막순수한 업무 로직깔끔하게 분리하면 난이도가 낮아진다앱 모델 의존 중간 계층UI·Windows API 밀착 계층

그림 24: 라이브러리는 3계층으로 분류하고, 순수한 로직부터 순서대로 구출해 나간다.

8.2 netstandard2.0은 지금도 유효한 다리다

Microsoft의 가이던스에서는 .NET Framework 쪽과도 공존해야 하는 shared library라면, 먼저 .NET Standard 2.0을 고려하는 것이 기본입니다.

여기서 중요한 것은 2가지입니다.

  • .NET Framework는 .NET Standard 2.1을 지원하지 않는다
  • shared library를 old / new 양쪽에서 참조하고 싶다면 2.0이 현실적인 해법이 되기 쉽다
netstandard2.0이라는 다리.NET Framework는 .NET Standard 2.1을 지원하지 않으므로, shared library를 신구 양쪽에서 참조하고 싶다면 .NET Standard 2.0이 현실적인 해법이 되기 쉬움을 보여주는 그림.참조할 수 있다참조할 수 있다Framework는 비대응.NET Framework 쪽netstandard2.0의 shared librarymodern .NET 쪽netstandard2.1

그림 25: 신구 양쪽에서 참조하는 다리로는 2.1이 아니라 2.0이 현실적인 해법이 된다.

8.3 netstandard2.0으로 하면 무엇이 달라지는가

방침 어떻게 달라지는가 어울리는 경우 주의점
netstandard2.0 old / new 양쪽에서 참조하기 쉽다 순수한 업무 로직, 공통 계약, 유틸리티 app model 고유 API는 올릴 수 없다
multi-target(예: net48;net10.0) 공통 코드를 유지하면서 환경별 차이를 가질 수 있다 환경 차이가 조금 있는 라이브러리 조건 분기나 build 관리가 늘어난다
곧바로 net10.0 전용화 장래에는 가장 깔끔하다 old / new 공존이 필요 없는 신규 계층 .NET Framework에서는 참조할 수 없다

8.4 호환 모드는 만능이 아니다

.NET Standard 2.0에는 .NET Framework 라이브러리를 참조하는 호환 모드가 있습니다. 다만 이것은 무엇이든 투명하게 동작하는 마법이 아닙니다.

예를 들어 WPF처럼 app model 고유 API를 전제로 한 라이브러리는 여전히 어렵습니다. 즉, shared library라 해도 정말로 공유할 수 있는 책임만으로 범위를 좁히는 것이 중요합니다.

8.5 ASP.NET 계열 라이브러리는 System.Web을 떼어낼 수 있는지가 관건

ASP.NET Framework를 단계적으로 이행할 때, shared library가 HttpContext.CurrentSystem.Web에 직접 매달려 있으면 상당히 힘듭니다.

이때의 기본 전략은 다음 중 하나입니다.

  • System.Web 의존을 인터페이스 밖으로 밀어낸다
  • HttpContext에서 온 정보를 DTO로 받도록 바꾼다
  • 이행 과도기에는 adapter를 사용한다
  • 그래도 안 되면 multi-target으로 단계적으로 떼어낸다

8.6 라이브러리는 leaf-first로 올린다

ASP.NET의 incremental migration 가이드에서는 supporting library를 postorder depth-first, 즉 잎(leaf)부터 순서대로 올리도록 명시하고 있습니다.

이것은 Web에 한정되지 않고 일반 솔루션에서도 상당히 유효합니다.

  • 의존 대상이 먼저 올라가 있으므로 상위 계층의 전망이 좋아진다
  • 호환성 문제를 국소화하기 쉽다
  • 라이브러리 단위로 테스트하기 쉽다
leaf-first로 올린다supporting library를 의존의 잎부터 순서대로 올리면, 의존 대상이 먼저 올라가 있어 상위 계층의 전망이 좋아지고, 호환성 문제를 국소화해 라이브러리 단위로 테스트하기 쉬워짐을 보여주는 그림.의존의 잎 라이브러리를 먼저 올린다의존이 끝난 중간 계층을 올린다마지막으로 상위 앱 계층문제를 국소화해 테스트할 수 있다

그림 26: 잎부터 순서대로 올리면, 상위 계층에 착수할 무렵에는 발밑이 갖춰져 있다.

9. NuGet / 외부 의존 / 서드파티 부품을 점검한다

여기를 대충 하면 이행 후반에서 가장 아픈 꼴을 봅니다.

9.1 의존 관계는 4가지로 나누면 정리하기 쉽다

  1. 공개 NuGet 패키지
  2. 사내 private package / internal library
  3. 로컬 DLL 참조
  4. COM / ActiveX / 네이티브 DLL / SDK

이 중 1만 봐서는 부족합니다. 정말로 위험한 것은 3과 4입니다.

의존의 4가지 분류와 위험도의존 관계는 공개 NuGet, 사내 패키지, 로컬 DLL 참조, COM이나 ActiveX나 네이티브 DLL의 4가지로 나눌 수 있으며, 공개 NuGet만 봐서는 부족하고 정말로 위험한 것은 로컬 DLL과 COM·네이티브 계열임을 보여주는 그림.의존 관계를 점검한다공개 NuGet·사내 패키지로컬 DLL 참조COM / ActiveX / 네이티브 DLL정말로 위험한 것은 이쪽이다

그림 27: 공개 NuGet만 세어서는 부족하며, 로컬 DLL과 COM·네이티브 계열이야말로 먼저 점검한다.

9.2 의존별로 확인하고 싶은 것

각 의존에 대해 최소한 다음까지는 확인합니다.

  • modern .NET을 타겟으로 하고 있는가
  • PackageReference에 대응하고 있는가
  • SDK 스타일로 문제가 없는가
  • x86 / x64 / ARM64의 제약은 없는가
  • 디자인 타임 도구나 Visual Studio 확장에 의존하고 있지 않은가
  • install script / config transform을 전제로 하고 있지 않은가
  • 지원이 계속되고 있는가

9.3 서드파티 UI / 리포트 / 디자인 타임 부품은 별도 항목으로 가늠한다

WinForms / WPF / ASP.NET의 이행에서는 이 부분이 상당히 크게 작용합니다.

  • 그리드
  • 리포트 엔진
  • PDF 출력 부품
  • 그래프 부품
  • 디자이너 통합형 UI 라이브러리
  • ActiveX 래퍼

이들은 runtime뿐만 아니라 디자인 타임 지원까지 얽혀 있습니다. 이행 견적에서 “컴파일할 수 있는가”만 보면 대개 놓치게 됩니다.

9.4 네이티브 DLL과 bitness는 반드시 확인한다

.NET Framework 시절에 AnyCPU로 동작하고 있던 것처럼 보여도, 실제로는 다음과 같은 것에 의존하고 있는 경우가 있습니다.

  • x86 고정 COM
  • 32bit 전용 ActiveX
  • 특정 버전의 VC++ Runtime
  • 서명된 네이티브 DLL

이 부분은 modern .NET화로 갑자기 생겨난 문제가 아니라, 원래부터 있던 제약이 표면화되는 것일 뿐입니다. 그렇기 때문에 이행 전에 가시화해 둘 가치가 있습니다.

bitness 제약의 표면화AnyCPU로 동작하는 것처럼 보여도 x86 고정 COM이나 32bit 전용 ActiveX, 특정 버전의 VC++ Runtime 등에 의존하고 있을 수 있으며, 이는 원래부터 있던 제약이 modern .NET화로 표면화되는 것뿐임을 보여주는 그림.AnyCPU로 동작하는 것처럼 보였다x86 고정 COM·32bit 전용 ActiveX 등에 의존이행으로 원래의 제약이 표면화된다이행 전에 가시화해 둔다

그림 28: bitness 문제는 이행이 만드는 것이 아니라, 원래 있던 제약이 드러나는 것일 뿐이다.

10. EF6, 시리얼라이저, 데이터 관련은 별개 문제로 다룬다

runtime의 이행과 데이터 액세스·시리얼라이즈의 재설계는 가능한 한 별개 문제로 다루는 편이 잘 진행됩니다.

10.1 EF6 → EF Core는 직접 업그레이드가 아니다

Microsoft의 EF 가이드에서도 EF Core는 EF6의 total rewrite이며, direct upgrade path는 없다고 되어 있습니다.

그래서 EF6을 사용하는 앱에서는 다음과 같은 순서가 현실적입니다.

  1. 먼저 modern .NET으로 옮긴다
  2. 필요하다면 EF6을 유지한 채 앱을 동작시킨다
  3. 그 후 EF Core로 별도 프로젝트로서 이행한다

runtime migration과 ORM migration을 같이 하지 않는다. 이것만으로도 난이도가 상당히 낮아집니다.

EF6과 runtime의 분리 이행EF Core는 EF6의 전면 재작성으로 직접적인 업그레이드 경로가 없으므로, 먼저 modern .NET으로 옮기고 필요하면 EF6을 유지한 채 동작시킨 뒤, 이후 별도 프로젝트로서 EF Core로 이행하는 순서가 현실적임을 보여주는 그림.동시에 하면먼저 modern .NET으로 옮긴다필요하면 EF6을 유지한 채 동작나중에 별도 프로젝트로 EF Core로 이행ORM의 동작 차이가 섞여 무거워진다

그림 29: runtime과 ORM은 동시에 다루지 않고, EF6을 남긴 채 먼저 runtime을 옮기는 것이 현실적이다.

10.2 EF6을 남기면 무엇이 달라지는가

  • 좋은 점
    • 데이터 액세스 계층의 차이를 뒤로 미룰 수 있다
    • business logic이나 app model 이행에 집중할 수 있다
    • “EF Core의 동작 차이”가 섞이지 않는다
  • 주의점
    • 신규 개발 관점에서는 EF Core가 본선이다
    • EF6 Designer / EDMX 사용 형태에는 별도의 제약이 있다

10.3 EDMX 기반 EF6은 “디자인 타임”까지 확인한다

EF6의 문서에는 EF Designer는 .NET / .NET Standard 프로젝트나 SDK 스타일의 .NET Framework 프로젝트에서 직접 지원되지 않는다고 쓰여 있습니다.

즉 EDMX 기반 앱에서는 다음 3가지를 나누어 생각해야 합니다.

  • 실행 시에 동작하는가
  • Designer를 쓸 수 있는가
  • 생성된 코드를 어떻게 다룰 것인가

EDMX를 많이 사용하고 있다면, 이것은 처음부터 견적에 넣어 두는 편이 안전합니다.

10.4 BinaryFormatter나 자체 시리얼라이즈는 “숨은 의존”이 되기 쉽다

시리얼라이저는 코드 검색만으로는 놓치기 쉽습니다.

  • 영속화 포맷
  • 메시징
  • 캐시
  • 구 WCF / SOAP 계약
  • ResX
  • 클립보드 / drag & drop

이 부분은 데이터 호환성도 얽혀 있습니다. 즉, 단순히 “빌드할 수 있는가”가 아니라 기존 데이터를 읽을 수 있는가까지 확인이 필요합니다.

11. 구성, 배포, 운영, CI/CD까지 이행 대상에 포함한다

이행의 대상은 소스 코드만이 아닙니다.

11.1 설정 파일

.NET Framework 쪽에서는 app.config / web.config에 꽤 많은 것이 실려 있는 경우가 있습니다.

  • connection string
  • custom config section
  • WCF endpoint 설정
  • binding redirect
  • diagnostics
  • ASP.NET의 각종 설정
  • package install 시의 transform 결과

modern .NET 쪽에서는 구성을 다루는 방식이나 읽어 들이는 경로가 바뀌는 부분이 있습니다. 그래서 “설정 파일은 나중에”는 위험합니다.

가장 먼저 할 일은 설정 점검입니다.

  • 무엇이 설정 파일에 있는가
  • 어느 것이 앱 기동 시에 필수인가
  • 어느 것이 환경별 차이인가
  • 어느 것이 NuGet이나 installer에 의해 자동으로 주입되고 있었는가

11.2 배포 방식

배포 형태도 착수 전에 확인해 둡니다.

  • IIS 아래인가
  • Windows Service인가
  • Scheduled Task인가
  • ClickOnce / MSI / 자체 installer인가
  • 온프레미스 서버 전제인가
  • self-contained / framework-dependent 중 어느 쪽이 적합한가

실행 본체가 이행되어도 배포와 기동 구조가 오래된 전제 그대로라면 마지막 단계에서 막힙니다.

11.3 로그, 모니터링, 운영 절차

운영 관련도 놓치기 쉽습니다.

  • Windows Event Log를 전제로 하는가
  • Performance Counter를 보고 있는가
  • WMI 기반의 모니터링인가
  • 서비스 계정이나 권한이 고정인가
  • 로그 출력 위치가 로컬 파일 전제인가

이행 후 코드는 동작하는데 운영이 돌아가지 않는다는 것은 흔히 있는 일입니다.

11.4 CI/CD와 build agent

이행 전에 다음도 확인합니다.

  • build agent에 필요한 .NET SDK가 설치되는가
  • nuget.exe / msbuild.exe를 전제로 한 pipeline을 어떻게 할 것인가
  • dotnet CLI 기반으로 옮길 것인가
  • 테스트 실행, coverage, publish의 job을 어떻게 업데이트할 것인가
  • 사내 템플릿이나 reusable pipeline이 오래된 형식을 전제로 하고 있지는 않은가

로컬 환경에서는 동작하는데 CI에서는 실패한다는 것은 이행에서 흔히 겪는 일입니다.

이행 대상은 코드만이 아니다실행 본체를 이행할 수 있어도, 설정 파일, 배포 방식, 로그나 모니터링 같은 운영, CI/CD와 build agent가 오래된 전제 그대로면 마지막 단계에서 막히므로, 이들도 이행 대상에 포함해야 함을 보여주는 그림.소스 코드의 이행그것만으로는 끝나지 않는다설정 파일과 배포 방식로그·모니터링·운영 절차CI/CD와 build agent로컬에서는 동작하는데 CI에서 실패한다

그림 30: 설정·배포·운영·CI/CD까지 포함해야 비로소 이행 대상을 다 헤아렸다고 할 수 있다.

12. 현실적인 이행 진행 방식

여기까지의 논점을 바탕으로 하면, 현실적인 진행 방식은 대체로 다음 형태로 정리됩니다.

12.1 먼저 현행 Framework 쪽을 정비한다

  1. .NET Framework 4.7.2 이상, 가능하면 4.8.1로 맞춘다
  2. 의존 관계를 올린다
  3. packages.config을 재검토한다
  4. 가능한 범위에서 PackageReference와 SDK 스타일로 전환한다
  5. 현행 앱이 그 상태에서 제대로 동작하는지 확인한다

여기만 해 두어도 후반의 차이가 상당히 줄어듭니다.

12.2 shared library를 먼저 구출한다

다음으로 업무 로직이나 공통 계약을 netstandard2.0 또는 multi-target으로 옮깁니다. 올리는 순서는 leaf-first가 기본입니다.

12.3 앱 본체는 app model별로 전략을 달리한다

  • 클래스 라이브러리 / 콘솔 / 일부 서비스 비교적 곧바로 진행하기 쉽다
  • WinForms / WPF Windows 전용인 채로 modern화한다
  • ASP.NET MVC / Web API 작으면 일괄, 무거우면 단계적 이행
  • Web Forms 화면 자산 교체를 전제로, shared logic을 먼저 옮긴다
  • WCF 서버 CoreWCF 유지인지 gRPC 재설계인지 먼저 정한다

12.4 “한 번에 전부 하지 않는다”를 지킨다

특히 피하고 싶은 조합은 다음과 같습니다.

  • runtime 이행 + ORM 전면 교체
  • runtime 이행 + 인증 기반 변경
  • runtime 이행 + 클라우드 전면 이행
  • runtime 이행 + 모니터링 기반 변경
  • runtime 이행 + UI 프레임워크 쇄신

전부 필요하더라도 같은 스프린트에 담지 않는 편이 대체로 잘 진행됩니다.

12.5 테스트와 베이스라인을 확보한 뒤 움직인다

최소한 다음 정도는 준비하고 나서 움직이고 싶습니다.

  • 단위 테스트
  • 주요 업무 흐름의 결합 테스트
  • 대표적인 화면 / API의 스냅샷 형태 확인
  • 성능 베이스라인
  • 주요 로그 확인 방법
  • 롤백 절차

이행 후 “무엇이 망가졌는가”를 특정할 수 없는 상태로 진행하는 것은 상당히 위험합니다.

움직이기 전에 준비해 둘 것테스트와 성능 베이스라인, 로그 확인 방법, 롤백 절차를 준비한 뒤 이행에 나서면 이행 후 무엇이 망가졌는지 특정할 수 있고, 준비 없이 진행하는 것은 위험함을 보여주는 그림.테스트와 베이스라인을 준비그다음 이행에 나선다무엇이 망가졌는지 특정할 수 있다준비 없이 진행한다망가져도 특정할 수 없어 위험하다

그림 31: 이행은 움직이기 전의 준비로 승부가 갈리며, 베이스라인이 있어야 비로소 망가진 곳을 특정할 수 있다.

13. 착수 전 체크리스트

그대로 프로젝트 관리에 붙여 쓸 수 있는 형태로 정리해 둡니다.

13.1 방침

  • 왜 이행하는지를 한 문장으로 말할 수 있다
  • 이번 착지점이 Windows 전용의 modern .NET인지 장래의 크로스 플랫폼화인지 정해져 있다
  • target .NET 버전을 정했다
  • 이번 스코프에 포함하지 않을 것(EF Core화, 인증 쇄신, 클라우드 전면 이행 등)이 정해져 있다

13.2 현행 .NET Framework 쪽 정비

  • .NET Framework 4.7.2 이상, 가능하면 4.8.1로 맞췄다
  • 의존 관계를 최신 쪽으로 올렸다
  • packages.config의 유무를 점검했다
  • PackageReference화 가능 여부를 확인했다
  • SDK 스타일화 가능 여부를 확인했다
  • 현행 앱이 그 상태에서 빌드·기동·테스트할 수 있다

13.3 앱 종류와 기술 선정

  • 클래스 라이브러리 / 데스크톱 / Web / WCF 등 종류별로 난이도를 나눴다
  • WinForms / WPF가 Windows 전용 그대로라는 점을 이해하고 있다
  • ASP.NET Framework는 ASP.NET Core로의 app model 이행이라는 점을 이해하고 있다
  • Web Forms의 UI 계층 교체를 견적에 넣었다
  • WCF는 클라이언트와 서버를 나누어 평가했다

13.4 비대응 기술·요주의 API

  • AppDomain 의존을 점검했다
  • Remoting / MarshalByRefObject / BeginInvoke / EndInvoke를 점검했다
  • CAS / Security Transparency / COM+ / WF를 점검했다
  • BinaryFormatter 의존을 점검했다
  • System.Web 의존을 점검했다

13.5 Windows 전용 의존

  • 레지스트리, WMI, EventLog, Windows Service, Directory Services 사용을 점검했다
  • System.Drawing.Common 사용을 점검했다
  • COM / ActiveX / Office Interop / P/Invoke / 네이티브 DLL을 점검했다
  • x86 / x64 / ARM64 제약을 확인했다

13.6 shared library와 데이터 액세스

  • shared library를 업무 로직 / app model 밀착 계층으로 분류했다
  • netstandard2.0화할 수 있는 것을 점검했다
  • multi-target이 필요한 라이브러리를 점검했다
  • EF6을 남기고 runtime만 먼저 옮길 수 있는지 판단했다
  • EDMX / Designer 의존을 확인했다

13.7 운영과 build

  • 설정 파일 점검을 했다
  • 배포 방식(IIS / Service / MSI / ClickOnce 등)을 확인했다
  • 로그 / 모니터링 / 권한 / 실행 계정 전제를 확인했다
  • CI/CD와 build agent의 업데이트가 필요한지 확인했다
  • 롤백 절차를 만들었다

14. 정리

.NET Framework에서 .NET으로의 이행에서 중요한 것은 “어느 명령으로 옮길 것인가”보다 무엇이 그대로 갈 수 있고 무엇이 별개 문제인지를 착수 전에 꿰뚫어 보는 것입니다.

핵심을 추리면 다음 6가지입니다.

  • 이행 전에 .NET Framework 쪽을 정리한다
  • 앱 모델별로 난이도를 나눈다
  • 쓸 수 없는 기술을 먼저 점검한다
  • Windows 전용 전제를 어디까지 허용할지 정한다
  • shared library를 어떻게 자를지 정한다
  • ORM, 인증, 클라우드 이행을 동시에 지나치게 담지 않는다

이행은 첫 1주일 사이에 견적의 정밀도가 크게 달라집니다. 반대로 말하면 그 1주일 동안 논점을 정리할 수 있다면, 후반은 상당히 평범한 개발 쪽으로 옮겨 갈 수 있습니다.

첫 1주일의 활용법첫 1주일 동안 무엇이 그대로 갈 수 있고 무엇이 별개 문제인지 논점을 정리할 수 있으면 견적의 정밀도가 올라가고, 후반은 상당히 평범한 개발로 옮겨 갈 수 있음을 보여주는 그림.첫 1주일 동안 논점을 정리견적의 정밀도가 올라간다후반은 평범한 개발로 옮겨 간다그대로 갈 수 있는 것과 별개 문제의 구분

그림 32: 첫 1주일을 점검에 쓸 수 있는지가 이행 전체의 정밀도를 좌우한다.

“일단 net10.0으로 바꿔 보자”는 탐색으로서는 나쁘지 않습니다. 다만 실제 이행으로서는 그 전에 봐야 할 것이 있습니다. 이 글에서 정리한 것이 바로 그 부분입니다.

15. 참고 자료

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

.NET Framework에서 .NET으로 이행하기 전에 가장 먼저 무엇을 해야 하나요?
구현에 들어가기 전에 .NET Framework 쪽 정리를 먼저 끝내야 합니다. Microsoft의 공식 가이드에서도 이식 전에 .NET Framework 4.7.2 이상(실무에서는 가능하면 4.8.1)으로 올리고, packages.config을 PackageReference로 전환하고, SDK 스타일 프로젝트 형식으로 옮기고, 의존 관계를 최신 쪽으로 업데이트할 것을 추천하고 있습니다. 이 작업을 먼저 해 두면 이후 modern .NET화 단계에서 나오는 차이가 크게 줄어들고, 호환성 문제의 원인이 「Framework가 오래된 탓」인지 「.NET화 탓」인지 구분하기 쉬워집니다. 아울러 AppDomain, Remoting, BinaryFormatter 등 비대응 기술의 사전 점검도 착수 전에 진행합니다.
.NET Framework에 그대로 남는 판단도 있을 수 있나요?
충분히 있을 수 있습니다. .NET Framework 4.8.1은 지원되는 Windows에 실려 있는 한 계속 지원되므로, 지금 당장 전부 modern .NET으로 바꾸지 않으면 즉시 위험하다는 이야기는 아닙니다. Web Forms 화면 자산이 대량으로 있거나, WCF 서버 호환을 엄격히 유지해야 하거나, Workflow Foundation이나 COM+ 의존이 깊거나, 서드파티 디자인 타임 부품이 비대응인 경우라면 당분간 4.8.1에 맞춰 안정적으로 운영하면서 별도 라인에서 교체 계획을 세우는 것이 합리적입니다. 다만 Windows 전용에서 벗어날 수 없고, 새로운 .NET의 성능이나 언어 기능의 혜택을 받기 어렵다는 제약은 남습니다.
.NET으로 이행할 수 없거나 막히기 쉬운 기술은 무엇인가요?
AppDomain 생성, .NET Remoting, CAS(코드 접근 보안), COM+(System.EnterpriseServices), Workflow Foundation은 modern .NET에서 비대응이며 재설계가 필요한 빨간불입니다. WCF 서버는 built-in으로는 그대로 동작하지 않아 CoreWCF 유지 또는 gRPC / HTTP API로의 재설계 중에서 선택해야 합니다. BinaryFormatter는 .NET 9 이후에는 구현 자체가 포함되지 않아 항상 예외를 던지므로, 영속화 데이터나 ResX, clipboard / drag & drop까지 포함한 감사가 필요합니다. 그 밖에 packages.config의 install.ps1 / XDT 변환, 네이티브 DLL, COM / ActiveX, x86 전제도 빌드는 통과해도 실행 시에 떨어지기 쉬운 요주의 지점입니다.
WinForms나 WPF 앱을 .NET으로 이행하면 크로스 플랫폼이 되나요?
되지 않습니다. WinForms / WPF는 .NET으로 이행해도 Windows 전용 프레임워크 그대로입니다. 이행으로 얻는 것은 modern .NET의 런타임·언어 기능·SDK 스타일·CI/CD와의 상성 같은 혜택이며, Linux 컨테이너에 실릴 수 있게 되는 것은 아닙니다. 장래 Linux / 컨테이너화를 노린다면 System.Drawing.Common, 레지스트리, WMI, EventLog, Windows Service, COM, Office Interop 등 Windows를 전제로 하는 API를 이른 단계에서 점검할 필요가 있습니다. 반대로 Windows 전용으로 갈 것이라면 Windows Compatibility Pack을 사용해 우선 runtime을 modern화하는 현실적인 노선을 택할 수 있습니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기