Можно ли сохранить конечный автомат, встроенный в Workflow Foundation, в БД с помощью Nhibernate? - PullRequest
2 голосов
/ 10 ноября 2010

У меня есть приложение, которое содержит несколько экземпляров конечного автомата при запуске. Я хотел бы, чтобы они неявно сохранялись в базе данных для того, чтобы при перезапуске приложения их можно было повторно загрузить из базы данных, и они возобновят работу в том же состоянии, в котором они закончили, вместе со всеми установленными свойствами объекта пока экземпляр был в памяти.

Возможна ли такая вещь?

Я напрасно искал в Google, что означает одну из трех вещей:

  1. Это невозможно!
  2. Я ужасно использую Google
  3. Приличный ответ на этот вопрос поможет многим другим людям

Я надеюсь, что ответ 3! :)

Ответы [ 3 ]

3 голосов
/ 10 ноября 2010

Да, но это не пикник.

У меня запущена эта реализация, и для ее выполнения потребовалось много работы Я не буду предоставлять полную реализацию (много кода и нераскрытия), но я дам строительные блоки, которые привели меня к конечному результату.

  • http://msdn.microsoft.com/en-us/library/dd483375.aspx, расположенный в WF_WCF_Samples\WF\Application\PurchaseProcess\CodedWorkflow\CS\WfDefinition\XmlWorkflowInstanceStore.cs, имеет XML-персистент для рабочего процесса. Это позволяет обойти проблему, связанную с необходимостью иметь таблицы SQL, и просто позволяет хранить все это в одном блобе XML;

  • Этот сериализатор (де) сериализует код с NetDataContractSerializer. Этот сериализатор должен иметь набор SurrogateSelector, с которым вы переводите свои сущности. Проблема в том, что вы не хотите хранить свои объекты. Кроме того, что все ленивые сущности будут сериализованы вместе с вашей сущностью, к тому времени, как десериализуется ваш XML, ваша сущность устареет. Вместо этого вы хотите, чтобы только внутренний идентификатор был сериализован. Итак, вы делаете SurrogateSelector, который проверяет, является ли сериализуемый объект сущностью. Если это так, вы замените его другим классом, скажем EntityReference, который имеет тип и идентификатор;

  • Когда XML десериализуется, с тем же SurrogateSelector, вы проверяете наличие экземпляров EntityReference. Если вы нашли это, вы делаете ISession.Load() с типом и идентификатором в ссылке и возвращаете это вместо ссылки.

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

Надеюсь, это поможет вам.

2 голосов
/ 10 ноября 2010

Nhibernate не особенно полезен для этого, потому что операция физического сохранения является второстепенным аспектом сохранения рабочего процесса. Участвующая часть - это все сервисы, которые поддерживают выгрузку, перезагрузку и активацию рабочих процессов в соответствующее время и т. Д. Внутренняя работа среды выполнения и сервисов также усложняется тем фактом, что рабочие процессы охватывают границы приложений, которые могут длиться бесконечно долго. Различные объекты могут находиться в разных состояниях в любой момент времени. Поскольку для вызова не может быть гарантированно даже наличие клиента в этих условиях, то, что на самом деле делает среда выполнения, когда вы вызываете событие в рабочем процессе, например, помещает сообщение в очередь, а не вызывает фактический указатель на функцию. Вот как вы можете «вызвать» событие в рабочем процессе, который не запущен.

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

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

http://wftools.codeplex.com/

0 голосов
/ 11 ноября 2010

Будет ли это подходящим решением?

Использование специального обработчика персистентности FilePersistence.cs, который я обнаружил в ссылке на скачивание в следующей статье:

http://msdn.microsoft.com/en-us/library/ms741725%28v=VS.85%29.aspx

   public class FilePersistenceService : WorkflowPersistenceService
{

    public FilePersistenceService(bool unloadOnIdle)
    {
       // ...
    }

    protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
    {
        // ...
    }

    private void ReloadWorkflow(object id)
    {
        // ...
    }

    protected override Activity LoadWorkflowInstanceState(Guid instanceId)
    {
        // ...
    }

    protected override void UnlockWorkflowInstanceState(Activity state)
    {
        // ...
    }

    protected override void SaveCompletedContextActivity(Activity activity)
    {
        // ...
    }

    protected override Activity LoadCompletedContextActivity(Guid activityId, Activity outerActivity)
    {
        // ...

    }

    protected override bool UnloadOnIdle(Activity activity)
    {
        // ...
    }

    private void SerializeToFile(byte[] workflowBytes, Guid id)
    {
        // ... Direct workflowBytes to DB, indexed by Guid
    }


    private byte[] DeserializeFromFile(Guid id)
    {
        // ... Load bytes from DB, by Guid
    }

}

... переопределяя SerializeToFile и DeserializeFromFile для перенаправления вызовов в БД, а не в файловую систему.

Я бы, вероятно, использовал бы NHibernate для выполнения загрузки / сохранения - чтобы сохранить общий DAL во всем приложении и, надеюсь, сохранить независимость от БД (если потребуется использовать другую платформу БД).

Есть ли серьезные недостатки в этом плане?

...