Share via


.NET의 엔터프라이즈 서비스(COM+) 이해

 

섀넌 팔
Microsoft Corporation

2002년 4월

요약: Microsoft .NET 및 COM+ 서비스의 통합에 대한 기술 세부 정보를 제공하고 관리 코드에 사용할 수 있는 서비스에 대해 설명합니다. (26페이지 인쇄)

콘텐츠

소개
트랜잭션
배포
서비스된 구성 요소
개체 수명
보안
원격 구성 요소
결론

소개

이 문서에서는 Microsoft®.NET Framework 및 COM+ 서비스에 대해 잘 알고 있어야 합니다. Enterprise Services에 대한 친숙함은 필요하지 않지만 도움이 될 것입니다. 이러한 topics 대한 좋은 배경 지식은 다음을 참조하세요.

COM은 구성 요소 기반 애플리케이션을 작성하는 한 가지 방법을 제공합니다. COM 구성 요소를 작성하는 데 필요한 배관 작업은 중요하고 반복적인 것으로 잘 알려져 있습니다. COM+는 새 버전의 COM에 대해 그다지 많지 않습니다. 대신 COM+는 구성 요소에 대한 서비스 인프라를 제공합니다. 구성 요소는 배포의 용이성으로 높은 처리량을 달성하는 확장 가능한 서버 애플리케이션을 빌드하기 위해 COM+ 애플리케이션에 빌드된 다음 설치됩니다. (구성 요소가 서비스를 사용할 필요가 없는 경우 COM+ 애플리케이션에 배치하면 안 됩니다.) 확장성 및 처리량은 트랜잭션, 개체 풀링 및 활동 의미 체계와 같은 서비스를 사용하도록 처음부터 애플리케이션을 설계하여 달성됩니다.

이 .NET Framework 구성 요소 기반 애플리케이션을 작성하는 또 다른 방법을 제공하며, 더 나은 도구 지원, CLR(공용 언어 런타임) 및 훨씬 더 쉬운 코딩 구문의 COM 프로그래밍 모델에 비해 이점이 있습니다. COM+ 서비스 인프라는 관리 코드 및 관리되지 않는 코드에서 액세스할 수 있습니다. 관리되지 않는 코드의 서비스를 COM+ 서비스라고 합니다. .NET에서 이러한 서비스를 Enterprise Services라고 합니다. ServicedComponent에서 클래스를 파생하면 구성 요소에 서비스가 필요합니다. (구성 요소가 서비스를 사용할 필요가 없는 경우 ServicedComponent에서 파생되어서는 안 됩니다.) 프로그래머가 서버 기반 애플리케이션을 작성할 수 있도록 도구 지원이 개선되었지만 확장성 및 처리량과 동일한 문제는 여전히 좋은 프로그래밍 방식의 영역에 있습니다. 서비스의 기본 개념은처음부터 처리량 및 확장성을 위해 design이고 Enterprise Services를 활용하여 적절한 경우 이러한 디자인 패턴을 쉽게 구현하는 것입니다.

서비스 인프라 디자인은 실제로 COM 또는 구성 요소와는 거의 관련이 없다고 주장할 수 있습니다. COM+ 서비스는 이제 COM 구성 요소, .NET 구성 요소, ASP 페이지 또는 임의 코드 블록과 같이 구성 요소로 간주되지 않는 다른 엔터티에도 적용할 수 있습니다(Microsoft Windows® XP의 구성 요소 COM+ 기능이 없는 서비스 참조).

현재 사용할 수 있는 모든 COM+ 서비스는 .NET 및 COM 개체에서 사용할 수 있습니다. 이러한 서비스 중 일부는 트랜잭션, 개체 풀링 및 생성 문자열, JIT, 동기화, 역할 기반 보안, CRM 및 BYOT를 포함합니다. Microsoft Windows 2000의 전체 서비스 목록은 플랫폼 SDK에서 COM+에서 제공하는 서비스를 참조하세요. Microsoft Windows XP에는 .NET 구성 요소와 함께 사용할 수 있는 추가 서비스가 있는 COM+ 1.5라는 새 버전의 COM+가 포함되어 있습니다.

트랜잭션

서비스를 사용하는 관리되는 애플리케이션을 작성하려면 서비스가 필요한 클래스가 ServicedComponent에서 파생되고 다양한 사용자 지정 특성을 사용하여 필요한 실제 서비스를 지정해야 합니다. 이 섹션에서는 이러한 개념과 이러한 개념이 관리 코드 작성에 미치는 영향을 소개합니다. 자세한 설명은 이후 섹션에서 제공합니다.

클래스 계정이 작성되었고(실제 코드는 나중에 나열됨) BankComponent 어셈블리에 있다고 가정합니다. 이 클래스는 다음과 같이 사용할 수 있습니다.

BankComponent 클라이언트

using system;
using BankComponent;
namespace BankComponentClient
{
      class Client
      {
        public static int Main() 
        {
          Account act = new Account();
          act.Post(5, 100);
          act.Dispose();
          return 0;
        }
      }
}

클라이언트를 빌드하려면 BankComponent 네임스페이스에 참조를 추가해야 합니다. 또한 System.EnterpriseServices 어셈블리에 대한 참조를 추가해야 합니다. BankComponentClient 네임스페이스에서 클라이언트는 BankComponent를 포함하는 어셈블리가 아닌 System.EnterpriseServices에 정의된 메서드인 Dispose() 및 ServicedComponent 생성자를 호출합니다. 파생 클래스가 모든 기본 클래스 메서드를 재정의하지 않는 경우 일반적인 .NET 요구 사항입니다.

BankComponent 서버 코드는 트랜잭션을 사용하는 .NET에서 계정 클래스의 구현을 보여 줍니다. 클래스 계정은System.EnterpriseServices.ServicedComponent 클래스에서 파생됩니다. Transaction 특성은 클래스를 트랜잭션이 필요한 것으로 표시합니다. Transaction 특성이 사용되므로 동기화 및 JIT 서비스가 자동으로 구성됩니다. AutoComplete 특성은 메서드를 실행하는 동안 처리되지 않은 예외가 throw된 경우 런타임이 트랜잭션에 대해 SetAbort 함수를 자동으로 호출하도록 지정하는 데 사용됩니다. 그렇지 않으면 SetComplete 함수가 호출됩니다. ApplicationName 특성은 이 어셈블리를 이 애플리케이션의 서비스 구성 데이터를 저장하는 COM+ 애플리케이션과 연결합니다. 이 클래스에 필요한 추가 수정 내용은 코드에서 강조 표시됩니다.

BankComponent 서버

using System.EnterpriseServices;
[assembly: ApplicationName("BankComponent")]
[assembly: AssemblyKeyFileAttribute("Demos.snk")]

namespace BankComponentServer
{
      [Transaction(TransactionOption.Required)]
      public class Account : ServicedComponent
      {
            [AutoComplete]
            public bool Post(int accountNum, double amount)
            {
            // Updates the database, no need to call SetComplete.
            // Calls SetComplete automatically if no exception is thrown.
            }
      }
}

BankComponent Server 네임스페이스의 코드는 .NET에서 COM+ 서비스를 사용하는 것이 얼마나 쉬운지를 보여 줍니다. 코딩에서 배포까지의 전체 프로세스에 대한 요약은 다음과 같습니다.

  1. 서버 어셈블리를 작성합니다.

  2. 어셈블리를 빌드합니다.

    1. 어셈블리에 서명 합니다. 프로젝트에 대해 키 파일을 한 번 생성할 수 있습니다. 각 컴파일에 대해 하나를 생성할 필요는 없습니다. Microsoft .NET 명령 프롬프트를 사용하여 키를 만들고 다음을 sn.exe.

      sn –k Demos.snk
      
    2. 코드를 컴파일합니다. System.EnterpriseServices에 대한 참조를 추가해야 합니다.

  3. 애플리케이션을 배포합니다.

    서비스된 구성 요소를 사용하는 어셈블리는 COM+ 카탈로그에 등록해야 합니다. ServicedComponent 클래스 및 사용자 지정 특성은 관리 코드에서 COM+ 서비스에 액세스하기 위한 두 가지 주요 개념입니다. 서비스의 구성은 COM+ 카탈로그에 저장됩니다. 개체가 상주하고 CLR 내에서 실행됩니다. 관리되는 개체 및 관련 COM+ 컨텍스트는 그림 1에 설명되어 있으며 다음 두 섹션에서 더 명확해집니다.

    그림 1. 관리되는 구성 요소와 연결된 서비스

    COM+ 구성 요소를 사용하면 카탈로그를 수동으로 구성해야 하지만 서비스 구성 요소를 사용하면 코드의 특성에 따라 카탈로그를 업데이트할 수 있습니다. 명령줄 도구 regsvcs.exe 사용하거나 관리되는 API에 액세스하는 스크립트를 작성하여 어셈블리를 명시적으로 등록할 수 있습니다. 자세한 내용은 아래 배포 세부 정보 섹션에 나와 있습니다. 개발 중에 어셈블리를 애플리케이션 디렉터리에 복사하기만 하면 XCopy 배포가 편리하게 제공됩니다. 클라이언트 애플리케이션이 ServicedComponent에서 파생된 클래스의 인스턴스를 만들 때마다 런타임은 COM+ 애플리케이션에 어셈블리를 이미 등록했는지 여부를 검색합니다. 등록되지 않은 경우 로컬 디렉터리가 어셈블리를 검색하고 있는 경우 어셈블리의 모든 서비스 구성 요소가 COM+ 애플리케이션에 등록되고 활성화를 진행할 수 있습니다. 이를 지연 등록이라고 하지만 모든 시나리오에서 작동하지는 않습니다. instance 경우 COM+ 서버 앱으로 표시된 어셈블리에는 명시적 등록이 필요하며(아래 참조), 관리되는 서비스 구성 요소를 호출하는 관리되지 않는 클라이언트에는 지연 등록이 작동하지 않습니다. 지연 등록은 개발 중에 유용하며, 그렇지 않으면 스크립트, 코드 또는 RegSvcs를 사용하여 어셈블리를 등록합니다.

  4. GAC에 어셈블리를 배치할 수 있습니다. 자세한 내용은 배포 섹션을 참조하세요.

  5. 클라이언트를 실행합니다.

