라벨이 C#인 게시물 표시

puppeteer의 waitForXpath는 더 이상 사용되지 않는다. 대체 방법.

puppeteer의 waitForXpath는 더 이상 사용되지 않는다. Obsolete API - waitForXpath 조금 늦은 감이 있지만, 아무튼 Puppeteer 16.1.0 부터 waitForXpath 메서드 등 XPath 관련 독립 메서드들이 모두 더 이상 사용되지 않게 됐다. 그렇다고 더 이상 XPath를 사용하여 엘리먼트를 선택할 수 없는 것은 아니다. waitForSelector를 사용한 xpath 쿼리 이제부터는 waitForSelector를 사용해 xpath를 쿼리할 수 있다. 이렇게 하려면 셀렉터에 xpath/ prefix를 붙여주면 된다. await elementHandle . waitForSelector ( 'xpath/' + xpathExpression ) ; 즉 xpath/ 까지가 본체이고 이후에는 통상 xpath를 입력하면 된다는 말. 즉 ../input[@id='query'] 를 쿼리하고자 한다면 await elementHandle . waitForSelector ( 'xpath/../input[@id="query"]' ) ; 와 같이 사용하면 된다. //button[@type='submit'] 을 찾고자 한다면, 슬래쉬 세 개가 들어간다고 두려워하지 말고 await elementHandle . waitForSelector ( 'xpath///button[@type="submit"]' ) ; 과 같이 사용하면 된다. PuppeteerSharp puppeteer 의 C#용 포팅 라이브러리인 PuppeteerSharp 역시 이와 같은 변경 사항이 적용되었으니 같은 방식으로 사용하면 되겠다.

WPF Prism에서 AutoMapper 사용하기

