2014-11-25 5 views
3

У меня болит голова, пытаясь собрать простую функциональность.F # Проблема с асинхронным рабочим процессом и попробуйте/с

Рассмотрим следующие определения:

type Entity = {Id:int;Data:string} 

type IRepository = 
    abstract member SaveAsync: array<Entity> -> Task<bool> 
    abstract member RollBackAsync: array<Entity> -> Task<bool> 

type INotification = 
    abstract member SaveAsync: array<Entity> -> Task<bool> 

Использование Task<T>, потому что они являются библиотеки, разработанные в других языках .NET.

(я создал этот код ради примера)

В принципе, я хочу, чтобы сохранить данные в службе хранилища, а затем сохранить данные в службе уведомления. Но если эта вторая операция завершается с ошибкой и включает исключения, я хочу отменить операцию в репозитории. Тогда есть две ситуации, когда я хотел бы вызвать операцию отката, первый, если notification.SaveAsync возвращает false, а второй, если он выдает исключение. И, конечно, я хотел бы запрограммировать этот призыв к откату один раз, но я не могу найти способ.

Это то, что я пробовал:

type Controller(repository:IRepository, notification:INotification) = 

    let saveEntities entities:Async<bool> = async{ 

    let! repoResult = Async.AwaitTask <| repository.SaveAsync(entities) 
    if(not repoResult) then 
     return false 
    else 
     let notifResult = 
     try 
      let! nr = Async.AwaitTask <| notification.SaveAsync(entities) 
      nr 
     with 
      | _-> false 

     if(not notifResult) then 
     let forget = Async.AwaitTask <| repository.RollBackAsync(entities) 
     return false 
     else 
     return true 
    } 

    member self.SaveEntitiesAsync(entities:array<Entity>) = 
    Async.StartAsTask <| saveEntities entities 

Но, к сожалению, я получаю сообщение об ошибке на let! nr = ... говоря: Эта конструкция может быть использована только в расчетных выражениях

Какой бы правильный путь делать это?

ответ

8

Проблема заключается в том, что при использовании в вычислениях выражения let v = e выражение e является обычным выражением, которое не может содержать дополнительные асинхронные конструкции. Это именно то, что происходит здесь:

let notifResult = 
    try 
     let! nr = Async.AwaitTask <| notification.SaveAsync(entities) 
     nr 
    with _-> false 

Вы можете превратить это в гнездовой async блока:

let! notifResult = async { 
    try 
     let! nr = Async.AwaitTask <| notification.SaveAsync(entities) 
     return nr 
    with _-> return false } 
+0

Что интересно, я не заметил, что вы можете вложить их. Благодаря! – vtortola

Смежные вопросы