배포

사용자 지정 특성은 관리 코드에서 COM+ 서비스에 액세스하는 두 가지 주요 개념 중 하나입니다. 사용자 지정 특성은 이전 코드 목록의 트랜잭션 사용자 지정 특성과 같이 필요한 서비스를 지정하는 데 사용됩니다. 이러한 특성은 어셈블리 메타데이터에 서비스에 대한 구성 옵션을 저장합니다. 사용자 지정 특성은 일부 코드가 어셈블리를 로드하고 리플렉션을 사용하여 특성의 인스턴스를 만들고 특성에 메서드를 호출하여 특성에 저장된 서비스 구성을 추출하는 데 사용됩니다. 그런 다음 COM+ 카탈로그에 정보를 쓸 수 있습니다. 이러한 및 기타 단계를 수행하는 코드는 EnterpriseServices.RegistrationHelper 에 포함되어 있습니다. 등록 프로세스를 더 쉽게 만들기 위해 모든 형태의 등록은 EnterpriseServices.RegistrationHelper 구성 요소를 사용합니다. 이 구성 요소는 COM 개체뿐만 아니라 관리되는 클래스로 액세스할 수 있습니다.

그림 2. 서비스된 구성 요소 등록

개념적으로 RegistrationHelper는 다음 단계를 수행합니다.

  • RegistrationServices.RegisterAssembly를 사용하여 레지스트리에 어셈블리를 등록합니다. 따라서 클래스는 레지스트리에 관리 코드로 작성된 COM 구성 요소로 표시되고 InprocServer32 키가 mscoree.dll 가리킵니다. 관리되는 클래스가 인터페이스를 구현하지 않으면 ClassInterfaceAttribute를 사용하지 않는 한 클래스의 공용 메서드가 COM+ 카탈로그에 표시되지 않습니다. 즉, 메서드 수준과 연결된 서비스 구성을 카탈로그에 저장할 수 없습니다. 그러나 일부 COM+ 서비스는 메서드 수준에서 구성할 수 있으며 구성 요소가 COM+ 카탈로그에 표시된 대로 인터페이스를 노출하도록 요구할 수 있습니다. 예를 들어 메서드 수준에서 COM+ 역할 기반 보안을 사용하려면 구성 요소가 서비스를 구성하기 위해 인터페이스를 구현해야 합니다. 이 문제에 대한 자세한 내용은 보안 섹션에서 설명합니다.
  • TypeLibConverter를 사용하여 어셈블리에서 COM 형식 라이브러리를 생성합니다. ConvertAssemblyToTypeLib.
  • 형식 라이브러리를 등록합니다. 지금까지 이것은 RegAsm.exe /tlb와 매우 동일합니다.
  • COM+ 애플리케이션을 찾거나 만듭니다. 이름은 ApplicationName 특성, 어셈블리 이름 또는 제공된 애플리케이션 이름/GUID에서 추출됩니다.
  • 형식 라이브러리를 사용하여 COM+ 관리자 API를 사용하여 COM+ 애플리케이션을 구성합니다.
  • 모든 사용자 지정 특성을 살펴보고 IConfigurationAttribute를 사용하여 특정 서비스에 대한 구성 데이터를 COM+ 카탈로그에 씁니다.

RegistrationHelper는 .NET이 설치될 때 생성되는 COM+ 애플리케이션 내의 클래스인 RegistrationHelperTx를 사용하여 트랜잭션 내에서 이러한 단계를 수행하려고 시도합니다. 따라서 등록에 실패하면 COM+ 카탈로그 및 레지스트리가 원래 상태로 복원됩니다. 그러나 현재 생성된 형식 라이브러리는 디스크(또는 어셈블리가 GAC에 있는 경우 GAC)에 유지됩니다. 등록된 어셈블리가 COM+ 서비스를 사용하는 다른 어셈블리를 참조하는 경우 종속성 그래프 모든 어셈블리는 위에 나열된 것과 동일한 단계를 거칩니다.

RegistrationHelper는 COM+ 카탈로그에 액세스하므로 머신에 대한 관리되지 않는 코드 권한 및 관리자 권한이 필요합니다. 따라서 클라이언트가 RegistrationHelper에 대해 즉 지연 등록, RegSvcs 또는 스크립트/코드와 같은 경우도 마찬가지입니다. 이는 인터넷에서 다운로드하거나 네트워크 공유에 저장된 코드를 등록할 수 없음을 의미합니다.

트랜잭션 요구 및 동기화를 사용 안 함으로 설정하는 등 호환되지 않는 특성 조합을 코딩할 수 있습니다. 이러한 조합은 현재 컴파일 시간이 아닌 COM+ 카탈로그에 쓸 때 등록 시간 동안 검색됩니다. 일부 특성은 다른 특성에 대한 암시적 종속성을 가지며, instance 트랜잭션 특성만 사용하는 경우 Transaction, JustInTimeActivation 및 Synchronization 특성을 사용하는 것과 같습니다. 관리되는 구성 요소가 등록되면 특성이 '구성되지 않은' 기본값을 덮어쓰는 데 사용되지 않는 한 COM+ 카탈로그 기본값이 사용됩니다. instance 구성 요소가 등록되어 있고 Transaction 특성이 지정되지 않은 경우 카탈로그의 트랜잭션 설정에 대해 구성되지 않은 기본값이 TransactionOption.Disabled로 설정됩니다. 이 방법을 사용하면 구성 요소가 더 이상 필요하지 않은 경우 개발자가 코드에서 특성을 제거한 다음 어셈블리가 다시 등록되면 트랜잭션에 대한 카탈로그 항목이 적절하게 다시 설정됩니다. 이러한 구성되지 않은 기본값에 대한 자세한 목록은 온라인 설명서에 지정되어 있습니다. 기본 구성 값은 특성 매개 변수의 기본값입니다. instance 경우 [Transaction] 특성만 사용하면 TransactionOption.Required가 표시됩니다.

관리되는 클래스의 서비스에 대한 구성 데이터는 COM+ 카탈로그에 저장되므로 어셈블리를 등록한 후 특정 카탈로그 항목이 관리적으로 수정될 수도 있습니다. 일부 서비스는 이러한 방식으로 수정해서는 안 됩니다. instance 경우 카탈로그에서 트랜잭션 서비스를 사용하지 않도록 설정하면 코드가 잘못 작동할 수 있습니다. 등록 후 개체 생성 문자열 및 보안 역할과 같은 배포 관련 설정을 조작할 수 있습니다. 등록 후 설정을 만들 때 서비스 구성 요소가 포함된 어셈블리의 XCopy 배포로는 충분하지 않을 수 있습니다. COM+ 애플리케이션 가져오기 및 내보내기 기능은 애플리케이션의 현재 상태를 배포하는 데 도움이 됩니다. 가져오기 및 내보내기에 대한 자세한 내용은 원격 섹션에서 제공합니다.

경우에 따라 카탈로그는 구성 데이터에 대해 참조되지 않지만 어셈블리 메타데이터에서만 추출됩니다. 사례는 자동 완성, JIT, 개체 풀링(카탈로그에서 풀 크기가 추출되지만) 및 보안 메서드 특성에 대한 것입니다. 이 문제에 대한 자세한 내용은 해당 서비스를 설명하는 섹션에서 설명합니다.

어셈블리를 등록하는 프로세스는 COM+에 필요한 GUID를 자동으로 생성합니다. 어셈블리가 서명되지 않은 경우 GUID는 형식 및 네임스페이스 이름에 따라 생성됩니다. 따라서 어셈블리가 서명되지 않은 경우 고유하지 않은 GUID를 생성할 수 있습니다. COM+ 서비스를 사용하지 않지만 고유한 형식 이름이 필요한 .NET 어셈블리에도 비슷한 운명이 적용됩니다. 따라서COM+ 서비스를 사용하는 ssemblies에 서명해야 합니다. 어셈블리가 서명되지 않은 경우 등록이 실패합니다. 또한 등록은 COM+ 서비스를 사용하는 .NET 클래스에 하나의 전역 구성 데이터 저장소가 있음을 의미합니다. 프라이빗 어셈블리를 여러 애플리케이션 디렉터리에 복사할 수 있지만 이러한 모든 애플리케이션은 궁극적으로 서비스된 구성 요소에 대한 하나의 구성 데이터를 참조합니다. 따라서 COM+ 카탈로그에서 구성 데이터를 변경하면 클래스를 사용하는 모든 애플리케이션에 영향을 줍니다. 이는 서비스된 구성 요소를 사용하는 동일한 어셈블리의 복사본을 구성하는 Microsoft ASP.NET 구성의 여러 vroot에서 분명하게 드러납니다. 동일한 COM+ 애플리케이션에 대해 여러 구성을 사용하는 한 가지 방법은 Microsoft Windows .NET에서 COM+ 파티션을 사용하는 것입니다. .NET에서 COM+ 파티션 서비스를 사용하려면 ApplicationID 특성을 사용하지 마세요. 동일한 구성 요소를 여러 파티션에 설치하려면 COM+에 고유한 애플리케이션 ID가 필요합니다.

