기본 콘텐츠로 건너뛰기

[Framework] 개발 프레임워크 구성을 위한 기본적인 정리...

>>> 잡설... ㅠㅠ 지금까지 미루고, 뒤집고, 포기하고, 다짐하고, 매번 재 시작을 하면서도 진행을 하지도 못하고 매번 실패로 끝날 수 밖에 없던 개발 프레임워크 만들기에 다시 한번 도전을 한다. 벌써 많은 세월이 흘러서 더 이상의 도전은 없을 듯 하다. 아니 내가 원해도 시장과 환경들이 기회를 주지 않을 듯 하다. 세상의 수 많은 사람들이 개발 프레임워크에 대해서 고민하고, 토의하고, 격론을 통해서 나온 좋은 프레임워크들은 이미 많다. 내가 구성하고 싶은 프레임워크 역시도 많은 단점을 가질 것이고, 앞서 나온 수 많은 훌륭한 프레임워크를 흉내조차 내지 못할지도 모르고, 너무 시대에 뒤 떨어진 것일지도 모른다. 하지만, 내가 하고 싶었고, 내가 원하는 방향으로 나만의, ... 내 이름을 걸고 하나의 프레임워크가 있었으면 좋겠다는 생각이다. 제발 이번만은 먹고 살기 위해서 프로젝트 뛰느라.. 포기하게 되는 그런 무책임하고 무모한 도전으로 끝나지 않기를 희망한다. 얼마만큼의 시간과 노력이 들어갈지는 모르지만... [ 전제 조건 들 ] 메타 정보를 기반으로 한다. 개발 툴(현재는 Visual Studio)에 융합되어야 한다. 메타 정보는 손 쉽게 변경과 적용이 가능해야 한다. 메타 정보를 기반으로 여러 가지 어플리케이션(모바일, 웹, 데스크탑, ...) 에 적용이 가능해야 한다. 메타 정보를 기준으로 실행을 할 수도, 실제 어플리케이션에 맞는 컴파일 및 구동이 가능한 코드로의 변환이 가능하여야 한다. 본 개발을 진행하기 전에 간단한 시나리오를 통해서 메타 정보를 구성하고, 프로토타입 검증이 가능하여야 한다. 성능 모니터와 연동하여 구성 컴포넌트들의 라이프사이클 추적이 가능하여야 한다. [ 요소 항목 들 ] 메타 정보 처리를 위한 메타 프레임워크 메타 정보 작성을 위한 메타 디자인 프레임워크 메타 정보 구동을 위한 구동엔진 프레임워크 어플리케이션 유형에 맞는 코드 출력을 위한 코드 생성 프레임

[Visual Studio] Visual Studio 관련 정보들 정리...

