C# 将异步lambda包装到异步方法
我正在尝试将我的C# 将异步lambda包装到异步方法,c#,wcf,asynchronous,async-await,C#,Wcf,Asynchronous,Async Await,我正在尝试将我的操作契约包装到try-catch块。问题是我的EF上下文在同一时间范围内被破坏。我猜问题编译器不知道该怎么做。我的catch块也不处理任何异常。对不起,我的英语,我希望我的代码能说明我的意思: private static async Task<T> SurroundWithTryCatch<T>(Action t, T response) where T : BaseResponse { try { await Task
操作契约
包装到try-catch块。问题是我的EF上下文在同一时间范围内被破坏。我猜问题编译器不知道该怎么做。我的catch块也不处理任何异常。对不起,我的英语,我希望我的代码能说明我的意思:
private static async Task<T> SurroundWithTryCatch<T>(Action t, T response) where T : BaseResponse
{
try
{
await Task.Run(t);
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async delegate
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
private static async Task SurroundWithTryCatch(Action t,t response),其中t:BaseResponse
{
尝试
{
等待任务。运行(t);
}
捕获(例外e)
{
回答:成功=错误;
响应.错误.添加(e.Message);
}
返回响应;
}
公共异步任务CreateAsync(CreateRequest请求)
{
var response=newcreateresponse();
return wait SurroundWithTryCatch(异步委托
{
var newUser=newapplicationuser{UserName=request.UserName,Email=request.Email};
等待Database.UserManager.CreateAsync(newUser,request.Password);
//另一种逻辑。。。
wait Database.CommitAsync();
},回应);
}
CreateAsync
方法第二行中的问题<代码>用户管理器已由GC先前清理。所以我有了ObjectDisposedException
Database
是IUnitOfWork
的实现,由Autofac
注入您正在打破Wait
链-t
不再返回任务。由于您不再有任务,因此执行将在第一个wait
之后继续,而不是在完成整个方法之后。将wait
视为return
-如果您不返回(和wait
/wait)任务,您将失去同步的机会
相反,您希望传递Func
,并直接等待它:
private static async Task<T> SurroundWithTryCatch<T>(Func<Task> t, T response) where T : BaseResponse
{
try
{
await t();
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async () =>
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
private static async Task SurroundWithTryCatch(Func t,t response),其中t:BaseResponse
{
尝试
{
等待t();
}
捕获(例外e)
{
回答:成功=错误;
响应.错误.添加(e.Message);
}
返回响应;
}
公共异步任务CreateAsync(CreateRequest请求)
{
var response=newcreateresponse();
return wait SurroundWithTryCatch(异步()=>
{
var newUser=newapplicationuser{UserName=request.UserName,Email=request.Email};
等待Database.UserManager.CreateAsync(newUser,request.Password);
//另一种逻辑。。。
wait Database.CommitAsync();
},回应);
}
Task.Run
也可以运行,但您可能无论如何都不希望这样做-您的代码是异步的,而且(猜测)您正在ASP.NET请求中运行,因此启动任务只是等待另一个任务的结果没有任何好处Task.Run
用于在单独的线程中执行CPU工作,这是ASP.NET中通常要避免的事情。您正在打破wait
链-t
不再返回任务。由于您不再有任务,因此执行将在第一个wait
之后继续,而不是在完成整个方法之后。将wait
视为return
-如果您不返回(和wait
/wait)任务,您将失去同步的机会
相反,您希望传递Func
,并直接等待它:
private static async Task<T> SurroundWithTryCatch<T>(Func<Task> t, T response) where T : BaseResponse
{
try
{
await t();
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async () =>
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
private static async Task SurroundWithTryCatch(Func t,t response),其中t:BaseResponse
{
尝试
{
等待t();
}
捕获(例外e)
{
回答:成功=错误;
响应.错误.添加(e.Message);
}
返回响应;
}
公共异步任务CreateAsync(CreateRequest请求)
{
var response=newcreateresponse();
return wait SurroundWithTryCatch(异步()=>
{
var newUser=newapplicationuser{UserName=request.UserName,Email=request.Email};
等待Database.UserManager.CreateAsync(newUser,request.Password);
//另一种逻辑。。。
wait Database.CommitAsync();
},回应);
}
Task.Run
也可以运行,但您可能无论如何都不希望这样做-您的代码是异步的,而且(猜测)您正在ASP.NET请求中运行,因此启动任务只是等待另一个任务的结果没有任何好处Task.Run
用于在单独的线程中执行CPU工作,这是ASP.NET中通常要避免的事情。尝试将SurroundWithTryCatch(Action t,t response)
替换为SurroundWithTryCatch(funct t,t response)
和返回wait SurroundWithTryCatch(异步代理
withreturn wait SurroundWithTryCatch(async()=>
@YacoubMassad)感谢您的快速回复!它很有效!!我在两点钟或更长的时间里都在挣扎。您能解释一下发生了什么并将其作为答案发布吗?尝试用trycatch替换SurroundWithTryCatch(动作t,t响应)
(Func t,t response)和return await SurroundWithTryCatch(异步委托
withreturn await SurroundWithTryCatch(异步()=>
@YacoubMassad感谢您的快速回复!它很有效!!我在两点钟或更长的时间里一直在挣扎。您能解释一下发生了什么并将其作为答案发布吗?非常感谢!您今天救了我一命!如果我的T
是前置类型,我能做同样的事情吗?我有一个包装原始类型的想法,但可能是更好的方法。@user3818229我不确定“基元类型”的确切含义。一般来说,泛型可以处理您想要的任何类型;如果您想做一些更具体的事情,可以使用泛型类型约束(正如您在这里所做的)或强制转换。@user3818229那么你是说值类型?包装它们可以很好地用于泛型。诀窍是确保修改的是共享值,而不是复制的值(值类型按值传递给方法,因此它们总是创建副本)。一种方法是使用ref T
,另一种方法是创建您自己的包装器类。非常感谢!您