아디봉의.net

C# 트래잭션및 com+트랜잰셕정리 본문

C#

C# 트래잭션및 com+트랜잰셕정리

아디봉 2012. 8. 22. 14:21

 

1-1    SqlTransaction 을 이용한 방법

         

         

SqlConnection conn = new SqlConnection(커넥션 스트링);

conn.Open();

SqlTransaction transaction = new SqlTransaction();

SqlCommand command = new SqlCommand();

command.Transaction = transaction;

 

try{

    command.CommandText = insert into .;

    command.ExecuteNonQuery();

   

    command.CommandText = update xxx set …….. where ;

    command.ExecuteNonQuery();

   

    transaction.Commit();

}catch(Exception e){

    transaction.Rollback();

}finally{

    conn.Close();

}

 

 

1-2              Stored Procedure 를 이용하는 방법

트랜잭션이 발생하는 쿼리 묶음을 저장 프로시저로 만들고 호출한다.

 

1-3              System.EnterpriseServices 를 이용하는 방법(Com+)

 

.

using System.EnterpriseServices;

 

namespace . {

   

[Transaction(TransactionOption.Required)]

public class xxxx{

 

    public void addCart(int id ,

int productCode,

string productName,

int quantity)

    {

        SqlConnection conn;

        try{

                conn = new SqlConnection(접속문자열);

                SqlCommand command = new SqlCommand();

 

                command.CommandText = insert .;

                command.ExecuteNonQuery();

 

                command.CommandText = update ..;

                command.ExecuteNonQuery();

 

                ContextUtils.SetComplete();

  }catch(Exception e){

    ContextUtils.SetAbort();

  }finally{

    conn.close();

  }

}

}

}

 출처 : http://blog.naver.com/yheesungRedirect=Log&logNo=20013782396

요약


이 문서에서는 Visual C# .NET 클래스에서 COM+(구성 요소 서비스) 트랜잭션을 사용하는 방법을 단계별로 설명합니다.
데이터베이스 작업의 집합은 하나의 단위로 간주됩니다.
모든 작업이 성공하면 전체 트랜잭션이 성공하고 한 작업이라도 실패하면 전체 트랜잭션이 실패합니다. 실패하는 경우 시도된 모든 데이터베이스 작업은 기본 데이터베이스에 게시되지 않습니다.

 

요구 사항


다음은 권장 하드웨어, 소프트웨어, 네트워크 인프라, 기술과 지식 및 필요한 서비스 팩 목록입니다.


* Microsoft Windows 2000 Server SP1 
* Microsoft Internet Information Services(IIS) 4.0 이상 
* Microsoft Internet Explorer 5.0, 5.5 또는 6.0 

 

이 문서에서는 사용자가 다음 항목에 대해 잘 알고 있는 것으로 가정합니다.


* 트랜잭션 개념 및 처리 
* COM+(구성 요소 서비스) 

 

COM+ 트랜잭션 서비스

Microsoft .NET Framework에서 System.EnterpriseServices 네임스페이스를 사용하여 트랜잭션 처리를 구현할 수 있습니다. COM+ 트랜잭션 서비스에 액세스하려면 클래스를 만들어야 합니다. 이렇게 하려면 다음 단계를 수행하십시오.

 

using System;
using System.Data;
using System.Data.SqlTypes;
using System.Data.Common;

using System.Data.SqlClient;


using System.EnterpriseServices;
//EnterpriseServices를 사용하려면 참조추가의 NET 탭의 구성 요소 이름에서 System.EnterpriseServices를 참조해야합니다.

 

namespace prjEnterprise
{

