때는 바야흐로 2009년 7월이네요. Velocity 를 공부하면서 메모해 놓은 것을 이제서야 발견하여 포스팅을 하고 있습니다. ^^;

현재는 Windows Server AppFabric 이라는 이름으로 공개가 되고 있으며, 코드명은 바로 "Velocity" 라는 이름입니다. 현재 AppFabric Beta 1 까지 출시되었고 이제는 거의 모습을 찾아가고 있는 것 같습니다. 차후에 Velocity 의 현재 제품이름인 AppFabric 을 자세히 살펴보기로 하며, Velocity CTP 3 기준으로 설치와 사용 방법을 간단히 알아보고자 합니다.

   

Why Windows Server AppFabric (Codename "Velocity") ?

Velocity 는 분산 캐싱 프레임워크입니다. 우선 분산 캐싱이 왜 필요한지 이해가 필요합니다. 기존에는 캐싱이라고 함은 in-proc 캐싱을 의미했으며 즉 메모리 상에서 객체를 캐싱(Caching)하거나 풀링(Pooling)하기 위해 시스템의 리소스(Resource) 를 사용했습니다.

하지만 점차 엔터프라이즈 솔루션은 대규모, 대용량화 되어감에 따라 in-proc 캐싱은 시스템 리소스나 성능에 영향을 받게 되었습니다. 기존의 엔터프라이즈 솔루션은 데이터베이스의 대용량 아키텍처에 민감했고, 즉 데이터 중심의 아키텍처링을 할 수 밖에 없었습니다. 데이터의 정합성, 안정성, 성능은 기업에서 돈(Money) 와 직결되는 문제이기 때문이죠.

하지만 이미 데이터와 관련된 기술과 노하우는 이미 포화 상태이고, 엔터프라이즈 전체적인 아키텍처를 보았을때 단지 병목은 데이터에서만 존재하는 것이 아니었다는 것입니다. Middleware 나 Application Server 의 아키텍처링도 이미 포화 상태이고, 이것을 극복하기 위해서는 바로 캐싱(Caching) 이라는 기술이 필요했습니다.

위에서도 언급하였듯이 in-proc 캐싱은 굉장히 단순한 아키텍처입니다. 서버의 리소스가 받쳐 주느냐 그렇지 않느냐의 문제였고 in-proc 그리고 더 나아가 out-proc 를 이용하여 서버 자원을 최대한 활용하고자 합니다. 하지만 여기에서 또 문제가 발생합니다. 분산 out-proc 캐싱을 하자니 분산된 캐싱 데이터의 정합성을 어떻게 보장하느냐 입니다. 즉, out-proc 로 인해 캐싱은 중앙 집중화가 될 수 밖에 없으며 이것은 서버의 리소스에 의존하는 문제의 원점으로 돌아간다는 것이죠.

   

About Windows Server AppFabric (Codename "Velocity")

이러한 엔터프라이즈 환경의 서비스 확장에 대해서 고질적인 문제였던, 그리고 성능을 극대화 할 수 있는 캐싱이라는 기술을 어떻게 활용하느냐에 관심을 갖게 되었습니다. 현재 이런 문제를 해결할 수 있는 솔루션이 Windows Server AppFabric(Codename "Velocity") 입니다.

데이터의 정합성, 안정성, 성능은 기존의 아키텍처를 버리고 전용 Repository 를 통해 해결할 수 있습니다. 그것은 데이터베이스가 될 수 있고, 그 밖에 다른 Repository 가 될 수 도 있겠죠. 바로 이러한 컨셉은 캐싱을 어떤 분산 시스템간이라도 공유한다는 의미입니다. 이러한 캐싱을 클러스터링한다는 것은 흔히 Caching Dependency 를 해결할 수 있는 아주 좋은 해결 방법이기도 합니다. 어떤 로컬 시스템이건, 어떤 원격 시스템이건 캐싱 정책을 적용받게 되는 것입니다.

   

   

   

Install Windows Server AppFabric (Codename "Velocity")

아래는 필자는 게으름으로 Velocity CTP 3 기준으로 설치하는 방법입니다. (지금이라도 포스팅 하는걸 보면 대견스럽습니다만;;;)

기본적으로 캐싱 데이터는 데이터베이스를 사용합니다. 데이터베이스의 파일이 저장이 될 경로를 입력하거나 Storage 타입을 정하시면 됩니다.

 

   

 

이번에는 두번째로 프로젝트를 만들거나 새롭게 cs 또는 vb 파일을 추가할 도움이 되는 것입니다.

 

바로 프로젝트를 생성할 나타나는 화면입니다.

 

 

여기서 우리는 그냥 해당하는 프로젝트를 선택합니다. 그리고 프로젝트 만들기를 하는데 VS 2008에서는 .NET 플랫폼의 선택 기능이 있었습니다. VS 2010에서는 다른 보다 우선 설치된 템플릿과 기존에 만들었던 템플릿들 온라인 템플릿으로 나우어 집니다. 첫번째인 Recent Templates 최근에 만들었던 것으로 여러분들이 기존에 만들었던 템플릿을 불러옵니다.


 

이렇게 기존에 만들었던 템플릿을 가져와서 템플릿을 이용하여 다시 만들수가 있습니다. 다음은 설치된 템플릿입니다.

설치된 템플릿은 여러분들 설치한 VS 2010 언어에 맞추어 템플릿이 표시됩니다.

 

 

 

바로 이렇게 표시가 되죠.^^ 그렇다면.. 바로 위에 있는 Enable loading of per user extensions 틀릭하면 도구상자의 옵션 대화상자를 열고 안에 있는 Extension Manager 메뉴를 호출합니다. 여기서 "Automatically check.." 하면 자동으로 자기가 템플릿 관련 확장을 체크하여 업데이트를 합니다.

 

 

 

다음이 온라인 템플릿입니다. 템플릿은 온라인상에서 템플릿을 불러오는데 바로 사용자를 추가로 새롭게 템플릿을 만든 것을 지원하는 것입니다. 바로 사이트에 있는 내용을 가져오는 것입니다.

 

http://visualstudiogallery.msdn.microsoft.com/en-us

 

 

화면은 이렇게 나오는데 왼쪽 템플릿 메뉴에 여러 목록이 있는데 목록에 해당하는 것을 선택하면 선택한 것만 표시됩니다.

  

 

 물론 기존의 VS 2008 있는 .NET 선택할 있게 되어있는 것은 그대로입니다. 하나 추간된 것은 왼쪽의 Sort by라고 하는 부분이 추가되어 정렬도 있습니다. Sort by VS 2008에서는 없는 것입니다.

 

 

.NET 선택 시에는 2.0 버전부터 선택할 있으며(이건 당근이죠 ^^) 그외 .NET 버전도 선택할 있습니다.

 

 

여기 More Frameworks 부분입니다. 그러면 닷넷 프레임 워크 홈페이지로 이동을 합니다. 주소는

http://msdn.microsoft.com/en-us/netframework 이쪽으로 이동을 하여 추가적인 닷넷 프레임워크를 지원합니다. 사이트에는 지금까지의 닷넷을 다운로드 받을 있도록 하고 있습니다.(예를 들어 SharePoint 2010 개발하기 위하여는 최소한 .NET Framework 3.5 이상을 선택해야 합니다.)

 

이제 이번 글의 하이라트라고 있을까요? Search 입니다.

 

부분은 IE 에서 많이 보셨거나 Windows Desktop Search 사용해 보신 분은 이거~ 하실 겁니다.

바로 VS 프로젝트 템플릿을 찾아주는 역활을 합니다. 제가 여기서 C 라고 입력하면 C 관련된 템플릿이 표시됩니다.


 

cs 하면 C#관련 내용일 것입니다. 이것이 중요한 것은 중간에 파일을 추가할 class 파일을 추가 할때 어떨가요? 해당 프로젝트에서 클래스 하나 추가할 때에도 도움이 됩니다.(사실 중간에 강의 하거나 갑자기 class 파일 하나 만들때 가끔 어디 있는지 못찾을 때가 .)

 

 

바로 생각외로 도움이 것입니다.(사실 정말 도움이 됩니다 ㅋㅋㅋ)

 

오늘은 VS 에서 새롭게 프로젝트를 생성하거나 중간에 프로젝트를 추가 또는 class 이나 cs 또는 aspx파일을 같은 것을 추가하는 대화 상자를 봤습니다. 사실 여기서 집고 넘아가는 것은 개발자에게 파일을 찾기, 또는 추가 할때 위치가 어디 있는지 갑자기 당황 스럽거나 또는 기존에 만들었던 템플릿을 다시 만들고자 할때 쉽고 빠르게 만들 있도록 도와 준다는 것입니다.

 

한가지 확실히 도움을 받습니다. 프로젝트 파일을 추가할 경우 저는 C# , C++, Modeling 같이 있으며 Web Services파일등이 있을 추가하려고 하는 파일을 쉽게 찾아서 추가 한다는 것입니다. 정말 편리합니다. 이것을 조금 유식하게(?) 하면 바로 생산성 향상 측면으로 볼수 있을 겁니다.

 

그럼 다음 번에는 실제 코딩과 관련 있는 부분을 보겠습니다.


 

안녕하세요.^^ 오늘은 IDE 4번째 시간으로 C# 개발자분들은 위한 IDE 소개하곘습니다.

이미 PDC 09 사이트에서 IDE관련한 동영상이 있고 C#, VB.NET 있습니다. 오늘은 C#&VB.NET 으로 개발하시는 분들을 위한 설명을 할까 합니다. 그럼 다음은?? ㅎㅎ VB.NET 입니다. 그리고 다음은 .. Web, C++ Project Management 마지막이 General 마무리를 지으려 합니다. 사실 PDC에서는 별도의 섹션으로 되어 있으나 제가 그냥 하나로 합쳐서 글을 씁니다. 이유는 글을 끝까지 읽어보시면 됩니다.

 

그럼 첫번째 C# 하기 전에 PDC 09 DJ Park 이란 분의 동영상과 자료는 이곳에서 다운로드 받을 있습니다.

 

http://microsoftpdc.com/Sessions/FT35

 

마지막에 분은 1분안에 코딩을 완료하는.. 멋진 모습(?) 보실 있습니다.(저도 해보고 싶지만.. ㅋㅋ 실력이 딸려서 . 그렇지만 언제는 해보고 싶습니다.^^ 세미나에서 1 코딩 완성 ㅎㅎㅎㅎ)

여기서는 동영상에서 나온것을 일단 정리하면서 C# 개발자 분들에게 도움이 될만한 IDE 환경에 대하여 한번 써보겠습니다.

 

 

화면을 아시는지요??(.. 뭐냥. 이건.. 아는 건뎅. .) 화면은 모두 아시겠지만 여러분들이 개발하는 언어를 선택하면 언어에 맞는 환경 구성을 한다는 것입니다. 여기서 환경이라고 하면.. 당근 개발 환경이겠지요. General Development Settings 으로 합니다. 일반적인 개발 환경으로는 개발 속도가 조금 다를것입니다. 일단 C#이므로 C#으로 선택합니다. 물론 중간에 설정 변경을 있습니다. 중간 변경은 Tool 에서 Import and Export Settings 에서 변경할 있습니다.

중간 변경화면 입니다.

 

 

처음 설정을 C# 개발자 하여 환경설정을 해보죠^^(중간에 변경 가능 아시죠?)

 

이렇게 경우 C# 개발 환경으로 변경이 되는데 변경되는 것은 키보드의 단축키와 IDE 환경이 변화게 됩니다.

IDE 환경에서 개발 언어 또는 관리자에 맞게 IDE 환경을 변경하여 최적의 개별 환경을 꾸미는 것입니다. 그럼 C# 최적은 무엇일가? 단축키?( 쓰지 않습니다 .) VS 시작할 시자화면? 모두 개발의 생산성이나 편리성에 맞추어 개발자가 바로 개발을 있다는 것입니다.

 

이렇게 C#으로 선택하면 초기에는 왼쪽은 박스, 오른쪽에는 솔루션탐색기와, 탁색기, 속성만 일단 표시됩니다. 다음 여러분들이 추가/변경 하실 있습니다. 다음은 바로 단축키 입니다. 단축키 부분이 변경이 되는데 소스 코드 한줄 할줄 생성할 여러분들이 단축키를 이용하면 오타를 많이 줄일 있습니다.( 사실 오타 땜시 오타쟁이라고 소문이 .)

 

첫번째는 Modernize the IDE라고 하는 부분입니다.

짧은 영어 실력으로 번역을 해보면 현대적인 IDE 환경을 이야기 합니다. 현대적인? 현대화 라고 하는데.. 정확히는 IDE환경을 조금 현대적으로 또는 우리가 마음대로 바꿀 있도록 했다는 것이며, 요즘 모두 모니터가 2 이상을 사용하는 추세이므로(HDMI까지 하면 노트북에서도 3개까지 가능합니다.) 멀티 모니터의 지원입니다. 사실 멀티 모니터는 개발자들에게 매우 많은 도움이 것이라는 것은 믿어 의심치 않습니다. ^^. 그럼. 현대적인 개발환경에서 첫번재 시작화면을 이야기를 하겠습니다.

 

시작 화면은 이미 변경 가능하다는 것으로, 일단 부분은 다른 블로그에서 소개 했습니다. 시작 페이지의 변경이 없으면 화면에서 왼쪽은 새로운 프로젝트와 시스템 연결선택 메뉴가 있고 바로 밑에 Recent Projects 메뉴가 있습니다. 사실 메뉴는 프로젝트 목록을 불러오는 것인데, 개발자에 따라 사용도 하고 그렇지 않은 경우도 있습니다.(사실 느린 시스템이나 인터넷이 연결 안된 상황에서는 시작페이지를 뛰우지 않습니다 . 가끔 그런상황이 있죠?? ㅎㅎ ) Recent Projects에서 해당 프로젝트의 목록을 이제부터는 Pin 형식으로 고정 사라지게 있다는 것입니다.

 

 

 

  여기서 보시면 제가 빨간색으로 체크한 부분입니다. 부분이 추가됐구요..

 

 

이제 위의 화면은 바로 두번째 메뉴입니다. 바로 해당하는 폴더를 바로 열어 있습니다.(사실 TFS 연결시 실제 폴더를 찾기 위해 소스제어에서 폴더 위치를 가끔 확인하곤 합니다 ^.^ 역시 바부팅 .) 그리고 하나씩 삭제도 가능하죠. ^^ 다음이 바로 밑에 있는 두개의 체크 박스입니다.


 

부분은 시작페이지의 표시 여부와 프로젝트 로드 시에 작업을 체크하는 것입니다. 이것은 그냥 Pass VS 2008에도 있었던 것이므로, 그렇지만. 여기서는 시작페이지에 표시되었다는 것이 조금 다르지요 옛날에는 메뉴에서 환경 설정에서 변경 했는데 편하게 변경되었습니다. 그것이 조금 눈에 들어오고, PDC PPT에서는 첫번째 체크 항목에 대하여 나왔는데 바로 프로젝트를 로드하고 페이지를 닫을 것인지에 대한 체크입니다.

 

