공통 메시지 관리에 대하여..
여러분은 공통 메시지 관리를 어떻게 하시나요?
그러니깐,예를 들자면.. 모든 aspx 페이지에 공통적으로 사용할 메시지같은 것들을 어떻게 관리하냐는 질문이랍니다.
"그런 것 없는데..."
라고 너무 빨리 대답하지 마세요. -_-++
잘 생각해보면 있으실 겁니다. 그러니깐, 예를 들면, "잠시만 기다려 주십시요"나 "에러가발생하였습니다. 자세한 에러는 에러로그를 확인하십시요" 라던가 "*** 님. 어서오십시요"와 같은 메시지들 있지 않습니까?혹은 다중언어를 지원해야 하는 사이트 같은 경우는 그러한 메시지들의 영어 버전, 중국어 버전등등 각 언어별메시지를 별도로 저장해두고 사용해야 할 경우도 있겠죠? 그런 경우는 어떻게들 하고 계시나요?
"우린 한국어만 하는데.... 다중언어는 필요없어요..."
라고 짧게 거부하지 말아주세요. ㅠㅠ 제가 아무리 오랜만에강좌 올린다고 해도 그렇지.. 이런 식으로 야박하게 나오시면 저.. 매우 쌔드해집니다. ㅜㅜ
물론, 적은 개발시간과 과도한 업무로 인해 이러한 부분을 신경조차 쓸 수 없는 환경에 있으신 분들도 있으시겠지만, 그 일은그렇다쳐도.. 분명 개인적으로 한, 두번씩은 이러한 유사한 고민은 해보셨을 거라 생각합니다. 공통적으로 여러 어플리케이션에서공유해서 사용해야 할 메시지가 있다거나, 혹은 사이트를 영어 버전과 한국어 버전 등 2가지 이상의언어버전으로 만들어야 할 경우 특히나 이러한 공통적인 메시지의 관리방법은 중요한 문제로 다가오거든요...
제일 쉬운 방법은 직접 소스에다가 그러한 메시지를 하드코딩하는 방법이겠죠? 아마 많은 분들이 이 방법을 사용하실 것입니다만, 이 방법의 단점은 차후에 메시지를 바꿔야 할 경우, 소스에서그러한 메시지들을 일일히 찾아서 고쳐야 하고, 심지어는 컴파일 및 빌드를 다시 해야할 수도 있기에 사실 관리성 측면에서 가장 떨어지는 방법이라 할 수 있습니다.(이렇게 말하는 저도 실은 하드코딩을 주로~ 사용했었다는 -_-+)
하지만, 다소 규모있는 사이트나 경험이 많은 개발자들은 그러한 공통 메시지들을 데이터베이스나 텍스트 파일(XML 등)에저장해두고 어플리케이션에서는 그 메시지를 동적으로 읽어와서 사용하기도 하셨을 것입니다. 성능을 위해서 그러한 데이터를웹 어플리케이션 구동시에 Cache와 같은 곳에 넣어두고 사용하실 수도 있겠죠? 그렇죠?
그런데, 갑자기 이러한 이야기는 왜 하냐구요?
강좌 제목을 보시면 이미 아시겠지만, 바로 그러한 부분을 보다 쉽고, 유지보수성 높게 관리할 수 있는 .NET적인 방식을알려드리려고 이러한 이야기들을 꺼낸 것이랍니다. ^^
일단, 공통 메시지들은 데이터베이스로 관리가 되는 것이 좋습니다. 물론, XML 파일로 관리되는 것도 좋죠. 혹은 메시지들을 데이터베이스에 넣어두고 정기적으로그 데이터들을 XML로 동적 생성해서, 실제 어플리케이션에서는 XML을 이용하도록 구성하는 것도 좋습니다. 아무래도성능을 생각하면 데이터베이스를 직접 접근하는 것보다는... 일종의 파일캐쉬(Cache)로서 XML 파일을 구성하여 이를 사용하는 것이 바람직할테니까요. ^^
이러한 이유로 .NET에서는 그러한 리소스 데이터(문자열 등)를 쉽게 관리할 수 있도록 .resx 라는 파일 형식을지원하구요. resx 파일의 데이터를 쉽게 이용할 수 있게 해 주는 ResourceManager 라는 클래스도 제공합니다. resx 형식의 리소스 파일은겉으로 보기에는 이진 파일처럼 보이지만 실제 내부적으로는 데이터를 XML 구성으로 관리하는 일종의 XML 파일입니다. ^^
그리고, 이 resx 형식을 이용할 경우에는 다중 언어지원이 필요할 경우에도 매우 쉽게 그 지원기능을 어플리케이션에 추가및 확장할 수 있다는 큰 장점도 있습니다. 해서, 대부분의 엔터프라이즈급(기업급)의 어플리케이션에서는 resx로공통 자원들을 관리하는 것이 보편적이죠. 그렇지 않나요??
여러분 중 몇몇 분들은 이미 이렇게 관리하고 계시는 분들도 있을텐데요^^; 그 분들은 복습차원에서 한번 다시 살펴보시는 것도 좋다고 생각하구요. 아직 모르셨던 분들이 있다면 이 강좌를 읽고서 현재 개발중인 어플리케이션에 한번 적용해 보시라고 권해드리고 싶네요.
이렇게 공통 메시지를 리소스 파일을 통해서 관리하고, 이를 확장하여 다국어를 지원하는 방식은 매우 효과적이라는 평을 이미 대,내외적으로 얻었기에, .NET 2.0(ASP.NET 2.0 포함)부터는 아예 이를 보다 쉽게 사용할 수 있도록, 웹폼에서 직접적으로 리소스 형식을 쉽게 접근할 수 있는 방법도 제공하게 됩니다. 고로, ASP.NET 2.0이등장하면, 이러한 기능을 아마도 New Features(새로운 기능)!!이라는 제목으로 보시게 될 가능성이 높답니다. 사실 오늘 제가 다 설명 드릴 것이기에.. 알고보면 완전히 새로운 기능도 아닌데 말입니다. ^^;;
어쨌든, 기왕이면 .NET 2.0 발표 전에 리소스 관리 기법을 미리 알아두면 여러모로 우리에게 이로웁겠죠?그래야 뭔가 좀 차별된 개발자의 느낌이 들지 않겠습니까? 그러면서 서서히 중급 개발자라고 자부할 수도있게 되는 것이구요 ^^ 그렇죠?? 그러면 달려봅시다~~인생 뭐 있습니까? 달릴 땐 그냥 사정없이 달리는 겁니다.. 기왕 달리는 거. 이 강좌 이대로 끝까지 한번에끝내버립시다. 집에 가서 마저 봐야지~ 이따가 담배 피구와서 봐야지~ 이런거는 배반입니다!!! 달릴때 걍 달리는 겁니다.
핫!! 갑자기 그 분이 오셨네여.... -_-;;; 저...... 잠시 화장실을 좀.... -_-
(10분 경과...)
그러니까 말입니다.....!! 달리는 겁니다!!!! 음... 설득력이 많이 떨어지는 느낌이 드는군요...
자. 그러면 이제 본격적으로 시작해 보겠습니다. 우선 여러분은 새로운 웹 어플리케이션을 하나 VS.NET(C#)을 이용해서 만들도록 하세요. ^^;; 전 프로젝트이름을 SampleProject라고 주어보았습니다. (사실, 웹 어플리케이션이던 윈도우 어플리케이션이던 동일하게 적용할 수 있습니다만.. 우리는 웹 어플리케이션으로 해보겠습니다)
그리고... 그 프로젝트에 다음과 같이 리소스들만을 모아놓을 새 폴더를 하나 추가하시구요.(저는 폴더 이름을 Resources 라고 해 주었습니다)

그 폴더에 다음과 같이 '어셈블리 리소스 파일' 형식의 resx 파일을 추가해 보세요. 파일의 이름은 저의 경우 AppResources.resx 라고 주었습니다.

resx 파일이 추가되면, 다음 그림과 같이 VS.NET 디자이너에 표 모양으로 데이터를 넣을 수 있는 편집도구가 나타날 것입니다.

이제 여기에다가 필요한 메시지들을 기록하시면 됩니다. 저는 다음과 같이 기록해 보았습니다.

이것은 예를 들기 위한 강좌니깐, 메시지들이 단순합니다만, 실제 업무에 사용되는 메시지들은 좀 더 격식있고, 업무적인 메시지가 될 것입니다. ^^
자. 현재 상태에서 디자이너 좌측 하단을 보시면 XML 편집기로 바꾸어서 볼 수 있는 버튼이 있죠? 위의 그림에서 좌측 하단에 보이는 것처럼 말입니다. 찾으셨으면 그것을 한번 클릭해 보시겠어요?
그러면 다음과 같이 XML 파일이 나타나게 될 것입니다. 디자이너에서 바둑판 구조의 편집기가 나타났던 것은 VS.NET이 제공해주는 도구였을 뿐이었구요. 사실 Resx 파일은 이렇게 XML 구조로 구성되어져 있습니다. XML 파일을 열어보면 상단에는 스키마가 주욱 나오는 것을 볼 수 있구요. 우리가 편집기에다가 기록한 메시지 데이터는 XML 하단에 나오고 있는 것을 보실 수 있습니다. 다음 그림처럼 말이죠 ^^
그렇습니다. 사실은 이렇게 XML 데이터로서 메시지들이 관리되고 있었던 것이죠 ^^
일단, 공통 메시지들을 취합해서 정리하는 것은 이제 완료했다고 가정을 해 보겠습니다. 근데요. 참고로 힌트를 하나 드리자면 말입니다. 이렇게 공통 데이터로 관리할 수 있는 것이 달랑 문자열 메시지만 있는 것은 아니랍니다. 이미지(Image)의 경우도 이처럼 리소스 파일로 관리할 수가 있어요. ^^ 이 부분은 나중에 시간이 날 때 이야기해 보도록 하구요. 우리는 계속 진도를 나가보도록 하겠습니다.
자. 이제 공통 메시지들은 준비가 되었네요. 그렇다면, 이 메시지를 우리의 ASPX 페이지에서는 어떻게 불러올 수 있을까요? 이제 그것을 이야기해 볼까요? 그렇다면, 프로젝트에 웹 폼을 하나 추가해 주세요. 만일, 기본적으로 WebForm1.aspx 파일이 이미 존재하고 있다면 그 친구를 이용해도 무관하겠습니다. ^^
폼을 준비하셨다면 다음과 같이 레이블 하나와 버튼 하나를 각각 올려주세요 ^^

뭐.. 예제이다보니, 구동하는 방식만을 알아보면 될 것 같아서... 폼은 이렇게 단순하게 구성했습니다. 이미 어떻게 하려는 것인지 눈치채셨겠지만, 페이지가 로드될 때, 리소스 파일로부터 웰컴 메시지와 클릭 메시지를 가져와서, 각각 레이블과 버튼에 출력하려는 것이랍니다.
자. 여기까지 준비가 되셨으면... 이제 소스마저 채우고 이야기를 계속 나누도록 하겠습니다. 코드 비하인드 페이지에서 Page_Load 이벤트에 다음과 같은 코드를 기입해 주세요 ^^
private void Page_Load(object sender, System.EventArgs e) { string fullName = "SampleProject.Resources.AppResources";
System.Reflection.Assembly Assem = System.Reflection.Assembly.GetExecutingAssembly(); ResourceManager appResourceMgr = new ResourceManager(fullName, Assem);
Button1.Text = appResourceMgr.GetString("Msg.Click"); Label1.Text = appResourceMgr.GetString("Msg.Welcome"); } |
그리고, 페이지를 실행해 봅니다. ^^;; 예상하셨듯이, 멋드러지게 리소스 파일로부터 메시지를 읽어와서 그것을 출력하게 될 것입니다. 하하하!

자. 그럼 이제 코드를 살펴볼까요?
실제 Resx 파일로부터 데이터를 가져오기 위해서 필요한 핵심 클래스는 바로 ResourceManager 입니다. 이 친구가 특정 resx 파일로부터 우리가 원하는 데이터를 뽑아올 수 있도록 도와주는 클래스이거든요. 이 클래스의 더욱 구체적인 설명은 MSDN에서 한번 찾아보시길 권해드립니다.
일단, ResourceManager 클래스는요. 사용법이 간단합니다. 클래스의 인스턴스를 만들면서 생성자에 2가지의 매개변수를 지정해 주시면 되거든요. 즉, 우리가 사용하려는 리소스 파일의 논리적인 이름(전체 이름)을 첫번째 인자로 그리고, 사용하려는 리소스 파일이 들어있는 어셈블리를 두번째 인자로 지정해 주시면 되는 것입니다.
그렇다면, 우리가 사용하려는 리소스 파일의 논리적인 이름 즉, 루트 이름은 어떻게 알 수 있을까요? 이 이름은 네임스페이스를 포함한 리소스의 명칭을 말하는 것이잖습니까? 그렇기에, 일단 그 명칭의 시작은 프로젝트의 네임스페이스인 SampleProject. 으로 시작하겠죠? 그리고, 현재 Resources 라는 폴더안에 들어있으므로, 완전한 명칭은 SampleProject.Resources.AppResources이 될 것입니다.
물론, 이것은 C#인 경우 그런 것이구요. VB.NET으로 프로젝트를 만드셨다면 이야기가 약간 달라집니다. 왜냐하면, C#은 기본적으로 컴파일 시에, 폴더가 있으면 그 폴더 이름을 네임스페이스에 추가해서 달고 가는 반면, VB.NET은 그 폴더명을 무시하거든요. 즉, 현재의 경우 C# 프로젝트이고, 우리가 사용하려는 리소스 파일이 Resources 폴더 안에 있으니,
SampleProject.Resources.AppResources
가 완전한 리소스 파일의 논리적인 이름이 되겠지만, VB.NET의 경우는 폴더명을 무시하기에
SampleProject.AppResources
가 된다는 것입니다. ^^;; (맨 뒤에 .resx가 없는 것에 주의하세요 ^^)
사실, 이 부분(논리적인 이름경로)은 VS.NET을 설치하면 같이 설치되는 유틸리티인 ILDASM.exe으로 확인해보면 더 확실한데요. 예를 들면, 다음 그림이 바로 ILDASM을 이용해서 현재 프로젝트의 컴파일된 DLL을 까(?) 본 것이거든요.

그 중 MENIFEST 부분을 더블클릭해서, 살펴보면 관련 자원들의 목록이 주루룩 나열되어져 있는 것을 보실 수 있을 거예요. 그 중에 보면 낯익은 얼굴이 보이죠??? 그렇습니다. 이를 사용해주시면 되는 거예요 ^^

참고 : ILDASM에서 위의 그림과는 달리 리소스 경로가 안나옵니다!! 그럴 수 있슴다. 만일, 속성 창에서 AppResources.resx 파일의 [빌드작업]의 값을 바꾸셨다면 말이죠.리소스 파일은 그 자체가 DLL안에 포함되어야 하기 때문에, 반드시 다음 그림처럼 [빌드작업]의 값이"포함 리소스"여야 합니다. 이것을 꼭 확인해 보세요 ^^ 
|
근데, 왜 그림에서는 경로의 마지막에 .resources 라는 것이 붙어있냐고 물어보시려 하시는구려~
그것은 이것이 리소스 파일이기 때문에 붙여지는 것이랍니다. 원래 우리눈에 보기에 .resx 였던 것의 본명이 제대로 붙여진 것이지요 ^^;; 하지만, ResourceManager 클래스를 이용해서 리소스 파일을 로드하는 경우에는 전체 경로에서 .resources 라는 부분은 무시하셔도 됩니다. 왜냐하면, ResourceManager 를 이용하면 이 친구는 알아서 .resources로 끝나는 리소스들을 찾게 되니까요 ^^
자. 장황하긴 했지만 특정 리소스 파일의 논리적인 루트경로를 어떻게 알아낼 수 있는지 이야기를 해 보았습니다. 이제 다시 원래의 소스코드로 돌아가서 이야기를 계속해 보겠습니다. 우리의 소스 코드의 두번째 라인은 다음과 같았습니다.
System.Reflection.Assembly Assem = System.Reflection.Assembly.GetExecutingAssembly();
이 코드는 무엇을 의미하는 것일까요? 이는 .NET 리플렉션이라는 기법을 이용하고 있는 것인데요. 이 코드의 의미는 바로 현재 구동중인 어셈블리 자체를 얻어오는 것입니다. 우리가 사용하고자 하는 리소스 파일이 현재 실행되고 있는 어셈블리에 들어있으므로, 이를 .NET 리플렉션을 이용해서 얻어오는 것이죠. 말은 어려울지 모르지만 코드는 매우 간단합니다.
즉, System.Reflection.Assembly.GetExecutingAssembly() 라는 코드를 이용하시면 현재 실행중이 DLL이나 EXE 어셈블리 자체를 얻어올 수가 있게 됩니다. 왜 이 어셈블리를 얻어오냐구요? 음.... 앞에서 집중을 조금 덜 하셨었군여!!!
ResourceManager 클래스의 생성자가 요구하는 두번째 인자라 뭐라고 했었죠? 바로 사용하려는 리소스 파일이 들어있는 어셈블리라고 했었죠? 그렇습니다. 그렇기 때문에 이렇게 어셈블리를 얻어오는 것입니다. ^^
참고 : 리플렉션이란? MSDN을 참고해 보면 말입니다. MSDN에서는 리플렉션을 다음과 같이 설명하고 있습니다. 리플렉션을 사용하여 형식의 인스턴스를 동적으로 만들거나, 형식을 기존 개체에 바인딩하거나, 기존 개체에서 형식을 가져올 수 있습니다. 그리고 나서 형식의 메서드를 호출하거나 형식의 필드 및 속성에 액세스할 수 있습니다. 리플렉션의 일반적인 용도는 다음과 같습니다. Assembly를 사용하여 어셈블리를 정의 및 로드하고, 어셈블리 매니페스트에 나열된 모듈을 로드하며, 이 어셈블리에서 형식을 찾아 형식의 인스턴스를 만듭니다. MethodInfo를 사용하여 메서드의 이름, 반환 형식, 매개 변수, public 또는 private 같은 액세스 한정자, 추상 또는 가상 같은 구현 정보를 검색합니다. Type의 GetMethods 또는 GetMethod 메서드를 사용하여 특정 메서드를 호출합니다. FieldInfo를 사용하여 필드의 이름, 액세스 한정자, public 또는 private 같은 액세스 한정자, static 같은 구현 정보를 검색하고, 필드 값을 가져오거나 설정합니다. .... (이후 생략) |
* 위의 글은 MSDN(VS.NET 한글 도움말)에서 인용한 것임을 밝힙니다. |
이제, 필요한 두가지 인자가 모두 준비되었으니 ResourceManager 클래스의 인스턴스를 생성해 보겠습니다. 코드의 3번째 라인이 바로 그 작업을 하고 있죠?
ResourceManager appResourceMgr = new ResourceManager(fullName, Assem);
그렇습니다. 이것으로 모든 준비는 끝난 것입니다. 이제 appResourceMgr 라는 변수명을 이용해서 맘껏 리소스 파일안의 데이터들을 불러올 수가 있게 된 것입니다.
데이터를 불러오기 위해서는 꼴랑~ GetString라는 메서드를 사용해 주시면 됩니다. ^^ 이미지나 이진 데이터를 불러오기 위해서 GetObject라는 메서드도 이용할 수 있긴 합니다만, 현업에서는 주로 문자열 메시지들을 담게 될 것이기에... GetString 만을 기억하고 계셔도 무난합니다 ^^.. 예를 들면, 다음 코드처럼 말이죠
Button1.Text = appResourceMgr.GetString("Msg.Click");
GetString 메서드의 인자로는 불러오고자 하는 메시지의 키 값을 적어주시면 됩니다. 그러면 그에 해당하는 값을 뽑아낼 수 있는 것이죠 ^^;; 쉽지 않습니까?
뭔가 초기 세팅이 복잡해 보일 수도 있는데요. 한번 해보고 나면 한개두 안 복잡합니다.
그리고, 컴포넌트 개발에 익숙하신 분이라면 위의 코드 중 공통적인 부분을 따로 빼서... 별도의 헬퍼 클래스를 만들어서 ResourceManager를 좀 더 사용하기 쉽게 만드실 수도 있겠네요 ^^
그런데!!!!!!
여기까지 따라하신 분들 중, 혹은 여기까지 따라하지는 않고 눈팅만 하신 분들 중에... 이렇게 생각하시는 분들 꼭 있다!!! 베스트 3!!!
1. 근데, 왜 이렇게 복잡하게 해야 해? 오히려 더 복잡한거 같아.. 그냥 디비 쓰자
2. 메시지를 관리하긴 뭘.... 그냥 코드에 박아!!!
3. 닷넷은 피곤해....
하시는 분들 있죠?
하아... 역시나 이정도만으로는 감동하지 못하시는 것일까요? 단 코드 3,4 줄을 사용하는 것으로... XML 기반의 리소스 파일로부터 문자열 데이터들을 맘껏 가져다 쓸 수가 있는데도... 전혀 감동적이지 않으신 것이군요...
그렇다면 어쩔 수 없네요.... 이제 진짜 감동적인 것을 보여드릴 수 밖에 없네요
감동적인 것??? 그게 뭐냐구요? 그것은 바로 리소스 파일을 이용해서 다국어를 지원하는 것입니다. 다국어 지원을 해 보신 분이 있다면 상당히 고민해야 할 것도 많고, 피곤했던 기억들이 한번씩은 있을 것입니다. 그쵸그쵸???
하지만, Resx 를 이용하면 이 마저도 매우 편리해 집니다. 그렇다면, 그 환상적인 모습을 한번 같이 볼까요? 어때요? 막 궁금해 지시나요???
히힛.. 그 감동적인 내용은 다음 강좌에서 이어집니다~~ (담주에 뵈어요)
참고 : ASP.NET 2.0에서는 리소스 파일을 다루기가 더욱 편해집니다. 다음은 ASP.NET 2.0에서 리소스 파일을 사용하는 코드 샘플인데요. 이렇게 간단해 집니다. private void Page_Load(object sender, System.EventArgs e) { LinkButton1.Text = Resources.리소스파일명.키값; //예 : LinkButton1.Text = Resources.AppResources.MyMessage; } 어떠세요? 매우 간단해지죠? 위의 코드는 코드 단에서 사용하는 방법이라면, UI단에서 바인딩 표현식으로 사용하는 방식은 다음과 같습니다. 
쉽죠? |
OK!!! 여기까지~~~