WPF Prism에서 AutoMapper 사용하기 AutoMapper AutoMapper는 서로 다른 두 클래스를 보다 쉽게 매핑하기 위해 사용하는 라이브러리이다. 내 경우(그리고 많은 오픈소스 프로젝트의 경우) 모델과 DTO 사이의 매핑을 손쉽게 처리하기 위해 주로 사용된다. Prism Prism 프레임워크, 또는 라이브러리 1 는 이전 포스트 에서 자세히 다룬 바 있다. 다시 간략하게 정리하자면 MVVM 기반 프로젝트 개발을 더 쉽게 할 수 있도록 도와주는 프레임워크이다. Prism에서 AutoMapper DI하기 ASP.NET 프로젝트에서 AutoMapper 사용은 정말 쉽다. 애초에 AutoMapper에서 확장 메서드를 제공하기 때문에 서비스를 구성할 때 해당 메서드를 호출하고, AutoMapper.Profile 을 상속받은 클래스를 만들어 아무 곳에다가 배치해놓은 뒤 실행하면 된다. 그러나 Prism용 확장 메서드는 자체적으로 제공되지 않으므로 직접 만들어 써야 한다. IAutoMapperProvider interface 일단 DI를 위해 사용할 인터페이스부터 구성한다. public interface IAutoMapperProvider { IMapper GetMapper ( ) ; } AutoMapperProvider class 이제 위 인터페이스를 상속한 AutoMapperProvider 클래스를 작성한다. public class AutoMapperProvider : IAutoMapperProvider { private readonly MapperConfiguration _configuration ; public AutoMapperProvider ( IContainerProvider containerProvider ) { _configuration = new MapperConfiguration ( config ...

프리즘 생산성 도구들

프리즘 생산성 도구들 생산성 도구 현재 프리즘은 Visaul Studio 및 Visual Studio Mac과 연동해 WPF, UWP, 네이티브 iOS 및 Xamarin.Forms를 사용한 Android 앱을 개발하기 위한 매우 생산적인 개발자 워크플로우를 지원한다. 코드 스니펫, 아이템 템플릿, 프로젝트 템플릿을 사용해 빠르게 프리즘 앱 제작을 시작할 수 있다. 현재 다음과 같은 도구를 사용할 수 있다. Prism Template Pack Prism Template Studio Prism Extensibility Pack Prism Template Pack 프리즘 템플릿 팩은 프리즘을 사용한 WPF 및 Xamarin.Forms 개발을 위한 여러 코드 스니펫, 아이템 템플릿 및 프로젝트 템플릿을 포함하고 있다. Snippets propp - Property, with a backing field, that depends on BindableBase private string _fieldName ; public string PropertyName { get { return _fieldName ; } set { SetProperty ( ref _fieldName , value ) ; } } cmd - Creates a DelegateCommand property with Execute method private DelegateCommand _fieldName ; public DelegateCommand CommandName = > _fieldName ? ? ( _fieldName = new DelegateCommand ( ExecuteCommandName ) ) ; void ExecuteCommandName ( ) { } c...

프리즘 프레임워크 시작하기

프리즘 프레임워크 시작하기 프리즘 다운로드 및 설치 이번 글에서는 프리즘을 다운로드하고 설치하는 방법을 의역해 옮기도록 하겠다. 전체적인 프리즘 릴리즈 노트는 깃헙 페이지 에서 확인할 수 있다. 프리즘 소스 코드 다운로드 및 셋업 프리즘 소스 코드에서 셋업을 진행하기 위해서는 다음과 같은 단계를 따른다. 시스템 요구 사항 설치 프리즘 소스 코드 및 문서 다운로드 및 압축 해제 컴파일 및 샘플 실행 1단계. 시스템 요구 사항 설치 프리즘은 윈도우 8 데스크탑, 윈도우 7, 비스타, 2008 OS에서 작동하도록 디자인되었다. 1 이 가이드에서 빌드된 WPF 앱은 .NET Framework 4.5를 필요로 한다. 1 2 프리즘 라이브러리를 사용하기 전, 다음과 같은 요구 사항이 설치되어야만 한다. .NET Framework 4.5 또는 그 이상의 버전 MS Visual Studio 2017 이상의 버전(2019 권장) 3 Prism.Forms를 사용하려면 Xamarin 워크로드가 반드시 설치되어야 함 4 2단계. 프리즘 소스 코드 및 문서 다운로드 및 압축 해제 프리즘 리포지토리 를 fork하면 손쉽게 진행할 수 있다. 샘플 코드는 다음과 같다. WPF 샘플 Xamarin.Forms 샘플 위 단계 대신 Prism 관련 NuGet 패키지 를 설치해도 된다. 3단계. 샘플 컴파일 및 실행 모든 샘플은 프리즘 NuGet 참조를 사용하므로 각 솔루션에서 직접 컴파일하고 실행할 수 있다. 문서가 구버전이라 이렇게 적혀 있으나 프리즘 8은 윈도우 10, 11을 지원하고 오히려 8.1 이하를 지원할 계획이 없다고 한다. ↩︎ ↩︎ 현재 시점의 최신 프리즘(버전 8)은 .NET 7에서도 잘 돌아간다. ↩︎ 글을 쓰는 현재 VS2022에서도 문제없이 잘 돌아간다. ↩︎ Visual Studio Installer에서 Xamarin 워크로드를 활성화하고 설치하면 된다. ↩︎ ...

WPF - 프리즘 프레임워크

WPF - 프리즘 프레임워크 C#/WPF. 불편해. Node.JS 개발을 하다 보니 WPF 개발이 참 난감해졌다. 예전에는 당연히 이 정도 기능을 코딩하려면 미리 만들어놓은 라이브러리가 없을 때 이만큼의 시간이 걸리는 건 당연하지 라고 생각했었는데, 리액트와 NextJS 등을 사용하다가 WPF 개발 쪽으로 돌아가려니 도저히 못해먹겠다 싶은 생각 뿐이었다. 아, 이건 이런 HTML 태그와 이런 CSS를 쓰면 쉽게 가능한데… 아, 저건 이러이러한 타입스크립트로 쉽게 되는데… 이런 경우가 너무 많이 생긴다는 것이다. 이럴 때 사용할 수 있는 라이브러리나 프레임워크가 있나 찾아보다가 발견하게 된 것이 프리즘이다. 일단, 아직 한 번도 프리즘을 사용해보지 않았으므로 공식 문서를 의역하면서 하나씩 알아가보고자 한다. Prism: XAML 앱용 프레임워크 프리즘은 느슨하게 결합된 관리와 테스트가 용이한 XAML 앱용 프레임워크이다. 1 프리즘을 사용하면 MVVM, DI, commands, EventAggregator 등등 여러 디자인 패턴들의 구현을 제공받게 된다. 대상 플랫폼 프리즘은 .NET Standard 및 .NET 4.5 또는 4.8 버전에서 사용할 수 있도록 크로스 컴파일되어 제공된다. 또한 WPF, Xamarin Forms, 버전 8의 경우 UNO에서 사용할 수 있다. 단, 8버전 이후로 Silverlight나 윈도우 8/8.1/윈도우 폰 8.1, UWP에 대한 지원 계획은 없다고 한다. 이 경우엔 이전 버전 을 사용하라고 권하고 있다. https://prismlibrary.com/docs/index.html ↩︎

Microsoft.AspNetCore.Authentication.JwtBearer 사용 중 토큰이 잘못됐을 때 올바른 401 응답을 반환하는 방법

Microsoft.AspNetCore.Authentication.JwtBearer 사용 중 토큰이 잘못됐을 때 올바른 401 응답을 반환하는 방법 JWT 토큰 인증 J SON W eb T oken은 이름 그대로 웹에서 사용되는 JSON 토큰이다. 웹 에서 JSON 형식의 토큰 을 사용해 인증을 처리하는 데 주로 사용된다. ASP.NET에서 JWT를 사용하는 데 주로 쓰이는 패키지는 Microsoft.AspNetCore.Authentication.JwtBearer 패키지인데, 일반적인 상황에서는 그냥저냥 기본 설정만 건드린 채 사용해도 문제가 없으나 내 경우에는 CORS 호출이 기본인 상황에서 사용하다가 예상하지 못한 문제를 맞이했다. 1 프론트엔드에서 fetch 사용 시 401 Unauthorized 문제 Next.JS로 구축된 프론트엔드에서는 문제가 없다. 크롬 확장 프로그램 의 팝업 페이지나 커스텀 페이지 에서도 문제가 없다. 문제는 콘텐츠 스크립트 에서 발생했다. 콘텐츠 스크립트는 React를 사용하여 구현되어 있는 상태이고, 직접 만든 Provider 및 hook을 사용해 JWT 토큰을 일정 시간마다 받아오고, 리프레시할 때 401 또는 403 에러가 발생하면 그에 맞는 처리를 하도록 코드를 짰다. 문제는 정상적인 상황에서, 즉 팝업 또는 사용자 정의 페이지에서 인증을 완료하고 이를 API 서버에서 검증하려 할 땐 아무 문제 없이 정상 작동하던 로직이 토큰의 기한이 만료되어 401 상태 코드를 받아와야 하는 상황에서는 작동하지 않고 예외를 던진다는 것이다. 분명 ASP.NET 서버에서 다음과 같이 CORS를 허용하였는데 app . UseCors ( builder = > { builder . AllowAnyOrigin ( ) . AllowAnyHeader ( ) . AllowAnyMethod ( ) ; } ) ; 막상 에러를 까보면 cors 에러도 함께 ...

SemaphoreSlim을 사용해 동시 병렬 처리 개수 제한

SemaphoreSlim을 사용해 동시 병렬 처리 개수 제한 병렬 처리 병렬 처리는 잘 쓰면 굉장한 성능 이점을 가져올 수 있지만, 잘못 쓰면 오히려 굉장한 성능 하락을 가져온다. 병목 현상이고 뭐고 멀리 갈 것도 없이 다음과 같은 경우에는 확실하게 성능이 저하된다. A 로직이 실행되는 데에 시스템 리소스의 10%가 필요함. 한 번에 20개의 A 로직 병렬 실행 이런 경우에는 한 번에 처리할 수 있는 병렬 처리 작업의 최대치를 정해야 한다. Parallel.ForEachAsync Parallel.ForEach 는 완료를 대기하지 않으므로 .NET 6 이상이라면 Parallel.ForEachAsync 를 사용해 다음과 같이 구성할 수 있다. var rnd = new Random ( ) ; var voList = Enumerable . Range ( 0 , 99 ) . ToList ( ) ; await Parallel . ForEachAsync ( voList , new ParallelOptions { MaxDegreeOfParallelism = 10 } , async ( i , token ) = > { await Task . Delay ( rnd . Next ( 200 , 1200 ) ) . ConfigureAwait ( false ) ; Console . WriteLine ( $ "{DateTime.Now:HH:mm:ss.fff}: Finished work: {i:#,##0}" ) ; } ) . Con...

[C#/GraphQL] dotnet ef scaffold된 DB에서 HotChocolate Many-To-Many 또는 One-ToMany 프로퍼티가 empty list로 반환되는 문제

  스카폴드로 생성된 프로퍼티에 setter가 없어서 발생한 문제입니다.    스택 오버플로우 글 을 참조해 setter를 추가하니 잘 됩니다.   만약 스카폴드로 생성한 DB가 아닌데도 똑같은 문제가 생긴다면, ICollection 가상 속성에 setter를 추가해주시면 됩니다.

DllNotFoundException: DLL 'SQLite.Interop.dll'

이미지
  프로젝트 빌드 중  DllNotFoundException: DLL 'SQLite.Interop.dll'  에러가 발생해 해결 방법을 찾아보니, SQLite.Interop.dll을 배포시 첨부하라는 답변을 얻었습니다.   문제는, 이렇게 할 경우 AnyCPU 구성을 사용하기 불편 해집니다.   방법이 없나 찾다가 패키지 폴더 구조를 봤더니 다음과 같이 되어 있었습니다. 1. SQLite.Interop.dll 상위 디렉토리   각 플랫폼 폴더 안에 SQLite.Interop.dll이 들어가 있는 식이죠.   지금까지는 파워쉘 스크립트를 작성해 빌드 후 이벤트에서 호출하고, 플랫폼에 맞는 DLL을 복사하는 방식으로 진행하고 있었는데, 혹시나 하여 그냥 저 폴더 자체를 갖다가 넣어보니 구성을 x86이나 x64로 지정하지 않고 AnyCPU로 두어도 잘 작동하더군요. 프로젝트에 포함된 SQLite.Interop.dll 출력 디렉토리에 복사를 사용해 자동 복사 (폴더 구조까지) 출력 디렉토리에 복사된 모습   이대로 실행하면 AnyCPU 구성에서도 정상적으로 로드하는 것을 확인 할 수 있었습니다.   어찌 된 일인가 찾아보니, 스택 오버플로우에 잘 정리된 글 이 있었습니다. SQLite가 알아서 현재 플랫폼에 맞는 바이너리를 x86, x64 폴더 중에서 선택해 로드한다고 합니다.

WPF의 컨버터가 호출되지 않을 때 체크해보세요.

  제 경우에는 BoolToVisibilityConverter를 만들어서 쓰고 있었습니다. LambdaConverters 패키지를 사용해 간편하게 만들어서요.   해당 컨버터는 bool   소스의 값을 bool ConverterParameter 에 따라 Visibility 로 변경해주는 역할을 합니다.   패러미터가 true일 때엔 소스가 true 라면 Visible , 아니라면 Collapsed 를 반환하지만   패러미터가 false일 때엔 반대로 소스가 true 라면  Collapsed , 아니라면 Visible 을 반환하는 식입니다.   문제는, 이 컨버터를 사용하려 할 때에 발생했습니다. <DataGrid Binding="{IsRecordExists}", Converter="{x:Static cvt:VisibilityConverters.BoolToVisibilityConverter}", ConverterParameter=True} />   위와 같이 작성하고 테스트를 해보았으나 의도한 바와 전혀 다르게 작동하는 모습을 보였습니다.   왜 의도한 것과 다르게 작동하는지 알아보기 위해 이것 저것 테스트하다가, 컨버터의 Convert 메서드쪽에 브레이크포인트를 걸고 디버그를 돌려보니, 아예 Convert 메서드 쪽으로 진입조차 하지 않는 것을 확인하게 되었죠. 소리 없는 암살자   이건 제가 LambdaConverter 패키지를 사용해서 생긴 문제일 수도 있습니다만, 아무튼 정말 아무런 메세지도, 경고도, 에러도 없이 그냥 메서드 자체가 호출되지 않고 넘어가더군요.   이는 생각보다 심각한 문제였습니다. 에러도 없고 경고도 없어서 이것 저것 쓸데 없는 오만가지를 다 건드리다가 심지어 WPF의 버그인가? 라는 생각도 잠시 스쳐 들 정도였으니까요.   아무튼 그래서 왜 그럴까... 하고 생각하다가 문득 떠오른 것이 있었습니다. 패러미터는 기본적으로...

WPF에서 Dispatcher가 필요한지 아닌지 확인하는 방법

 WPF에서 코딩을 하다 보면 수시로 마주하게 되는 Dispatcher  프로퍼티. System.Windows.Timer 를 사용하는 경우, Task 를 통해 비동기로 작업을 실행하는 경우 등등 비동기 프로그래밍을 하게 될 경우 UI 스레드에서 실행되어야 하는 메서드 호출을 위해 자주 사용되죠. (예: Close() , TextBlock.Text 수정, ... ) 예시 중 UI 엘리먼트의 프로퍼티 수정은 WPF의 강력한 Binding  기능으로 대체하면 되지만, 일정 시간 후 창이 닫히는 기능 등의 구현에는 XAML로 작성하는 것보다 간단하게 System.Windows.Timer 를 사용해 Elapsed  이벤트 발생 시 Close 를 호출하는 것이 간편합니다. 이런 상황에서, 그냥 Close 를 호출하면 크로스 스레드 문제가 발생하므로 Dispatcher를 사용해 UI 스레드에서 작업을 실행하게 되죠. 하지만 상황이 항상 이렇게 딱 정해져 있지는 않죠. 코딩을 하다가 보면 많은 경우를 마주하게 되고, Dispatcher를 호출해야 하는 상황인지 아닌지 확인해야 하는 상황 이 생기기도 합니다. 이 때 쓸 수 있는 것이 바로 Dispatcher.CheckAccess 메서드 입니다. private void CloseDialog() { DialogResult = false; // check if current context is ui context if (Dispatcher.CheckAccess()) Close(); else Dispatcher.Invoke(Close); } 위와 같이 Dispatcher.CheckAccess  메서드를 호출했을 때, 호출한 스레드가 해당 Dispatcher에 연결된 스레드이면 true 를, 아니라면 false 를 반환합니다. 따라서 true가 반환되었다면 그냥 UI 스레드 작업을 호출하면 되고, 아니라면 Dispatcher....

Flags Attribute를 사용해보세요.

개발 중에는 때때로 하나의 enum 타입을 가지고 여러 value에 대해 분기해 처리해야 하는 경우가 생깁니다. public enum EnumExample { A, B, C } 위와 같은 enum 타입이 있을 때, 상황이 항상 A이거나, B이거나, C이거나 셋 중 하나로 끝나면 매우 바람직하겠지만 대개 그렇지 않죠. A이거나, A와 B이거나, A와 C거나, B거나, ... 이런 상황이 자주 나옵니다. 그럼 어떻게 코딩해야 할까요? 아래처럼? if (value == EnumExample.A) { // ... } else if (value == EnumExample.A && value2 == EnumExample.B) { // ... } 말이 안 되죠. System.FlagsAttribute Class MSDN 문서 에 따르면, 이 어트리뷰트가 적용된 enum은 비트 필드로 취급될 수 있다고 합니다. 즉, C언어 등에서 사용되는 비트 필드마냥 사용할 수 있게 된다는 뜻이죠. 다음 예시를 보세요. [Flags] public enum FlagsExample { NONE = 0, A = 1, B = 2, C = 4, D = 8, E = 16, } 위와 같이 선언된 enum은 각각의 값이 비트 필드로 취급됩니다. 즉 0은 0000 0000 0000 0000, A는 0000 0000 0000 0001, B는 0000 0000 0000 0010, C는 0000 0000 0000 0100, D는 0000 0000 0000 1000, E는 0000 0000 0001 0000과 같은 식으로 생각하시면 됩니다. 이렇게 되면 어떤 방식의 코딩이 가능해지냐? enum 값에 대한 비트 연산이 가능해집니다. var abc = FlagsExample.A | FlagsExample.B | FlagsExample.C; // abc = A, B, C 따라서 위와 같이 하나의 enum 변수에 여러...

C# 인터렉티브에서 .NET Core 사용하기

이미지
저는 꽤나 자주 C# 인터렉티브 콘솔을 사용합니다. 간단한 로직을 테스트하거나, 현재 C# 버전의 어떤 기능이 어떻게 작동하는지 기억이 안 날 때 확인하는 용도로 말이죠. 디버그를 걸어도 물론 되지만 코드 입력과 실행 결과 확인에 길어야 1, 2분도 채 걸리지 않는 테스트를 위해서 코드를 새 파일에 작성하고 빌드하고 디버그하는 것은 너무나도 귀찮기 때문입니다. 이럴 때 C# 인터렉티브 콘솔은 그야말로 딱이죠. 심지어 Visual Studio에 내장되어 있는 기능이라 따로 실행파일을 직접 실행하지 않아도 간편히 작업할 수 있다는 장점까지 있습니다. .NET Framework, .NET Core 이번에 제가 확인하고자 했던(까먹었던) 기능은, C#의 Ranges and Indices 기능입니다. a .. b 혹은 a .. ^b 식으로 사용하는 것이란 건 기억이 나는데, str[a .. b] 와 같이 사용했을 때 문자열의 a번째 인덱스부터 b번째 인덱스까지였는지, 아니면 a번째 인덱스부터 b - 1번째 인덱스까지였는지가 기억이 나질 않았죠. 기본값은 .NET Framework 그래서 어느 때와 같이 단축키로 C# Interactive 콘솔을 열어 다음과 같이 입력해봤습니다. 그랬더니 위와 같이 System.Range , System.Index 를 정의하지 않았거나 가져오지 않았다며 CS0518 에러가 발생했습니다. 구글링은 필요없다! 다행히도, 예전에 .NET Framework 프로젝트에서 Ranges, Indices를 사용하는 방법에 대해 찾던 중 이런 에러를 마주한 적이 있기 때문에 이 에러가 왜 발생했는지 바로 알 수 있었습니다. C# 인터렉티브 콘솔이 Core가 아닌 .NET Framework에서 실행되고 있기 때문 라는 것을요. .NET Core 인터렉티브로 전환 그리고 거의 동시에 예전, 즉 C# 8.0이 출시된지 얼마 안 됐을 때 비슷한 경험을 한 적이 있다는 사실을 떠올렸습니다. 그 때엔 분명 C# 인터렉...

닷넷 Random.Next(minValue, maxValue) 사용시 주의사항

개발을 하다보면 생각보다 자주 System.Random 클래스를 사용하게 됩니다. 닷넷의 랜덤 클래스에는 미리 정의된 Random.Next(int, int) 라는, 최솟값과 최댓갑 사이의 값을 반환해주는 좋은 기능이 있죠. 예전에 루아를 사용할 때엔 이게 없어서 직접 n * (max - min) + min 과 같은 식을 함수로 만들어서 썼었는데 정말 고마운 프레임워크입니다. maxValue 오늘도 어김없이 개발을 하던 도중, GitLab에 이슈가 올라왔습니다. 최소 설정값과 최대 설정값 사이의 랜덤한 값으로 작업이 반복되어야 하는 로직이 있는데, 이게 작동을 안 한다는 것이었죠. 해당 부분의 코드는 제가 만든 것이 아니기 때문에 디버그를 하며 어디가 문제인지 찾아봤습니다. 그러다가 찾은 다음 코드. public int RandomValue { get { return m_rnd . Next ( COND_MIN , COND_MAX ) ; } } 아... 설마? 하고 브레이크포인트를 걸어봤습니다. 아니나 다를까, COND_MAX 값에 사용자가 입력한 값이 그대로 들어가있더군요. 예를 들어, 사용자가 최소 설정값을 1, 최대 설정값을 2로 지정했다면 COND_MIN = 1, COND_MAX = 2가 되는 식이었습니다. 그렇다면 이게 뭐가 문제일까요? 얼핏 보면 minValue, maxValue라는 인자명을 생각해보면 당연히 해당 코드가 1 또는 2를 반환하리라 생각됩니다. 하지만, 그게 바로 함정 입니다. MSDN의 Random 클래스 문서를 보면, 다음과 같은 내용이 있습니다. A 32-bit signed integer greater than or equal to minValue and less than maxValue ; that is, the range of return values includes minValue but not maxValue. If minValue e...

NamedPipeServerStream.WaitForConnectionAsync(CancellationToken) 메서드가 토큰이 취소됐음에도 무기한 대기할 때 해결 방법

NamedPipeServerStream NamedPipeServerStream C#에서는 Named Pipe를 손쉽게 사용하기 위한 클래스인 NamedPipeServerStream , NamedPipeClientStream 을 지원합니다. 이 중 NamedPipeServerStream 은 그 이름에서 알 수 있듯 서버 기능 구현을 위한 스트림입니다. 연결 대기 서버는 당연히 클라이언트가 있어야 의미가 있습니다. 서버 혼자서는 아무것도 할 게 없기 때문이죠. 이런 당연한 얘기는 제쳐두고, 서버를 구현하다 보면 자연스레 클라이언트가 연결이 됐는지 안 됐는지 확인하는 코드가 필요하게 됩니다. TCP 소켓 같은 경우에는, AcceptAsync 등을 사용해 아예 클라이언트 소켓 자체를 받아오거나, Pending 메서드를 사용해 접속 대기중인 클라이언트가 있는지 확인할 수 있습니다. 그럼 NamedPipeServerStream 에는 뭐가 있을까요? WaitForConnection, WaitForConnectionAsync 당연히 NamedPipeServerStream 에도 클라이언트 접속 여부를 판단하는 메서드가 있습니다. 바로 WaitForConnection , WaitForConnectionAsync 입니다. 첫 번째 메서드는 동기 방식으로 대기합니다. 이 경우에는 해당 메서드가 호출된 시점부터 클라이언트가 접속할 때까지 호출된 스레드가 블럭 됩니다. 이번 포스트에서 다룰 것은 두 번째 메서드, WaitForConnectionAsync 입니다. CancellationToken WaitForConnectionAsync 메서드는 인자로 CancellationToken 을 받을 수 있습니다. 따라서, 해당 토큰에 취소 요청이 받아들여지면 대기를 중지하고...

[C#/NLog] NLog 타겟이 Exception을 출력할 때 새로운 줄에 출력하도록 하기(newline)

NLog NLog. 정말 좋습니다. 예전 회사에 다닐 때엔 자바를 사용하며 log4j를 썼는데, 퇴사 후 C#으로 넘어오면서 log4j같은 것, 혹은 그보다 좋은 라이브러리가 없을까 하며 찾아보니 처음에는 log4net이, 그 다음에 바로 NLog가 눈에 들어오더군요. 그때 당시에는 제가 못 찾은건지 모르겠지만 log4net이 제대로 업데이트가 되고 있지 않아보였기에 NLog를 주력 로깅 라이브러리로 선택해 아직까지 잘 사용중입니다. LayoutRenderer 지원 NLog는 LayoutRenderer를 통한 다이나믹 로깅을 지원합니다. 예를 들어, <target layout="${longdate} ${level:uppercase=true} [${threadid}/${threadname}] ${logger}.${callsite:methodName=true} - ${message}" /> 위와 같은 레이아웃을 지닌 타겟은, 다음과 같은 형태의 로그를 출력하게 됩니다. 2020-12-15 11:50:34.4618 INFO [1/] HSUpdateUploaderGUI.MainWindow.HSUpdateUploaderGUI.MainWindow.Window_Loaded - Application is loaded. Exception 객체 지원 위와 같은 레이아웃 렌더러를 통해 예외 출력도 마음대로 설정할 수 있습니다. 기본적으로 ${exception} 렌더러를 사용합니다. 해당 렌더러는 NLog.Logger.(Trace|Debug|Info|Warn|Error|Fatal) 메서드의 첫 번째 인자로 Exception 객체가 주어졌을 때 해당 Exception 객체의 내용을 렌더러의 설정에 따라 출력합니다. 반대로, Exception 객체가 null일 경우에는 아무것도 출력하지 않고요. 하지만 여기서 문제가 생깁니다. 만약 예외 메세지를 다른 라인에 출력하고 싶다면? Exception 내용을 새 줄에...

[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 ...