다음이 뉴스 부분입니다. 부분은 조금 쉽게 변경되었다고 있습니다. Microsoft 에서 동안 너무 일방적인(?) 부분으로 개발관련 자료는 웹이나 로컬에 MSDN 설치해서 봐야하고 특정 목차가 초급자가 쉽게 접근할 없었습니다. 그런데 ~ 처음에는 Welcome 으로 초급자에게 쉽게 VS 사용법을 접근할 있도록 표시두었다는 것입니다. 전에는? 최신정보도 좋았지만 초급자가 원하는 정보는 찾기가 힘들었다는 것입니다. 그렇다면 고급자는 뉴스 메뉴에 Guidance and Resources 선택하면 조금 고급으로 넘어갑니다.

 

정리하면,  초급자에게 접근하기 좋은 화면 Get Started

              중급자 이상이 보기에 좋은 화면 Guidance and Resources

 

 

 

 

 이렇게 정리할 있습니다.

물론 RSS feed 수저할 있거나 URL 변경, 최신정보로 가져올 있습니다. 변경은 Latest News 에서 수정 또는 갱신이 가능합니다.


 

이제 다음으로 넘어가서 초기 기본으로 제공하는 시작화면에 대하여는 여기서 끝입니다. ^^

그럼 이제 프로젝트 부분인데 이것은 다음에 다시.^^ 글을 씁니다.



먼저 이전 포스트의 "MEF 는 Generic Type 을 지원하지 않는다!" 에서 언급했고, .NET CLR 2.0 부터 Generic Type 을 지원함에도 불구하고, .NET Framework 4.0 에 포함되는 MEF 가 Generic Type 을 지원하지 않는다는 것은 솔직히 납득하기가 어렵습니다. MEF 개발 PM 이 말하는 강력한 계약 기반(Strongly Contract Based) 의 모델이라는 점은 머리로는 이해는 되지만, 사실 안될 것도 없습니다. -_-;

MEF 가 갖는 대표적인 키워드인 Composable 은 현재 Generic Type 을 지원하지 않지만, 상당히 매력이 있습니다. 이미 현대적인 프레임워크는 Modular 에 집중하고 있고, MEF 는 더 나아가 Modular + Composite 이라는 상당한 매력을 가진 프레임워크입니다.

일단 서두는 이쯤에서 접어두고, MEF 가 Generic Type 을 지원하기 위한 몇 가지 공개되어 있는 방법을 알아보고, 다시 이야기를 나누어 봅시다. 
   

How to support Generic Type of MEF ?    

첫 번째 방법 - Factory Provider

가장 간단한 방법이 바로 Factory Pattern 을 이용한 방식입니다. 객체의 생성은 Factory 를 통해 생성하도록 하고, Factory 는 객체의 Type 을 받음으로써 객체의 생성을 Factory 에게 모두 의존하는 방법입니다. 우선 아래의 링크를 참고하세요.

 ExportProvider 를 재정의하여 객체의 Type 을 등록하여 원하는 Type 의 객체를 생성하도록 합니다.

1: public interface IService { }

2: public interface IUserService : IService { }

3:  

4: [Export]

5: public class UserController {

6: [ImportingConstructor]

7: public UserController(IUserService userService) { }

8: }

9:  

10: // in your application

11: private void Compose() {

12: var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());

13: var factoryProvider = new FactoryExportProvider<IService>(GetService);

14: var container = new CompositionContainer(catalog, factoryProvider);

15: container.AddPart(this);

16: container.Compose();

17: }

18:  

19: public IService GetService(Type type) { return ... }

   

하지만, 이 방법은 상당히 문제가 많은 방법입니다. 가장 즐겨쓰고, 흔히 볼 수 있는 Pattern 이기 때문에 추가되는 Factory 마다 객체 등을 Factory Provider 에 등록을 해 주어야 합니다. 그 뿐만이 아니죠. Factory Pattern 의 특성상 객체를 생성하는 Factory 는 일일이 각 객체의 타입을 체크하여 반환해 주어야 합니다.

그리고 위의 코드에서는 Type 인자가 1개이지만, 그 이상이라면??? 가령, Generic Type Class<T1,T2,T3,T4,T5> 가 된다면 대략 난감하겠죠. 일단 작은 코드에서는 쓸만할 수 있지만, 꾸준히 성장하는 코드라면 이러한 Factory 방식은 코드의 변경이 너무 잦아집니다.

   

두 번째 방법 - Type Mapping

MEF 는 Codeplex 에 공개가 되어있고, MEF Contrib 으로 불리우는 MEF 의 확장 라이브러리 입니다. MEF Contrib 의 가장 큰 특징 중에 하나인 ComposablePartCatalog 를 재정의 하는 Generic Catalog 를 지원해 줍니다. 이 링크에서 Type Mapping 을 통한 문서를 볼 수 있습니다.

public class GenericCatalogContext
{
protected AggregateCatalog _aggegateCatalog;
protected GenericCatalog _genericCatalog;
protected ImportDefinition _repositoryImportDefinition;

public GenericCatalogContext()
{
var typeCatalog = new TypeCatalog(typeof(OrderProcessor), typeof(RepositoryTypeLocator));
_aggegateCatalog =
new AggregateCatalog();
_aggegateCatalog.Catalogs.Add(typeCatalog);
_genericCatalog =
new GenericCatalog(_aggegateCatalog);
string orderProcessorContract = AttributedModelServices.GetContractName(typeof(OrderProcessor));
var orderProcessPartDefinition = typeCatalog.Parts.Single(p => p.ExportDefinitions.Any(d => d.ContractName == orderProcessorContract));
_repositoryImportDefinition = orderProcessPartDefinition.ImportDefinitions.First();
Context();
}

public virtual void Context()
{

}
}

[InheritedExport]
public abstract class GenericContractTypeMapping
{
public GenericContractTypeMapping(Type genericContractTypeDefinition, Type genericImplementationTypeDefinition)
{
}

public Type GenericContractTypeDefinition { get; }
public Type GenericImplementationTypeDefinition { get; }
}

public class RepositoryTypeLocator : GenericContractTypeMapping
{
public RepositoryTypeLocator()
:
base(typeof(IRepository<>), typeof(Repository<>))
{
}
}

public class Repository<T> : IRepository<T>
{
}

이러이러한 과정을 통해서 아래와 같이 Type Mapping 을 통해 Generic Type 을 사용할 수 있습니다.

[TestFixture]
public class When_querying_catalog_for_an_order_repository_and_no_closed_repository_is_present : GenericCatalogContext
{
[Test]
public void order_repository_part_definition_is_created()
{
Assert.IsNotNull(_result.Item1);
}

[Test]
public void order_repository_export_is_created()
{
Assert.IsNotNull(_result.Item2);
}

public override void Context()
{
_result = _genericCatalog.GetExports(_repositoryImportDefinition).Single();
}

private Tuple<ComposablePartDefinition, ExportDefinition> _result;
}

Contract Type 와 Mapping Type 을 매핑하여 Locator 로 등록하여 주고, 각각 Mapping Class 를 통해 실제 계약의 Generic Type 매핑이 이루어 집니다.

다시 말해서, Generic Class 별로 Locator Class, Mapping Class, 그리고 Mapping Context Class 를 만들어주어야 합니다. 배보다 배꼽이 더 커지는 격입니다. 일단, 아이디어는 좋지만 안쓰고 말랍니다.

   

세 번째 방법 - MEF + Unity 조합

아마도 가장 이상적인 방법이긴 합니다. Unity Application Block 은 Unity Container Extension 을 지원하기 때문에 객체의 Register, Resolve 등의 이벤트를 가로채서 Unity 의 기능을 확장할 수 있습니다. 이 이벤트를 MEF 에서 받도록 하여 MEF 의 ExportProvider 의 GetExportsCore 를 통해 Unity 의 객체에서 Resolve 하도록 하는 방법입니다.

UnityContainerExtension 을 재정의하여, 아래와 같이 이벤트를 받고, 이것을 MEF ExportProvider 로 전달하는 방법입니다.

UnityContainerExntension 에서는 아래와 같이...

protected override void Initialize()
{
this.Context.Registering += new EventHandler<RegisterEventArgs>(Context_Registering);
this.Context.RegisteringInstance += new EventHandler<RegisterInstanceEventArgs>(Context_RegisteringInstance);
}

MEF 의 ExportProvider 에서는 아래와 같이…

protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
{
if (definition.ContractName != null)
{
Type contractType;
if(Mapping.TryGetValue(definition.ContractName, out contractType))
{
if (definition.Cardinality == ImportCardinality.ExactlyOne || definition.Cardinality == ImportCardinality.ExactlyOne)
{
var export = new Export(definition.ContractName, () => serviceLocator.GetInstance(contractType));
return new List<Export> { export };
}

}
}
return Enumerable.Empty<Export>();
}

일단 가장 완벽해 보입니다만, 이 속에는 그 이상 많은 문제들이 생기게 됩니다. MEF 도 내부적으로 Injection(주입) 기법을 사용하고, Unity 에서도 Injection 을 사용하는데 바로 이 Injection 방법이 달라지게 되는 것입니다. 즉, MEF 기반의 코드와 Unity 기반의 코드의 Injection 선언 방법이 틀려지고, 서로 호환할 수 없다는 것입니다.

결국 DI 프레임워크는 특정 DI Container 에 의존할 수 밖에 없어지고, 더불어 Compisite 과 Injection 은 두 가지의 사용 방법이 혼재될 수 밖에 없다는 것이죠.

   

Conclusion

MEF 에서 Generic Type 을 사용하고 싶어서 안달이 난 1은 여러 가지 방법을 찾아보았지만, 사용성, 재사용성, 확장성, 유연성 등 모든 면에서 원하는 해답을 찾지 못했습니다. 그리고 현재까지 MEF 에서 Generic Type 을 지원하기 위한 대략적인 3가지 방법을 정리해보도록 하죠.

  

장점

단점

MEF Factory Export Provider

  • 구현이 쉽다
  • Factory 의 관리가 힘들다
  • Factory 의 확장이 힘들다
  • 모든 Factory 를 Catalog 로 관리해야 한다.

MEF Contrib Type Mapping

  • 합리적이다
  • Type Mapping 코드가 복잡하다
  • Mapping/Locator/Context 클래스를 구현해야 한다
  • 상속 기반이다

MEF + Unity Integrated

  • 합리적이고 , 구현이 쉽다
  • Injection 기법이 서로 달라진다
  • Injection 코드가 서로 달라진다
  • Injection 이 호환되지 않는다
  • 각각의 객체간의 Composite 이 불가능하다

이제 슬슬 머리가 아파옵니다. 향후 .NET Framework 4.0 에서 가장 큰 빛을 보게 될 MEF 이지만, Generic Type 을 지원하지 않는다는 것은 가장 큰 오점이 아닐까 생각합니다. 우선 이쯤에서 마무리하고 어떻게 해야 할지 생각해 보도록 하지요.


MEF 에서 Generic Type 문제는 코드 플랙스에 MEFGeneric 으로 공개하였습니다.
[.NET/.NET Framework] - MEFGeneric 코드 플랙스에 공개합니다.

.NET Framework 4.0 에 포함이 될 Managed Extensibility Framework(이하 MEF) 는 Generic Type 을 지원하지 않습니다. ( MEF is not supporting Generic Type!!!! )   

상당히 충격입니다. MEF 는 현재 Generic Type 을 지원하지 않습니다. 이것을 가지고 현재 중요한 프로젝트를 진행하기 위해 여러 가지 리뷰를 해 보고 있습니다만, MEF 가 Generic Type 을 지원하지 않는 것은 쉽게 말해 'MEF 는 아직…' 이라는 결론이 나는군요.    


Managed Extensibility Framework Basic

이것을 이해하기 위해서는 MEF 의 기본부터 이해해야 할 필요가 있습니다. 자세한 내용은 아래의 필자의 블로그 링크를 클릭하시면 Managed Extensibility Framework 에 대한 아티클을 볼 수 있습니다.

우선 이러한 원인은 MEF 가 Contract Model(계약 모델) 기반이라는 있다는 이유 입니다. 우리가 흔히 사용하는 계약 모델은 쉽게 이야기하면 제공자와 소비자로 구분할 수 있습니다. 제공자와 소비자의 거래가 성립이 되기 위해서는 바로 계약이라는 것이 필요하죠. MEF 로 비유하자만 Import/Export 가 바로 그것이며 그 계약을 성립시켜 주는 것이 MEF Container 와 Composition Batch 로 볼 수 있습니다.

바로 이러한 계약 기반과 Composable Part 라는 개념으로 기존의 컴포넌트의 재사용성을 높일 수 있게 되며, 좀 더 동적이며, 추상화가 가능한 프레임워크 입니다. 더 쉽게 얘기하면, 새로운 C 라는 컴포넌트는 A 와 B 라는 컴포넌트와 계약하여 결합시키거나, 기존 컴포넌트를 변형시키는 등 Composable Application 을 만들기 위해 계약의 명세만 알면 다양한 컴포넌트를 재생산, 변형, 다양성, 재활용 등을 할 수 있습니다.

 

MEF 는 내부적으로 이러한 명확한 계약을 위해 여러 가지 방법으로 계약을 정의할 수 있습니다. 기본적으로 ExportAttribute 을 사용하여 String, CLR Type, ExportMetadata 를 사용하게 되어 있지요. 하지만 MEF 는 모든 계약의 명세는 바로 String 을 사용하는 데에서 문제가 발생하게 됩니다. 그리고 이것이 Dependency Injection(DI) 와 Inversion Of Control(IoC) 와 다른 점입니다. 대부분의 DI 프레임워크는 Object 의 Lifecycle 을 관리하고 객체의 의존성을 낮추기 위해 역제어 하는 것에 초점이 맞추어져 있기 때문에 CLR Type 기반으로 Container 에 등록이 됩니다.

예를 들어 보면, 아래와 같은 것이 MEF 에서는 계약 명세 규격에 어긋난다는 의미입니다. (특정 DI 프레임워크에 종속되지 않는 코드입니다)

var container = new Container();
container.Register<IUMC<>>();

var obj = container.Resolve<IUMC<string>>();
obj.SayHello();

   

Why MEF is not supporting Generic Type?

MEF 가 Generic Type 을 지원하지 않는 것에 이미 많은 사람들이 문제를 발견했고, 몇 가지 해결 방법이 있긴 있습니다.

이미 Ayende Rahien 이라는 사람의 블로그에는 MEF 가 Generic Type 을 지원하지 않는 것에 대한 이야기를 합니다. 내용을 보면 처음부터 Microsoft 의 MEF 개발 팀은 Generic Type 을 배제하고 있었던 것 같습니다. 하지만 Ayende Rahien 씨는 이 문제에 대해 반드시 해결해야 한다는 이야기를 MEF 개발 팀과 나누었습니다. 저도 이 문제가 반드시 해결 되리라 생각합니다만… 현재로써는 글쎄 ^^;

