визуализация подпроцесса в рамках бизнес-операции

StatusIDPriorityType
Closed4925ВысокийВопрос
ProfileReply
MaksimClient

в документации нужен пример визуализации подпроцессов в бизнес-операциях.

У нас из контроллера вызывается бизнес-операция таким образом:

        private void ImportFromTXT_Execute(object sender, SimpleActionExecuteEventArgs e)
        {
            IObjectSpace os = View.ObjectSpace;
            var importTxtService = new ImportTxtService
                    {
                        ObjectSpace = os
                    };
            var runner = BOMethodRunner.Create(Application, BusinessOperationMethod.Execute);

            runner.Run((m, bo, svp) => { MessageObject.CreateMessageSuccess(e.ShowViewParameters, Application, "Сообщение", "Импорт выполнен успешно"); }, importTxtService, e.ShowViewParameters);
        }

Реализация бизнес-операции такая:

public override void Execute(IBusinessOperation bOperation)
        {
            bo = (ImportTxtService)bOperation;

            objectSpace = ((ImportTxtService)bOperation).ObjectSpace ??
                     BusinessOperationManager.Instance.Application.CreateObjectSpace();
            const int steps = 11;
            bo.Process.TotalStep = steps;
            bo.Process.NextStep("Импорт подразделений.", 1, steps);
            TestData.ReadFromTXT(objectSpace, "Department.txt", TestData.CreateDepartments, 1, bo);                       
            bo.Process.NextStep("Импорт должностей.", 2, steps);
            TestData.ReadFromTXT(objectSpace, "Job.txt", TestData.CreatePositions, 1, bo);
            bo.Process.NextStep("Импорт штатного расписания.", 3, steps);
            TestData.CreateManningTables(objectSpace);
            bo.Process.NextStep("Импорт приказов о приеме на работу.", 4, steps);           
            TestData.CreateTestActionHiring(objectSpace, bo);
            bo.Process.NextStep("Импорт начислений.", 5, steps);
            TestData.ReadFromTXT(objectSpace, "SUMVIDOP.txt", TestData.CreateAccrualsByTxt, -1, bo);
            bo.Process.NextStep("Импорт годового дохода.", 6, steps);
            TestData.ReadFromTXT(objectSpace, "SUMULTEC.txt", TestData.CreateTotalAmountsByTxt, -1, bo);
            bo.Process.NextStep("Импорт родственников.", 7, steps);
            TestData.ReadFromTXT(objectSpace, "PSNLINKS.txt", TestData.CreateRelativeByTxt, -1, bo);
            bo.Process.NextStep("Импорт удержаний.", 8, steps);
            TestData.ReadFromTXT(objectSpace, "Retention.txt", TestData.CreateRetentionsByTxt, -1, bo);
            bo.Process.NextStep("Импорт постоянных удержаний.", 9, steps);
            TestData.ReadFromTXT(objectSpace, "PermanentRetention.txt", TestData.CreatePermanentRetentionsByTxt, -1, bo);
            bo.Process.NextStep("Импорт налогов на ФОТ.", 10, steps);
            TestData.ReadFromTXT(objectSpace, "TaxesOnFOT.txt", TestData.CreateTaxesOnFotByTxt, -1, bo);
            bo.Process.NextStep("Импорт индивидуальных настроек налогов.", 11, steps);
            TestData.ReadFromTXT(objectSpace, "PersonalTax.txt", TestData.CreatePersonalTaxByTxt, -1, bo);
        }

Сейчас удается видеть только смену 11 шагов, но хотелось бы видеть прогресс внутри каждого шага.
При попытке использовать метод
bo.Process.CreateSubProcess(..);
ожидается параметр типа ManagedOperationItem:
ManagedOperationItem CreateSubProcess(ManagedOperationItem item, int? index);

Не понятно что это за тип и как сделать правильно вызов, примеров не смог найти. Сейчас в документации другие типы используются.

Replies

UserDescriptionPosted On
Oleg KrupenkinSupport Manager

