Опубликован: 11.05.2007 | Доступ: свободный | Студентов: 1698 / 235 | Оценка: 4.36 / 4.25 | Длительность: 16:06:00
Лекция 7:

Промежуточная среда COM+ и служба Enterprise Services

Создание компенсирующего менеджера ресурсов

Компенсирующий менеджер ресурсов позволяет использовать в транзакциях среды COM+ какие либо ресурсы, которые не имеют прямой поддержки транзакций COM+. Этот механизм включает следующие классы из пространства имен System.EnterpriseServices.CompensatingResourceManager:

  • журнал операций ( log ), заполняемый операциями над ресурсом;
  • секретарь (класс Clerk ), ведущий журнал операций;
  • компенсатор (наследника класса Compensator ), который восстанавливает первоначальное состояние ресурса в случае отката транзакции и вносит изменения в ресурс при успехе транзакции.

Сам менеджер ресурсов должен решить задачу изоляции ресурса в рамках транзакции и ведения журнала операций. При успехе транзакции компенсатор вносит постоянные изменения или отменяет их в соответствии с журналом операций. Следует отметить, что какие-либо временные изменения, производимые менеджером с ресурсом, могут вероятно нарушить требования изоляции транзакции, поскольку могут быть видимыми для внешних по отношению к транзакции объектов. С другой стороны, объекты внутри транзакции должны наблюдать происходящие с ресурсом изменения до успешного завершения транзакции.

В качестве примера менеджера ресурсов рассмотрим работу с файлами небольшого размера. Менеджер ресурсов предоставляет следующие сервисы:

  • открытие документа на чтение;
  • открытие документа на перезапись;
  • закрыть файл с сохранением изменений.

С целью изоляции транзакций запись в файл происходит в момент успешного завершения транзакции. До этого момента данные хранятся в памяти. Такое решение безусловно не является эффективным с точки зрения траты ресурсов решение, оно используется в качестве примера. При чтении в рамках транзакции документа, уже ранее измененного в этой же транзакции, вместо чтения из файла происходит чтение последней относящийся к этому файлу записи из журнала операций. Журнал операций хранит пары из имени файла (в нижнем регистре) и содержимого файла.

Пример компилируется и запускается make файлом, который можно передать как параметр входящей в состав .NET SDK утилите nmake.exe. Этот файл имеет следующее содержание.

# Файл: makefile
all: CrmSample.exe
# сборка должна быть подписана
CrmSample.key:
    sn -k CrmSample.key
CrmSample.exe: CrmSample.cs CrmSample.Key
    csc /r:System.EnterpriseServices.dll CrmSample.cs 
    	/keyfile:CrmSample.key
install:
# установить приложение COM+
    regsvcs CrmSample.exe
uninstall:
    regsvcs –u CrmSample.exe

Поскольку для регистрации сборки как приложения COM+необходимо, чтобы она была подписана, то вызовом утилиты sn.exe из состава .NET SKD создается пара ключей. Затем компилятор языка C# csc.exe создает сборку, используя этот файл ключей. При команде nmake install сборка устанавливается в качестве приложения COM+ вызовом утилиты regsvcs.exe Microsoft Windows.

Далее будет рассмотрено содержание файла CrmSample.cs.

// Файл CrmSample.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.EnterpriseServices;
using System.EnterpriseServices.CompensatingResourceManager;

[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: ApplicationCrmEnabled]
[assembly: ApplicationName("Seva CRM")]
[assembly: Description("Пример на использование CRM")]

Данные атрибуты сборки из пространства имен System.EnterpriseServices управляют параметрами создаваемого приложения COM+:

  • ApplicationActivation – задает тип приложения COM+ (серверный или библиотечный);
  • ApplicationCrmEnabled – необходим для использования CRM в приложении COM+;
  • ApplicationAccessControl – управляет контролем доступа к приложению, в данном примере – отключен;
  • Атрибут System.ComponentModel.DescriptionAttribute задает описание сборки.

Класс StreamLog содержит статический метод для записи в файл буфера, вызываемый при завершении транзакции.

public static class StreamLog
{      
    public static void Save(LogRecord log)
    {        
        if (log.Record is object[])
        {    
            object[] record = (object[])log.Record;
            string fileName = (string) record[0];
            byte[] buffer = (byte[]) record[1];                         
       
            using (FileStream file = new FileStream(fileName, 
                FileMode.Create, FileAccess.Write)) 
            {         
                file.Write(buffer, 0, buffer.Length);
            }
        }
    } // Save() 
} // StreamLog