오늘은 5일차 강좌로 닷넷 어셈블리를 정리하도록 하겠습니다. ~~~
어셈블리 특성들
어셈블리의 매니페스트에는 외부 어셈블리 참조 이외에도 자신에 대한 정보가 포함 됩니다 . 이들을 assembly attribute 라고 부릅니다 .
AssemblyInfo.cs
VS.Net 에서 클래스 라이브러리 프로젝트를 만드는 경우 자동적으로 assemblyInfo.cs 파일이 생깁니다 . 이 파일은 어셈블리 버전 번호 , 이름 등등 매니페스트 안에 들어 갈 어셈블리 속성을 설정 하는데 쓰이는데 그 내용은 아래와 같습니다 .
using System.Reflection;
using System.Runtime.CompilerServices;
//
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 제어됩니다 .
// 어셈블리와 관련된 정보를 수정하려면
// 이 특성 값을 변경하십시오 .
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다 .
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 번호
//
// 모든 값을 지정하거나
// 아래와 같이 '*' 를 사용하여 수정 번호 및 빌드 번호가 자동으로 지정되도록 할 수 있습니다 .
[assembly: AssemblyVersion("1.0.*")]
//
// 어셈블리에 서명하려면 사용할 키를 지정해야 합니다 . 어셈블리 서명에 대한 자세한 내용은
// Microsoft .NET Framework 설명서를 참조하십시오 .
//
// 서명하는 데 사용할 키를 제어하려면 아래 특성을 사용합니다 .
//
// 참고 :
// (*) 키를 지정하지 않으면 어셈블리에 서명할 수 없습니다 .
// (*) KeyName 은
// 사용자 컴퓨터의 CSP( 암호화 서비스 공급자 ) 에
// 설치되어 있는 키를 참조하고 KeyFile 은 키가 포함된 파일을
// 참조합니다 .
// (*) KeyFile 과 KeyName 값을 모두 지정하면
// 다음과 같은 프로세스가 발생합니다 .
// (1) CSP 에 KeyName 이 있으면 해당 키가 사용됩니다 .
// (2) KeyName 은 없고 , KeyFile 이 있으면
// KeyFile 의 키가 CSP 에 설치되어 사용됩니다 .
// (*) sn.exe( 강력한 이름 유틸리티 ) 를 사용하면 KeyFile 을 만들 수 있습니다 .
// KeyFile 을 지정하는 경우
// KeyFile 의 위치는 %Project Directory%\obj\ 의 프로젝트 출력 디렉터리 위치를 기준으로 하는 상대 위치이어야 합니다 .
// 예를 들어 , KeyFile 이 프로젝트 디렉터리에 있는 경우
// AssemblyKeyFile 특성을
// [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 로 지정합니다 .
// (*) 서명 연기는 고급 옵션입니다 .
// 이 옵션에 대한 자세한 내용은 Microsoft .NET Framework 설명서를 참조하십시오 .
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
[assembly: AssemblyXxxx("")] 형태의 대괄호 문장이 하나의 특성입니다 . 이는 C# 의 특별한 구문으로 어셈블리의 특정 속성을 설정하는 역할을 하는 것 입니다 . 맨 앞의 assembly: 는 이것이 어셈블리 자체에 대한 특성임을 의미 하는 것 입니다 .
이 파일은 VS 에 의해 자동으로 생성되며 필요한 부분을 개발자가 채워 넣을 템플릿 역할을 하며 명령줄 (Command Line) 을 이용하는 경우라면 csc 로 컴파일하는 소스 파일안에 이 특성을 사용 할 수도 있습니다 . 특성들 중 Title, Company 같은 것들은 정보 제공을 위한 것으로 적절한 값으로 아래와 같이 채워도 무방 합니다 .
[assembly: AssemblyTitle("MyCompany Shape Class Library")]
[assembly: AssemblyDescription("Classes for Manipulation of Shapes")]
다음은 버전번호에 대해 알아 보도록 하죠~
주버전, 부버전, 빌드번호, 리비전
처음 두부분은 VS 6.0 에서 흔히 볼 수 있는 번호로 이 경우 6 이 주버전이며 0 이 부버전 입니다 . 그 다음 두 부분은 세밀한 버전 관리를 위한 것으로 빌드번호는 어셈블리를 빌드 할 때 마다 증가되는 번호 입니다 . 리비전은 더 세부적인 수준의 번호로 기능상 큰 차이는 없고 단지 몇몇 버그를 잡아서 다시 빌드 한 경우 증가 시키는 번호 입니다 . 어셈블리의 버전 특성은 ildasm 안에서 볼 수 있는데 shapes.dll 의 매니페스트를 보면 참조된 어셈블리 마다 .assembly 블록안에 .ver 지시자가 있음을 확인 할 수 있습니다 .
System.Xxxx 어셈블리나 CLS(mscorlib) 같은 외부 참조는 모두 동일하게 나타 납니다 . 만약 명령줄 컴파일러를 사용 했다면 shapes 어셈블리의 .ver 지시자가 다음처럼 모두 0 으로 나타 날 겁니다 .
.ver 0:0:0:0
이는 shapes 어셈블리에 대한 버전 번호를 지정하지 않았기 때문 입니다 . VS.Net 으로 빌드 했다면 VS.Net 에서 자동으로 번호를 붙일 것 입니다 .
AssemblyVersion 특성
VS.Net 의 경우 버전 번호는 VS.Net 이 생성한 AssemblyInfo.cs 안의 Assembly Version 특성에 의해 결정 됩니다 .
[assembly: AssemblyVersion("1.0.*")] a 여기서 별표는 부 버전 이후의 두 부분들을 VS 가 자동으로 설정 하라는 의미 입니다 . ildasm 으로 어셈블리의 버전을 보면 실제 버전 번호를 확인 할 수 있습니다 . 예를들면 다음과 같습니다 .
.ver 1:0:585:24784
이 클래스를 수정 후 다시 빌드하면
.ver 1:0:585:25005
그리고 다음처럼 명시적으로 AssemblyVersion 버전 특성에 번호를 지정 하는 것도 가능 합니다 .
[assembly: AssemblyVersion("1.0.1.2")]
버전 호환성
.Net 런타임은 어셈블리를 로딩 할 때 버전 번호를 보고 호환성을 결정 합니다 . 그럼 버전 점검이 일어나는 방식을 살펴 보기로 하겠습니다 . 버전 점검은 오직 공유 어셈블리에서 일어나는데 어셈블리의 매니페스트에는 그 어셈블리의 버전 뿐 아니라 참조된 외부 어셈블리의 버전도 들어 있습니다 . .NET 런타임이 참조된 어셈블리를 로딩 할 때는 그 어셈블리의 매니페스트에 있는 버전을 점검하고 그것을 현재 명시된 버전과 비교 합니다 . 만약 주 버전 이나 부 버전이 다르면 호환이 안되는 것으로 간주하고 어셈블리를 로드 하지 않습니다 . 예를 들어 Shapes 버전 1.1 은 Shapes 버전 1.0, 1.2, 2.0 을 참조하는 프로그램과 호환이 되지 않는 것 입니다 .
만약 같은 시스템 안에서 프로그램 A 가 Shapes 1.0 을 사용하고 프로그램 B 가 Shapes 1.1 을 시용 한다면 어떻게 될까 ? 이러한 상황은 닷넷 런타임이 처리 합니다 . Side-BY-Side 공유 기능이라는 것이 있는데 이것은 같은 컴퓨터에 Shapes1.0 과 Shapes1.1 이 모두 설치 될 수 있게 하며 또한 그 버전들을 필요로 하는 프로그램들이 각각을 모두 사용 할 수 있게 합니다 .
또한 주 , 부 버전이 같고 빌드와 리비젼 번호가 다른 경우 .NET 런타임은 일단 호환이 된다고 간주 하고 어셈블리를 로딩 합니다 . 따라서 어셈블리 작성자는 새 빌드가 이전 버전과 호환이 안된 다면 주 버전이나 부 버전을 변경해야 합니다 . Side-BY-Side 기능에 의해 주 버전과 부 버전이 같고 빌드나 리비전 번호가 다를 경우 시스템은 최근의 어셈블리를 사용 합니다 .
어셈블리의 호출 예제
VS 에서 새 프로젝트 후 C# 콘솔 응용 프로그램을 하나 만들고 프로젝트 이름을 “ShapeUser” 라고 하자 . 물론 정상적인 컴파일이 될려면 Shapes.dll 을 참조추가 해야 한다 .
// 명령줄에서는 csc /r:shapes.dll shapeuser.cs 라고 컴파일 하면 된다 .namespace shapeuser{using System;using Shapes;public class ShapeUser{public static void Main (){Circle c = new Circle(1.0F);Console.WriteLine("Area of Circle(1.0) is {0}", c.Area());}}
}
|
ShapeUser.exe 를 ildasm 으로 보면 다음과 같다 .
MANIFEST 는 다음과 같다 .
전용 및 공유 어셈블리
지금까지는 전용 어셈블리 즉 하나의 단일한 응용 프로그램의 일부로서 배포되는 어셈블리에 대해 이야기를 했습니다 . 이러한 어셈블리 이외에 닷넷은 여러 응용 프로그램들이 하나의 어셈블리를 동시에 공유하는 기능을 제공 합니다 .
• 전용 어셈블리
기본적으로 어셈블리는 해당 프로젝트 전용으로 쓰입니다 . 전용 어셈블리는 반드시 해당 응용 프로그램과 동일한 디렉토리에 있어야 합니다 . Shapes.dll 역시 전용 입니다 . 이 어셈블리를 ShapeUSer 에서 참조하려면 두 프로젝트를 동일한 디렉토리에서 빌드 하거나 ShapeUSer 에서 명시적으로 프로젝트 참조를 추가해야 합니다 . 프로젝트 참조를 한 경우 VS 는 shapes.dll 의 복사본을 만들어 ShapeUser 디렉토리에 넣습니다 . Shapes.dll 이 복사되므로 원래의 shapes.dll 이 사라져도 문제되지 않습니다 . 그러나 많은 프로그램에서 참조되는 어셈블리의 경우 DLL 을 매번 복사하는 것은 비 효율적 입니다 . 이를 해결한 것이 공유 어셈블리 입니다
• 공유 어셈블리
공유 어셈블리는 시스템 안의 모든 프로그램들이 공유 하는 어셈블리 입니다 . 모든 공유 어셈블리는 전역 어셈블리 캐쉬 (Global Assembly Cache, GAC) 라는 특별한 .NET 시스템 디렉토리에 저장 되므로 프로그램들은 공유 어셈블리의 위치를 알 필요가 없습니다 . 공유 어셈블리들은 시스템 전반에서 사용되므로 .NET 런타임은 공유 어셈블리에 대한 보안이나 버전 호환성 면에서 좀 더 많은 점검을 수행 합니다 .
공유 어셈블리 작성
강력한 이름 (Strong Name) 을 가진 공유 어셈블리를 만들려면 어셈블리의 서명에 사용할 공개 / 비공개키 쌍을 만들어야 합니다 . 공개 / 비공개키 암호화 시스템은 암호화된 메시지를 보내는 사람만 알고 있는 비공개 키와 누구에게나 알려지는 공개키를 사용 합니다 . .NET 환경은 이러한 동일한 메커니즘을 이용해서 참조된 공유 어셈블리가 실제 그 어셈블리인지 점검을 하는 것 입니다 . 어셈블리 이름 , 버전 , 공개키 조합은 반드시 고유 하며 이러한조합을 강력한 이름 이라고 부릅니다 .
.NET Framework 은 이러한 강력한 이름을 만들어 내는 sn.exe(Strong Name) 라는 도구를 제공 하는데 이 도구는 명령 프롬프트에서만 사용 가능 합니다 . sn 의 사용법은 다음과 같습니다 .
sn ?k shapes.snk a 이렇게 하면 현재 폴더에 shapes.snk 라는 키 파일이 생 깁니다 . 이 키로 어셈블리를 서명 하려면 프로젝트의 AssemblyInfo.cs 안의 끝 부분에 있는 AssemblyKeyFile 특성을 수정해야 합니다 .
[assembly: AssemblyKeyFile("shapes.snk")]
아래 그림처럼 수정 해야 합니다 .
VS 에서 키 파일의 위치는 기본적으로 프로젝트 디렉토리의 obj\debug 이며 만약 키 파일을 다른 곳에 두었다면 상대 경로를 적절히 이용하면 됩니다 .
프로젝트를 정상적으로 빌드 하면 어셈블리에 서명이 추가 됩니다 . 다시 ildasm 으로 shapes.dll 의 MANIFEST 를 보면 서명이 추가되어 있는 것을 알 수 있습니다 .
이 시점에서 ShapeUser.exe 를 다시 컴파일 하지 않고 실행한다면 “ 어셈블리 참조가 일치 하지 않는다는 오류가 발생 합니다 .” 이 경우 다시 컴파일 하게 되면 ShapeUser 에서는 서명된 버전의 Shpaes.dll 을 참조하게 됩니다 . 아직까지 shapes.dll 은 공유 어셈블리가 된 것은 아닙니다 . 진정한 공유 어셈블리가 될려면 GAC 에 넣어야 합니다 . shapes.dll 을 GAC 폴더에 끌어 놓으면 됩니다 .
( 명령 프롬프트에서는 등록시 gacutil /I shapes.dll, 삭제시 gacutil /u shapes)
실제로 shapes.dll 이 캐시에 추가 되었는지를 확인 하기 위해 shapeuser.exe 가 있는 곳에 shapes.dll 을 삭제 후 shapeuser.exe 를 실행 해 보자 .
( 명령 프롬프트에서 ) gacutil /u shapes 라고 입력한 후 (shapes.dll 을 해제 후 ) 다시 실행을 하면 실행이 되지 않을 것이다 .
이상 전용 어셈블리 및 공용 어셈블리까지 살펴 보았다. 이해가 안된다면 천천히 실습을 따라해 보시고 반복해야 합니다.
수고 하셨습니다.
질문은 Forum에 올려 주세요~
댓글 없음:
댓글 쓰기