일반적으로 GAC는 클라이언트가 클라이언트 애플리케이션 디렉터리와 동일한 디렉터리에 없는 어셈블리에 액세스해야 하거나 어셈블리가 클라이언트의 디렉터리에 없는 다른 프로세스로 로드될 때마다 사용됩니다. 개념적으로 서비스 구성 요소를 사용하는 프라이빗 어셈블리는 실제로 공유되는 어셈블리이며, 공유된 구성 데이터를 사용합니다. ApplicationActivationOption이 라이브러리로 설정된 경우 어셈블리의 클래스에서 트랜잭션을 사용하고 모든 어셈블리가 동일한 디렉터리에서 로드되는 경우 한 클라이언트에서 해당 어셈블리를 사용할 수 있습니다. ApplicationActivationOption을 사용하는 어셈블리가 서버로 설정된 경우 어셈블리는 dllhost.exe 의해 로드됩니다. 이 어셈블리는 클라이언트와 동일한 디렉터리에 없을 가능성이 높습니다. COM+ 서버 앱에서 서비스되는 구성 요소를 사용하는 어셈블리는 GAC에 배치해야 합니다. COM+ 라이브러리 앱에서 서비스된 구성 요소를 사용하는 어셈블리는 GAC에 배치할 필요가 없습니다(다른 디렉터리에 있지 않은 경우). 유일한 예외는 ASP.NET 사용하여 호스팅하는 경우입니다.- 어셈블리를 GAC에 배치하여 섀도 복사본이 올바르게 작동하도록 해서는 안 됩니다.

서비스 구성 요소를 사용하는 .NET 애플리케이션을 제거하려면 GAC에서 어셈블리를 제거하고(GAC에 등록된 경우) regsvcs.exe 사용하여 COM+에서 어셈블리 등록을 해제한 다음 어셈블리 및 연결된 형식 라이브러리를 삭제합니다.

버전 관리

GUID 특성을 사용하여 COM+에서 요구하는 GUID를 수정할 수 있습니다. 그러나 GUID를 명시적으로 사용하는 대신 버전 관리를 사용하는 것이 좋습니다. 새 메서드 서명을 만들거나 클래스가 다른 서비스 특성으로 데코레이팅될 때마다 어셈블리의 주 버전 또는 부 버전 번호가 증가해야 합니다. 특정 버전에 대해 등록을 한 번 수행해야 합니다. 새 버전의 어셈블리를 등록할 때 해당 버전에 대해 새 GUID가 생성되고 구성 요소는 동일한 구성 요소 이름을 사용하여 동일한 COM+ 애플리케이션에 등록됩니다. 따라서 구성 요소는 COM+ 애플리케이션에 여러 번 표시됩니다. 그러나 각 구성 요소에는 GUID에서 제공하는 고유한 ID가 있습니다. 각 instance 구성 요소의 특정 버전을 참조합니다. 이는 Microsoft Visual Studio® .NET을 사용하여 .NET 애플리케이션을 빌드할 때 종종 발견됩니다. 환경은 [assembly: AssemblyVersion("1.0.*")] 특성을 프로젝트에 추가합니다. 프로젝트의 각 새 빌드는 새 빌드 번호를 생성하므로 어셈블리가 다시 등록될 때 새 GUID가 생성됩니다. 따라서 적절한 경우 빌드 번호를 수동으로 늘리는 것이 좋습니다. 클라이언트는 CLR 버전 정책을 사용하여 어셈블리에 바인딩되므로 COM+ 애플리케이션에서 올바른 버전의 클래스가 사용됩니다. 서비스 구성 요소를 사용하는 어셈블리(관리되는 서버)를 작성할 때의 몇 가지 병렬 시나리오는 다음과 같습니다.(아래에서 사용되는 활성화의 일부 측면은 다음 섹션에서 설명합니다).

  • 관리되는 클라이언트, 관리되는 서버, 어셈블리에 사용되는 고정 GUID가 없습니다.
  • 클라이언트는 버전 정책에 지정된 어셈블리를 로드합니다.
  • 관리되는 클라이언트, 관리되는 서버, 사용된 고정 GUID.
  • 클라이언트가 클래스를 활성화하고 버전 정책을 사용하여 이전 버전의 어셈블리에 액세스하는 경우 코드의 고정 GUID는 정품 인증 중에 사용하여 카탈로그에서 서비스 정보를 추출합니다. 따라서 이 GUID를 사용하여 마지막으로 등록된 어셈블리의 정보는 개체를 만드는 데 사용되며, 실제로 최신 버전일 수 있으므로 실제로 만든 개체(v2)에서 코드(v1)의 참조로 캐스팅하려고 할 때 형식 캐스트 예외가 발생합니다.
  • 관리되는 클라이언트, 관리되는 서버, 고정 GUID가 없는 경우 빌드 번호만 변경합니다.
  • 새 GUID가 생성되지만 형식 라이브러리에는 버전에 대한 두 개의 숫자만 있으므로 형식 라이브러리의 버전 번호는 여전히 동일합니다. 여전히 작동할 수 있지만 버전 2가 버전 1을 통해 설치된 경우 버전 1이 제거되면 버전 2의 형식 라이브러리가 등록 취소됩니다. 해결 방법 1: .NET Framework(V1.1)의 다음 릴리스에서는 형식 라이브러리를 어셈블리와 독립적으로 버전 관리하도록 설정하여 이 문제를 해결합니다. 이는 어셈블리 버전 번호를 변경할 때 형식 라이브러리 버전을 변경해야 했음을 의미합니다. 해결 방법 2: 주 버전 및 부 버전 번호만 사용합니다.
  • 관리되지 않는 클라이언트, 관리되는 서버, 고정 GUID가 사용되지 않습니다.
    • 클라이언트는 GUID를 사용하여 구성 요소를 만듭니다. Interop은 GUID를 이름으로 resolve 버전 정책이 적용됩니다. 어셈블리 버전 1 및 버전 2가 컴퓨터에 있고 정책을 사용하여 버전 2로 가져오는 경우 관리되지 않는 클라이언트는 버전 2를 가져옵니다.
    • 버전 1을 설치하고, 버전 2를 설치하고, 버전 1을 제거합니다. 이제 버전 2로 리디렉션할 버전 정책이 없는 한 클라이언트는 구성 요소를 만들 수 없습니다. 또한 버전 1 등록 정보에 대한 레지스트리 항목이 있어야 합니다. 제거된 버전 1에 대한 레지스트리 정보를 만드는 한 가지 방법은 Windows XP에서 COM+ 별칭 기능을 사용하는 것입니다.

버전 관리가 동일한 COM+ 애플리케이션의 모든 구성 요소에 적용됩니다. 즉, 애플리케이션 자체를 자동으로 버전 관리할 수 있는 방법은 없습니다. instance 경우 버전 정책을 사용하여 애플리케이션의 역할을 버전 관리할 수 없습니다. 애플리케이션 이름 특성을 사용하여 애플리케이션 버전 관리를 수행합니다.

서비스된 구성 요소

활성화

Enterprise Services 인프라는 컨텍스트의 개념에 따라 설립됩니다. 컨텍스트는 비슷한 실행 요구 사항이 있는 개체에 대한 환경입니다. 활성화 중 및/또는 메서드 호출 가로채기 중에 서비스를 적용할 수 있습니다. COM+ 서비스는 관리되지 않는 코드로 작성되지만 .NET과 COM+ 서비스의 통합은 .NET에서 COM interop 기술을 사용하는 것보다 훨씬 더 깊습니다. ServicedComponent에서 파생되지 않으면 등록 프로세스에 원하는 효과가 없습니다.

서비스 구성 요소는 다양한 조합으로 활성화 및 호스팅할 수 있습니다. 그림 3에 설명된 것처럼 이 토론은 In-Process(동일한 앱 도메인), 앱 도메인 간(동일한 프로세스) 및 프로세스 간 활성화의 세 가지 사례를 참조합니다. 이러한 경우의 중요성은 구성 요소에서 호출할 때 교차하는 경계입니다. In-Process 활성화는 잠재적인 교차 컨텍스트 경계를 발생시키고, 앱 도메인 간 사례는 크로스 컨텍스트 및 교차 앱 도메인 경계를 가지며, 교차 프로세스 사례는 컴퓨터 간/프로세스 간 및 교차 컨텍스트 경계를 처리합니다.

그림 3. 서비스된 구성 요소에 대한 활성화 호스트

서비스 구성 요소의 구현은 관리되지 않는 코드 또는 관리 코드로 작성된 서비스를 연결하는 확장 가능한 메커니즘을 제공하는 .NET 원격을 사용합니다. 서비스된 구성 요소는 ContextBoundObject에서 파생되고 IDisposable과 같은 다양한 인터페이스를 구현합니다. CLR의 활성화 체인은 ProxyAttribute 파생 사용자 지정 특성을 사용하여 쉽게 사용자 지정됩니다. 가로채기는 사용자 지정 실제 프록시를 작성하여 사용자 지정할 수 있습니다. 새 서비스 구성 요소 파생 클래스가 필요한 경우 활성화 호출이 실제로 CoCreateInstance에 대한 관리되는 C++ 래퍼를 호출하도록 활성화 체인이 사용자 지정됩니다. 이렇게 하면 COM+에서 이전에 등록된 어셈블리의 COM+ 카탈로그에 저장된 정보를 기반으로 관리되지 않는 컨텍스트 및 서비스를 설정할 수 있습니다. 지연 등록이 구현되는 단계이기도 합니다. 어셈블리를 등록하는 동안 InprocServer32 키는 mscoree.dll 가리키므로 COM+ CreateInstance를 런타임으로 다시 리디렉션하여 실제 관리되는 개체를 만듭니다. 따라서 활성화하는 동안 사용자 지정 실제 프록시 개체가 만들어집니다. 이 프록시의 In-process 버전을 서비스된 구성 요소 프록시 또는 SCP라고 합니다. 그림 4에 설명되어 있습니다.