ManagedOperationItem - базовый класс для ManagedOperation (об этом сказано в его документации: "Defines the base class for managed operations").
Он содержит несколько перегруженных версий метода CreateSubProcess:
1) public ManagedOperationItem CreateSubProcess(ManagedOperationItem item, int? index)
2) public ManagedOperationItem CreateSubProcess(string name, Action<IManagedOperation> action)
3) public ManagedOperationItem CreateSubProcess(string name, Action<IManagedOperation> action, int total, int? index = null)

В документации на xafari.ru (http://xafari.ru/documentation/managed_operations_examples_ru.html) есть примеры использования перегруженных версий методов 2 и 3.

Примера вызова версии 1 нет, но он вроде как тоже очевиден. Если в качестве аргумента используется ManagedOperationItem, значит ему необходимо передать экземпляр класса, являющийся ManagedOperationItem. Таким классом, например, является сам класс длительной операции - ManagedOperation:

var parentOperation = new ManagedOperation();

...

var childOperation = new ManagedOperation();

...

parentOperation.CreateSubProcess(childOperation);


parentOperation.Start();

Что касается приведенного примера бизнес-операции, то здесь немного сложней. Дело в том, что метод Execute реализации бизнес-операции вызывается уже на стадии выполнения длительной операции. Это не позволяет внутри данного метода добавить подпроцессы в родительскую длительную операцию. Подпроцессы необходимо добавлять еще до ее (длительной операции) старта.

Если каждый этап импорта необходимо выполнять последовательно, друг за другом, внутри одной бизнес-операции, то создание подпроцессов не совсем то, что нужно (подпроцессы выполняются асинхронно, параллельно). Можно попытаться "научить" методы TestData.ReadFromTxt вызывать callback delegate, например, который и выполнял бы NextStep:

....

TestData.ReadFromTxt(objectSpace, "department.txt", TestData.CreateDepartments, msg => (bo.Process.NextStep(msg,));

....

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

Возможный вариант решения может выглядеть так:

// Бизнес-операция
public class ImportTxtService : BusinessOperationManagedBase
{
// Переопределяем CreateManagedOperation, чтобы создавалась длительная операция с нужными подпроцессами
protected override IManagedOperation CreateManagedOperation()
{
var mo = (ManagedOperation)base.CreateManagedOperation();
// Создаем экземпляр реализации по умолчанию
var impl = (IImortTxtServiceImpl)GetDefaultOperationServiceInstance();
// Каждый делегат, описанный в реализации, добавляем как подпроцесс в управляемую операцию.
foreach (var action in impl.Actions)
{
Action<IBusinessOperation, IManagedOperation> action1 = action;
mo.CreateSubProcess("", p => action1(this, p));
}
return mo;
}
}


// Интерфейс, указывающий, что реализация относится к БО ImportTxtService
public interface IImortTxtServiceImpl
{
IEnumerable<Action<IBusinessOperation, IManagedOperation>> Actions { get; }
}


// реализация
public class ImortTxtServiceImpl : OperationServiceBase, IImortTxtServiceImpl
{
// Свойство возвращает перечень делегатов, которые должны быть вызваны (либо синхронно, либо асинхронно, как подпроцессы длительной операции).
public IEnumerable<Action<IBusinessOperation, IManagedOperation>> Actions {
get
{
yield return (bo, mo) => TestData.ReadFromTxt(GetObjectSpace(bo), "department.txt", TestData.CreateDepartments, 1, bo, mo);
yield return (bo, mo) => TestData.ReadFromTxt(GetObjectSpace(bo), "job.txt", TestData.CreatePositions, 1, bo, mo);
// ... остальные вызовы
}
}
public override void Execute(IBusinessOperation businessOperation)
{
// При вызове бизнес-операции как НЕ управляемой, будут последовательно вызываться все этапы импорта.
// Если же БО вызывается как управляемая - этот код выполнен не будет (вместо этого будут выполняться подпроцессы длительной операции).
foreach (var action in Actions)
{
action(businessOperation, ((ImortTxtServiceImpl)businessOperation).Process);
}
}
}

Здесь используется одна особенность длительных операций: если она содержит подпроцессы, то ее собственный делегат ProcessCode не вызывается. Таким образом удается сохранить работоспособность бизнес-операции при любом сценарии ее вызова (как в управляемом контексте (bo.ExecuteManaged), так и синхронно (bo.Execute)).

× This ticket is closed.