   //Transaction 특성은 클래스에 대한 트랜잭션 지원 수준을 지정하는 데 사용됩니다.
    [Transaction(TransactionOption.Required)]
    public class clsES:ServicedComponent
    //COM+ 트랜잭션 서비스를 사용하려면 클래스(clsES)가 ServicedComponent에서 기능을 상속해야 합니다.
    {
        public SqlConnection Conn;

        public void dbAccess(int pID1, int onOrder, int pID2, int inStock)
        {
            //데이터베이스 처리 중 발생할 수 있는 예외를 알리도록 try 블록을 설정합니다.
            //트랜잭션을 중단하기 위해서는 이러한 예외를 알려야 합니다.
            //try 블록에는 두 가지 데이터베이스 작업이 포함됩니다.
            //각 작업은 지정된 제품 테이블 레코드에서 서로 다른 필드를 업데이트합니다.
            try
            {  
                SqlConnection Conn = new SqlConnection("user id=<username>;password=<strong password>;Initial Catalog=northwind;Data Source=2E124\\SQL;");
                Conn.Open();

 

                //제품 테이블을 업데이트합니다. 처음 두 입력 매개 변수에 지정된 ID에 해당하는 제품의 onOrder 값으로  UnitsonOrder 필드를 업데이트합니다.
                SqlCommand sqlCommand = new SqlCommand("UPDATE myProducts SET UnitsonOrder = " + onOrder + " WHERE productID = " + pID1, Conn);
                sqlCommand.ExecuteNonQuery();

 

                //제품 테이블을 다시 업데이트합니다. 세 번째와 네 번째 입력 매개 변수에 지정된 ID에 해당하는 제품의 inStock 값으로 UnitsinStock 필드를 업데이트합니다.
                sqlCommand.CommandText = "UPDATE myProducts SET UnitsinStock = "
                                       + inStock + " WHERE productID = " + pID2;
                sqlCommand.ExecuteNonQuery();

 

                //업데이트가 COM+ 트랜잭션에 속해 있으므로 하나의 단위로 커밋되어야 합니다.
               
//오류가 발생하지 않을 경우 System.EnterpriseServices 네임스페이스에서 contextUtil 클래스의 setComplete 메서드가 트랜잭션(이 경우에는 위의 두 업데이트)을 커밋하는 데 사용됩니다.
                ContextUtil.SetComplete();

                Conn.Close();
            }
            catch(Exception e)
            //SQL 명령을 실행하는 동안 발생하는 예외를 알려 전체 트랜잭션을 중단할 수 있도록 해야 합니다.
            {
                //System.EnterpriseServices 네임스페이스에서 contextUtil 클래스의 setAbort 메서드가 전체 트랜잭션을 중단하는 데 사용됩니다.
                //첫 번째 업데이트가 성공하고 두 번째 업데이트가 실패하면 두 업데이트 모두 제품 테이블에 게시되지 않습니다.  알려진 예외를 호출자에게 나타내어 트랜잭션 실패를 알립니다.
                ContextUtil.SetAbort();
                throw e;
            }
            finally
            {
            }
        }
    }
}

 

이 구성 요소가 제대로 작동하려면 구성 요소에 강력한 이름이 있어야 합니다.
강력한 이름을 생성한 다음 강력한 이름으로 어셈블리에 서명하십시오. 이렇게 하는 방법은 다음과 같습니다.

 

a.  Visual Studio .NET 명령 프롬프트에서 sn.exe -k snEnterprise.snk를 입력하여 키 파일을 만듭니다.
b.  snEnterprise.snk를 프로젝트 폴더로 복사합니다. 
c.  AssemblyInfo.vc에서 다른 어셈블리 특성 문의 앞이나 뒤에 다음 코드를 추가합니다.
    [assembly: AssemblyKeyFileAttribute("..\\..\\snEnterprise.snk")]       
 d.  저장한 다음 프로젝트를 빌드합니다.


작동 여부 확인

 

이 코드를 테스트하기 위해 clsES 프로젝트를 사용하는 콘솔 응용 프로그램을 만듭니다. 첫 번째 경우에는 트랜잭션이 성공하고 지정된 제품의 onOrder inStock 필드가 업데이트됩니다. 두 번째 경우에는 지정된 제품의 onOrder 필드에 대한 업데이트가 성공하지만 지정된 제품 번호가 제품 테이블에 없기 때문에 제품의 inStock 필드에 대한 업데이트가 실패합니다. 이에 따라 트랜잭션이 실패하고 무시됩니다.

 

1. Visual Studio .NET의 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 누릅니다. 