그림 4. 활성화 경로

활성화 호출의 반환 경로는 관리 코드에서 관리되는 참조를 관리되지 않는 COM+를 통해 관리 코드로 다시 마샬링합니다(그림 4의 줄 1의 역방향 경로). 실제 개체가 만들어진 위치에 따라 클라이언트 쪽은 참조를 관련 양식으로 마샬링 해제합니다. In-Process 활성화의 경우 그림 5는 참조가 TP(투명 프록시)에 대한 직접 참조로 마마샬링되지 않음을 나타냅니다. 앱 도메인 간 참조는 .NET 원격 프록시로 숨기지 않습니다. 크로스 프로세스 또는 컴퓨터 간 참조(그림 6)를 더 이상 숨기지 않도록 해야 합니다. COM interop은 활성화 및 비마슬링 중에 ServicedComponent에서 구현한 IManagedObject를 호출합니다. RSCP(원격 서비스 구성 요소 프록시)는 활성화 중에 IServicedComponentInfo를 호출하여 서버 개체의 URI를 얻습니다. 이는 활성화 중에 두 번의 원격 호출이 발생했음을 의미합니다. 메서드 수준에서 COM+ 역할 기반 보안이 필요한 경우 인프라에서 이러한 인터페이스를 호출할 때 경계 해제가 성공하려면 이러한 인터페이스를 역할과 연결해야 합니다. 보안 섹션에서는 프로세스 간 활성화 및 마샬링이 역할 기반 보안을 구성하는 데 미치는 영향에 대해 설명합니다.

그림 5. In Process 호출에 대한 인프라

그림 6. Out of Process 호출을 위한 인프라

따라서 활성화 체인은 사용자 지정 실제 프록시를 만들고(가로채기에 사용됨) 관리되지 않는 컨텍스트를 만들기 위해 사용자 지정되었으며, COM+에는 가로채기 서비스의 의미 체계를 수행하는 데 필요한 컨텍스트 인프라만 남게 됩니다. COM+ 컨텍스트는 이제 COM 개체가 아닌 관리되는 개체와 연결됩니다.

Interception

그림 7은 In-Process 메서드 호출 인프라를 보여 줍니다. SCP(사용자 지정 프록시)를 사용하면 관리되는 호출을 가로챌 수 있습니다. 활성화하는 동안 COM+ 컨텍스트 ID는 SCP에 저장됩니다. 한 관리되는 개체가 서비스 구성 요소를 호출하면 대상 SCP에 저장된 컨텍스트 ID가 현재 컨텍스트의 컨텍스트 ID와 비교됩니다. 컨텍스트 ID가 동일한 경우 호출은 실제 개체에서 직접 실행됩니다. 컨텍스트 ID가 다른 경우 SCP는 COM+를 호출하여 컨텍스트를 전환하고 메서드 호출을 입력하는 서비스를 렌더링합니다. In-Process 호출의 경우 AppDomain.DoCallBack과 비슷하지만 AppDomain이 COM+인 경우입니다. 'DoCallBack' 함수는 먼저 COM+(그림 7의 2단계)를 입력하여 컨텍스트를 전환하고 서비스를 렌더링한 다음, 콜백 함수가 SCP에서 를 호출합니다. SCP는 데이터 마샬링을 수행하고 실제 개체에서 메서드를 호출합니다. 메서드가 종료되면 반환 경로를 사용하면 COM+에서 메서드 호출을 종료하기 위한 의미 체계를 렌더링할 수 있습니다(그림 7의 5단계). COM+는 서비스를 렌더링하는 데만 사용됩니다. 메서드를 호출할 때 String과 같은 형식을 BSTR로 변환할 필요가 없도록 데이터 마샬링 및 메서드 호출은 .NET 런타임*,* 내에서 수행됩니다. COM interop이 In-process 호출에 사용된 경우 데이터 마샬링이 필요합니다*.* 관리되지 않는 코드에서 서비스를 렌더링하는 호출은 프로세스 내 호출에 대한 COM interop 호출이 아닙니다.

그림 7. In Process 호출에 대한 인프라

정적 메서드에 대한 호출은 투명 및 실제 프록시로 전달되지 않습니다. 따라서 정적 메서드는 가로채기 서비스를 사용할 수 없습니다. 대신 클라이언트의 컨텍스트 내에서 호출됩니다. 내부 메서드는 올바른 컨텍스트 내에서 호출됩니다. 즉, 새 트랜잭션에 대해 구성된 개체에서 내부 메서드를 호출하는 클라이언트가 새 트랜잭션에 참여합니다. 그러나 메서드 수준 서비스에는 COM+ 카탈로그에 인터페이스가 필요하므로(다음 항목 및 보안에 대한 자세한 내용은) 메서드 수준 서비스에 대해 내부 메서드를 구성할 수 없습니다. 서비스는 속성에 적용할 수 있지만 메서드 수준 특성(예: AutoComplete)은 getter 및 setter 메서드에 개별적으로 배치되어야 합니다.

자동 완성 특성은 서비스에 액세스하는 코드를 작성하지 않고도 트랜잭션을 사용하는 편리한 방법입니다. 또는 ContextUtil.SetAbort 또는 ContextUtil.SetComplete를 사용할 수 있습니다. 이 서비스는 메서드의 속성에 대한 확인란을 설정하여 COM+ 탐색기에서 구성할 수 있습니다. 그러나 관리되는 개체는 인터페이스를 구현할 필요가 없습니다. 서비스된 구성 요소의 경우에도 마찬가지입니다. 메서드가 인터페이스에 선언되지 않은 경우 등록 시 메서드 수준 서비스에 대한 구성을 카탈로그에 쓸 수 없습니다. 구성은 메타데이터에만 저장할 수 있습니다. 메서드에 대한 인터페이스가 없으면 AutoComplete 특성이 있을 때 IRemoteDispatch.RemoteDispatchAutoDone에 저장된 구성 정보를 사용하여 SCP에서 컨텍스트 전환이 수행됩니다. 자동 완성이 없으면 IRemoteDispatch.RemoteDispatchNotAutoDone이 사용됩니다. IRemoteDispatch는 ServicedComponent에서 구현하는 인터페이스입니다. 관리되지 않는 클라이언트는 IDispatch(지연 바인딩)를 사용하는 인터페이스가 없는 서비스된 구성 요소만 호출할 수 있으므로 이 경우 실제 프록시가 없기 때문에 자동 완성 의미 체계를 적용할 수 없습니다. 인터페이스를 사용하는 경우에도 자동 완성의 구성은 관리되는 클라이언트에 대한 메타데이터에 의해 계속 구동됩니다. DCOM 메서드 호출은 Out of process 사례에서만 RemoteDispatchAutoDone에서 수행됩니다. Out-of-process 구성 요소는 DoCallBack 메커니즘을 사용하지 않고 대신 DCOM을 사용하여 호출을 전달하고 서비스를 렌더링할 수 있습니다. 메서드가 인터페이스에 있으면 원격 서비스 구성 요소의 인터페이스 메서드가 DCOM을 사용하여 호출되고, 그렇지 않으면 호출이 ServicedComponent의 IRemoteDispatch 인터페이스로 디스패치됩니다. 즉, Dispose()와 같은 호출도 DCOM을 통해 호출되며, 그 의미는 나중에 설명됩니다.

컨텍스트

ContextUtil 클래스는 연결된 COM+ 개체 컨텍스트 및 해당 속성에 액세스하는 데 사용됩니다. 이는 관리되지 않는 코드에서 CoGetObjectContext에서 반환된 개체와 유사한 기능을 제공합니다. 서비스 구성 요소와 연결된 관리되는 개체 컨텍스트는 연결된 관리되지 않는 개체 컨텍스트와 다른 용도로 사용됩니다. 이는 트랜잭션 필요(루트 역할을 하는)가 있는 관리되는 개체 3개를 작성하여 매니페스트되고, 다른 두 개체는 서비스된 구성 요소에서 파생되지 않습니다(컨텍스트-Agile 관리 개체를 예시하는 자식 개체로 작동). 서비스되지 않은 구성 요소는 트랜잭션이 지원되는 서비스된 구성 요소처럼 동작합니다. 즉, 리소스 관리자를 호출하고 필요한 경우 ContextUtil.SetAbort를 사용할 수 있습니다. 루트 개체가 만들어지면 연결된 관리되지 않는 컨텍스트가 만들어지고 현재 스레드와 연결됩니다. 자식 개체를 호출하면 관리되지 않는 컨텍스트와 연결되지 않으므로 COM+ 컨텍스트 변경이 필요하지 않으므로 스레드는 여전히 루트의 관리되지 않는 컨텍스트 ID를 유지 관리합니다. 자식 개체가 리소스 관리자를 호출하면 리소스 관리자는 루트 개체의 관리되지 않는 컨텍스트인 자식 개체를 실행하는 스레드에서 관리되지 않는 컨텍스트를 추출합니다. 이를 사용하는 것은 위험하며 이후 버전에서는 관리되지 않는 컨텍스트가 관리되는 컨텍스트와 병합될 수 있으므로 자식 개체가 잠재적으로 다른 관리되는 컨텍스트와 연결됩니다. 리소스 관리자는 루트 개체의 컨텍스트를 선택하지 않습니다. 따라서 새 버전의 .NET으로 업그레이드하면 이러한 유형의 동작에 따라 코드가 중단됩니다.

성능 결과