여기에서 MEF 개발 팀은 조금 구차한 변명을 합니다. 위에서 얘기한 MEF 의 기본은 계약 기반의 프레임워크라는 것입니다. 이 문제에 대해 추측을 해보면, MEF 가 Generic Type 을 지원한다는 것은 Strongly Contract Based 가 될 수 없기 때문이고, Generic Type 으로 인해 명확한 계약이 이루어질 수 없다는 것입니다. 특히 MEF 는 계약의 명세가 모두 MEF 가 내부적으로 관리하고 있기 때문에, Generic Type 에 의한 객체 의 계약 관리는 엄청난 메모리 사용량을 증가로 이어질 가능성이 충분합니다.

실제로 Microsoft 에서 MEF 개발 팀의 PM 을 맡고 있는 Glenn Block 씨는 이 아티클에서는 MEF v1 에서는 Generic Type 을 지원하지 못할 것이라고 합니다. 만약에 Generic Type 을 지원하게 된다면 차기 버전이 될 듯 합니다.

하지만, 다시 한번 MEF 는 계약 기반의 모델이라는 것을 생각하지 않을 수 없습니다. 만약 계약이 명확하지 않다면 계약 자체가 불명확하다는 의미입니다. C# 2.0 부터 지원하는 Generic Type 의 명확하지 않는 타입이 계약에 존재한다면 이것은 계약 자체가 성립되기 힘들다는 전제 조건을 포함하게 됩니다.

MEF 의 예를 들어 봅시다. 아래와 같은 Generic Type 의 계약이 존재합니다. (현재의 MEF 로는 전혀 불가능한 코드입니다^^;)

public interface IUMC<T>
{

void SayHello<T>();
}

[Export(typeof(IUMC<>))]
public class UMC<T> : IUMC<T>
{
public void SayHello()
{
// TODO Impl...
}
}

CLR(Common Language Runtime) 의 Generic Type 의 특성상 Generic T Parameter 는 굉장히 다형적입니다. UMC<string> 또는 UMC<int> 또는 모든 Class Type 이 T Parameter 에 대입될 수 있습니다. 단순히 어떤 타입도 올 수 있다는 것을 떠나 물건을 팔 사람은 도대체 소비자가 누구와 계약한 것인지 알 수 없고, 실제 상거래와 같은 상황이라면 사기와도 같다는 것이죠. 굳이 예를 들자면, 주민등록번호가 다름에도 불구하고, 주민등록증의 이름이 같은 동명인에게 언제든지 계약을 할 수 있다는 것이죠.

DI(Dependency Injection / IoC) 는 CLR Type 을 기반으로 합니다. 일부 DI 프레임워크는 Tag 와 같은 Contract Data 를 제공하기는 하지만 이것은 Metadata 그 이상의 역활을 하지 않습니다. 즉 Contract(계약) 와는 전혀 무관하다는 이야기 입니다. 객체를 질의(Query) 하기 위함이지 Composable 을 위한 것은 아닙니다.

 

OK! I'm understand. But…!!

처음부터 MEF 는 계약 기반의 Composable/Plugin Model/Contract Based 라는 용어를 자주 만나게 됩니다. 그리고 계약 자체라는 의미에서 Generic Type 은 가장 큰 장애 요소임이 확실합니다. 그렇기 때문에 현존하는 모든 DI(Dependency Injection) 프레임워크는 계약(Contract) 라는 용어를 절대 사용하지 않습니다. 목적 자체가 계약과는 전혀 무관하기 때문입니다.

하지만, MEF 의 계약 모델은 내부적으로 String Based Contract 를 사용하고 있고, Generic Type 또한 String 으로 표현이 가능하기 때문에, 문자열의 Parsing 만으로 어느 정도의 Generic Type 을 지원할 수 있을 거라고 생각했습니다.

필자는 처음 MEF 를 본 순간 "이것을 물건이다!" 라는 걸 느꼈습니다만, 아마도 MEF 개발 팀은 두 가지의 고민을 했을 거라고 생각합니다. Silverlight 를 지원할지, Generic Type 을 지원할지에 대한 범용성에 대해서 말입니다. 하지만, Generic 에 대해 많은 피드백을 받음에도 불구하고 MEF v1 에 지원하지 않을 듯한 대답은 사실 "구차한 변명" 으로 밖에 들리지 않는답니다. 결국, 현재 MEF 는 Silverlight 를 지원하는 등 .NET Framework 의 범용성에 치중하였고, 결국 Generic Type 은 현재 시점에서 릴리즈 시점까지 구현이 불가능할 거라고 예상합니다.

아쉽긴 하지만, 현재 MEF 가 불가능한 Generic Type 에 대한 영역은 몇 가지 Open Source 에서 제공을 하고 있습니다. 단지 실제 사용성에 대한 의구심과 필자의 견해로는 안쓰는게 나을 것 같다는 판단입니다.

다음에 당장 지원하지 않는 Generic Type 을 어떻게 사용할지 알아보고 함께 돌파구를 찾아보도록 하겠습니다. 


MEF 에서 Generic Type 문제는 코드 플랙스에 MEFGeneric 으로 공개하였습니다.
[.NET/.NET Framework] - MEFGeneric 코드 플랙스에 공개합니다.

nullptr

C++0x 2010. 1. 28. 09:00 Posted by 알 수 없는 사용자

오랜만에 팀 블로그에 C++0x 관련 글을 올립니다.

이미 알고 계시겠지만 Visual Stuido 2010 Beta2에 새로운 C++0x 기능이 추가 되었습니다.

추가된 것은 nullptr 이라는 키워드 입니다.

nullptr C++0x에서 추가된 키워드로 널 포인터(Null Pointer)를 나타냅니다.

 

 

null_ptr이 필요한 이유

 

C++03까지는 널 포인터를 나타내기 위해서는 NULL 매크로나 상수 0을 사용하였습니다.

그러나 NULL 매크로나 상수 0을 사용하여 함수에 인자로 넘기는 경우 int 타입으로 추론되어 버리는 문제가 발생 합니다.

 

< List 1 >

#include <iostream>

 

using namespace std;

 

void func( int a )

{

cout << "func - int " << endl;

}

 

void func( double *p )

{

cout << "func - double * " << endl;

}

 

int main()

{

func( static_cast<double*>(0) );

                 

func( 0 );

  func( NULL );

                 

getchar();

return 0;

}

 

< 결과 >

 


첫 번째 func 호출에서는 double* 로 캐스팅을 해서 의도하는 func이 호출 되었습니다. 그러나 두 번째와 세 번째 func 호출의 경우 func( doube* p ) 함수에 널 포인터로 파라미터로 넘기려고 했는데 의도하지 않게 컴파일러는 int로 추론하여 func( int a )가 호출 되었습니다.

 

바로 이와 같은 문제를 해결하기 위해서 nullptr 이라는 키워드가 생겼습니다.

 

 

 

nullptr 구현안

 

C++0x에서 nullptr의 드래프트 문서를 보면 nullptr은 아래와 같은 형태로 구현 되어 있습니다.

 

const class {

public:

    template <class T>

    operator T*() const

    {

        return 0;

    }

 

    template <class C, class T>

    operator T C::*() const

    {

        return 0;

    }

 

private:

    void operator&() const;

 

} nullptr = {};

 

 

 

nullptr 사용 방법

 

사용방법은 너무 너무 간단합니다. ^^

그냥 예전에 널 포인터로 0 이나 NULL을 사용하던 것을 그대로 대처하면 됩니다.

 

char* p = nullptr;

 

<List1>에서 널 포인트를 파라미터로 넘겨서 func( double* p )가 호출하게 하기 위해서는

func( nullptr );

로 호출하면 됩니다.

 



nullptr의 올바른 사용과 틀린 사용 예

 

 

올바른 사용

char* ch = nullptr; // ch에 널 포인터 대입.

sizeof( nullptr ); // 사용 할 수 있습니다. 참고로 크기는 4 입니다.

typeid( nullptr ); // 사용할 수 있습니다.

throw nullptr; // 사용할 수 있습니다.

 

 

틀린 사용

int n = nullptr; // int에는 숫자만 대입가능한데 nullptr은 클래스이므로 안됩니다.

 

Int n2 = 0

if( n2 == nullptr ); // 에러

 

if( nullptr ); // 에러

 

if( nullptr == 0 ); // 에러

 

nullptr = 0; // 에러

 

nullptr + 2; // 에러

 

 

 

nullptr 너무 간단하죠? ^^

VC++ 10에서는 예전처럼 널 포인터를 나타내기 위해서 0 이나 NULL 매크로를 사용하지 말고 꼭 nullptr을 사용하여 함수나 템플릿에서 널 포인터 추론이 올바르게 되어 C++을 더 효율적으로 사용하기 바랍니다.^^

 

 

 

짜투리 이야기...... ^^


왜 nullptr 이라고 이름을 지었을까?

nullptr을 만들 때 기존의 라이브러리들과 이름 충돌을 최대한 피하기 위해서 구글로 검색을 해보니 nullptr로 검색 결과가 나오는 것이 별로 없어서 nullptr로 했다고 합니다.

제안자 중 한 명인 Herb Sutter은 현재 Microsoft에서 근무하고 있는데 그래서인지 C++/CLI에서는 이미 nullptr 키워드를 지원하고 있습니다.

 

 

C++0x 이야기

근래에 Boost 라이브러리의 thread 라이브러리가 C++0x에 채택 되었다고 합니다. Boost에 있는 많은 라이브러리가 C++0x에 채택되고 있으므로 컴파일러에서 아직 지원하지 않는 C++0x의 기능을 먼저 사용해 보고 싶다면 꼭 Boost 라이브러리를 사용해 보기 바랍니다.

 


 

참고

http://d.hatena.ne.jp/faith_and_brave/20071002/1191322319

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf

http://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/nullptr

http://d.hatena.ne.jp/KZR/20080328/p1

 

 

[JumpToDX11-10] GPGPU 를 위한 DirectCompute.

DirectX 11 2010. 1. 27. 09:00 Posted by 알 수 없는 사용자


아주 오래 전 컴퓨터에는 GPU 라는 개념이 특별히 존재하지 않았습니다.
그저 화면에 얼마나 많은 픽셀을 나타낼 수 있는가 정도가 그래픽 카드의 성능을 나타내는 기준이였습니다.
그랬던 상황이 오늘 날에 이르게 된 것입니다.( 굳이 자세히 언급할 필요가 없을 것 같습니다.^^ )

오늘날의 GPU 의 성능은 가히 놀라울 정도입니다.
하지만 이런 놀라운 성능을 가진 GPU의 processing unit 들이 대부분의 시간을 놀면서 있다는 것이
우리의 신경에 거슬렸던 것입니다.
그래서 이들에게 일감을 분배시키기 위한 방안을 생각하게 되었고,
이를 배경으로 등장한 것이 바로 GPGPU 입니다.

GPU 를 활용한 일반적인 처리 방식을
GPGPU( General-purpose computing on graphics processing uints ) 라고 합니다.
범용성 있게 GPU 를 활용해서 처리하겠다는 것이지만,
사실 CPU 와 GPU 의 목적은 엄연히 다릅니다.

CPU 는 광범위한 영역에서도 효율적으로 이용될 수 있도록 설계를 된 것이지만,
GPU 는 그래픽 처리를 위한 산술 연산에 특화된 processing unit 입니다.
오늘 날 PC 는 멀티코어 형식이 많아지고 있는 추세인데,
하나의 CPU 는 기본적으로 특정 시간에 하나의 연산만 수행할 수 있습니다.
GPU 의 경우에는 병렬처리 형식에 완전히 특화된 형태입니다.
오늘날 GPU의 코어는 32개라고 합니다.
즉 32개가 연산이 동시에 실행될 수 있다는 얘기입니다.
아래 그림을 한번 보실까요?




GPU 에는 SIMD 라는 것이 굉장히 많은 것을 볼 수 있습니다.
SIMD( Single Instruction Multiple Data ) 라는 것은 병렬 프로세서의 한 종류입니다.
벡터 기반의 프로세서에서 주로 사용되는데,
하나의 명령어를 통해서 여러 개의 값을 동시에 계산할 수 있도록 해줍니다.
( http://ko.wikipedia.org/wiki/SIMD  --> 여기서 참고 했습니다^^ )

벡터 기반이라는 사실에 우리는 주목할 필요가 있습니다.
GPU 는 광범위한 목적으로 설계된 processing unit 이 아닙니다.
즉, GPGPU 를 활용하는 목적은 주로 수치 연산에만 국한된 이야기 입니다.
일반적인 로직으로 GPGPU 를 활용하는 것은 그리 좋은 선택이 아니라는 것입니다.
현재 GPGPU 가 활용되고 있는 영역은 이미지 프로세싱, 비디오 프로세싱, 시뮬레이션 등과 같이
많은 수학 연산이 필요한 영역입니다.
분명한 것은 이들 수치 연산에 국한된 모델이라 할지라도, 그 성능이 무척 매력적이라는 것입니다.

이런 GPGPU 활용을 위해서 마이크로소프트는 어떤 준비물을 가지고 등장했을까요?
그것이 바로 'DirectCompute' 라는 것입니다.^^
아래 그림을 한번 보실까요?



DirectCompute 외에도 친숙한 이름이 보이시나요?
개인적으로 현재 GPGPU 분야에서 가장 앞서 있다고 보여지는 CUDA 가 있습니다.
이것들에 대한 우열을 가리기는 어려운 문제입니다.
여러분이 처한 상황에서 최선의 선택을 하면 되는 것입니다.
그 중에 DirectCompute 도 하나의 선택지일 뿐입니다.
CUDA 도 굉장히 훌륭한 GPGPU 모델입니다.
( 사실 저도 CUDA 를 공부하면서 GPGPU 의 개념을 잡았습니다.^^ )
CUDA 는 제가 지금 언급하지 않아도 될 정도로 많은 정보들이 공개되어 있습니다.

DirectCompute 는 마이크로소프트에서 가지고 나온 GPGPU 모델입니다.
앞으로 OS 의 강력한 지원을 가지고 등장하게 될 것입니다.

사실 GPGPU 와 DirectCompute 는 매우 혼란스럽게 사용될 수 용어들입니다.
그래서 오늘은 이들 두 용어를 확실히 구분하는 것으로 마무리 하겠습니다.^^
다음 시간부터는 DirectCompute 에 대해서 조금씩 살펴보겠습니다.


참고 자료
http://microsoftpdc.com/Sessions/P09-16
본 내용은 위의 PDC 를 참고해서 만들었습니다.

설치 과정 중에 TF255040 문제

Team Foundation Server 2010 을 설치하는 중 TF255040 오류가 발생하였습니다. 아래의 그림과 같이 SQL Server 의 Reporting Services 와 관련된 컴포넌트가 설치 되지 않았다는 오류입니다. 훔...

SQL Server Analysis Services 인스턴스를 찾지 못한다는 오류 메시지가 나타납니다.

 

TFS 설치 오류 로그를 자세히 보면 아래와 같이 문제 지점의 예외 메시지를 찾을 수 없습니다.

[Error @12:07:34.650] Microsoft.TeamFoundation.Admin.TfsAdminException: TF255040: Install SQL Server Reporting Services or at a minimum SQL Client Connectivity Tools on the application tier to ensure Analysis Services object model is present for warehouse processing. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.AnalysisServices, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' or one of its dependencies. 지정된 파일을 찾을 수 없습니다.

at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)