2. 프로젝트 형식에서 Visual C# 프로젝트를 누른 다음 템플릿에서 콘솔 응용 프로그램을 누릅니다.


3. 이름 입력란에 testES를 입력합니다. 솔루션에 추가 옵션이 선택되어 있는지 확인합니다.


4. 확인을 눌러 솔루션에 이 프로젝트를 추가합니다. 


5. testES가 clsES를 테스트하도록 하려면 참조를 추가해야 합니다. 위에서 추가한 솔루션 탐색기의 testES에서 참조를 마우스 오른쪽 단추로 누른 다음 참조 추가를 누릅니다.


6. 참조 추가 대화 상자가 나타납니다. 프로젝트 탭에서 prjEnterprise를 두 번 누릅니다.


7. 선택한 구성 요소에 참조가 나타납니다. 확인을 눌러 프로젝트에 이 참조를 추가합니다. 


8. System.EnterpriseServices 라이브러리에 프로젝트에 대한 참조를 추가합니다.  솔루션 탐색기에서 참조를 마우스 오른쪽 단추로 누른 다음 참조 추가를 누릅니다.


9. 참조 추가 대화 상자가 나타납니다. .NET 탭의 구성 요소 이름에서 System.EnterpriseServices를 두 번 누릅니다. 


10. 선택한 구성 요소에 System.EnterpriseServices가 나타나는지 확인합니다. 확인을 누릅니다. 


11. 콘솔 응용 프로그램(testES)을 마우스 오른쪽 단추로 누른 다음 시작 프로젝트로 설정을 누릅니다.


12. Class1 클래스의 Main 함수에 다음 소스 코드를 붙여 넣습니다.

 

    prjEnterprise.clsES myTest = new prjEnterprise.clsES();
    try
    {
        myTest.dbAccess(1, 777, 2, 888);
        Console.WriteLine("TRANSACTION ONE -- SUCCESS");

        myTest.dbAccess(1, 5, 2, -20);
        Console.WriteLine("TRANSACTION TWO -- SUCCESS");
    }
    catch (Exception e)
    {
        Console.WriteLine("TRANSACTION FAILURE");
    }


13. F5 키를 눌러 테스트 코드를 실행합니다.
7단계의 코드에서 첫 번째 dbAccess 호출은 성공합니다. 제품 1과 제품 2가 제품 테이블에 있습니다. 제품 1의 onOrder 필드가 777로 업데이트되고 제품 2의 inStock 필드가 888로 업데이트됩니다. 이 트랜잭션이 성공했기 때문에 출력 창에 다음 메시지가 표시됩니다.

 

    TRANSACTION ONE - SUCCESS

 

    두 번째 dbAccess 호출은 실패합니다. 따라서 제품 테이블에 대한 dbAccess의 업데이트 문이 데이터베이스에 게시되지 않습니다.  제품 1의 onOrder 필드가 5로 업데이트되었을 수 있지만 제품 2의 inStock 필드는 -20으로 설정될 수 없습니다. 제품 테이블 정의에 정의되어 있는 제약 조건 때문에 inStock에 음수 값이 허용되지 않습니다.  따라서 이 dbAccess 호출은 실패하고 전체 트랜잭션도 실패합니다.  제품 테이블은 dbAccess 호출 전의 상태를 유지합니다.  catch 문은 dbAccess에서의 트랜잭션 실패 알림을 처리하며, 출력 창에는 다음 오류 메시지가 표시됩니다.

 

    TRANSACTION FAILURE

 

14. SQL Server 엔터프라이즈 관리자를 사용하여 Northwind 제품 테이블의 내용을 검토합니다. 제품 1을 보면 onOrder 필드가 777입니다. 제품 2를 보면 inStock 필드가 888입니다. 따라서 두 필드에 이와 다른 값을 설정하는 두 번째 dbAccess 호출은 실패했음을 알 수 있습니다. 


문제 해결


* COM+ 서비스를 사용하는 프로젝트가 강력한 이름을 갖고 있는지 확인합니다. 


* COM+ 서비스를 사용하는 모든 클래스는 서비스 대상 구성 요소에서 상속해야 합니다.
   서비스 대상 구성 요소는 System.EnterpriseServices 네임스페이스에 있습니다. 