이 섹션에서는 관리되는 클라이언트, 관리되는 서버 서비스 구성 요소 솔루션의 성능을 관리되지 않는 클라이언트/서버 솔루션과 비교합니다. In-Process 사례는 다음 표에 설명되어 있습니다. 트랜잭션에 대해 구성된 ServicedComponent는 단순히 숫자를 추가하는 단일 메서드를 사용하여 C#으로 작성되었습니다. 해당 C++ 구현이 비교에 사용되었습니다. 이 비교는 실제 작업을 수행하지 않고 관리되는 솔루션과 관리되지 않는 솔루션 간의 차이를 보여 줍니다. In-Process 활성화는 관리형 솔루션에서 약 3.5배 느리며, 컨텍스트 전환이 있을 때 메서드 호출은 약 2배 더 비쌉 수 있습니다. 그러나 컨텍스트 전환이 필요한 서비스 구성 요소 메서드 호출과 그렇지 않은 호출을 비교할 때는 처리 중인 서비스 구성 요소 가로채기 인프라의 성공을 나타내는 약 3개의 크기 차이가 있습니다. Out of process 솔루션의 경우 정품 인증은 약 2배 더 비싸고 컨텍스트 간 메서드 호출은 약 3배 더 비쌉니다.

표 1에서는 관리형 솔루션과 비관리형 솔루션을 사용하여 프로세스 내 활성화 및 메서드 호출에 대한 크기 조정된 시간을 보여 줍니다.

표 1. In-Process 활성화 및 메서드 호출

  관리되는 솔루션 관리되지 않는 솔루션
활성화 35 10
크로스 컨텍스트-do-nothing 메서드 호출 2 1
Cross-context-do-work 메서드 호출 200 100

활성화는 'do-nothing' 메서드에 대한 메서드 호출보다 크기가 약 1차원 더 비쌉 수 있습니다. DTC 트랜잭션을 가져오기 위해 일부 작업을 추가하면(하지만 아무 작업도 수행하지 않음) 활성화 및 메서드 호출 시간이 동일한 크기의 순서로 수준을 조정합니다. 메서드 호출이 단순히 풀된 데이터베이스 연결을 열면 메서드 호출 작업은 활성화 및 'do-nothing' 메서드 호출을 결합한 것보다 큰 크기로, 실제 작업이 실험에 추가될 때 서비스 구성 요소 인프라의 오버헤드가 이론적임을 증명합니다.

개체 수명

Just-In-Time 활성화

JIT(Just-In-Time) 서비스는 일반적으로 격리된 상태로 사용되지 않습니다. 트랜잭션 서비스와 함께 암시적으로 사용되며 개체 풀링에서 가장 자주 사용됩니다. 그러나 이 예제는 몇 가지 흥미로운 topics 강조 표시하는 데 도움이 됩니다. 아래 코드에서는 JIT 서비스만 사용하는 .NET 클래스가 작성됩니다.

using System;
using System.EnterpriseServices;
[assembly: AssemblyKeyFile("Demos.snk")]
[assembly: ApplicationName("JITDemo")]

namespace Demos
{
    [JustInTimeActivation]
    public class TestJIT : ServicedComponent
    {
       public TestJIT()
       {  // First to get called
       }
       [AutoComplete]
       public void DoWork ()
       {       // Show doneness using .. 
                  // 1. The autocomplete attribute or
                  // 2. ContextUtil.DeactivateOnReturn = true or
                  // 3. ContextUtil.SetComplete();
       } 
       public override void Dispose(bool b)
{      // Optionally override this method and do your own 
// custom Dispose logic. If b==true, Dispose() was called
// from the client, if false, the GC is cleaning up the object
}
    }
}

클래스는 ServicedComponent에서 파생되며 JIT 특성을 사용하여 필요한 특정 서비스를 나타냅니다. 비관리 코드에서 Activate 및 Deactivate 메서드를 재정의하려면 클래스가 IObjectControl 인터페이스를 구현해야 합니다. 대신 ServicedComponent 클래스에는 Activate 및 Deactivate 이벤트를 처리하기 위해 재정의될 수 있는 가상 메서드가 있습니다. 그러나 ServicedComponent와 실제 프록시 SCP는 IObjectControl을 구현하지 않습니다. 대신 SCP는 COM+에서 IObjectControl 인터페이스를 요청할 때 프록시 해제를 만듭니다. 그런 다음, 해체 시 COM+의 호출은 ServicedComponent의 가상 메서드로 전달됩니다. DeactivateOnReturn 비트는 메서드의 AutoComplete 특성, ContextUtil.SetComplete(), ContextUtil.SetAbort() 또는 ContextUtil.DeactivateOnReturn 설정을 사용하여 설정됩니다. 각 메서드 호출 중에 DeactivateOnReturn 비트가 설정되어 있다고 가정하면 메서드 호출 시퀀스는 클래스의 생성자, Activate, 실제 메서드 호출, Deactivate, Dispose(true) 및 결국 클래스의 종료자(있는 경우)입니다. 다른 메서드를 호출할 때 동일한 시퀀스가 반복됩니다. 개체를 꺼내 개체 풀에 다시 배치하는 시기를 알 수 있도록 Activate 및 Deactivate 메서드만 재정의하는 것이 좋습니다. 활성화 및 비활성화의 나머지 논리는 클래스의 생성자 및 Dispose(bool) 메서드에 배치되어야 합니다. DeactivateOnReturn 비트는 다음 방법 중 하나를 사용하여 설정할 수 있습니다.

  1. 클라이언트는 단일 메서드 호출에 대해서만 개체의 상태를 사용합니다. 메서드를 입력하면 새 실제 개체가 만들어지고 SCP에 연결됩니다. 메서드를 종료하면 먼저 Dispose(true)를 호출한 다음 실제 개체 종료자(있는 경우)를 호출하여 실제 개체가 비활성화됩니다. 그러나 연결된 COM+ 컨텍스트, SCP 및 TP는 활성 상태로 유지됩니다. 클라이언트 코드는 여전히 실제 개체(투명 프록시)라고 생각되는 항목에 대한 참조를 유지합니다. 동일한 참조에서 클라이언트가 다음 메서드를 호출하면 메서드 호출을 처리하기 위해 새 실제 개체가 만들어지고 SCP에 연결됩니다(새 개체를 만드는 요구 사항을 제거하려면 개체 풀링 섹션 참조). 실제 개체를 비활성화하려면 메서드 호출이 종료되면 실제 개체가 완료를 나타내야 합니다. 이 작업은 다음을 사용하여 수행할 수 있습니다.
    1. 클래스의 메서드에 대한 AutoComplete 특성
    2. ContextUtil 클래스의 두 메서드 호출 중 하나인 DeactivateOnReturn 또는 SetComplete
  2. 클라이언트는 메서드를 종료하기 전에 doneness 비트를 false로 설정하여 각 메서드 호출 후 개체를 비활성화하지 않고 동일한 개체에서 여러 메서드 호출을 수행합니다. 예를 들어 양식 수준에서 JIT를 사용하는 서비스 구성 요소의 범위를 지정하고 메서드가 완료도 비트를 false로 명시적으로 설정하여 두 개의 양식 단추가 동일한 개체에서 메서드를 호출하도록 instance. 어느 시점에서 완료 비트는 true로 설정되어야 합니다. 이 방법은 클라이언트와 개체 사이에 계약이 있음을 의미합니다. 이 작업은 클라이언트에서 암시적으로 또는 명시적으로 수행할 수 있습니다.
    1. 클라이언트는 개체를 비활성화하기 위해 개체가 수행되면 개체에서 특정 메서드를 호출하는 것을 알고 있습니다. 메서드 구현은 옵션 1의 아이디어를 사용합니다. 동일한 호출 시퀀스를 사용하여 개체 참조를 다시 호출할 수 있습니다. 이는 새 실제 개체가 생성됨을 의미합니다.
    2. 개체는 개체에서 Dispose() 메서드를 호출할 때 클라이언트에 의해 명시적으로 제거됩니다. Dispose()는 ServicedComponent에 정의된 메서드이며, 클래스의 종료자(있는 경우)인 Dispose(true)를 차례로 호출한 다음 연결된 COM+ 컨텍스트를 중단합니다. 이 경우 개체 참조에 대해 더 이상 메서드 호출을 수행할 수 없습니다. 이 작업이 시도되면 예외가 throw됩니다. 동일한 개체를 사용하는 클라이언트가 많은 경우 마지막 클라이언트가 개체로 완료된 경우에만 Dispose()를 호출해야 합니다. 그러나 JIT 개체의 상태 비정상 특성은 디자인 사례를 클라이언트 모델당 단일 instance 만듭니다.
    3. 개체는 완료 비트가 true로 설정되지 않으며 클라이언트는 Dispose()를 호출하지 않습니다. 가비지 수집이 수행되면 실제 개체, 프록시 및 컨텍스트가 제거됩니다. GC에서 시작한 메서드 호출 순서는 Deactivate, Dispose(false) 클래스 종료자(있는 경우)입니다.