at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)

at System.Reflection.Assembly.Load(String assemblyString)

at Microsoft.TeamFoundation.Admin.UIHelper.CheckAnalysisInstanceLoad(String analysisInstance)

--- End of inner exception stack trace ---

at Microsoft.TeamFoundation.Admin.UIHelper.CheckAnalysisInstanceLoad(String analysisInstance)

at Microsoft.TeamFoundation.Management.Controls.WizardCommon.ServerTestControl.m_testWorker_DoWork(Object sender, DoWorkEventArgs e)

at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)

at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)


그래서 Microsoft.AnalysisServices, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91 어셈블리가 GAC 등록이 되어 있는지 확인을 보았습니다. 역시나 문제는 위의 어셈블리가 설치가 되지 않아서 발생한 문제입니다.

      

TF255040 오류 문제 해결하기

해결 방법은 가지가 있습니다. 중에 번째 방법을 추천 드립니다.

왜냐하면 SQL Express 버전을 설치하면 되지만, 결국 SQL Server 인스턴스를 만들어야 하기 때문에 왠지 TFS 전용 서버의 순결함을 잃는 하군요.. 사용하지도 않을 SQLEXPRESS 라는 반갑지 않은 인스턴스와 말이죠. 번째 SQL Server 2008 Feature Pack SQL Server 구성 요소 일부만 설치할 있습니다. 제가 필요로 하는 Analysis Service 관련 어셈블리만 설치되도록 설치 패키지를 제공해 주고 있습니다.

  • 그럼 Microsoft SQL 2008 관련 구성 요소를 설치해 주어야 하는데, 아래의 주소에서 기본적인 클라이언트가 설치되도록 합니다. 근데 Management Studio Express 설치하게 되면 SQLEXPRESS 라고 하는 인스턴스가 설치가 되는데 Team Foundation Server Application Tier SQLEXPRESS 인스턴스가 그다지 필요해 보이지도 않고, 설치 시간도 오래걸리고요.

  • 위의 방법은 Analysis Services Object 어셈블리만 설치하는 방법입니다. HTML 페이지가 다운로드 되면 HTML 파일을 열어봅니다. 다운로드 가능한 여러 가지 목록 중에 아래 Analysis Services Object 골라서 다운로드 하시는 것이 좋겠죠?

       

아래를 설치하고 Team Foundation Administrator Console 다시 실행해 주시면 아래의 그림과 같이 정상적으로 SQL Server Analysis Services 접근할 있습니다.

   


TFS 2010 Build Service 설치

Team Foundation Server 2010. 1. 26. 09:00 Posted by POWERUMC

Configure Team Foundation Build Service 에서 Start Wizard 를 클릭합니다.

   

아래는 Build Service 설치 안내 페이지 입니다. 다음을 클릭합니다.

   

Team Build 를 수행한 Team Project Collection 을 지정해야 합니다. Browser 를 클릭하여 Team Project Collection 을 선택합니다. 만약 Team Foundation Server 와 연결되지 않은 상태일 경우 Team Foundation Server 와 연결해야 합니다.

   

   

기본 설정대로 Recommended 를 선택하고 다음을 클릭합니다.

   

Team Build 를 수행할 계정과 포트를 입력합니다. 필자는 TFSBUILD 계정으로 사용하였고, 환경에 따라 NETWORK SERVICE 등으로 사용하셔도 됩니다.

   

모든 설정이 완료 되었고, Verify 를 클릭하여 Team Build 환경을 점검합니다.

   

모든 점검이 완료되면, Configure 를 클릭하여 설치를 진행합니다.

   

아래는 Team Foundation Build Service 설치가 완료된 화면입니다.

   

   

TFS 2010 설치 하기

Team Foundation Server 2010. 1. 26. 09:00 Posted by POWERUMC

Team Foundation Server 2010 은 기존의 2008 버전에 비해 굉장히 설치가 간단해 졌습니다.  

사실 설치과 구성 패키지 자체는 TFS 2008 이 간단하긴 했지만, 구성이 올바르게 완료되어야만 설치가 가능했었습니다. 이런 문제로 인해서 초기 설정이 유효하지 않을 경우 설치를 완료한들 다시 제거를 하고 재설정을 했던 경우가 많았습니다. 그리고 TFS 2008 에서는 설정 정보가 IIS 의 TFS Web Service 의 web.config 와 데이터베이스의 특정 필드를 직정 수정해야 하는 관리상의 불편함이 많았습니다.

하지만 이번 Team Foundation Server 2010 는 이런 면에서 초기 설치 단계에서 구성하는 단계까지 많이 편리해졌습니다. 설치와 구성을 따로 따로 하도록 말이죠.  

아래는 Team Foundation Server 2010 을 설치하고, Team Foundation Server Administration Console 을 이용하여 TFS 환경을 구성하는 방법입니다. 

아래의 설치 과정은 3-tier 로 구성된 서버에 TFS 2010 을 설치하는 단계입니다.

  • 서버 1 : Active Directory, DNS 서버
  • 서버 2 : MSSQL 2008
  • 서버 3 : Team Foundation Server 2010

   

Team Foundation Server Administrator Console 을 실행하여 Configure Installed Features 를 클릭합니다.

   

다중 Tier 환경으로 설치할 예정이므로, Advanced 를 선택하고 Start Wizard 를 클릭합니다.

   

Wizard 안내 페이지입니다. 그냥 다음으로 넘어 갑니다.

   

SQL Server 의 인스턴스를 입력하고 Test 를 클릭합니다. 인스턴스가 유효하면 푸른색 V 표시가 나타나고, 다음으로 넘어 갑니다.

   

Service Account 계정을 입력하고 Test 를 클릭해보고, 계정이 유효하면 다음으로 넘어갑니다.

   

Team Foundation Server 2010 의 웹 서비스의 설정을 합니다. 그냥 기본 구성 그대로 다음으로 넘어갑니다.

   

보고서를 구성하는 페이지의 안내입니다. 필자는 보고서를 구성할 것이므로, Configure Reporting for use with Team Foundation Server 항목 체크 박스를 체크 한 후에 다음으로 넘어갑니다.

   

Reporting Service 인스턴스를 입력하고 Populate URLs 를 클릭하면 유효한 보고서 서비스를 찾아줍니다. 그리고 다음으로 넘어갑니다.

   

TFS Report 서비스의 실행 계정을 지정해 줍니다. 필자는 기본 계정인 NETWORK SERVICE 계정을 사용합니다.

   

아래는 Sharepoint 를 설치를 안내하는 페이지 입니다. 다음으로 넘어갑니다.

   

Sharepoint 서버의 계정을 입력하고 Test 를 클릭하여 유효성을 검사합니다. 그리고 다음으로 넘어갑니다.

   

기본적으로 Team Project Collection 이 체크되어 있습니다. 그대로 다음으로 넘어갑니다.

   

모든 설정이 완료 되었습니다. Verify 를 클릭하여 최종 점검을 진행합니다.

   

Verify 결과가 양호할 경우 설치를 진행하도록 합니다. Configure 를 클릭하여 설치를 진행합니다.

   

아래는 Team Foundation Server 2010 이 설치가 완료되었습니다.

   

   

이제 설치가 완료되었고, Team Foundation Server 관리를 위하여 관리 권한을 지정합니다.

Application Tier 의 Administer Group Membership 을 클릭합니다.

   

Team Foundation Administrators 그룹을 더블 클릭(또는 Properties 클릭) 하고, 관리자 계정을 지정해 줍니다.

   

   

이제 모든 설치와 구성을 마쳤습니다. 아래의 그림은 Visual Studio 2010 으로 Team Foundation Server 2010 에 연결된 모습입니다.

   


WCF의 기본 <Contract> - Service Contract

WCF 2010. 1. 26. 09:00 Posted by 알 수 없는 사용자
지금까지 세번의 포스팅으로 WCF의 기초에 대해 알아보았습니다.
기초를 뗏으니, 이제 기본으로 넘어가야죠~ ^^

WCF의 기본 중에서 가장 먼저 알려드리고 싶어 꺼내 든 주제는 Contract 입니다.

Contract의 사전적 의미는,, "계약" 이죠.
(네이X 사전에서 찾아보니 계약이란 의미 외에 살인 청부, 줄어들다, 수축하다,, 등의 의미가 있군요,,)

그럼, "계약"의 사전적 의미는 무엇일까요? (약간 글이 엉뚱한 방향으로 흐르는 것 같지만,, ^^;;)
역시, 네이X 국어 사전에서 찾아본 결과,, 
"관련되는 사람이나 조직체 사이에서 서로 지켜야 할 의무에 대하여 글이나 말로 정하여 둠" 이라고 합니다.

잘 아시겠지만 계약은 약속이랑 비슷하지만 약속 보다는 좀 더 강력한 의미로 쓰입니다.(법적 효력도 있죠,,)

다시, 본론으로 돌아와서,, 그럼, WCF 에서의 Contract 는 무엇을 말하는 걸까요?
네,, 다들 예상 하셨겠지만, WCF 에서의 Contrat 역시 사전적 의미와 비슷하게 쓰이며, WCF 서비스와 클라어언트 사이에 어떤 계약을 정의할 때 사용하는 것을 말합니다.

좀 더 자세하게 설명을 하자면, 이 Contract 라는 것은 서비스와 클라이언트가 서로 통신할 때 사용하는 메세지의 명세(specification)를 정의하는 것을 말합니다.

WCF 는 총 세가지 타입의 Contract가 있으며, 다음은 이 타입들에 대한 정의입니다.

  • Service contract : 서비스에 의해 구현되는 기능들에 대해 설명하며, 서비스 계약(service contract)으로 정의 된 .NET 타입의 클래스는 WSDL의 services, port types의 엘리먼트로 매핑됩니다. 서비스 계약과 함께 Operation contract는 서비스 계약 내에서 정의되며, 서비스의 동작(operation)을 설명합니다.

  • Data contract : 서비스가 통신(communication)을 하는데 사용하는 데이터 구조를 나타냅니다. 이는 CLR 타입을 XSD(XML Schema Definitions) 로 매핑해주는 역할을 수행하는데, WCF 가 통신할 때 사용되어지는 데이터들을 어떻게 직렬화(serialization) 또는 역직렬화(deserialization)를 수행하는지를 설명합니다.

  • Message contract : 메세지 계약은 CLR 타입을 SOAP 메세지로 매핑해주며, SOAP 메세지의 포맷을 설명합니다. 메세지 계약은 SOAP 헤더에서 바디까지 컨트롤할 수 있게 해줍니다.

예전 포스팅에서 몇 번 언급한 점이기 때문에 다들 아실거라 생각하는데,, WCF 서비스는 많은 시스템과의 상호 운용성(interoperability)을 높이기 위해 WSDL을 사용합니다. 위에서 설명한 세 가지의 Contract 들은 WCF 서비스나 서비스에서 사용하는 여러 데이터들을 WSDL 또는 SOAP의 요소들로 매핑 시키는 역할을 수행합니다. 이 말은 곧, 서비스와 통신하기 위한 메세지의 포맷을 정의한다는 말이기도 하지요.(앞에서 언급했듯이,,)

이제 Contract의 정의에 대해선 조금 이해가 가시지요? ^^

그럼, 이러한 Contract들이 어떻게 쓰이는지 하나씩 살펴보겠습니다.
우선, Service Contract 와 Operation Contract에 대해 알아보구요, 한 두번에 걸쳐서 Data Contract와 Message Contract에 대해서도 알아보도록 하겠습니다.

서비스 계약은 지금까지 몇번 언급했던 것 같습니다.
다시 한번 더 얘기하자면, 서비스 계약은 서비스가 제공하는 여러 기능(동작)들을 정의하는 인터페이스이며, 서비스 자체를 정의한다고 생각하면 될듯 합니다. 
그리고, 서비스에서 제공하는 기능들을 외부로 노출(?)하기 위해 사용하는 Operation Contract가 있습니다. 이는 Service Contract 내부에서 정의됩니다.

백문이 불여일견이니, 코드를 한번 보도록 하죠. 음,, 예전에 만들었던 코드를 다시 살펴 보면서 이해하는게 좋을 것 같네요 ^^

[ServiceContract]
interface IProductService
{
    [OperationContract]
    string GetFirstName(string empID);
}


우리가 만들었던 첫 WCF 서비스의 코드 중 일부입니다.
서비스는 ServiceContract 특성을 인터페이스에서 선언하고, 그 메소드에 OperationContract 특성을 선언해줌으로써, 서비스 계약을 정의해주었습니다.
기억하시겠지만, 실제 구체적인 서비스의 기능은 Service Contract가 선언된 인터페이스를 상속 받아 구현해야 했었죠.

그럼, 이렇게 서비스가 정의됐을 때 WSDL이 어떻게 만들어지는지 살펴보겠습니다.
우리가 작성했었던 첫 WCF 서비스를 동작시킨 상태에서 웹 브라우저를 이용해 http://localhost:8000/ProductService?wsdl 로 접근해 보면 다음과 같은 화면을 확인할 수 있습니다.


이것이 바로 WCF 서비스가 제공하는 WSDL입니다.
앞에서 언급했듯이 Service Contract로 정의 되어진 정보는 WSDL의 "service", "port type" 엘리먼트로 매핑된다고 하였습니다. 또한 Operation Contract로 정의된 부분은 "operation" 엘리먼트로 매핑된다고 했었죠,, 
이것 역시 다음과 같이 확인할 수 있었습니다.





이렇게 WCF를 이용하여 만들어진 서비스는 WSDL로 제공되어지며, 클라이언트에서 서비스를 사용할 수 있게 되는 것입니다.

그리고, ServiceContract 특성 클래스에는 Namespace 속성을 제공합니다. 이 속성은 WSDL과 SOAP 메세지의 Namespace의 값을 명시적으로 설정할 수 있게 합니다.

다음과 같이 기존의 서비스를 조금 수정해 보았습니다.

[ServiceContract(Namespace="http://RuAAService.co.kr/")]
interface IProductService
{
    [OperationContract]
    string GetFirstName(string empID);
}


그리고, 다시 이 서비스의 WSDL을 확인해보면, 서비스의 네임스페이스가 다음과 같이 바뀌어져있는 것을 확인할 수 있습니다.



자~ Service Contract에 대한 설명은 여기까지 입니다.
이번에는 실습보다는 이론적인 설명이 위주였습니다. 그래서 조금 재미가 없을 수도 있을 것 같네요 ㅎ
하지만, 이론도 중요하다는 것,, 아시죠? ^^
아무 생각없이 닷넷 인터페이스 만들고 ServiceContract 특성을 주는 것 보다 이러한 작업으로 서비스가 어떻게 클라이언트에 노출되는지를 알고 있는 것이 서비스를 구성하고, 클라이언트를 개발하는데 있어서 많은 도움을 줄 것이라 확신합니다.