* 디버깅하는 동안 트랜잭션이 커밋되거나 중단되기 전에 시간이 초과될 수 있습니다.
   시간 초과를 막으려면 트랜잭션 특성에서 제한 시간 속성을 사용하십시오.
   다음 예제에서 관련 메서드의 트랜잭션 완료 제한 시간은 1,200초입니다.
   [Transaction(TransactionOption.Required,timeout:=1200)]

출처 : http://blog.naver.com/saga111?Redirect=Log&logNo=120007734612

---------------------------------------------------------------------------------------------------

EventTrackingEnabled  :

COM+에 설치된 구성용소가 실행될 때 발생하는 이벤트와 통계의 지원여부를 결정하는 속성이다.
기본값은 True

 

Just-in-Time-Activation(JITA)

JITA는 COM+에서 제공하는 인스턴스 관리 기능이다.
JITA는 클라이언트가 객체를 호출하는 동안만 인스턴스를 생성하고 관리하게  하는 기능을 가지고 있다.
따라서 COM+의 JITA기능을 사용하면 클라이언트가 객체를 호출하여 메소드를 사용하고 나면 JITA는 이를 감지해 생성되어 있던 인스턴스를 즉시 해제하는 역활을 함으로서 자원을 효율적으로 관리해준다.
기본값은 True

Example

namespace CCWEULPrint
{
    /// <summary>
    /// VULPrint에 대한 요약 설명입니다.
    /// </summary>
    [JustInTimeActivation (true)]
    [EventTrackingEnabled (true)]
    public class VULPrint  : ServicedComponent
    {

        //생성자 및 메서드

    }

}

[Transaction(TransactionOption.Required,Timeout=1200)] <-- 의미 
    [JustInTimeActivation(true)]
    public class XXX: ServicedComponent
    {

}

 

Disabled 현재 컨텍스트에서 모든 트랜잭션을 무시합니다.
NotSupported 트랜잭션을 제어하지 않고 컨텍스트에서 구성 요소를 만듭니다.
Required 트랜잭션이 있으면 트랜잭션을 공유하고 필요하면 새 트랜잭션을 만듭니다.
RequiresNew 현재 컨텍스트의 상태에 관계 없이 새 트랜잭션으로 구성 요소를 만듭니다.
Supported 트랜잭션이 있으면 트랜잭션을 공유합니다.

 

=====================================

 

비지니스레이어 => Select                     =>NotSupported
                            insert,update,delete =>Required

데이타 액세스레이어                             => 무조건 Supported

 

 

### 비지니스 레이어(select)

 

using System;
using System.Data;
using System.Data.SqlClient;
using System.EnterpriseServices;
using Microsoft.Framework.Data;

namespace Microsoft.Sample.Biz
{
 /// <summary>
 /// Class1에 대한 요약 설명입니다.
 /// </summary>
 [Transaction(TransactionOption.Required)]
 [JustInTimeActivation(true)]
 public class Order_Tx : SampleFramework.EnterpriseServices.RuleBase
 {
  [AutoComplete]
  public int InsertOrder(DataPack packMain, DataPack[] packSub)
  {
   using(Dac.Order_Dac orderDac = new Dac.Order_Dac())
   {
    int nOrderID = orderDac.InsertOrder(packMain);

    orderDac.InsertOrderDetails(nOrderID, packSub);

    return nOrderID;
   }
  }
 }
}

 

### 비지니스 레이어(insert,update,delete)

using System;
using System.Data;
using System.Data.SqlClient;
using System.EnterpriseServices;
using Microsoft.Framework.Data;

namespace Microsoft.Sample.Biz
{
 /// <summary>
 /// Class1에 대한 요약 설명입니다.
 /// </summary>

 [Transaction(TransactionOption.NotSupported)]
 [JustInTimeActivation(true)]
 public class Order_NTx : SampleFramework.EnterpriseServices.RuleBase
 {
  [AutoComplete]
  public DataSet GetOrders(int nID)
  {
   _exeTimeLog.Prepare();

   using (Dac.Order_Dac dacObj = new Dac.Order_Dac() )
   {
    return dacObj.SelectOrdersList(nID);
   }
  }