모든 서비스 구성 요소에는 SCP(또는 원격 사례의 RSCP)에 참조로 저장되는 연결된 COM+ 컨텍스트가 있습니다. 참조는 GC가 발생하거나 클라이언트가 Dispose()를 호출하는 경우에만 해제됩니다. 컨텍스트를 클린 위해 GC에 의존하지 않는 것이 좋습니다. COM+ 컨텍스트는 하나의 OS 핸들을 유지하고 일부 메모리는 GC가 발생할 때까지 이러한 핸들의 릴리스를 지연시킬 수 있습니다. 또한 ServicedComponent에는 종료자가 없지만 SCP는 종료자를 구현합니다. 즉, COM+ 컨텍스트 참조는 첫 번째 컬렉션에서 가비지를 수집하지 않습니다. 실제로 SCP의 종료자가 호출될 때 컨텍스트는 종료자 스레드에 의해 제거되지 않습니다. 대신 컨텍스트 삭제 작업은 종료자 스레드에서 제거되고 내부 큐에 배치됩니다. 이는 서비스된 구성 요소가 빠르게 생성되고 사용되며 scope 벗어나는 특정 스트레스 환경에서 종료자 스레드가 작업에서 사용될 수 있다는 것을 발견했기 때문에 수행되었습니다. 대신 내부 스레드는 큐를 서비스하여 이전 컨텍스트를 삭제합니다. 또한 새 ServicedComponent를 만드는 모든 애플리케이션 스레드는 먼저 큐에서 항목을 가져와서 이전 컨텍스트를 삭제하려고 시도합니다. 따라서 클라이언트에서 Dispose()를 호출하면 클라이언트 스레드를 사용하여 COM+ 컨텍스트가 더 빨리 중단되고 컨텍스트에서 사용하는 핸들 및 메모리 리소스가 해제됩니다. Dispose()가 예외를 throw할 수 있는 경우가 있습니다. 한 가지 경우는 개체가 중단된 루트가 아닌 트랜잭션 컨텍스트에 있는 경우입니다. Dispose() 호출은 CONTEXT_E_ABORTED 예외를 관찰할 수 있습니다. 또 다른 사례는 개체 풀링에 설명되어 있습니다.

성능 관점에서 ServicedComponent 파생 클래스에서 종료자를 구현하지 않고 대신 Dispose(bool) 메서드에 이 논리를 배치하는 것이 좋습니다. SCP는 종료자를 구현하지만 실제 개체의 종료자는 리플렉션을 사용하여 호출됩니다.

JIT를 사용하는 좋은 디자인 방법은 다음과 같습니다.

  • 종료자를 구현하지 않고 생성자 및 Dispose(bool) 메서드에 사용자 지정 활성화 및 종료 코드를 배치하고 메서드에서 AutoComplete 특성을 사용하여 완료를 표시하여 단일 호출 패턴을 사용합니다.
  • 클라이언트가 개체를 사용하여 완료되면 클라이언트에서 Dispose()를 호출합니다.

논의에서는 클라이언트가 관리되고 구성 요소가 진행 중이라고 가정했습니다. 구성 요소가 out-of-process인 경우: (자세한 내용은 원격 섹션에 설명되어 있습니다.)

  • GC는 클라이언트 활성화 개체에 대한 .NET 원격 임대 시간이 만료된 경우에만 개체를 클린.
  • 앞에서 설명한 대로 Out-of-process 구성 요소에서 메서드를 호출할 때 DCOM은 컨텍스트를 전환하고 메서드 호출을 전달하는 데 사용됩니다. 구성 요소가 이전에 JIT에 의해 비활성화된 다음 Dispose()에 대한 호출이 이루어지면 서버 컨텍스트가 입력되고 DCOM 호출을 처리하기 위해 실제 개체가 다시 만들어지고 마지막으로 다시 비활성화됩니다. In-Process 구성 요소의 경우 실제 개체가 비활성화된 경우 Dispose() 호출을 서비스하기 전에 올바른 컨텍스트로 전환하려고 시도하지 않고(구성 요소를 다시 활성화하는) 컨텍스트만 제거됩니다.

개체 풀링

개체 풀링의 기본 전제는 개체 재사용입니다. 개체 풀링이 JIT에서 가장 자주 사용됩니다. 이는 풀된 COM 구성 요소와 풀된 .NET 구성 요소 모두에 해당합니다.

using System;
using System.EnterpriseServices;
[assembly: AssemblyKeyFile("Demos.snk")]
[assembly: ApplicationName("OPDemo")]

namespace Demos
{
[ObjectPooling(MinPoolSize=2, MaxPoolSize=50, CreationTimeOut=20)]
[JustInTimeActivation]
public class DbAccount : ServicedComponent
{
   [AutoComplete]
   public bool Perform ()
   {      // Do something
   }
   public override void Activate()
   {   // .. handle the Activate message
   }
   public override void Deactivate()
   {   // .. handle the Deactivate message
   }
   public override bool CanBePooled()
   {  // .. handle the CanBe Pooled message
      // The base implementation returns false
      return true;
   }
}
}

JIT를 사용하는 경우와 마찬가지로 개체 풀링을 다음 두 가지 방법 중 하나로 사용할 수 있습니다.

  1. 단일 호출 패턴입니다. 코드에서 클라이언트가 메서드 호출을 시도하면 개체가 풀에서 검색되고, JIT가 개체 풀링과 함께 사용되고 완료 비트가 메서드 호출 중에 true로 설정된 경우 단일 메서드 호출에서 종료 시 풀로 반환됩니다. JIT를 사용하는 동일한 단일 호출 방법도 여기에 적용됩니다. 생성자는 개체를 만들고 풀에 배치할 때 한 번만 호출됩니다. JIT 및 풀된 개체를 사용할 때 메서드 호출 순서는 Activate, 메서드 호출, 비활성화, CanBePooled입니다. CanBePooled가 true를 반환하면 개체가 풀에 다시 배치됩니다(앞에서 설명한 대로 컨텍스트가 활성 상태로 유지됨). 풀에서 임의의 개체를 추출한 후(생성자를 다시 호출하지 않고) 후속 메서드 호출에 대해 동일한 메서드 호출 순서가 반복됩니다(서비스된 구성 요소는 매개 변수가 있는 생성자를 사용할 수 없음). 마지막으로 클라이언트가 풀된 개체에서 Dispose()를 호출하는 경우 컨텍스트만 in-process 사례에서 제거됩니다. Out-of-process의 경우 앞에서 설명한 대로 Dispose()에 대한 호출은 개체를 다시 활성화할 수 있습니다. 개체가 풀된 경우 풀에서 개체를 가져와야 합니다. 즉, Dispose()가 CO_E_ACTIVATION_TIMEOUT 예외를 throw할 수 있습니다.
  2. 다중 호출 패턴. JIT 서비스에서 강조 표시된 유사한 여러 메서드 호출 방법을 사용하여 개체에 대한 여러 메서드 호출 후에만 개체를 풀에 다시 배치할 수 있습니다. 그러나 클라이언트가 Dispose를 호출하지 않고 JIT를 사용하지 않는 경우 GC에서 개체를 풀에 다시 넣을 때 종료가 필요한 풀된 개체의 자식 개체가 다시 부활할 수 있도록 할 수 없습니다. 풀된 개체가 가비지 수집되면 Deactivate 내에서 여전히 유효한 멤버를 보장할 수 없습니다. .NET Framework(V1.1)의 다음 릴리스에서는 canBePooled 및 Deactivate가 호출되지 않고 개체가 풀에 다시 배치되지 않습니다. 이 방법을 사용하면 보다 일관된 모델이 있습니다. 자식 개체 비활성화가 활성 상태이고 Dispose()에서 자식 개체가 활성 상태임을 보장하지 않습니다. 따라서 JIT를 사용하지 않는 풀된 개체에 대해 Dispose()를 호출해야 합니다. 그렇지 않으면 개체가 풀로 반환되지 않습니다.

어셈블리를 배포하고 등록한 후 관리자가 풀 크기 및 시간 제한을 수정할 수 있습니다. 풀 크기 변경은 프로세스가 다시 시작될 때 적용됩니다. Windows XP 이상에서는 풀 크기가 프로세스 내의 각 애플리케이션 도메인에 적용됩니다. Windows 2000에서 풀 크기는 풀링된 개체가 기본 애플리케이션 도메인에 있는 전체 프로세스입니다. 즉, 동일한 프로세스 내의 다른 앱 도메인에서 풀링된 개체가 필요한 경우 클라이언트는 앱 도메인 간에 풀링된 개체로 효과적으로 통신합니다. 한 가지 실현은 각 IIS vroot가 별도의 애플리케이션 도메인에 보관되는 ASP.NET 애플리케이션 내에서 COM+ 라이브러리 애플리케이션에 정의된 풀된 .NET 개체를 사용하는 것입니다.

서비스 구성 요소는 매개 변수가 있는 생성자를 사용할 수 없습니다.

보안

CAS(코드 액세스 보안)

.NET Framework 보안을 사용하면 코드가 리소스에 액세스할 수 있는 권한이 있는 경우에만 리소스에 액세스할 수 있습니다. 이를 표현하기 위해 .NET Framework 코드가 보호된 리소스에 액세스할 수 있는 권한을 나타내는 사용 권한 개념을 사용합니다. 코드는 필요한 권한을 요청합니다. .NET Framework 코드 액세스 권한 클래스를 제공합니다. 또는 사용자 지정 권한 클래스를 작성할 수 있습니다. 이러한 사용 권한은 코드가 수행할 수 있는 작업을 .NET Framework 표시하고 코드 호출자가 수행할 권한을 부여해야 하는 작업을 나타내는 데 사용할 수 있습니다. System.EnterpriseServices를 통한 모든 코드 경로는 관리되지 않는 코드 권한을 요청합니다.

.NET의 코드 액세스 보안은 웹에서 코드를 다운로드하고 작성자를 완전히 신뢰하지 않을 수 있는 애플리케이션에서 가장 유용합니다. 일반적으로 서비스 구성 요소를 사용하는 애플리케이션은 완전히 신뢰할 수 있으며, 여러 프로세스 간에 흐르고 배포 시 역할 구성을 사용하도록 설정하려면 보안이 필요합니다. 이러한 기능은 COM+ 역할 기반 보안에 의해 노출되는 기능입니다.

