F # with asynchronous workflow and try / with

I have a headache trying to put together a simple functionality.

Consider the following definitions:

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>

      

Usage Task<T>

because these are libraries developed in other .NET languages.

(I created this code for example)

Basically, I want to store the data in the repository service and then store the data in the notification service. But if this second operation fails and throws exceptions, I want to undo the operation on the repository. Then there are two situations where I would like to trigger a rollback operation, the first if it notification.SaveAsync

returns false and the second if it throws an exception. And of course I would like to program this call to rollback once, but I cannot find a way.

Here's what I've tried:

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

      

But unfortunately I am getting a compiler error in let! nr = ...

: This construct can only be used in computation expressions

What would be the correct way to do this?

+3


source to share


1 answer


The problem is that when an expression is used let v = e

in computation expressions, the expression e

is a regular expression that cannot contain additional asynchronous constructs. What exactly is happening here:

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

      



You can turn this into a nested block async

:

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

      

+9


source







All Articles