  [AutoComplete]
  public DataSet GetSalesByYear(DataPack pack)
  {
   _exeTimeLog.Prepare();

   using (Dac.Order_Dac orderDac = new Dac.Order_Dac())
   {
    return orderDac.SelectSalesByYear(pack);
   }
  }

  [AutoComplete]
  public DataSet QueryOrdersByCompanyName(DataPack pack)
  {
   using(Dac.Order_Dac orderDac = new Dac.Order_Dac())
   {
    return orderDac.SelectOrdersByCompanyName(pack);
   }
  }

  [AutoComplete]
  public DataSet QueryOrdersByCompanyID(DataPack pack)
  {
   using(Dac.Order_Dac orderDac = new Dac.Order_Dac())
   {
    return orderDac.SelectOrdersByCompanyID(pack);
   }
  }

  [AutoComplete]
  public DataSet FetchOrderDetails(int orderID)
  {
   using(Dac.Order_Dac orderDac = new Dac.Order_Dac())
   {
    return orderDac.SelectMultiByExactOrderID(orderID);
   }
  }
 }
}

 

### 데이타 엑세스 레이어(모든경우)

using System;
using System.Data;
using System.Data.SqlClient;
using System.EnterpriseServices;
using Microsoft.Framework.Data;
using System.Text;

namespace Microsoft.Sample.Dac
{
 /// <summary>
 /// Class1에 대한 요약 설명입니다.
 /// </summary>
 [Transaction(TransactionOption.Supported)]
 [JustInTimeActivation(true)]
 public class Order_Dac : SampleFramework.EnterpriseServices.DacBase
 {
  [AutoComplete]
  public DataSet SelectOrdersByCompanyName(DataPack pack)
  {
   string strSql = "OrdersQueryByCompanyName";

   SqlParameter[] paramArray = pack.ToSqlParameters();

   return _agent.Fill(strSql, "OrdersQueryByCompanyName", null, paramArray, CommandType.StoredProcedure);
  }

  [AutoComplete]
  public DataSet SelectOrdersByCompanyID(DataPack pack)
  {
   string strSql = "SELECT   o.OrderID, o.CustomerID, o.EmployeeID, o.OrderDate, o.RequiredDate, "+
           "o.ShippedDate, o.ShipVia, o.Freight, o.ShipName, o.ShipAddress, o.ShipCity, "+
           "o.ShipRegion, o.ShipPostalCode, o.ShipCountry, c.CompanyName, "+
           "c.ContactName, e.LastName, e.FirstName "+
           "FROM      Orders o INNER JOIN "+
           "Customers c ON o.CustomerID = c.CustomerID INNER JOIN "+
           "Employees e ON o.EmployeeID = e.EmployeeID "+
           "WHERE c.CustomerID = @CustomerID";

   SqlParameter[] paramArray = pack.ToSqlParameters();

   return _agent.Fill(strSql, "OrdersQueryByCompanyName", null, paramArray);
  }

  [AutoComplete]
  public DataSet SelectSalesByYear(DataPack pack)
  {
   string strSql = "[Sales by Year]";

   SqlParameter[] paramArray = pack.ToSqlParameters();

   DataSet ds = new DataSet();
   return _agent.Fill(strSql, "Sales by Year", ds, paramArray, CommandType.StoredProcedure);
  }

  [AutoComplete]
  public DataSet SelectOrdersList(int nID)
  {
   SqlParameter[] paramArray = null;

   string strQuery = "SELECT   Orders.OrderID, Orders.OrderDate, Orders.RequiredDate, Orders.ShippedDate, "+
            "Orders.ShipVia, Orders.Freight, Orders.CustomerID, Orders.EmployeeID, "+
            "Orders.ShipName, Orders.ShipAddress, Orders.ShipCity, Orders.ShipRegion, "+
            "Orders.ShipPostalCode, Orders.ShipCountry, Customers.CompanyName,  "+
            "Employees.LastName, Employees.FirstName "+
            "FROM      Orders INNER JOIN "+
            "Customers ON Orders.CustomerID = Customers.CustomerID INNER JOIN "+
            "Employees ON Orders.EmployeeID = Employees.EmployeeID";

   if(nID != -1)
   {
    strQuery += " where Orders.OrderID=@OrderID";
    paramArray = new SqlParameter[] { new SqlParameter("@OrderID", nID) };
   }

   DataSet ds = new DataSet();
   _agent.Fill(strQuery, "OrderCustomerEmployee", ds, paramArray);

   return ds;
  }