System.EnterpriseServices를 통한 모든 코드 경로에는 관리되지 않는 코드 권한이 필요합니다. 이것은 다음을 의미합니다.

  • 서비스된 구성 요소에서 컨텍스트 간 호출을 활성화하고 수행하려면 관리되지 않는 코드 권한이 필요합니다.
  • 서비스된 구성 요소에 대한 참조가 신뢰할 수 없는 코드에 전달되는 경우 ServicedComponent에 정의된 메서드는 신뢰할 수 없는 코드에서 호출할 수 없습니다. 그러나 ServicedComponent에서 파생된 클래스에 정의된 사용자 지정 메서드는 경우에 따라 신뢰할 수 없는 코드에서 호출될 수 있습니다. 컨텍스트 전환, 가로채기 서비스가 필요하지 않은 사용자 지정 메서드에서 신뢰할 수 없는 코드의 호출을 수행할 수 있으며, 메서드 구현이 System.EnterpriseServices의 멤버를 호출하지 않는 경우.

또한 .NET 버전 1에서는 서비스된 구성 요소 내에서 사용자 지정 보안 권한을 사용하지 않도록 스레드 스위치를 만들 때 보안 스택이 복사되지 않습니다.

RBS(Role-Based 보안)

System.EnterpriseServices는 COM+ 보안 메커니즘의 기능을 미러 .NET 개체에 보안 서비스를 제공합니다. COM+ 서버 애플리케이션을 사용하여 구성 요소를 호스트하는 경우 RBS 기능을 사용하려면 DCOM 전송 프로토콜을 사용하여 원격 클라이언트에서 구성 요소를 활성화해야 합니다. 원격에 대한 자세한 내용은 다음 섹션에서 제공합니다. 따라서 COM+의 보안 호출 컨텍스트 및 ID를 관리 코드에서 사용할 수 있습니다. 또한 CoImpersonateClient, CoInitializeSecurity 및 CoRevertClient는 일반적으로 서버 쪽에서 사용되는 친숙한 호출이며 CoSetProxyBlanket은 일반적으로 클라이언트 쪽에서 사용됩니다.

특정 보안 설정은 특성을 사용하여 메타데이터에 저장되지 않으며, instance 역할에 사용자를 추가하고 프로세스 보안 ID를 설정합니다. 그러나 어셈블리 수준 특성을 사용하여 COM+ 서버 애플리케이션에 대한 COM+ 탐색기의 보안 탭에 표시되는 항목을 구성할 수 있습니다.

  • 애플리케이션에 대한 권한 부여 사용 (ApplicationAccessControlAttribute(bool)) RBS를 지원하려면 이 작업을 수행해야 합니다.

  • 보안 수준 (ApplicationAccessControlAttribute(AccessChecksLevelOption))입니다. AccessChecksLevelOption.Application으로 설정하면 애플리케이션의 역할에 할당된 사용자가 프로세스 보안 설명자에 추가되고 구성 요소, 메서드 및 인터페이스 수준에서 세분화된 역할 검사가 해제됩니다. 따라서 보안 검사는 애플리케이션 수준에서만 수행되며 라이브러리 애플리케이션은 프로세스 수준 보안을 위해 호스트 프로세스를 사용합니다. 특성이 AccessChecksLevelOption.ApplicationComponent로 설정된 경우 애플리케이션의 역할에 할당된 사용자가 프로세스 보안 설명자에 추가되고 애플리케이션에서 역할 기반 보안 검사가 수행됩니다. 또한 클래스에 ComponentAccessControl 특성을 적용하여 RBS가 필요한 각 구성 요소에 대해서도 액세스 검사를 사용하도록 설정해야 합니다. 라이브러리 애플리케이션에서 역할 기반 보안 검사는 서버 애플리케이션인 것처럼 수행됩니다. 보안 속성은 애플리케이션 내의 모든 개체에 대한 컨텍스트에 포함되며 보안 호출 컨텍스트를 사용할 수 있습니다. 개체가 작성자의 컨텍스트와 호환되지 않는 구성이 있는 경우 자체 컨텍스트에서 활성화됩니다. 프로그래밍 방식의 역할 기반 보안은 보안 호출 컨텍스트의 가용성에 의존합니다.

    COM+ 라이브러리 애플리케이션에 대해 의미 있는 액세스 검사가 작동하려면 프로세스 및 구성 요소 수준에서 액세스 검사를 수행하도록 선택합니다.

  • 가장인증 선택은 ApplicationAccessControl 특성의 ImpersonationLevel 및 Authentication 속성에 해당합니다.

    SecurityRole 특성은 어셈블리, 클래스 또는 메서드 수준에 적용할 수 있습니다. 어셈블리 수준에서 적용된 경우 해당 역할의 사용자는 애플리케이션의 모든 구성 요소를 활성화할 수 있습니다. 클래스 수준에 적용된 경우 해당 역할의 사용자는 구성 요소에서 모든 메서드를 호출할 수 있습니다. 애플리케이션 및 클래스 수준 역할은 메타데이터에서 구성하거나 COM+ 카탈로그에 액세스하여 관리적으로 구성할 수 있습니다.

    메타데이터를 사용하여 어셈블리 수준에서 RBS 구성:

    [assembly: ApplicationAccessControl(true,
    AccessCheckLevel=AccessChecksLevelOption.ApplicationComponent)]
    // adds NTAuthority\everyone to this role
    [assembly:SecurityRole("TestRole1",true)]
    // add users to roles administratively
    [assembly:SecurityRole("TestRole2")]
    

    메타데이터의 클래스 수준에서 RBS 구성:

    [assembly: ApplicationAccessControl(true,
    AccessCheckLevel=AccessChecksLevelOption.ApplicationComponent)]
    …
    [ComponentAccessControl()]
    [SecurityRole("TestRole2")]
    public class Foo : ServicedComponent
    {
    public void Method1() {}
    }
    

    어셈블리 또는 클래스 수준의 RBS는 어셈블리가 등록된 후 COM+ 카탈로그에 존재하기 때문에 관리적으로 구성할 수 있습니다. 그러나 앞에서 설명한 대로 클래스 메서드는 COM+ 카탈로그에 표시되지 않습니다. 메서드에서 RBS를 구성하려면 클래스가 인터페이스의 메서드를 구현해야 하며 클래스 수준에서 SecureMethod 특성 또는 메서드 수준에서 SecureMethod 또는 SecurityRole을 사용해야 합니다. 또한 특성은 인터페이스 정의의 인터페이스 메서드가 아니라 클래스 메서드 구현에 표시되어야 합니다.

  • 메서드에서 RBS를 사용하는 가장 쉬운 방법은 클래스 수준에서 SecureMethod 특성을 적용한 다음 역할을 구성하는 것입니다(관리적으로 또는 메서드에 SecurityRole 특성을 배치).

    [assembly: ApplicationAccessControl(true,
    AccessCheckLevel=AccessChecksLevelOption.ApplicationComponent)]
    Interface IFoo
    {
    void Method1();
    void Method2();
    }
    [ComponentAccessControl()] 
    [SecureMethod]
    public class Foo : ServicedComponent, IFoo
    {
    // Add roles to this method administratively
    public void Method1() {} 
    // "RoleX" is added to the catalog for this method
    SecurityRole("RoleX")
    public void Method2() {}
    }
    

    클래스 수준에서 SecureMethod를 사용하면 클래스의 모든 인터페이스에 대한 모든 메서드를 COM+ 카탈로그의 역할로 관리적으로 구성할 수 있습니다. 클래스가 각각 동일한 메서드 이름과 역할을 사용하여 두 인터페이스를 구현하는 경우 COM+ 카탈로그에 표시되는 두 메서드에서 역할을 구성해야 합니다(클래스가 특정 메서드를 구현하지 않는 한 instance IFoo.Method1). 그러나 SecurityRole 특성이 클래스 메서드에 사용되는 경우 어셈블리가 등록될 때 동일한 메서드 이름을 가진 모든 메서드가 해당 역할로 자동으로 구성됩니다.

  • SecureMethod 특성은 메서드 수준에도 배치할 수 있습니다.

    [assembly: ApplicationAccessControl(true, 
    AccessCheckLevel=AccessChecksLevelOption.ApplicationComponent)]
    Interface IFoo
    {
       void Method1();
       void Method2();
    }
    [ComponentAccessControl()] 
    public class Foo : ServicedComponent, IFoo
    {
    // Add roles to this method administratively
    [SecureMethod]  // Or use SecurityRole (translates to
      SecureMethod++)
       public void Method1() {}
       public void Method2() {}
    }
    

    이 예제에서 IFoo와 두 메서드는 모두 COM+ 카탈로그에 표시되므로 두 메서드 중 하나에서 역할을 관리적으로 구성할 수 있지만 메서드 수준 RBS는 Method1에만 적용됩니다. 메서드 수준 RBS 보안에 참여하거나 이전에 설명한 대로 클래스 수준에서 SecureMethod를 배치하는 데 필요한 모든 메서드에서 SecureMethod 또는 SecurityRole을 사용합니다.

RBS가 메서드 수준에서 구성될 때마다 마샬러 역할이 필요합니다. 메서드 호출이 수행되고 메서드에 RBS가 구성되지 않은 경우 서비스 구성 요소 인프라는 IRemoteDispatch를 호출합니다. 메서드 호출이 이루어지고 메서드에 RBS가 구성된 경우(SecureMethod 특성이 있는 경우) 메서드 호출은 메서드와 연결된 인터페이스를 사용하여 DCOM을 사용하여 이루어집니다. 따라서 DCOM은 RBS가 메서드 수준에서 적용되도록 보장합니다. 그러나 활성화 및 가로채기 섹션에서 설명한 대로 COM interop 및 RSCP는 IManagedObject(원격 활성화자가 해당 공간으로 참조를 마샬링하도록 허용) 및 IServicedComponentInfo(원격 개체를 쿼리하기 위해)를 호출합니다. 이러한 인터페이스는 서비스된 구성 요소와 연결됩니다. 구성 요소는 메서드 수준 검사를 수행하도록 구성되었으므로 인프라가 이러한 호출을 성공적으로 수행하려면 역할을 이러한 인터페이스와 연결해야 합니다.