이 글 역시, 많은 분들에게 조금이라도 도움이 되었으면 하는 바람을 가지면서 이만 줄이겠습니다 ^^
다음 포스팅때 뵙죠~ ㅎ

5. Assembly - Strongly named assemblies

CLR 2010. 1. 26. 09:00 Posted by 알 수 없는 사용자
CLR에서는 Assembly를 크게 두 종류로 나눌 수 있습니다. Strongly named assemblies(강력한 이름의 어셈블리 - 뭔가 말이 좀 이상하지요?) 그렇지 않은 Assembly 입니다. 

Strongly named assemblies는 해당 assembly의 제공자를 확인할 수 있는 유일한 공개/개인키 쌍으로 서명되어 있고 이 키들은 assembly는 고유한 ID의 일부분으로 인식되어 안전하게 버전이 관리되며 이 키를 통해서 서명된 assembly는 어느곳에서라도 유일한 이름으로 인식되며 배포가 가능하게 됩니다. 

assembly는 크게 전용(Private)으로 배포하는 방식과 전역(Global)으로 배포하는 방법으로 배포 방법을 나눌 수 있습니다. 

전용 배포라는 것은 매우 일반적인 방법의 배포방식으로 배포할 프로그램의 기본 디렉토리와 그 디렉토리의 하위 디렉토리에 관련 assembly들이 설치되어 배포된 형태이며 전역 배포라는 것은 Global Assembly Cache - GAC(전역 어셈블리 캐시) 같은 잘 알려진 특정 디렉토리에 배포되는 방식을 말합니다.

Strongly named assemblies는 전용, 전역 배포가 가능하지만 그렇지 않은 assembly는 전용 배포는 가능하나 전역 배포는 안됩니다. 위에서 알았다시피 Strongly named assemblies가 아닌 경우 유일하게 해당 assembly를 인식할 수 있는 방법이 없으니 당연히 전역적인 배포가 불가능합니다.


자 그럼 Strongly named assemblies를 어떻게 만들 수 있는지 살펴보도록 하지요. 그 전에 잠깐 왜 Strongly named assemblies가 필요한지 잠깐 생각해 봅시다.

다양한 프로그램들이 자신들이 사용하는 assembly를 사용하려고 하는 상황입니다. 일반적으로 그렇듯이 여러 프로그램에서 자주 사용하는 assembly는 잘 알려진 디렉터리에 위치해 있어야 다양한 프로그램들이 사용하기 용이할 것입니다. 

CLR 프로그램 이전의 배포 방식을 되새겨 볼까요.

Visual Studio 6, 7 버전의 Visual C++ 프로그램을 살펴보면 Visual C++ 컴파일러로 생성된 프로그램들은 공통적으로 msvcp71.dll이라던가 msvcp60.dll 등의 공용 모듈을 사용하게 됩니다. 그래서 일반적으로 프로그램 설치시 위의 모듈들을 설치되는 프로그램과 같은 경로에 넣기도 하지만 windows 폴더의 system32 디렉터리에 넣어놓곤 하지요. 일반적으로 MS관련 프로그램을 설치하게 되면 위의 ms..로 시작하는 dll들은 system32 디렉터리에 설치가 되기 때문에 응당 위의 모듈이 모든 PC의 system32 폴더에 있겠거니 착각하고 배포본에 넣어놓지 않았다가 낭패를 보는 경우도 적지 않게 있었지요. 

MS관련의 공통모듈 뿐만이 아니라 다양한 프로그램에서 자주 사용하는 모듈들은 Windows가 설치된 PC라면 설치된 프로그램이 어느 디렉터리에 설치가 되던지 참조가 가능한 system32 폴더에 설치해 놓는 경우가 많습니다. 이러면서 문제가 발생하게 되었는데 다른 회사에서 같은 파일 이름을 가진 모듈을 system32 폴더에 설치를 하게 되었다던가, 같은 이름을 가지지만 버전이 틀린 파일을 설치하게 되어 특정 프로그램은 정확히 자신이 참조해야 하는 모듈을 찾을 수 없어 프로그램이 정상적으로 실행되지 않는 이른바 DLL Hell과 관련된 문제가 생기가 된 것입니다. 무엇보다 별 생각없이 system32같은 중요한 디렉터리에 자신들이 배포하는 프로그램과 관련한 모듈들을 무작정 설치하는 것도 DLL Hell을 만들게 된 중요한 원인 중 하나였지요.

최근에도 그런 문제가 있었습니다. 인터넷 익스플로러 8과 아래아 한글과의 충돌 문제였지요,

인터넷 익스플로러 8이 설치된 PC에 아래아 한글이 설치되면 인터넷 익스플로러 8이 시작하자마자 다운되는 문제가 발생했는데 그 원인은 이미 인터넷 익스플로러 8 이 사용하는 system32폴더에 설치된 최신 버전의 jscript.dll 모듈을 아래아 한글이 사용자 PC에 설치되면서 구 버전의 jscript.dll모듈로 교체 설치를 함으로써(같은 파일명이니 덮어씌워지는 형태로 설치가 되어버린 겁니다.) 인터넷 익스플로러 8은 자신이 사용하는 jscript.dll 파일을 찾지 못해 뻗어버리게 된 것이지요.

단순히 파일 이름만으로 프로그램 자신이 참조해야 하는 모듈 또는 assembly를 찾는 건 좋은 방법이 아니라는 것이 증명된 것입니다. 그래서 CLR의 경우 정확히 자신이 참조해야 하는 assembly를 식별하기 위해서 다음과 같은 4가지 요소를 이용하여 assembly를 식별하게 됩니다.

1. 파일 이름 (확장자를 제외한)
2. 버전 번호
3. 컬쳐 (로케일)
4. 공개키 (또는 공개키를 이용하여 생성한 작은 해시값)

어떤 프로그램이 자신이 원하는 assembly를 찾을 때 저 4가지 요소가 정확히 맞아야지 해당 assembly를 자신이 찾는 assembly라고 확신하고 사용하게 된다는 말이지요. Strongly named assemblies에 해당하는 이야기입니다.

저 4가지 요소중 1, 2, 3번 요소는 굉장히 드물기는 하겠지만 다른 회사와 동일 할수도 있습니다. 하지만 4번 공개키는 공개/개인키 쌍을 만들어서 사용하는 것이니만큼 해당 assembly의 제작자가 틀리다면 같을 수가 없을 것입니다.

Strongly named assemblies가 아닌 경우는 공개키를 제외한 요소들을 manifest metadata로 가질 수 있지만 assembly를 찾을 때는 단순히 파일 이름만을 이용하여 찾게 됩니다.

자 그럼 이젠 Strongly named assemblies를 만드는 방법을 살펴보도록 합시다.

우선은 키를 생성해야 합니다. 키를 생성하기 위해 .NET Framework에서는 SN.exe 라는 툴을 제공합니다. Visual Studio Command Prompt 2010을 실행하여 다음과 같이 실행해 보면-

SN -k VSTSTeam.keys

VSTSTeam.keys 라는 파일명의 공개/개인키의 쌍을 생성하게 됩니다. 이 파일은 바이너리의 형태로 공개/개인키의 쌍을 갖고 있습니다. 우리는 공개키를 사용해야 합니다. 공개키를 확인하기 위해서는 만들어진 키 파일을 이용하여 다음과 같이 SN.exe 를 한번더 실행해야 합니다.

SN -p VSTSTeam.keys VSTSTeam.publickey

결과로 VSTSTeam.publickey 라는 파일이 생성됩니다. 이 파일은 공개키를 포함하고 있는 바이너리 파일입니다. 이 파일의 공개키를 한번 확인해 봅시다.

SN -tp VSTSTeam.publickey

그럼 다음과 같이 굉장히 긴- 공개키 값을 확인할 수 있습니다.


이렇게 공개키는 확인할 수 있지만 개인키를 확인할 수 있는 방법은 제공하지 않고 있습니다.

이렇게 생성한 키를 이용하여 assembly를 컴파일 할 때 다음과 같은 Argument를 이용하여 assembly에 공개키를 포함시키게 됩니다.

csc /keyfile:VSTSTeam.keys hello.cs

당연히 Visual Studio IDE에서도 이런 작업이 가능합니다.



Sign the assembly 라는 체크박스에 체크를 한 후 새로 key를 생성해도 되고 이미 생성된 key 파일이 있다면 해당 key파일을 이용하여 사용하면 됩니다.



참고 자료
CLR Via C# 2nd. Ed.

'CLR' 카테고리의 다른 글

7. System.Object  (0) 2010.02.16
6. Assembly - GAC(Global Assembly Cache)  (2) 2010.02.02
4. Assembly  (2) 2010.01.15
3. MSCorLib & Metadata  (4) 2010.01.06
2. CLR! CLR! CLR!  (3) 2009.12.30

[MFC] 리스타트 매니저(Restart Manager) - (2/3) : 사용하기

MFC 2010. 1. 25. 09:00 Posted by 알 수 없는 사용자
Intro
안녕하세요. MFC 카테고리의 꽃집총각 입니다.
지난번 [MFC] 리스타트 매니저(Restart Manager) - (1/3) : 기능 소개 편에 이어서 이번에는 실제로 리스타트 매니저를 사용하려면 어떻게 해야 하는가를 알아보도록 하겠습니다.


리스타트 매니저 사용하기

리스타트 매니저를 새로운 응용프로그램 프로젝트에 적용하는 방법과, 기존에 작성된 응용프로그램에 적용하는 방법에는 조금 차이가 있습니다. 하나씩 나누어서 알아보죠.

1. 새로운 프로젝트에서 리스타트 매니저 사용하기 
새 프로젝트로 MFC Application을 선택하면, MFC Application Wizard로 넘어가면서 프로젝트 설정을 하게 됩니다. 이 때 AdvancedFeatures 페이지에서 Support Restart Manager (리스타트 매니저 지원) 사항을 체크하면 됩니다.

(그림 1) 응용프로그램 마법사의 리스타트 매니저 지원 항목.


(그림 1)에서 보시는 대로 체크버튼이 세 개가 있습니다. 체크버튼의 선택 사항에 따라 지원 범위를 세가지로 선택할 수 있습니다.
  1. ① - 리스타트 매니저 지원 사항만 체크하는 경우
    이 경우 응용 프로그램은 재시작 기능만을 지원하게 됩니다. 응용 프로그램은 업그레이드나 크래시 발생 후 자동으로 재시작하는 기능이 추가되지만, 문서를 자동으로 열어주거나 복구해주는 처리는 하지 않습니다.
  2. ① + ②  - '리스타트 매니저 지원' 항목과 '이전 문서 다시열기' 항목에 체크하는 경우
    재시작 기능과 함께, 이 경우는 이전에 열려있던 문서를 다시 열어주는 기능까지 제공하지만 문서의 자동저장 버전을 복구하는 처리는 하지 않습니다.
  3. ① + ② + ③ - 싸그리 다 체크하는 경우
    자동 재시작 기능, 문서 다시 열어주기 기능, 자동 저장된 버전으로 복구하는 기능까지 모두 제공합니다.

참고 사항:

  • ② 항목을 선택하기 위해서는 반드시 ① 항목을 선택해야 하며 ( case B ), ③ 항목을 선택하기 위해서는 반드시 ② 항목을 선택해야 합니다. ( case C )
  • 다이얼로그 기반의 응용 프로그램에서는 ②, ③ 항목은 자동으로 비활성화 됩니다.