  [AutoComplete]
  public DataSet SelectMultiByExactOrderID(int orderID)
  {
   string query = "SELECT   OrderDetails.OrderID, OrderDetails.ProductID, OrderDetails.UnitPrice, OrderDetails.Quantity, " +
          "OrderDetails.Discount, Products.ProductName, Categories.CategoryName FROM " +
          "[Order Details] OrderDetails WITH (NOLOCK) INNER JOIN " +
          "Products WITH (NOLOCK) ON OrderDetails.ProductID = Products.ProductID INNER JOIN " +
          "Categories WITH (NOLOCK) ON Products.CategoryID = Categories.CategoryID " +
          "WHERE  (OrderDetails.OrderID = @OrderID)";

   SqlParameter[] paramArray
    = {
      new SqlParameter("@OrderID",SqlDbType.Int)
     };
   paramArray[0].Value = orderID;

   return _agent.Fill(query, "OrderDetails", null, paramArray);
  }

  [AutoComplete]
  public void InsertOrderDetails(int nOrderID, DataPack[] packs)
  {
   string strSql = "INSERT INTO " +
           "[Order Details] " +
           "( "+
           "OrderID, ProductID, UnitPrice, Quantity, Discount "+
           ") "+
           "VALUES "+
           "( "+
           "  @OrderID, @ProductID, @UnitPrice, @Quantity, @Discount "+
           "); ";

   foreach(DataPack pack in packs)
   {
    pack.AddProperty("OrderID", typeof(System.Int32), nOrderID);

    SqlParameter[] paramArray = pack.ToSqlParameters();

    _agent.ExecuteNonQuery(strSql, paramArray);
   }
  }

  [AutoComplete]
  public int InsertOrder(DataPack pack)
  {
   string strSql = "INSERT INTO " +
           "Orders "+
           "( "+
           " CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, "+
           "  Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, "+
           "  ShipCountry, UpdDate "+
           ") "+
           "VALUES "+
           "( "+
           "  @CustomerID, @EmployeeID, @OrderDate, @RequiredDate, @ShippedDate, "+
           "  @ShipVia, @Freight, @ShipName, @ShipAddress, @ShipCity, @ShipRegion, "+
           "  @ShipPostalCode, @ShipCountry, GETDATE() "+
           ") ; "+
           "SELECT  "+
           "  Orders.OrderID, Orders.CustomerID, Orders.EmployeeID, Orders.OrderDate, "+
           "  Orders.RequiredDate, Orders.ShippedDate, Orders.ShipVia, Orders.Freight, "+
           "  Orders.ShipName, Orders.ShipAddress, Orders.ShipCity, Orders.ShipRegion, "+
           "  Orders.ShipPostalCode, Orders.ShipCountry, Customers.CompanyName, "+
           "  Customers.ContactName, Employees.LastName, Employees.FirstName "+
           "FROM     "+
           "  Orders WITH (NOLOCK) INNER JOIN "+
           "  Customers WITH (NOLOCK) ON Orders.CustomerID = Customers.CustomerID INNER JOIN "+
           "  Employees WITH (NOLOCK) ON Orders.EmployeeID = Employees.EmployeeID "+
           "WHERE "+
           "  (Orders.OrderID = @@IDENTITY)";

   SqlParameter[] paramArray = pack.ToSqlParameters();

   int nOrderID = (int) _agent.ExecuteScalar(strSql, paramArray);
   return nOrderID;
  }
 }
}

출처 : http://cafe.naver.com/phplinux/497

 

---------------------------------------------------------------------------------------------------