개인적으로 Visual Studio에 통합된 개발 프레임워크를 만드는 것에 관심이 많다. 아직은 시작조차 하지 못하고 시간만 보내고 있지만... ㅠㅠ 앞으로의 작업을 위해서 하나씩 정보를 모아 놓도록 한다. [ Project Kind ] Visual Studio로 많은 프로젝트를 구성할 수 있다. Visual Studio를 확장하게될 경우에는 프로젝트가 어떤 것인지를 판단하여야 할 수 있는 기준이 필요하다. 이 때 사용할 수 있는 것이 Project.Kind 속성이다. 아래는 각 프로젝트별 속성을 식별하기 위한 정보를 정리한 것이다. Project Type Description Project Type Guid Windows (C#) {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Windows (VB.NET) {F184B08F-C81C-45F6-A57F-5ABD9991F28F} Windows (Visual C++) {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} Web Application {349C5851-65DF-11DA-9384-00065B846F21} Web Site {E24C65DC-7377-472B-9ABA-BC803B73C61A} Distributed System {F135691A-BF7E-435D-8960-F99683D2D49C} Windows Communication Foundation (WCF) {3D9AD99F-2412-4246-B90B-4EAA41C64699} Windows Presentation Foundation (WPF) {60DC8134-EBA5-43B8-BCC9-BB4BC16C2548} Visual Database Tools {C252FEB5-A946-4202-B1D4-9916A0590387} Database {A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124} Database (other project types) {4F174C21

[ORACLE] SQL Developer 사용 사에 ORA-12505 오류가 발생하는 경우...

로컬 PC에 테스트를 위해서 Oracle XE 11g 버전을 설치해서 사용하고 있다. 그런데 가끔은 연결된 접속이 끊어지고, 다시 연결하려고 하면 아래와 같은 오류 메시지가 발생하면서 접속이 되지 않는 경우가 많다. 아마도 구글에서 검색을 많이 해 보면 대략 다음과 같은 대답들이 존재한다. lsnrctl services 를 실행해서 DEDICATED 로 표시된 SID를 사용해라. OracleServiceXE 서비스가 죽었으니 다시 실행해라. 서버 명이나 유동 IP로 변경되어서 그러니 잘 설정해라. -_- 위와 같은 대답이 틀린 것은 아니지만, 모두 다 환경들이 다를테니 좀 더 객관적인 사실에 근거해서 설명이 되어 있었으면 좋겠다는 생각이다. 일단 오류 메시지를 다시 살펴 보도록 하자. ORA-12505, TNS:listener does not currently know of SID given in connection descriptor. 즉, 접속 정보에 설정한 SID를 현재 인식하지 못한다는 말이다. 이런 일이 발생할 수 있는 소지는 다양하다. 위에서 언급했던 것과 같이 서버 명이 바뀐 상태이거나 유동 IP라서 서비스가 시작되었을 때의 IP 와 현재 IP 가 다른 경우도 있다. 이런 상황이라면 좀 더 덜 변할 수 있는 상황으로 설정을 변경하면 된다. 그리고 기본적으로 설치되는 Listener의 설정은 명확하게 SID를 명시하지 않고 있다. 따라서 아래와 같이 명시적이 될 수 있도록 수정해서 다시 시작하면 된다. [ 원본 ] SID_LIST_LISTENER =   (SID_LIST =     (SID_DESC =       (SID_NAME = PLSExtProc)       (ORACLE_HOME = C:\oraclexe\app\oracle\product\11.2.0\server)       (PROGRAM = extproc)     )     (SID_DESC =       (SID_NAME = C

[Visual Studio] ContextSwitchDeadlock 오류에 대한 처리...

이번 프로젝트에서 BackOffice를 사용하는 사용자 간에 메시지 공유와 서버와 클라이언트 간의 Real Message 수신, FTP File Upload 등의 통신 기능을 적용해야 한다. 그리고 메시지 수신에 따라서 사용자의 어플리케이션에 NotifyIcon 처리를 해 주어야 한다. 이런 저런 처리들을 가능하면 최대한 공통화를 하다 보니 Thread 가 난무한다. -_-+ 그렇게 많은 상황들을 정리하면서 테스트를 하던 중에 갑자기 나타난 오류 메시지.... CLR에서 60초 동안 COM 컨텍스트 xxxxx 에서 COM 컨텍스트 xxxxx 로 전환하지 못했습니다. 대상 컨텍스트/아파트를 소유하는 스레드가 펌프 대기를 수행하지 않거나, Windows에서 메시지를 펌프하지 않고 매우 긴 실행작업을 처리하고 있는 것 같습니다. 이러한 상황은... 위의 오류의 내용을 유추하면 Thread 간에 전환이 제대로 처리되지 못하고 마치 무한루프와 같은 상태에 빠진 것으로 보인다. 잘 처리되던 것이 몇 가지를 추가한 후에 저런 오류를 뿜어내는 것으로 보아서 추가한 부분이 또 다른 Thread에서 연결되면서 발생하는 것이 아닌지 의심이 된다. 일단 구글의 검색에 따르면 디버그 모드에서만 발생한다고 정리해 논 글들이 많다. 하지만 얼마 전까지만 해도 되던 상태였으니 딱히 긍정이 되지는 않지만, 일단 처리 방식을 정리해 놓도록 한다. Visual Studio > 디버그 > 예외 를 선택해서 예외 설정 창을 열고 Managed Debugging Assistants 목록을 클릭한 후에 "ContextSwitchDeadlock" 항목을 선택 해제하면 된다. 음~ 일단 저렇게 처리해도 지금의 상황에서는 동일하게 문제가 발생한다. Debug 빌드가 문제일지 아니면 Thread 처리가 복잡하게 얽혀서 생기는 문제인지 좀 애매하다. ㅠㅠ

[C#] Thread 종료 처리하기...

프로젝트를 수행하다보면 어떤 외부 연동 기능이나 메시지 송/수신 기능을 구현하기 위해서 Thread를 이용하게 된다. Thread 자체를 사용하는 것은 그닥 어렵지는 않다. 그러나 이를 종료해야 하는 경우는 상황이 좀 다르다. 예를 들면 메인 Thread에서 큰 파일을 업로드 또는 다운로드 하고 있고, 추가 Thread에서는 진행률을 실 시간으로 표시하는 것으로 구현을 했다고 하면... 메인 Thread에서 파일 처리가 끝나면 당연히 진행률을 표시하던 Thread를 죽여야 한다. 보통 Thread는 자기가 해야할 작업이 완료되면 정상적으로 종료가 된다. 그런데 Thread.Abort나 TerminateThread와 같은 Windows API를 이용해서 Thread를 강제 종료하게 되면 예외가 발생하거나 Thread가 사용하던 자원이 해제되지 않는 문제가 발생하게 된다. 따라서 위의 예와 같은 경우에는 메인 Thread가 작업이 완료되었을 때 진행률을 관리하는 Thread에 강제 종료가 아닌 종료 신호를 보내고 Thread 자신이 신호에 따라서 스스로 종료하도록 처리를 하면 깔끔하게 문제가 해결된다. 신호라는 것이 뭐.. 별다른 것은 아니고 단지 종료해야할지에 대한 boolean 값을 설정하는 것으로 처리하면 된다. [ Thread 처리 샘플 ] using System; using System.Threading; public class ThreadWorker { #region Fields // 다른 Thread에서도 접근할 수 있도록 volatile 설정을 한다. private volatile bool isStop = false; #endregion // Thread 작업         public void DoWork() { // 신호가 없다면 계속 반복하고, 신호가 설정되면 중지                 while (!this.isStop)                     Conso

[ODP.NET] Empty Array 처리하기... 에러 OracleParameter.Value is invalid...

현재 진행 중인 프로젝트에서 Oracle 의 팩키지를 기준으로 업무 처리를 하고 클라이언트 어플리케이션과는 Array (PLSQLAssociativeArray) 방식으로 파라미터를 연동하고 있다. 그런데 Empty Array 처리가 되어야 한다고 해서, 열심히 ODP.NET Array 연동 부분을 검토해 본 결과, 정상적인 방법으로는 처리가 되지 않고, 다른 문서들에서도 버그다, 지원되지 않는다는 말 뿐이었다. 그러나 기능은 제공되어야 하기 때문에 (제공하지 않으면 너무 많은 부분을 수정해야 하기 때문에.. ㅠㅠ) Reflection으로 오류나는 메서드의 처리 조건들을 모두 검토하여 해결은 했다. 나중에 Oracle Array + ODP.NET 을 사용하는 환경에서 재 활용할 수 있도록 정리해 놓도록 한다. 해결하게 된 근본적인 원리는 다음과 같다. -  Oracle Document 의 내용 ... ODP.NET does not support binding an empty PL/SQL Associative Array. Therefore, Size cannot be set to 0 when OracleParameter object is used to bind a PL/SQL Associate Array. ... 위의 내용을 근거로 하면 일단 Array Size는 무조건 0보다는 커야 한다. - Reflection 처리 내용을 보면 (ResetCtx 메서드) 에서 값의 검증 과정에서 Array 인 경우 null, DBNull.Value는 허용되지 않는다. 위의 내용을 근거로 하면 null 이 아닌 Array 형식으로 값이 무조건 제공되어야 한다. - Reflection 처리 내용을 보면 (ResetCtx 메서드) 에서 Array이면서 null 이거나 DBNull.Value 인 경우는 ArrayBindStatus가 존재하는지를 검증한다. 위의 내용을 근거로 하면 Empty Array 처리를 하기 위해서는 추가적인 정보로 Ar

[C#] Enum 재활용... DataSource로 사용하기.

개발을 하다보면 특정한 값들을 사전 정의해서 사용하는데 enum을 많이 활용한다. 그런데 항상 값에 대한 사전 정의 용도로 코드에서 활용하는 것에 그치는 것이 대 부분이다. 그런데 이것을 좀 더 생각해 보면 더욱 다양하게 활용할 수도 있다. 이번에는 enum을 ComboBox 의 데이터소스로 활용해 보도록 하자. 아이디어는 간단하다. Enum의 값과 표시되는 문장을 구분해서 넣어주기만 하면 된다. [ 실제 활용 코드 ] public enum RequestDept {     CallCenter = 0,     Development,     Enrollment,     Implementation,     Sales,     Support } comboBox1.DataSource = Enum.GetValues(typeof(RequestDept))                                                      .Cast<RequestDept>()                                                      .Select(i => new { Key = (int)i, Value = i.ToString() } )                                                      .ToList(); comboBox1.DisplayMember = "Value"; comboBox1.ValueMember = "Key"; 위의 코드에서 중요한 것은 Enum의 값들을 익명 개체로 만들어서 Key, Value로 구성된 List로 만들어 주면 되는 것 이다. 이미 다들 이렇게 활용하고 있겠지만, 나중에 다시 사용하기 위해서 정리해 둔다. 그 외에도 Enum 항목에 "Display", "Description" 특성들을 적용하여 다양하게 운영할 수도 있다.

[OLEDB] Excel Sheet를 DataTable 로 올릴 때 데이터 형식 문제...

비즈니스 어플리케이션을 개발하는 경우에는 대부분의 회사에서 Office 제품에서 Excel을 많이 사용하기 때문에 Excel의 데이터를 Grid 로 로드해서 보여달라고 하는 경우가 많다. Office 2010 부터는  OPENXML 기준이기 때문에 해당 Library를 활용해서 Office Interop 처리를 하는 것이 가능하지만 관련된 라이브러리를 사용하는 것도, 구성하는 것도, 다양한 처리를 하는 것도 항상 시간이 필요한 것이 때문에 대부분은 쉽게 OLEDB Provider를 이용해서 처리하게 된다. 이번 프로젝트에서도 OLEDB Provider를 이용해서 Excel의 특정 Sheet를 DataTable로 로드하고 이를 Grid에 바인딩해 주는 방식으로 기본 라이브러리를 구성하였다. 오늘 들어온 새로운 문제점은 대 부분의 Excel은 잘 처리되는데 특정 Excel 에서는 특정 Cell의 데이터가 누락된다는 것이다. 검증을 해 보니, Excel의 Column 에 숫자형과 문자형이 같이 사용된 경우로 DataTable로 로드했을 때 숫자 데이터는 살아있고, 문자 데이터는 누락되어 없는 증상이었다. 유추해 보건데, OLEDB Provider가 Excel의 데이터 형식을 검증하는 과정에서 숫자형을 기준으로 잡았다가 문자 데이터가 들어오니, 데이터 변환을 시도했을 것이고, 변환이 실패하니 DBNull 처리를 한 것 같아서 여러 가지 자료를 검색해 보았다. 검색한 결과는 OLEDB Provider에 접속 문자열 (ConnectionString)을 구성할 때 데이터 형식을 유추할 수 있도록 기준을 설정해 주면 되는 것이었다. 물론 이런 설정을 해 준다고 해서 모든 문제점이 다 해결되는 것이라고는 할 수 없지만, 오늘 발생한 문제점은 해결이 되었다. [ 실제 적용한 샘플 코드 ] public static DataTable ImportMyDataTableFromExcel(string filePath) { DataTable dt = new

[WinForm] BackgroundWorker...

프로젝트에서 어떤 파일을 복사하거나, 어떤 업무 처리를 연속적으로 처리하거나, 또는 다른 서버로 정보를 전달하여야 하는 경우와 같이 시간이 소비되는 작업에서는 사용자에게 작업의 단계별 진행을 알려주어야 하는 경우가 많다. 보통은 UI Thread에서 대 부분의 작업을 진행하므로 별다른 문제가 없지만, 작업이 길고, 다량의 작업이 된다면 Thread가 먹통(?)이 되기 때문에 ProgressBar 에 진척 사항이 보여질 수가 없다. 즉 작업을 동기적으로 처리하게되면 Wait 상태가 되기 때문이다. 이런 경우는 대상 작업을 별도의 Thread로 분리해서 운영을 하여야 한다. 즉, UI Thread 가 Busy 상태로 빠지지 않게 하는 것이다. 이런 작업을 위한 부분이 아래와 같이 BackgroundWorker를 이용하는 것이다. (물론 Thread를 생성해서 처리를 해도 된다.) 다음은 대략적인 개념을 알 수 있는 샘플이다. public partial class Form1 : Form { #region Fields private BackgroundWorker worker; #endregion #region Constructors public Form1() { InitializeComponent(); worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; // 실제 작업 메서드 연결 worker.DoWork += new DoWorkEventHandler(worker_DoWork); // 진행 상황 처리 메서드 연결 worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); // 작업 완료 처리 메서드 연결 worker.RunWor

[ADO.NET] Row Filtering... DataTable.Select() vs DataView.RowFilter

ADO.NET 의 DataTable을 사용하는 경우에 DataTable내에서 데이터를 필터링하여 재 사용하여야 하는 경우가 많이 발생하게 된다. 이 때 고민에 빠지는 것이 DataTable의 데이터가 많은 경우에 다양한 조건으로 데이터를 필터링하여야 하는데 성능이 어떤 것이 좋은지? 에 대한 것이다. 여러가지 정보를 검색하던 중에 [  여기  ]에서 구체적으로 성능 시험을 한 부분이 있어서 정리해 본다. 위의 참고 자료를 기준으로 하면 근소하나마 DataView.RowFilter를 이용하는 것이 성능 상으로 좋다는 결론을 볼 수 있다. 그러나 또 궁금한 것은 DataTable에 대해서 Index의 설정과 이를 이용하는 경우와 이용하지 않는 경우의 필터링 조건에 따라 위의 결과가 다를 수도 있지 않을까? 하는 의문이다. 이 부분에 대해서는 MSDN에서 보조적인 설명을 해 주고 있다. "The Find and FindRows methods leverage the current index without requiring the index to be rebuilt." 위의 문장을 의역해 보면 "현재의 인덱스를 이용하면 인덱스를 재 구성하지 않고 사용하기 때문에 Find 나 FindRows 메서드가 최대의 성능을 낼 수 있다" 라고 할 수 있다. 즉, Index 를 구성하지 않는 컬럼을 기준으로 필터링을 한다면 DataView.RowFilter 를 사용하는 것이 좋다는 뜻이 된다. 이유는 DataView.RowFilter는 필터링을 하면서 해당 컬럼에 대한 인덱스를 구성하기 때문이다. 따라서 단순히 한번의 필터링을 한다면 그다지 큰 차이는 없겠지만, 필터링의 기준 컬럼의 값을 여러 번에 걸쳐서 필터링을 한다면 인덱스를 구성하고 이를 사용하게 되는 DataView.RowFilter가 더 좋은 성능을 발휘하다는 것이다. 물론 이런 생각과 정리는 많은 데이터를 사용하는 경우에 성능적인 향상을 볼 수 있다