따라서 어셈블리가 등록되면 마샬러 역할이 애플리케이션에 추가되고 사용자는 이 역할에 관리적으로 추가되어야 합니다. 대부분의 경우 애플리케이션의 모든 사용자가 이 역할에 추가됩니다. 이는 메서드에서 RBS를 구성하는 데 이 추가 구성 단계가 필요하지 않은 관리되지 않는 COM+와 다소 다릅니다. 등록하는 동안 이 역할에 '모든 사람'을 자동으로 추가하는 것은 잠재적인 보안 허점입니다. 이제는 누구나 활성화할 수 있는 권한이 없었을 수 있는 구성 요소를 활성화(호출하지 않음)할 수 있기 때문에 잠재적인 보안 허점이 있습니다. 또한 클라이언트가 개체를 삭제할 수 있도록 마샬러 역할이 IDisposable 인터페이스에 추가됩니다. Marshaller 역할의 대안은 사용자가 언급된 세 인터페이스 각각에 관련 역할을 추가하는 것입니다.

원격 구성 요소

ServicedComponent 클래스는 상속 트리에 MarshalByRefObject를 포함하므로 원격 클라이언트에서 액세스할 수 있습니다. 서비스 구성 요소를 원격으로 노출하는 방법에는 다양한 변형이 있습니다. 서비스된 구성 요소는 다음을 사용하여 원격으로 액세스할 수 있습니다.

  • ASP.NET 호출되거나 작성된 서비스 구성 요소가 있는 HTTP 채널은 알려진 확장성 및 성능과 함께 좋은 보안 및 암호화 옵션을 제공합니다. SOAP와 함께 사용하면 더 많은 상호 운용성 옵션이 있습니다. 서비스 구성 요소는 IIS/ASP.NET에서 COM+ 라이브러리 애플리케이션으로 호스트할 수 있습니다. COM+ 서버 애플리케이션을 사용하는 경우 IIS/ASP.NET 호스트는 DCOM을 사용하여 구성 요소에 액세스할 수 있습니다.
  • 서비스 구성 요소를 SOAP 엔드포인트로 노출하는 다른 방법은 COM+ 웹 서비스: XML Web Services로 Check-Box 경로에서 설명합니다.
  • 서비스된 구성 요소가 Dllhost에서 호스트되는 경우 DCOM입니다. 이 옵션은 최적의 성능과 보안 및 서비스 컨텍스트를 컴퓨터 간에 전달할 수 있는 기능을 제공합니다. 원격 기술을 선택할 때의 주요 디자인 질문은 서비스가 머신 간에 전달되어야 하는지 여부입니다. instance 경우 한 컴퓨터에서 트랜잭션이 만들어지고 트랜잭션이 다른 컴퓨터에서 계속되어야 하는 서버 팜 내에서 DCOM은 이를 달성하는 데 사용할 수 있는 유일한 프로토콜입니다. 그러나 클라이언트가 단순히 원격 ServicedComponent를 호출해야 하는 경우 HTTP 채널 또는 SOAP 엔드포인트 접근 방식이 좋은 대안입니다.
  • .NET 원격 채널(instance, TCP 또는 사용자 지정 채널의 경우). TCP 채널을 사용하려면 소켓에서 수신 대기하는 프로세스가 필요합니다. 일반적으로 사용자 지정 프로세스는 소켓에서 수신 대기한 다음 서비스 구성 요소를 COM+ 라이브러리 또는 서버 애플리케이션으로 호스트하는 데 사용됩니다. 또는 Dllhost를 수신기로 사용할 수 있습니다. 두 방법 중 하나를 사용할 가능성이 가장 큽니다. 검증된 성능, 확장성 및 보안을 사용하여 사용자 지정 소켓 수신기를 작성해야 합니다. 따라서 ASP.NET 또는 DCOM 솔루션은 대부분의 프로젝트에 가장 적합한 방법입니다.

DCOM을 사용하여 원격으로 서비스된 구성 요소에 액세스하고 Dllhost에서 호스트하려면 먼저 어셈블리가 COM+ 서버 애플리케이션에 등록되고 서버 컴퓨터의 GAC에 배치되었는지 확인합니다. 그런 다음 COM+ 애플리케이션 내보내기 기능을 사용하여 애플리케이션 프록시에 대한 MSI 파일을 만듭니다. 클라이언트에 애플리케이션 프록시를 설치합니다. 애플리케이션 프록시에 포함된 는 관리되는 어셈블리입니다. 또한 설치 관리자는 어셈블리를 등록하고 클라이언트 컴퓨터의 GAC에 배치합니다. 따라서

  • .NET Framework 클라이언트 및 sever에 설치해야 합니다. 관리되지 않는 클라이언트만 원격 서비스 구성 요소에 액세스하는 경우에도 클라이언트 컴퓨터에서 필요합니다. Windows 2000 플랫폼에서도 서비스 팩 3이 필요합니다.
  • 프록시를 제거한 후 GAC에서도 어셈블리를 제거해야 합니다.

서버 구성 요소가 클라이언트 쪽의 관리 코드에서 활성화된 후의 인프라는 그림 6에 나와 있습니다.

DCOM을 사용하면 CLR이 Dllhost에서 호스트됩니다. 즉, 애플리케이션 구성 파일 dllhost.exe.config system32 디렉터리에 상주합니다. 이는 구성 파일이 컴퓨터의 모든 Dllhost 프로세스에 적용된다는 의미이기도 합니다. .NET Framework(V1.1)의 다음 릴리스에서는 COM+ 애플리케이션 루트 디렉터리를 COM+ 애플리케이션에서 설정할 수 있으며 해당 디렉터리를 사용하여 애플리케이션에 대한 구성 파일 및 어셈블리를 검색합니다.

클라이언트 활성화 개체의 경우 개체의 URI가 요청될 때마다 해당 개체에 대한 수명 임대가 만들어집니다. 활성화 섹션의 앞부분에서 설명한 대로 원격 서비스 구성 요소 프록시에서 URI를 요청합니다. 이는 기존 In-Process 서비스 구성 요소가 원격 프로세스로 마샬링될 때도 발생할 수 있습니다. MBR 개체가 애플리케이션 도메인 외부의 .NET에 의해 마샬링될 때마다 URI가 요청됩니다. URI는 .NET의 개체 ID가 고유하도록 하고 프록시 체인을 방지하는 데 사용됩니다. 따라서 관리되는 클라이언트가 원격 서비스 구성 요소를 활성화하면 서버 개체에서 임대 시간이 사용됩니다. 관리되지 않는 클라이언트는 클라이언트 쪽에 원격 서비스 구성 요소 프록시가 없으므로 개체의 URI를 요청하지 않습니다. 대신 관리되지 않는 클라이언트는 DCOM을 사용하여 개체 ID를 보장합니다. 따라서 서비스된 구성 요소의 임대 시간은 관리되지 않는 클라이언트에서 활성화될 때 사용되지 않습니다.

임대 시간이 서비스된 구성 요소와 관련된 경우 InitialLeaseTime 및 RenewOnCallTime 시간 제한 값을 10초만큼 작은 값으로 설정하는 것이 좋습니다. 서비스된 구성 요소는 Dispose()를 사용하거나 GC가 개체를 클린 제거됩니다. Dispose()가 호출되면 원격 서비스 구성 요소 프록시는 DCOM 프록시에 있는 참조를 해제한 다음 다음 GC에서 사용할 수 있도록 합니다. 서버 개체는 Dispose 호출을 처리하거나 Dispose()에 대한 원격 호출을 처리하기 위해 새 서버 개체를 만들고, 연결된 COM+ 컨텍스트를 삭제한 다음, 임대 시간이 초과된 경우에만 다음 GC에서 사용할 수 있도록 합니다. 클라이언트가 Dispose()를 호출하지 않는 경우 서버는 먼저 클라이언트 쪽 GC가 DCOM 프록시에 대한 참조를 해제할 때까지 기다렸다가 임대 시간이 만료된 후 자체 및 COM+ 컨텍스트를 다음 GC에서 사용할 수 있도록 해야 합니다. 따라서 Dispose()를 호출하고 기본 임대 시간을 줄입니다. 클라이언트가 활성 상태로 유지되고 임대 시간이 만료되더라도 서버 개체에 대한 DCOM 참조는 서버 개체를 활성 상태로 유지합니다. 그러나 DCOM 참조가 항상 서비스된 구성 요소를 활성 상태로 유지하는 데 사용되는 것은 아닙니다. 클라이언트가 CLR 원격 채널 또는 COM+ SOAP 서비스를 통해 개체에 액세스하는 경우 임대로 인한 강력한 참조만 서비스된 구성 요소를 활성 상태로 유지합니다.

결론

이 문서에서는 관리 코드에 사용할 수 있는 서비스 중 일부에 대해 설명했습니다. 모든 COM+ 서비스는 트랜잭션 격리 수준, 프로세스 초기화, 구성 요소가 없는 서비스 및 프로세스 재활용과 같은 관리 코드에서 사용할 수 있습니다. 이제 .NET Framework 일관되고 논리적인 방식으로 모든 COM+ 서비스에 동등하게 액세스할 수 있습니다. 또한 ASP.NET, Microsoft ADO.NET 및 메시징과 같은 여러 혁신적인 .NET Framework .NET Enterprise Services와 긴밀하게 통합되어 트랜잭션 및 개체 풀링과 같은 서비스를 사용합니다. 이 통합은 일관된 아키텍처 및 프로그래밍 모델을 제공합니다. System.EnterpriseServices 네임스페이스는 관리되는 클래스에 서비스를 추가하는 프로그래밍 모델을 제공합니다.