:: JITA(Just In Time Activation)서비스의 이용 :: ASP.NET

2005/06/07 23:15

복사 http://blog.naver.com/tppsc/60013679115

▣ JITA(Just In Time Activation)서비스의 이용
   - 객체가 사용되고 난 후 객체의 사용이 끝나면 즉시 객체를 비활성화 시켜 프로세서의 유휴시간을 최소화 하는
     COM+의 서비스, Trace="true"로 확인하기
   - JITA는 Object Pooling서비스와 함께 안정적이고 빠른 COM+콤포넌트 운용을 지원해줌
   - JITA의 운영 순서
     ASP.NET Client --> Proxy --> Channel --> Stub --> (Object Pool)Object1
     ASP.NET Client --> Proxy --> Channel --> Stub
     ASP.NET Client --> Proxy --> Channel --> Stub --> (Object Pool)Object2
   - COM+는 기본적으로 상태를 가질 수 없는 자바의 Stateless Session빈과 같다.
   - COM+ 콤포넌트는 메소드단위로 호출됨으로 당연히 상태를 저장할 수 없다.
   - ContextUtil 클래스는 COM+의 문맥 데이터를 저장하고 있는 객체이며 2비트로 구성되어 있습니다.
     . COM+콤포넌트가 정상적으로 트랜잭션이 종료 되었는지 확인하는 중요한 속성입니다.
     . 1비트: 1은 정상적인 트랜잭션 종료, 0은 아직 작업중임을 나타냅니다.
     . 2비트: 객체와 수명과 관련이 있는 비트로 1이면 현재 객체의 메소드가 종료됨과 동시에 실행을 종료하며,
       0이면 객체가 작업중임으로 비활성화 되지 않습니다.




▣ COM+와 JITA서비스의 실습

1. 콤포넌트 프로젝트 추가
   - VS에서 Visual C# Project, 클래스 라이브러리 선택
   - 프로젝트명: JitaComp
   - 참조 추가: System.EnterPriseServices



2. JitaComp프로젝트 JITA.cs
using System;
using System.EnterpriseServices;

namespace JitaComp {
        [JustInTimeActivation(true)]
        public class JITA : ServicedComponent {
                private static int instance;

                public JITA() {
                        instance++;
                }//end of constructor

                [AutoComplete(true)]
                public int GetInstanceCount() {
                        return instance;
                }//end of method GetInstanceCount
        }//end of class JITA
}//end of namespace



3. dll 콤포넌트를 구분하기 위한 강력한 이름인 키파일을 만들기 위해
   PATH환경 변수에 "C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin"을 추가합니다.

   d:
   cd D:\temp\com\JitaComp\bin\Debug
   sn -k JitaComp.snk
   dir



4. AssemblyInfo.cs파일을 열고 아래처럼 수정합니다.

[assembly: AssemblyKeyFile("")] --> [assembly: AssemblyKeyFile(@"D:\temp\com\JitaComp\bin\Debug\JitaComp.snk")]



5. 빌드합니다.



6. COM+ 콤포넌트를 시스템 레지스트리에 등록합니다.
   - D:\temp\com\JitaComp\bin\Debug>Regsvcs JitaComp.dll JitaComp
   - 등록후 "구성요소 서비스"에서 확인 합니다.



7. VS에서 Visual C# Project, ASP.NET웹응용 프로그램 선택
   - 프로젝트명: JitaSample
   - 참조 추가: JitaComp, System.EnterPriseServices



8. JitaSample.aspx 파일을 열고 아래의 메소드를 작업합니다.
   - 참조:  JitaComp

using JitaComp;
~
~
~  
private void Page_Load(object sender, System.EventArgs e)
{
           JITA jita = new JITA();

           for (int i=0;i<10;i++)
           {
               int count = jita.GetInstanceCount();
               Response.Write(count);
               Response.Write("<br>");
           }

}



9. http://localhost:3001/JitaSample/JitaSample.aspx



10. 수정시는 Regsvcs /u JitaComp.dll를 해주세요.

출처: http://blog.naver.com/tppsc?Redirect=Log&logNo=60013679115