2. 기존의 프로젝트에서 리스타트 매니저 사용하기
기존의 응용프로그램에 적용하기 위해서는 CWinApp 파생 클래스의 생성자에 딱 한 줄의 코드만 추가해주면 끝입니다. (아래 코드는 각각 위에서 설명한 A, B, C 기능과 동일한 기능을 제공합니다.

  1. m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART
  2. m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART_ASPECTS
  3. m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS

사용된 플래그 상수들은 afxwin.h 파일에 정의되어 있으며, 정의된 위치를 찾아가보면 다른 플래들도 더 보이는 군요. 직접 찾아가 보시면 간단한 주석과 flag 결합 상태등을 좀 더 분명하게 확인하실 수 있습니다.

(그림 2) 소스코드에서 설정가능한 리스타트 매니저 지원 flag들 (in afxwin.h)

사실 어플리케이션 위자드에서 체크박스 항목으로 설정한 리스타트 매니저 지원사항들도 처음 기본 소스코드들을 생성해줄 때 위의 소스코드 한 줄을 선택사항에 맞춰 적절하게 적어주는 역할만을 할 뿐입니다.

(그림 3) 리스타트 매니저의 사용 설정 예시.



리스타트 매니저 사용에 대한 몇가지 팁들

팁 하나. 문서의 자동 저장 시간 간격 조절하기
CdataRecoveryHandler::SetAutosaveInterval() 함수를 사용하면 문서가 자동 저장되는 시간 간격을 조정할 수 있습니다. 기본값은 5분으로 설정되어 있습니다. CDataRecoveryHandler 클래스를 얻으려면 AfxGetApp()->GetDataRecoveryHandler()를 호출하면 됩니다.
혹은 CDataRecoveryHandler 클래스에 접근하지 않고도 바로 시간간격을 조절할 수도 있습니다. 바로 CWinApp 파생 클래스의 생성자에서 멤버변수 m_nAutosaveInterval에 값을 지정해주면 동일한 처리가 가능합니다.

(그림 4) 리스타트 매니저가 문서를 자동 저장하는 시간 간격 조절.

두가지 방법 모두 시간 단위는 밀리초로 입력합니다. 프로그램 실행 시 최초 1회만 시간설정을 하면 된다면 간단하게 CWinApp 생성자에서 설정해주면 되고, 사용자에게 설정 가능한 옵션으로 제공해 런타임에도 시간설정을 변경해야 한다면 SetAutosaveInterval() 함수를 사용하면 되겠지요.

팁 둘. 리스타트 매니저 직접 만들기(수정하기)
기본 제공되는 리스타트 매니저 만으로도 꽤나 유용한 기능을 사용할 수 있지만, 개발을 하다 보면 다른 방식의 데이터 저장 기능 등을 구현해야 할 때가 있습니다. 이런 경우에는 CWinApp::GetDataRecoveryHandler()를 오버로딩하고, CDataRecoveryHandler클래스를 상속받아 본인이 직접 구현한 CDataRecoveryHandler 파생 클래스를 붙여주면 됩니다.
참고로 윈도우 비스타 이전의 운영체제에서 이 함수가 시스템에 의해 호출되면 NULL을 리턴합니다. 앞서 말씀 드렸듯이 리스타트 매니저는 비스타 이후 OS에서만 지원됩니다. DataRecoveryHandler를 얻어내고자 하면 NULL이 반환되기 때문에, 비스타 이전 OS에서는 리스타트 매니저가 설정되지 않은 것처럼 동작하게 되지요. 그래서 리스타트 매니저를 사용하는 응용 프로그램을 비스타 이전 OS에서 구동하게 되어도 재시작 및 복구 기능만 비활성화 될 뿐, 오동작이나 다른 문제가 발생하지는 않습니다.

팁 셋. 업데이트 상황 재연하기

리스타트 매니저는 크래시가 발생한 경우 뿐만 아니라, 재실행을 필요로 하는 업데이트 진행시에도 사용할 수 있습니다. 크래시 상황을 재현하는 건 간단히 포인터 조작 오류 등을 넣어서 테스트 할 수 있고요, 인스톨러를 이용한 프로그램 업데이트 상황을 재연하고자 할 때에는 아래의 Rm...으로 시작하는 API 들을 사용해서 재현할 수 있습니다.

  • RmStartSession
  • RmRegisterResources
  • RmShutdown
  • RmRestart

이 API들은 윈도우 비스타부터 제공된 기능인 Restart Manager 를 설정 및 조작하는 함수들입니다. 응용 프로그램의 패치를 위해 윈도우즈 인스톨러 4.0 이상의 버전을 사용하는 경우는 자동으로 리스타트 매니저를 사용하게 되어 있고, 커스텀 인스톨러를 사용하는 경우도 역시 제공되는 API 함수들을 이용해 리스타트 매니저를 사용할 수 있습니다. 인스톨러에서 응용 프로그램의 종료 및 재시작을 제어하는 부분은 MFC 리스타트 매니저의 사용이라는 주제에서는 다소 벗어난 내용이므로, 본 포스팅에서는 다루지 않습니다. 보다 자세한 정보는 "메인 인스톨러에서 리스타트 매니저 사용하기(Using Restart Manager with a Primary Installer; http://msdn.microsoft.com/en-us/library/aa373681(VS.85).aspx)" 글을 참고하시기 바랍니다.
참고로 MSDN의 Restart Manager 부분을 한글 번역한 자료가 데브피아에 있습니다(http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=63&MAEULNo=24&no=11). 이것도 참고하시면 좋겠네요.


Outro
이번 포스팅에서는 MFC 응용 프로그램에서 실제로 리스타트 매니저를 사용하는 방법과 몇가지 팁들을 정리해 보았습니다. 다음 번에는 '활용하기' 편으로, 예제를 위주로 실제 사용시점에 참고할 만한 사항들을 확인해 보는 것으로 리스타트 매니저 편을 마치도록 하겠습니다.
그럼 다음 포스팅에서 또 만나기로 하고 여기서 줄이겠습니다.
감사합니다 ^^*


참고 자료 (reference)

 

[MFC] 리스타트 매니저(Restart Manager) - (1/3) : 기능 소개

MFC 2010. 1. 22. 09:00 Posted by 알 수 없는 사용자
Intro
안녕하세요. 이번에 팀블로그에 MFC 카테고리를 맡아 합류하게 된 꽃집총각 이라고 합니다.
앞으로 vs 2010에서 새롭게 선보인 MFC의 기능들을 주제로 포스팅을 하려고 합니다.
많은 관심과 격려 부탁드립니다 ^^

리스타트 매니저(Restart Manager) 의 소개
오늘은 첫 번째 포스팅으로, 응용 프로그램의 예상 못한 종료 상황에 요긴하게 사용될 기능인 리스타트 매니저(Restart Manager; 이하 한글 표기만 사용하겠습니다)에 대해 이야기 하고자 합니다.
리스타트 매니저는 윈도우 비스타 시스템에서 소개된 새로운 기능입니다. 이 기능은 응용 프로그램이 재시작을 필요로 하는 업데이트를 할 때나 처리하지 못한 exception 등으로 크래시가 발생했을 때, 데이터가 손실되지 않도록 도와줍니다. 비정상적인 종료가 발생했을 때 사용자가 이전에 작업 하면서 저장하지 못했던 데이터를 자동 저장 해주고, 응용 프로그램이 재시작 됐을 때 비정상 종료 전의 상태로 복구하는 것을 가능하게 만들어줍니다. 멋진 기능이죠!
쉽게 생각하면 이번에 인터넷 익스플로러 8의 새롭게 선보인 '세션 복구' 기능과 비슷하다고 볼 수 있습니다.

(그림 1) 인터넷 익스플로러 8.0의 세션 복구 기능.


익스플로러 버전 8 부터는 오류 등으로 인해 예상치 못한 종료가 발생하면 다음 재시작에서 위와 같은 창이 뜹니다. 세션 복구를 선택하면 종료 전에 열려있던 웹 페이지들이 다시 열리게 되죠. 이와 유사한 복구기능을 리스타트 매니저가 지원합니다. 

vs2010의 MFC를 통해 지원되는 리스타트매니저의 특징들은 간략히 아래와 같이 정리할 수 있습니다.
  1. vs2010으로 새롭게 제작되는 MFC 응용 프로그램들은 MFC 어플리케이션 위자드 (Application Wizard;응용 프로그램 마법사)를 이용해 아주 간단하게 프로그램 재시작 및 복구 기능을 사용할 수 있습니다.
  2. 리스타트 매니저 API중에서 개발자가 설정/변경 가능한 모든 부분들은 오버라이드 할 수 있는 가상멤버의 형식으로 제공됩니다.
  3. 예전에 만들어진 MFC 응용 프로그램에 기본 제공되는 리스타트 매니저의 기능을 붙이고 싶다면, vs2010으로 옮겨온 후 한 줄의 소스코드만 넣으면 됩니다!
  4. 문서파일을 다루는 응용 프로그램의 경우, 문서를 일정 주기마다 임시 파일로 자동 저장하는 기능이 추가됩니다. 자동 저장되는 주기 역시 개발자가 직접 설정할 수 있습니다. 응용 프로그램이 예외상황으로 크래시가 나는 경우, 해당 프로그램은 가장 마지막으로 백업된 임시 데이터를 복구해 새로 시작됩니다.
  5. 복구가 가능한 자동 저장된 버전의 문서가 존재하는 경우, 사용자에게 복구할 것인지를 묻는 UI 창이 기본 제공됩니다.


리스타트 매니저가 제공하는 기능들

MFC의 리스타트 메니저가 제공하는 기능은 크게 '재시작 기능'과 '복구 기능' 두 단계로 나누어 볼 수 있습니다.

1. 재시작 기능 (Restart Support) :
업그레이드나 크래시가 발생한 후 바로 재시작하는 기능. 이 기능은 모든 MFC 프로그램에서 지원됩니다. 다시말해 다이얼로그 기반이나 SDI, MDI 등의 도큐먼트-뷰 기반 등에 상관없이 MFC 프로젝트로 만든 실행파일은 모두 다 사용 가능하다는 의미입니다.

(그림 2) 크래시가 나면 해결 방법을 확인 중이라는 창이 뜹니다. 과연 뭘 하는 중일까요...

(그림 3) 그리고는 곧 '다시 시작하는 중'이라는 창이 뜨고, 프로그램은 자동 재실행 됩니다.

2. 복구 기능 (Application Recover Support) :
복구 기능은 또 다시 두 가지 기능으로 나누어 볼 수 있습니다.
  1. 종료되기 전에 열어두고 있었던 문서를 바로 다시 열어주는 기능.
  2. 자동 저장된 버전의 문서를 복구해 주는 기능.
복구 기능은 문서(Document)에 관련된 기능이니만큼, 도큐먼트-뷰 형식의 MFC 응용 프로그램에서만 사용 가능합니다. 다이얼로그 기반 프로젝트로 만든 실행파일에서는 사용할 수 없어요. 다시 정리하자면, 데이터를 복구한다는 의미는 도큐먼트-뷰 형식의 프로그램에서 Document에 해당하는 문서 데이터 부분을 대상으로 하는 말입니다. 개발자가 임의로 선언해 사용하는 (CDocument 클래스와 크게 상관이 없는) 커스텀한 데이터들은 복구 대상이 아닙니다. 
하지만 이건 기본 제공되는 리스타트 매니저에 대한 설명입니다. 추가 동작이 필요하다면 기본 기능을 확장할 수 있는 가상함수 형식의 인터페이스들을 통해 직접 기능 확장을 하면 됩니다. 또한 기본 제공 기능만으로도 문서형식의 데이터들은 손하나 대지 않아도 크게 손색이 없는 복구 기능을 붙일 수 있습니다.

(그림 4) 복구 가능한 문서가 존재할 때 사용자에게 노출되는 UI.

자동저장된 파일이 존재해 복구가 가능한 경우, 프로그램은 재실행 되자 마자 (그림 4)와 같은 대화상자를 출력합니다.


Outro
실제로 리스타트 매니저를 사용하는 방법까지 정리하면 포스팅이 너무 길어질 것 같네요. 일단은 첫 포스팅이기도 하니 가볍게 기능 소개만으로 끝을 맺고, 다음 포스팅에서는 지극히 쉽고 심플한 리스타트 매니저 사용법에 대해서 정리해 보겠습니다. 얼른 적용해 보고 싶으신 분들은 아래에 있는 참고자료 링크들을 찾아가 보세요. 정말 너무너무 쉽습니다!
그리고 리스타트 매니저는 비스타 이후의 OS에서 지원가능합니다. (비스타, 윈도우7, 윈도우 서버 2008) 그럼 리스타트 매니저를 사용하는 MFC 프로그램이 xp에서 크래시가 나면 어떻게 될까요? 자동 저장 기능은 그냥 disable만 되고 마는 것일까요? 이런 부분들도 차곡차곡 정리해서 포스팅 하도록 하겠습니다.
글 내용 중 잘못된 부분이나 부족한 부분은 댓글로 의견 주세요. 참고 반영 하겠습니다.
감사합니다 ^^*

참고자료 링크 (reference)

SharePoint 2010 Visual Web Part

SharePoint 2010 2010. 1. 21. 09:00 Posted by 알 수 없는 사용자

Visual Studio 2010에서 새롭게 제공되는 Visual Web Part를 생성해서 배포, 테스트하는 예를 알아보도록 하겠습니다.

이전버전의 웹 파트는 디자인하기가 시간이 걸리는 작업이며 AJAX 기능을 구현하려고 해도 설정과 코딩이 필요합니다. 하지만 Visual Studio 2010에서 Visual Web Part를 이용하면 얼마나 쉽게 생성할 수 있는지 알아보겠습니다.

Visual Studio 2010에서 프로젝트를 생성하면서 Empty SharePoint Project에서 새 항목을 추가하면서 Visual Web Part를 추가해도 되고 별도로 Visual Web Part 프로젝트를 통해서 생성해 됩니다.

 

Empty SharePoint Project는 해보았으니 새롭게 Visual Web Part 를 구성해보겠습니다.

프로젝트 이름은 VisualWPDemo 라고 하고 OK을 선택합니다.


SharePoint Customization Wizard에서는 OK를 선택합니다.

생성된 프로젝트의 솔루션 탐색기를 보면 새 항목으로 Visual Web Part 항목이 추가된 것을 알 수 있습니다. Visual Web Part에서는 Web Part와 항목이 동일한데 ascx ascx.cs가 들어가 있는 것을 확인할 수 있습니다.


그리고 VisualWebPart1.cs에서는 ascx 컨트롤을 CreateChildControls에서 로딩하는 것을 아래 그림에서 알 수 있습니다.


개발자들이 ascx에서 데이터바인딩과 디자인, AJAX 등에 대한 구현을 하면 일반 웹 파트와 동일하게 사용자 정의 컨트롤(ascx) Controls에 추가되어 처리됩니다.

 

자 그럼 데이터 바인딩과 AJAX를 가미해서 배포해보도록 하겠습니다.

AJAX 웹 파트를 위한 복잡한 web.config 구성 작업은 필요 없습니다.

디자인은 아래 그림에서처럼 AJAX UpdatePanel 안에 DropDownList GridView를 배치하고 GridView는 디자인을 적용했습니다.



ascx.cs
코딩은 생략하겠습니다. 일반적인 ADO.NET 이라..,

 

결과는 아래와 같습니다. 간단하게 AJAX 기능과 컨트롤의 디자인을 적용된 것을 확인 할 수 있습니다.


SharePoint 2010 개발 중에서 Visual Web Part에 대한 내용을 알아보았습니다.

일반 웹 파트 개발과 병행해서 사용하면 좋을 듯 합니다.

Welcome to Dynamic C#(13) - 아직도 가야할 길.

C# 2010. 1. 20. 09:00 Posted by 알 수 없는 사용자
- 제목이 표절인거 같은데...?

넵. 존경해 마지 않는 스캇 펙의 아직도 가야할 길을 요즘 감명깊게 읽고 있기 때문만은 아니구열. dynamic키워드로 아직도 써야 할 내용이 남아 있기 때문에, 한번 써봤습니당. 역시, 프로그래밍 언어의 현대적인 패러다임을 따라잡는 건, 단순히 사용하는 패턴만 익히는 게 아니라는 걸 다시한번 깨닫게 되네요. 그럼그럼~ 계속해서 한번 가보시져!


- 프로퍼티

d.Foo를 예로들면, d는 dynamic객체이고, Foo는 d속에 살고 있는 멤버 변수나 프로퍼티입니다. 컴파일러가 이런 구문을 만나면, 우선 Foo라는 이름을 payload속에다가 기록합니다. 그리고 런타임에게 d의 실제 타입을 찾아서 연결(바인드)해달라고 요청합니다.
payload : 캡슐화를 통해서 제공되는 컴퓨터 프로그램이나, 데이터 스트림속에서 사용자의 정보등을 나타내는 부분(출처 : http://en.wikipedia.org/wiki/Payload). 여기서는 C# 런타임 바인더가 해당 구문을 제대로 바인드하기 위해서 필요한 정보를 기록해 놓는 데이터 구조를 뜻합니당.

그리고 이런 프로퍼티는 항상 3가지경우 중 한가지경우에서 쓰이는데요. 값을 읽어오거나, 값을 대입하거나, 둘다 하거나(+=같이). 컴파일러가 사용된 모양을 보고, 어떻게 사용하려고 하는지도 payload에 같이 기록합니다. 즉, 읽기만 하는 경우에는 해당 프로퍼티는 읽기전용으로 기록을 하는 식으로 말이죠.

그리고 컴파일러는 이런 접근이 필드에 접근하는건지, 프로퍼티에 접근하는건지 딱히 구분하지 않습니다. 그건 나중에, 런타임이 구분을 하게됩니다. 그리고 컴파일할때, 이런 구문의 리턴 타입은 dynamic으로 설정됩니다.


- 인덱서

인덱서는 두가지로 생각해볼 수 있습니다. 첫번째는 매개변수가 있는 프로퍼티, 두번째는 배열이나 리스트같은 집합의 이름을 통한 메서드 호출. dynamic과 연관지어서 생각할때는 후자가 훨씬 도움이 됩니다. 메서드의 경우와 같이 인덱서도 정적으로 바운드 될 수 있지만, dynamic타입의 매개변수가 주어지고, 그 매개변수가 dynamic타입을 받는 인덱서로 정적 바운드가 되지 않는 경우, 오버로드 판별 과정에 유령이 끼어들게 됩니다. 그래서 인덱서의 수신자(receiver)는 정적타입이지만, 매개변수가 dynamic타입이라서 런타임에 늦은 바인딩이 일어나게 됩니다. 말로 설명하니깐, 깝깝하시죠? 실력부족으로 더 이상 말로는 깔끔하게 설명을 못드리겠네요-_-;; 예제로 설명을 드리면요.

public class C
{
    public int this[int i]
    {
        get
        {
            return i;
        }
    }

    public int this[dynamic d]
    {
        get
        {
            return d;
        }
    }
   
    static void Main(string[] args)
    {
        C c = new C();
        Console.WriteLine(c[5]);
        dynamic d = 7;
        Console.WriteLine(c[d]);
    }
}


위와 같은 코드를 보시면, C에 인덱서가 두개가 있습니다. 하나는 int를 매개변수로, 하나는 dynamic을 매개변수로 받죠. 그리고 Main메서드 안에서 하나는 int를, 하나는 dynamic타입의 매개변수를 넘겨주고 있습니다. 이 경우에 두번째 인덱서는 언제 어떻게 바인드될까요? 이경우는 비록 d가 타입이 dynamic이지만, 인덱서의 오버로드중에, 매개변수를 dynamic타입으로 받는 인덱서가 있습니다. 그래서 컴파일하는 시점에 "c[d]"이 인덱서 호출은 "public int this[dynamic d]"이 인덱서로 바인드 됩니다. 정적바인드가 되는거죠.

그런데, 만약에 dynamic을 받는 오버로드가 없다고 한다면 어떻게 될까요? 인덱서 호출을 받는 수신자는 c이고 c의 타입은 정적 타입인 C입니다. 하지만, 매개변수가 dynamic이죠. 그런데, dynamic과 일치하는 오버로드가 없습니다. 그래서 이때, 지지난 포스트에서 설명드렸던, 유령이 끼어들게 되는거죠.

메서드 처럼 생각하는게 편하다는 말씀은 드렸지만, 사실 프로퍼티와 유사한 면도 있습니다. 인덱서호출 역시 payload에다가 읽기, 쓰기등을 어떻게 하는지 기록합니다. 그래서 C# 런타임 바인더가 그 정보를 바탕으로 바인드할 수 있도록 말이죠. 그리고 인덱서의 리턴타입 역시 컴파일하는 시점에서는 dynamic으로 간주됩니다.


- 형변환

지지난 포스트에서 설명을 드릴때, dynamic은 다른 타입으로 암시적 형변환은 안되지만 되는 경우가 있다고 설명을 드렸었습니다. 그리고 지난 포스트에서 사실 그런 형변환이 대입 형변환이라는 설명도 드렸구요~. 형변환의 경우는 payload가 매우 단순해집니다. 왜냐면, 컴파일러는 이미 어떤 타입으로 형변환을 하려고 하는지 알고 있기 때문이죠. 그래서 컴파일러는 그냥 payload에 형변환 하려고 하는 타입을 기록하고, 런타임 바인더에게 가능한 모든 대입 형변환(형변환 연산자를 쓰는 경우에는 명시적 형변환도 같이)을 시도해보라고 이야기 해줍니다. 물론, dynamic타입이 아니라, 런타임에 결정될 실제 타입에서 목표 타입으로 시도해보겠죠.

형변환의 경우는 다른 모든 경우와 다르게 컴파일하는 시점에서 dynamic이 아닌 형변환의 목표타입을 리턴합니다. 위에서 말씀드렸듯이 이미 어떤 타입으로 형변환하려고 하는지 알 수 있게 때문이죠.


- 연산자

연산자는 초큼 특이합니다. 그냥 아무생각없이 훑어보면, 동적인 뭔가가 일어난다고 느끼기 힘들기 때문이죠. 그런데, d+1 같은 간단한 구문도 런타임에 바인드 되어야 합니다. 그 이유는 사용자정의 연산자가 끼어들 수 있기 때문입니다. 그래서, dynamic 매개변수를 갖는 모든 연산은 런타임에 바인드됩니다. +=나 -=같은 연산자도 포함해서 말이죠.

컴파일러는 연산자를 보면, d.Foo += 10 같이 멤버에 대입하는 연산이 있는지 혹은, d += 10 같이 변수에 대입하는 연산이 있는지 확인합니다. 그리고 그 과정에서 d를 ref를 통해 넘겨서 변경된 값이 유지되어야 하는지 확인합니다.

그리고 마지막으로 d.Foo += x 같은 구문이 있을 때, d.Foo가 바인드결과 delegate나 event타입이라면, 앞의 구문은 이벤트 수신자 추가 같은 적절한 메서드를 호출하도록 컴파일러가 연결해줍니다.


- 델리게이트 호출

데일게이트 호출은 메서드와 굉장히 유사합니다. 딱 한가지 틀린 점이 있다면, 호출되는 메서드의 이름이 명시되지 않는다는 것 뿐이죠. 그래서, 아래 예제의 두 호출은 모두 런타임에 바인드됩니다.

public class C
{
    static void Main(string[] args)
    {
        MyDel c = new MyDel();
        dynamic d = new MyDel();

        d();
        c(d);
    }
}


첫번째 호출은 매개변수가 없는 호출을 런타임에 바인드하게 됩니다. 런타임 바인더가 런타임에 호출의 수신자가 델리게이트 타입이 맞는지 확인하고 해당 델리게이트 시그니처와 일치하는 호출이 있는지 오버로드 판별을 통해서 찾게 됩니다.

두번째 호출은 매개변수가 dynamic타입이기 때문에, 런타임에 바인드됩니다. 컴파일러가 컴파일시점에서 c의 타입이 델리게이트라는 걸 확인할 수 있지만, 실제 오버로드 판별은 런타임에 가서 끝나게 됩니다.


- 마치면서

이제야 저는 dynamic에 대한 내용들이 머리속에서 아주 조금 자리를 잡은 듯한 느낌이네요. 저도 이런데 혼란스러웠던 지난 포스트를 보신 분들은 더 하시겠죠-_- 최대한! 최대한! 앞으로도 열심히 적겠습니다. 그럼 다음포스트에서 뵙죠~.

- 참고자료

1. http://blogs.msdn.com/samng/archive/2008/12/11/dynamic-in-c-v-indexers-operators-and-more.aspx

SharePoint 2010 Web Part 생성

SharePoint 2010 2010. 1. 19. 09:00 Posted by 알 수 없는 사용자

이전 블로그에서는 개발 환경 테스트 개념으로 간단한 Web Part를 생성해보았는데

여기서는 데이터베이스 연동과 여러 기능을 붙여 좀더 구체적으로 Web Part를 생성해보겠습니다.

 

말씀드릴 내용은 MOSS 2007에서 했던 내용과 동일한 내용입니다. Hello World는 너무 간단하여 데이터베이스 연동과 속성 노출 등을 구성해봅니다.

다음 블로그에서는 VS 2010에서의 SharePoint 지원 내용으로 Visual Web Part AJAX를 가미해서 보다 더 쉽고 강력하게 개발하는 내용을 다뤄보겠습니다.

 

완성된 모습은 아래와 같습니다. 텍스트 상자에 카테고리 ID를 입력하고 버튼을 누르면 해당 제품 이름과 가격 리스트가 표시되며 속성을 노출해서 카테고리 ID 기본값을 입력할 수 있습니다.


새로운 프로젝트를 생성합니다. SharePoint Empty 프로젝트를 선택하고 이름은 SP10WP 라고 지정합니다.



SharePoint Customization Wizard에서는 http://sp10:8090으로 선택합니다.



솔루션 탐색기에서 추가 > 새 항목> 웹 파트를 새로 추가합니다. 이름은 ProductsWP라고 합니다.


생성된 웹 파트 항목의 솔루션 탐색기 구조는 아래처럼 구성되어 있습니다.


Feature Package가 포함되어 있으며 디자이너를 통해 편집이 가능하며 향후 구체적으로 다루어 보겠습니다.

ProductsWP 폴더는 Elements.xml ProductsWP.cs, ProductsWP.webpart로 구성되어 있습니다.

Elements.xml Feature의 구체적인 파일로서 웹 파트 위치나 URL 등을 지정할 수 있습니다.

ProductsWP.webpart는 웹 파트의 메타데이터를 나타내는 파일입니다.

ProductsWP.cs 는 코딩으로 컨트롤과 데이터바인딩, 속성 등을 정의하는 파일입니다.

 

코드에서는 구체적으로 보지 말고 RenderContents, OnLoad 메서드만 보도록 하겠습니다.

해당 메서드에서는 화면에 입력 폼을 구성하고 데이터베이스 연동하여 데이터 바인딩을 해주는 내용입니다.


OnLoad 에서 컨트롤을 생성해주는 내용입니다. Web Part 항목에서는 디자이너를 제공하지 않아 직접 아래와 같이 생성해야 합니다.

속성 노출에 대한 내용은 아래와 같습니다.



위의 실제 결과는 아래 그림과 같습니다.



Hello World
보다 좀 더 발전된 웹 파트를 VS 2010 환경하에서 생성하고 테스트해보았습니다. 코드가 상당히 손이 많이 가고 디자인하기 좀 곤란한 측면이 있습니다. 하지만 어떤 경우에서는 위와 같이 생성해야 할 듯 합니다. 다음에 다룰 내용은 Visual Web Part AJAX로 더 손쉽고 강력하며 디자인이 지원되는 모습을 알아보도록 하겠습니다.

기본 WCF 프로그래밍 - 첫 WCF 서비스 만들기 2

WCF 2010. 1. 18. 10:00 Posted by 알 수 없는 사용자
요즘, 날씨가 심상치 않습니다. 세계적으로 여기저기서 한파, 폭설로 난리도 아니더군요~
몇몇의 과학자들은 지구가 예전 온도를 찾기 위한 자정작용을 하고 있는 것이라 하는데,,
어쨌든 지구가 정상이 아니란 건 사실인 것 같습니다.
설마,, 2012년에 정말 지구가 멸망하는건 아니겠죠? ^^;;;;;

WCF 세번째 이야기를 시작하겠습니다~ ^^
이번에는 지난 포스팅때 다 하지 못한 내용에 대해 이야기를 해볼까 합니다.
지난 포스팅에서는 Console 어플리케이션을 이용하여 간단한 WCF 서비스를 구현하였었죠,,
서비스를 구현하였으니, 이제 이 서비스를 이용할 수 있는 클라이언트를 구현해야 할 때입니다.

클라이언트도 Console 어플리케이션을 이용해보도록 하겠습니다. 지난번 서비스를 만들었던 같은 솔루션내에 새로운 프로젝트를 추가합니다. (새로운 솔루션을 만들어도 상관은 없습니다 ^^) 아래 그림과 같이 저는 "MyServiceClient"라는 이름의 콘솔 어플리케이션 프로젝트를 추가 하였습니다.


다음으로 클라이언트 프로젝트에 지난번 만들었던 서비스를 참조 추가해야합니다. 서비스를 참조 추가하는 방법은,, 다들 예상 했겠지만,, 아!주! 쉽습니다. ㅎ
비주얼 스튜디오 Solution Explorer의 클라이언트 프로젝트에서 마우스 오른쪽 클릭을 해주면, 다음과 같은 메뉴가 나타납니다. 여기서 "Add Service Reference"를 선택합니다.


그러면, 서비스를 참조 추가할 수 있는 창이 뜹니다. 이 창의 Address 텍스트 박스에"http://localhost:8000/ProductService" 를 입력하고, "Go" 버튼을 클릭합니다. (방금 입력한 주소는 서비스 엔드포인트 주소입니다. 기억나시죠?? ㅎ) 이렇게 하면~ 서비스를 찾는 메시지가 뜨고 얼마 뒤 다음 그림과 같이 서비스를 찾았다는 메시지가 뜨는 것을 확인할 수 있습니다.
참~!! 이때, 아주 당연한 얘기지만, 서비스가 실행 중이어야 합니다. ctrl + F5 를 눌러 서비스를 실행하는 콘솔 창을 띄워놓은 상태에서 서비스를 찾아야 합니다.


Namespace 텍스트 박스엔 "ServiceReference1"이라고 적혀있지만, 이는 개발자 마음대로 변경 가능합니다. 그래서, 저는 "MyService"라고 수정 후에 "OK" 버튼을 클릭하였습니다.

이 작업을 모두 완료하면 Solution Explorer의 모습이 다음 그림과 같이 조금 바뀌게 됩니다.


"Service Reference" 라는 폴더가 새로 생겼고, 그 밑에 방금 등록했던 "MyService"가 추가 되어있는 것을 확인할 수 있습니다.
이로써, 클라이언트에서 서비스를 사용할 준비는 거의 끝났습니다. 너무 쉬운가요? ^^ 

그렇습니다. 아주 쉽죠,, 이렇게 개발자가 쉽게 작업을 할 수 있는 건 역시 대부분의 일을 비주얼 스튜디오가 자동으로 해주는 일이 많기 때문입니다.

비주얼스튜디오가 자동으로 해주는 일은 바로, 서비스와 통신할 수 있는 proxy 클래스를 생성 해 주는 것입니다. 이는 예전 닷넷 웹서비스를 참조 했을 때, proxy 클래스를 생성해 주던 것과 아주 비슷합니다. 여기서 이에 대한 자세한 얘기는 생략하려 합니다. 저도 자동으로 생성되는 개체에 대해선 모르는 것이 많기도 하고, 여기서 이런 얘기까지 하는건 조금 초점이 빗나가는 이야기가 될 것 같기도 하거든요,,^^;;

어쨌든, 서비스와 통신을 할 수 있는 준비가 거의 끝났다는데 큰 의미가 있는 것 같습니다. ㅎㅎ

아ㅡ 본격적으로 서비스를 이용하기 전에 한가지 더 얘기를 하고 넘어가야할 것이 있습니다.
비주얼스튜디오에서 쉽게 서비스를 참조 추가할 수 있었던 또 다른 이유,, 바로 Metadata Exchange Endpoint 입니다.

WCF의 Metadata라 함은, WCF 서비스와 통신하는 방식을 설명한 것이라고 간단하게 생각하시면 됩니다. 그러면 MEX(Metadata Exchange Endpoint) 가 무엇인지 대충 감이 오시나요?

네,, 추측하신대로 이러한 메타데이터를 교환하기 위한 엔드포인트를 말합니다. 클라이언트에서 이 MEX로 요청 메시지(request message)를 보내면, MEX 에서는 서비스가 가지고 있는 엔드포인트에 대한 내용과 메시지의 포맷에 대한 내용을 WSDL 형태로 클라이언트에 전송해 주는 것입니다.

비주얼 스튜디오에서 "서비스 참조 추가"를 실행하였을 때, 프록시 클래스와 config 파일을 생성해 주는 것은 모두 MEX에서 보내준 WSDL을 이용한 것이죠~

MEX에 대해서까지 설명을 들으니, 클라이언트와 서비스가 통신하는 방법에 대한 그림이 대충 그려지지 않으시나요?ㅎ

그럼, MEX를 정의하지 않으면 WCF 서비스와 통신하지 못할까요?

꼭 그렇지만은 않습니다. 물론, 비주얼 스튜디오에서 지원해주는 "서비스 참조 추가"를 이용하진 못합니다.
하지만, svcutil.exe 라는 명령어를 이용하여 프록시 클래스를 생성해 줄 수 있고, 이를 통해 서비스와 통신할 수 있습니다. 이 명령어에 대해서도 정리할 수 있는 시간을 가질 예정이지만, 지금 당장은 그렇게 자세히 알 필요는 없을 듯 합니다. 우리에겐 Visual Studio 라는 훌륭한 툴이 있으니깐요~ ㅎ 
(개발자는 너무 툴에 종속적이면 좋지 않다 생각하고는 있지만,,, ^^;;;)

이제, 드디어,, 서비스에 정의 되어 있는 메소드를 호출하고 사용해 볼 시간이 왔습니다.

using MyServiceClient.MyService;

namespace MyServiceClient
{
    class Program
    {
        static void Main(string[] args)
        {
            ProductServiceClient proxy = new ProductServiceClient();
            string strResult = proxy.GetFirstName("WCF");

            Console.WriteLine(strResult);
        }
    }
}

위의 코드는 클라이언트 Console 어플리케이션의 Program.cs 파일 내용입니다.

using 구문을 이용하여 포함시킨 MyServiceClient.MyService 네임스페이스는 비주얼 스튜디오에 의해 생성된 프록시 클래스의 네임스페이스입니다.
이 네임스페이스에서 상위 네임스페이스는 서비스에 정의 된 네임스페이스에 "Client"가 붙은 형태로 생성되며, 하위 네임스페이스는 서비스 참조 추가를 할 때 입력하여 준 것과 동일한 형태로 생성되어 집니다.

그리고, ProductServiceClient 클래스는 비주얼 스튜디오에 의해 생성된 프록시 클래스 입니다. 이 클래스를 이용하면 서비스에 정의되어 있는 메소드들을 클라이언트에서 맘껏 사용할 수 있게 되는 것입니다. 아래와 같은 방식으로 말이죠~ ^^
string strResult = proxy.GetFirstName("WCF");

이로써, 클라이언트에 작성할 것도 모두 다 했습니다.

그럼, 실행을 한번 시켜 보도록 하죠~

현재, 솔루션에서 서비스 프로젝트와 클라이언트 프로젝트가 모두 동작해야 되기 때문에 솔루션의 속성을 조금 변경할 필요가 있습니다. 
아래 그림에서 볼 수 있듯이, 솔루션 속성 창에서 "Multiple startup projects"를 선택하고 두 개의 프로젝트 모두 "Start" 하도록 값을 변경하여 줍니다.


이제 실행만 하면 됩니다. 과감하게~ F5 키를 눌러 실행을 시켜 보죠~
아래와 같은 화면이 나타납니다. 두둥~~!!


결과 화면을 보고 실망하셨나요?? ^^;;
지금까지, 길~게 설명한 것에 비하면 결과는 아주 보잘것 없습니다. 하지만, 실망(?)하지 마시기 바랍니다 ^^;
처음부터 이 서비스는 아주 아주 간단한 서비스라고 말씀 드렸었고, 이 간단한 서비스를 이용해 우리는 WCF 에 대한 큰 그림을 그릴 수 있었으니깐, 결코 실망스러운 결과는 아닙니다.

이렇게 해서 WCF의 기초에 대해선 모두 끝이 났습니다.
글을 이용하지 않고, 옆에서 말로 설명을 했다면, 금방 끝날 수 있는 내용을 두 개의 포스팅에 걸쳐 설명을 했습니다. 
이렇게 하고 나니, 글을 이용해 정보를 전달한다는 것이 결코 쉬운 일이 아니란 것을 새롭게 깨닫게 되면서, 파워 블로거분들이 존경 스러워 지네요 ^^

포스팅을 시작한지 얼마되지 않아 많이 부족하지만, 꾸준히 하다보면 저도 다른 분들처럼 멋진 글을 쓸 수 있는 날이 오겠죠~ㅎㅎ 그때까지 포기하지 않고 열심히 하겠습니다 ^^

그럼, 다음 포스팅때 뵙겠습니다~

Visual Studio 2010 출시 일정

Visual Studio 2010 2010. 1. 18. 09:30 Posted by POWERUMC

오늘 Visual Studio 2010 출시 일정이 나왔습니다. Rob Caron 말에 의하면 2010년 4월 12일에 출시가 된다고 합니다. Microsoft 직원이 전하는 이야기이니 아마도 이 날에 출시하는 것을 신뢰하시면 될 것 같습니다.

Rob Caron 은 Microsoft 에서 마케팅 커뮤니케이션 매니저로 일하고 있으며, Developer, User Experience Runtime, Tools 과 관련된 일을 하고 있는 분입니다. Microsoft 에 입사 하기 전에 개발자 출신인데, Microsoft 에서 이전에는 개발자 마케팅과 MSDN 개발자 센터, Visual Studio 마케팅 사이트, 개발자 이벤트, MSDN Library 에 콘텐트를 게시하는 일도 하셨다고 합니다.

  

좀 아쉬운 것은 현재 문제나 개선되고 있는 부분을 좀 더 자세히 알고 싶은데, 출시 일정 외에 다른 언급은 전혀 없네요.   

Visual Studio 2010 의 처음 출시 일정은 2010년 1월에 RC 버전, 3월에 정식 버전을 출시하기로 예정하였습니다. 그러나 가상 메모리 관련, 성능 최적화 문제로 정확한 출시 일정을 공개하지 않고 출시 기간을 연장하였습니다. 일정이 연기된 것은 개인적으로 아쉽지만, 보다 충실한 플랫폼을 만들기 위해서라면 충분히 기다릴만 하다고 생각합니다. 써본 후에 투덜댈봐엔 좀 더 완성도 높은 플랫픔을 위한 것이라면 말이죠^^ 

언제나 언급했던 이야기 이지만, 예전의 Visual Studio 2008 까지는 기능에 충실했던 강력한 개발 도구임이 틀림이 없습니다. 하지만 Visual Studio 2010 과 관련된 플랫폼은 기능은 기대 이상 완벽히 충실하고 있으며, 편의성까지 갖추게 될 그야말로 차세대 플랫폼입니다. 앞으로 다가올 4월이 정말 기대가 됩니다.

Welcome to Dynamic C#(12) - dynamic은 외로운 아이.

C# 2010. 1. 18. 09:00 Posted by 알 수 없는 사용자

- 뭐시 외로운 아이여? 스타아닌겨?

네. 확실히 C# 4.0의 가장 큰 키워드는 Dynamic이기 때문에, dynamic은 스타일지도 모르겠습니다. 하지만, 화려한 모습뒤에 감쳐진 그들의 일상사는 때때로 자살같은 비극적인 사건을 통해서 세간에 알려지곤 하죠. 그럴때마다 세삼스럽게 사람들은 화려한 일상뒤의 모습은 변비때문에 우울해하는 것 같이, 보통사람과 전혀 다르지 않음을 재확인 합니다..... 왜 이런 헛소리를 또 하고 있을까요-_-;;; 아무튼. dynamic은 초큼 외로운 아이입니다. 증거를 제시해드리죠.



그림1. 출처 : http://blogs.msdn.com/cburrows/archive/2008/11/06/c-dynamic-part-iv.aspx

네. 다른 타입들은 System.Object로 부터 아주 사이좋게 이리저리 연결되어 있습니다만, dynamic은 천상천하유아독존입니다. 그저 혼자 있을 뿐이지요. 어린이집에서도 유별난 애들은 꼭 걔네들 기분에 잘 맞춰줘야 해서 선생님들이 고생을 하기도 하는데요. dynamic역시 독특한 면을 갖고 있습니다. 지난 포스트에 이어서 dynamic의 형변환 룰에 대해서 알아보면 아래와 같습니다.

1. dynamic에서 dynamic으로 동일한 형변환이 가능
2. 모든 참조형 타입에서 dynamic으로 암시적인 참조형변환이 가능
3. 모든 값형 타입에서 dynamic으로 암시적인 박싱형변환이 가능
4. dynamic에서 모든 참조형 타입으로 명시적인 참조형변환이 가능
5. dynamic에서 모든 값형 타입으로 명시적인 언박싱 형변환이 가능
리스트1. dynamic에서 다른 타입으로 형변환 가능여부.

  아래부분에 줄로 그어 버린 부분은 정식버전이 출시되면서 개념이 바뀐 부분들입니다. 그리고 밑에서 설명드리는 '대입형변환'이라는 용어도 여전히 의미가 있는지 불분명합니다. 다만, C# 4.0 명세서에 보면 '대입형변환'이라는 개념이 없는 걸로 봐서는 설명을 위해서 도입한 개념이 아닌가 싶은데요, 이에 관해서 Chris Burrows에게 질문을 남겨놨는데요, 답이 오면 바로 업데이트 하겠습니다. 바뀐 내용에 대해서는 이 글을 참조하시기 바랍니다.

매우 직관적으로 보이긴 하지만, 좀 생각해보면 이상한 점들이 발견됩니다. 그 첫번째가 바로 dynamic에서 object로 암시적인 형변환이 없다는 사실인데요. 위에서 1, 4번에서 언급했듯이 dynamic에서 dynamic을 제외한 모든 참조형타입으로 암시적인 형변환이 없다고 하고 있습니다. 그 이유는 연산을 하는 도중에 둘을 구분해내기가 매우 어렵기 때문이라고 합니다. 근데, 아래와 같은 코드가 컴파일 되고 실행되는 걸 확인할 수 있습니다.

dynamic d = null;
object o = d;

이건 분명히 암시적 형변환 처럼 보이는데, 왜 이게 컴파일이 되는 걸까요? 사실, 두번째줄은 암시적 형변환이 아니라 대입 형변환입니다. 대입 형변환은 또 뭘까요?

그림 2. 출처 : http://blogs.msdn.com/cburrows/archive/2008/11/11/c-dynamic-part-v.aspx

위 그림을 보시면, 형변환이 총 3가지로 분류가 되는 걸 확인하실 수 있습니다. 대입 형변환은 명시적 형변환과 암시적 형변환의 사이에 위치해 있는데요. 모든 대입 형변환은 사실 명시적 형변환이며, 모든 암시적 형변환은 대입 형변환 인거죠. 왜 이런 걸 새로 도입했어야 할까요? 사실 C# 4.0작업을 하면서 dynamic에서 다른 타입으로 암시적 형변환 도입을 검토했었다고 합니다. 그런데, 이렇게 하게 되면 문제가 생기는데요. 바로, dynamic을 통해서 아무타입에서 아무타입으로 형변환이 가능하기 때문입니다. 이 문제를 오버로드 판별을 예로 들어서 설명해보겠습니다.

public class C
{
    public static void M(int i){}

    public static void M(string s){}
   
    static void Main(string[] args)
    {
        dynamic d = GetSomeDynamic();
        C.M(d);
    }
}

코드1. 만약 암시적 형변환이 가능하다면?

위와 같은 코드가 있다고 할때요, 과연 어떤 메서드가 실행되어야 할까요? dynamic에서 모든 타입으로 암시적 형변환이 있다면, dynamic에서 int도 dynamic에서 string도 가능한 상황이 됩니다. 물론, dynamic에서 object같이 dynamic에서 int보다 더 나은 걸 찾을 수도 있겠지만, 그렇지 않은 경우가 훨씬 많이 발생하게 됩니다. 이런 모호함 때문에 dynamic에서 다른 타입으로 형변환을 할때는 명시적으로 선언을 하게 제한을 둔 거죠.

그렇다면, 대입 형변환은 또 뭘까요?

1. dynamic에서 모든 참조형 타입으로 대입 참조 형변환이 가능
2. dynamic에서 모든 값형 타입으로 대입 언박싱 형변환이 가능
리스트2. 대입 형변환의 설명

[리스트1]에서 4,5번을 보면 명시적 형변환에 대해서 이야기 하고 있죠? 사실은 그 명시적 형변환이 바로 이 대입 형변환을 말하는 겁니다. 모든 대입 형변환은 명시적 형변환이라고 말씀드렸던 걸 떠올리시면 고개가 절로 끄덕끄덕....교회 다니시는 분들은 교회로 끄덕끄덕 하실겁니다. 그리고 리스트2의 모든 형변환과 암시적 형변환을 모두 합하면 바로 대입 형변환이 되는 거죠.


- 그래그래 어디 계속 해봐.

대입이 일어나는 곳이 바로 컴파일러가 대입 형변환을 시전하는 곳입니다.

dynamic d = GetSomeDynamic();
Worksheet ws = d; //대입 형변환

이거 말고도, 대입 비스무리한 것들은 모두 대입 형변환을 사용합니다. return과 yield 그리고 프로퍼티와 인덱서, 배열 초기화구문, 그리고 foreach나 using같은 구문말이죠.

return d; //return할 타입으로 대입 형변환
yield return d; //반복자의 타입으로 대입 형변환
foo.Prop; //Prop의 타입으로 대입 형변환
foo[1] = d; //인덱서의 타입으로 대입 형변환
bool[] ba = new bool[] { true, d }; //bool로 대입 형변환
foreach(var x in d) {} //IEnumerable로 대입 형변환
using (d) {} //IDisposable로 대입 형변환
리스트3. 대입 형변환이 어디어디서 끼어드는지!

하지만, 이런 대입 형변환을 사용하지 않는 곳 중에 하나가 오버로드 판별입니다. [코드1]에서 보셨듯이 만약에 메서드를 호출하는데 대입 형변환을 적용하게 되면, 매번 메서드를 호출할때마다 모호함때문에 캐고생을 하게 될겁니다. 하지만, 대입 형변환을 적용하지 않는다고 해도, [코드1]은 제대로 컴파일 되지 않을거 같습니다. 왜냐면, d의 타입인 dynamic에서 C의 두 오버로드가 받는 파라미터 타입인 int와 string으로 형변환이 불가능 하기 때문입니다. 하지만, 이런 코드가 컴파일 되고 잘 돌아가야만 하니깐, 바로 지난 포스트에서 언급했던 유령 메서드가 끼어들게 되는거죠.


- 마치면서

어찌 퍼즐 조각이 좀 맞아 들어가시나요? 저도 글을 쓰면서 다시한번 자세히 읽다보니 퍼즐조각이 조금씩 맞아들어가는 느낌이 드는데요. 꼭 무슨 그것이 알고싶다에서 사건 조사하는 거 같은 기분이네요-_-. 그럼 다음 포스트에서 뵙져!!!


- 참고자료

1. http://blogs.msdn.com/cburrows/archive/2008/11/06/c-dynamic-part-iv.aspx
2. http://blogs.msdn.com/cburrows/archive/2008/11/11/c-dynamic-part-v.aspx