[.NET Core] 문제 해결: An assembly specified in the application dependencies manifest was not found:

이미지
뜬금없이 발생한 문제 밤을 새고 12시에 깨서, 배탈이 나서 화장실로 리다이렉트된 뒤 컴퓨터에 앉아 업무용 디스코드 서버를 들어가니 오늘도 역시 버그 제보가 올라와 있었습니다. 헌데, 이번 문제는 좀 특이했습니다. 240대의 동일한 환경의 컴퓨터 중 단 2대에서 문제가 발생한 것이죠. 디버깅 버그 제보에는 응용 프로그램이 실행되지 않는다고 올라옴과 동시에, 잘 되는 컴퓨터에서 통채로 복사해도 여전히 실행되지 않는다는 내용이 추가로 쓰여있었습니다. 여기서 직감적으로 느꼈습니다. 아. 이거 디펜던시 문제구나. 하지만, 정확히 어디서 문제가 생겼는지는 직접 확인해봐야 했기에, 원격으로 해당 컴퓨터에 접속해 문제를 파악하기 시작했습니다. 우선, 프로그램을 실행했습니다. 문제 없이 실행되는 것처럼 보였으나, 잠시 후 업데이트 단계에서 프로그램이 예고없이 종료되었습니다. 로그를 확인해봐도 프로그램 자체는 정상적으로 업데이터까지 실행했다고 나와있었고요. 그래서, 이번엔 업데이터를 수동으로 실행해봤습니다. 아직까지는 UI가 없는 콘솔 형태의 업데이터인지라, 프로그램이 꺼짐과 동시에 콘솔이 날아가버리는 것을 방지하기 위해 명령 프롬프트에서 실행했죠. 그랬더니 다음과 같은 에러가 보이더군요. An assembly specified in the application dependencies manifest (####.deps.json) was not found: 여기서 의심은 확신이 되었습니다. 구글링 의심이 확신이 된 것까진 좋은데, 어떻게 해결해야 할지는 바로 감이 오지 않는 상황이었습니다. 위 업데이터는 태어나서 처음으로 .NET Core 어플리케이션을 Publish, 그것도 단일 파일로 퍼블리시한 상태이기 때문에 도대체 어디서 문제가 생긴 것인지 알 수가 없었기 때문이죠. 하지만 당연히 문제가 될 것은 없습니다. 왜냐하면 저, 그리고 여러분에겐 구글과 스택오버플로우가 있기 때문입니다. 검색을 진행했죠. 키워드: An...

[C#/EF6] 서로 다른 컨텍스트가 업데이트된 레코드를 읽어야 할 때

여러개의 컨텍스트 사용 필연 우선 이 글은 커넥션 풀링과는 아주 관계가 없진 않으나, 관계가 없다고 생각한 채 읽으셔도 됨을 알려드립니다. 엔티티 프레임워크를 사용해 개발하다 보면 어쩔 수 없이 동일한 컨텍스트 클래스의 인스턴스를 여러 곳에서 생성해 사용하게 됩니다. 처음에 저는 단순한 프로젝트이니 그냥 컨텍스트 클래스를 싱글톤 패턴으로 만들어, 여러 사용처에서 호출해 사용하면 되지 않을까? 라는 어리석은 생각을 했으나, 아무리 단순한 프로젝트라도 그곳에 이벤트가 있고, 병렬 처리가 있다면, 그리고 그 곳에서 DB에 접근해야 한다면(즉, 컨텍스트 인스턴스 호출을 해야 한다면), 어쩔 수 없습니다. 싱글톤은 답이 아닙니다. 문제는 이렇게 할 경우에 여러 동일한 컨텍스트 클래스의 인스턴스에서 동일한 Entity의 정보를 읽고 쓸 수 있다는 것입니다. 예를 들어 동일한 컨텍스트 클래스의 서로 다른 인스턴스를 호출해 사용하는 A, B 클래스가 있다고 가정해봅시다. 아래 가정은 시간 순서로 쓰여졌습니다. B 인스턴스에서 Road 엔티티를 DB에서 컨텍스트로 읽어드렸습니다. (DB => In memory, FindAsync 사용) B 인스턴스에서 Road 엔티티의 (ICollection )Cars.Count 프로퍼티를 읽어 변수 prevCarCount 에 저장했습니다. B 인스턴스에서 유틸리티 클래스인 A 인스턴스의 AddCarOnRoad 를 호출했습니다. A 인스턴스에서 Road 엔티티의 (ICollection )Cars 프로퍼티를 수정했습니다. (새 컨텍스트 인스턴스에서 작업) B 인스턴스에서 Road 엔티티의 (ICollection )Cars.Count 프로퍼티를 읽어 변수 curCarCount 에 저장했습니다. B 인스턴스에서 prevCarCount와 curCarCount가 같으면 throw, 아니면 반환합니다. 위와 같은 상황에서, 어떤 한 로직을 빠뜨리면 3. 에서 Car 를 Road ...

[C#/EntityFrameworkCore] 닷넷 코어에서 Code First 마이그레이션 설정중 OnConfiguring을 오버라이드 할 수 없을 때 해결 방법 (+ SQLite UseSqlite 확장 메서드 사용 방법)

이미지
.Net Core EF 닷넷 코어도 당연히 닷넷 프레임워크와 같이 엔티티 프레임워크를 지원합니다. code-first 마이그레이션 역시 닷넷 프레임워크 EF와 굉장히 비슷합니다. 그러나, 패키지 설치 미스에 따라 곤란한 상황을 겪게 될 수도 있습니다. OnConfiguring 오버라이드 불가 그 문제는 바로 DbContext.OnConfiguring을 오버라이드해 사용해야 하는데, 정작 오버라이드할 DbContext 클래스의 OnConfiguring 메서드가 보이지 않는 문제입니다. OnModelCreating, OnChangeEventHandler등이 보이나, OnConfiguring은 보이지 않는 모습 왜 그럴까요? 사실, 생각해볼 것도 없이, 단순히 지금 여러분이 상속한 DbContext 클래스에 OnConfiguring 메서드가 없기 때문 입니다. 그렇다면 왜 없을까요? 여기서 바로 이 글 처음에 말했던 패키지 설치 미스가 나오게 됩니다. .Net Core EF Code-First를 사용하기 위해 필요한 패키지 닷넷 코어 엔티티 프레임워크를 사용하려면, 당연히 엔티티 프레임워크를 지원하는 DB의 라이브러리가 필요합니다. MySQL, MSSQL, SQLite, … 등등 많은 DB는 현재 엔티티 프레임워크를 지원하는 패키지를 NuGet에 배포하고 있습니다. 하지만, 거기서 끝이 아닙니다. 예를 들어 SQLite를 사용한다고 가정해볼까요? 여러분은 NuGet으로 System.Data.SQLite.Core, System.Data.SQLite.EF6 패키지를 설치할 겁니다. 만약 여기서 끝났다고 생각하고 DbContext를 만들면 위의 이미지와 같은 상황이 생기게 됩니다. 왜냐, System.Data.Entity.DbContext에는 OnConfiguration 메서드가 없기 때문입니다. 여러분이 제대로 된 DbContext를 상속받아 사용하시려면, Microsoft.EntityFrameworkCore 패키지 역시 설치...

[.NET/Build] 쉽고 간편하게 DLL을 EXE에 포함시켜보자

이미지
Embedding DLLs 어느 정도 규모가 있는 프로젝트를 개발하다 보면, 반드시 직면하게 되는 문제가 있습니다. 바로 수많은 하위 프로젝트들과 그에 따른 미친듯한 DLL의 폭증입니다. 이는 어쩔 수 없는 것이, 대형 프로젝트를 개발하다가 보면 이것저것 필요한 라이브러리를 가져와 사용할 수밖에 없고, 그것이 타인이 만든 라이브러리이든 자신의 라이브러리이든 관계없이 차곡차곡 쌓이다가 보면 어느새 한 개의 EXE에 수십 개의 DLL이 줄줄이 딸려오는 상황이 생기게 됩니다. 또한, 굳이 이러한 외부 라이브러리가 아니더라도, 호환성을 위해 .NET Framework의 기본적인 DLL을 배포할 때 포함할 경우도 마찬가지입니다. 예를들어, System , System.Buffers , System.Core , System.IO , … 등등 수많은 기본 DLL들을 말이죠. 특히 의존 관계가 적은 기본 DLL들은 실행 파일 폴더에 포함시켜주기만 하면 실행하는 쪽에서 번거롭게 .NET Framework를 설치하지 않아도 실행할 수 있게 되기 때문에 자주 쓰이는 방법입니다. 그러나 말씀드렸다시피, 이는 배포할 파일이 쓸데없이 많아지는 결과를 초래합니다. EXE 하나에 수십, 심하면 수백 개의 DLL이 줄줄이 딸려가는 상황을 생각해보세요. 끔찍합니다. 바로 이 때 사용할 수 있는 기법이 바로 Embedding DLL입니다. 간단히 말해, EXE에 DLL을 포함시켜 진입점에서, 혹은 필요한 시점에서 로드해 사용하는 방법입니다. 어떻게 EXE에 DLL을 포함시키나 사실 방법은 그리 어렵지 않습니다. 다만, 귀찮을 뿐입니다. 빌드된 DLL을 프로젝트에 포함시키고, 빌드 작업을 포함 리소스 로 변경합니다. 그런 뒤 적절한 위치에서 Assembly 클래스를 통해 어셈블리를 로드해주면 됩니다. 혹은 ILMerge등을 사용하는 방법도 있습니다. 글로 쓰면 짧죠? 하지만 구현하는 건 이것보단 긴 줄의 소스코드가 필요합니다. 그리고 무엇보다, 번거롭습니다. 프...

[C#/LINQ] MoreLINQ, LINQ를 확실히 활용하고싶다면 반드시 필요한 패키지!

LINQ? 다들 아시겠지만, .NET 프레임워크에는 LINQ라는 아주 뛰어난 기능이 잘 구현돼 있습니다. 이 링크 를 보시면 이에 대한 내용이 잘 정리돼 있으니 LINQ가 뭔지 모르시는 분이 계신다면, 한 번 보시는 것을 추천합니다. 아무튼, 요점은 이게 아닙니다. LINQ에 대한 개념이 없으신 분일지라도, C# 코딩을 하다가 한 번쯤은 List<T> 를 사용해봤을 것이고, 무조건 IEnumerable<T> 에 대한 접근을 해야만 했던 경우가 있었을 것입니다. 예를 들어 아래와 같이요. var listPeople = new List<People> { new People( "이정민" , "960528" ), new People( "염정실" , "600709" ), }; 위의 예제는 List<T> 의 사용 예입니다. 클래스명에서 알 수 있듯, 여러 타입에 대한 리스트를 만들고 관리하는 데 사용됩니다. 저는 지금 리스트 안에 두 개의 객체만 예시로 넣어놨으나, 거대한 데이터베이스에 수십만 개의 People 데이터가 쌓여있고, 그것을 가져와서 처리한다고 생각해보세요. 말로만 해서는 이해가 힘들 수도 있겠습니다. 그럼 한 번 그 수십만 개의 People 객체를 담고 있는 List<People> 객체에서 성씨가 이 씨인 사람만 뽑도록 해볼까요? var listPeopleStartsWithLee = listPeople.Where(_ => _.Name.StartsWith( "이" )); // 또는 var listPeopleStartsWithLee = from person in listPeople where person.Name.StartsWith( "이" ) select person; 자. 이게 바로 LINQ입니다. 마치 DB에 쿼리를 날리는...

[Kotlin] while문 안에서 변수에 대입하기

최근, 코틀린을 사용해 프로젝트를 진행하게 됐습니다. 그러던 중, 파일 I/O 작업이 필요하게 됐죠. 그래서, 평소 자바나 C#에서 하던대로 while문을 작성해봤으나 제대로 작동하지 않았습니다. 아래는 Java 코드입니다. while ((i = zipStream.read(buf)) != - 1 ) { // Do something... } 그리고 아래는 작성했던 코틀린 코드입니다. while ((i = zipStream.read(buf)) != -1) { // Do something... } 같은 것 같다고요? 맞습니다. 동일하게 작성했더니 안 되더라고요. 그래서 방법을 찾아봤습니다. 생각해보니, 람다 가 있었습니다. 익명 함수를 사용한 while문 내에서의 변수 할당 while ({i = zipStream.read(buf); i}() != -1) { // Do something... } 간단히 설명하면, zipStream.read(buf) 의 값을 변수 i 에 할당하고 그 값을 반환하는 익명 함수를 즉시 호출하고, 그 결과를 대조해 while문을 돌리면 되는 것이었죠! 이 과정에서 코틀린의 새로운 문법을 알게 됐습니다. 바로 익명 함수( { ... } )에서 return statement가 없으면 ; (세미콜론)을 대신 사용할 수 있다는 것입니다. 모두 유용하셨길 바라며, 오늘도 즐거운 하루 되시길 바랍니다. ​

[LUA] pairs, ipairs의 차이

루아의 반복문 루아에서 테이블 속 내용을 돌아가며 빼와서 작업할 때는 아래와 같은 식으로 쓰게 됩니다. -- 1. for i, v in pairs (t) do -- Do something... end -- 2. for i, v in ipairs (t) do -- Do something... end 간단한 작업을 할 때는 둘 중 어느 걸 사용하더라도 잘 작동할 것입니다. 하지만, 만약 특정 테이블에 대해 반복문을 실행할 때, 이터레이션을 ipairs 로 돌게 된다면 심각한 로직 에러가 발생할 수 있습니다. 지금부터 이 글에서 그 원인을 설명하고, 어떤 때에 pairs를 사용해야 하며 어떤 때에 ipairs를 사용하면 좋은지 알려드리도록 하겠습니다. 루아의 테이블 반복문 얘기하다가 갑자기 테이블 얘기를 꺼낸 이유가 있습니다. pairs와 ipairs가 굳이 나누어져있는 이유를 알고자 한다면, 반드시 테이블에 대한 이해가 우선시되어야 하기 때문이죠. 루아의 테이블(table)이란 데이터 타입은, 타 언어의 array와 map 데이터 타입의 특징을 둘 다 가지는 특이한 녀석입니다. 즉 아래의 모든 것이 테이블이라는 하나의 형식으로 사용된다는 의미입니다. local tblA = { 1 , 2 , 3 } local tblB = { "A" , "B" , "C" } local tblC = { nil , nil , nil } local tblD = { tblA, tblB, tblC, { 1 , 2 , 3 } } -- local tblA = { [1] = 1, [2] = 2, [3] = 3 } -- local tblB = { [1] = "A", [2] = "B", [3] = "C" } -- ... local tblE = { HP = 100 , MP = 100 , ATK = 1.5 } ...