C# 创建异步webservice方法
我已经尝试阅读了异步方法,现在正尝试创建自己的异步方法。该方法是返回错误日志列表的webservice调用。我不确定我是否理解正确,所以我想我应该分享我的代码,看看我是否应该做些不同的事情 我只希望代码通过调用方法GetAllErrorLogs()返回一个错误日志列表,这是一个同步方法。因为获取所有错误日志可能需要一秒钟的时间,所以我希望在调用GetAllErrorLogs()方法后有机会做其他事情。这是代码C# 创建异步webservice方法,c#,.net,async-await,C#,.net,Async Await,我已经尝试阅读了异步方法,现在正尝试创建自己的异步方法。该方法是返回错误日志列表的webservice调用。我不确定我是否理解正确,所以我想我应该分享我的代码,看看我是否应该做些不同的事情 我只希望代码通过调用方法GetAllErrorLogs()返回一个错误日志列表,这是一个同步方法。因为获取所有错误日志可能需要一秒钟的时间,所以我希望在调用GetAllErrorLogs()方法后有机会做其他事情。这是代码 [WebMethod] public async Task<List<Er
[WebMethod]
public async Task<List<ErrorLog>> GetAllErrorLogs()
{
List<ErrorLog> errorLogs = new List<ErrorLog>();
await System.Threading.Tasks.Task.Run(() => {
errorLogs = ErrorLogRepository.GetAllErrorLogs();
});
if (errorLogs == null)
return new List<ErrorLog>();
return errorLogs;
}
[WebMethod]
公共异步任务GetAllErrorLogs()
{
List errorLogs=新列表();
等待System.Threading.Tasks.Task.Run(()=>{
errorLogs=ErrorLogRepository.GetAllErrorLogs();
});
if(errorLogs==null)
返回新列表();
返回错误日志;
}
谢谢 我发现了这篇关于如何实现这一目标的伟大代码项目详细文章
**这可能是错误的,请阅读以下评论或附带问题: 如果
ErrorLogRepository.GetAllErrorLogs()
不是线程安全的,它将导致奇怪的错误,并可能导致异常。在切换到异步方法之前,请确保您的代码已准备好进行多线程操作,这显然是一个非常琐碎的建议,但常常被忽略。例如,如果在方法中引用HttpContext.Current
,则代码将在异步方法中消亡,有时甚至在wait
之后。原因是异步块中的代码可能在单独的线程上运行,该线程将无法访问相同的HttpContext。当前的thread静态属性和await
被编译为两个方法。在一个线程上运行await
之前的所有代码,然后在await关键字之后调用代码作为继续,但可能在另一个线程上。因此,有时您的代码甚至会在异步块中工作,结果在它“退出”异步后意外阻塞,返回到您认为是代码的同步部分(但实际上,wait
关键字之后的所有内容都不能保证是原始线程)。我最近在,我在幻灯片中谈到了这个问题
在服务器端,您希望避免使用Task.Run
和其他将工作排入线程池的构造。尽可能保持线程池线程可用于处理请求
因此,理想情况下,您的存储库应该有一个异步方法GetAllErrorLogsAsync
,它本身就是异步的。如果GetAllErrorLogs
不能是异步的,那么您可以直接调用它(删除wait任务。运行)
因为获取所有错误日志可能需要一秒钟的时间,所以我希望在调用GetAllErrorLogs()方法后有机会做其他事情
如果您有可用的GetAllErrorLogsAsync
,则可以使用Task.whalll
轻松完成此操作。但是,如果GetAllErrorLogs
是同步的,那么您只能通过在请求中执行并行工作(例如,多次调用Task.Run
,然后调用Task.whalll
)来实现这一点
服务器上的并行代码必须以极大的恐惧来处理。这仅在非常有限的一组场景中是可以接受的。服务器端的async
的全部要点是每个请求使用较少的线程,而当您开始并行化时,您的做法正好相反:每个请求使用多个线程。只有当你知道你的用户群很小时,这才是合适的;否则,您将破坏服务器的可扩展性。以下是一些生产代码
using System.Web.Http;
using AysncTask = System.Threading.Tasks.Task;
public class myController : ApiControllerBase
{
[HttpPut]
[Route("api/cleardata/{id}/{requestId}/")]
public async AysncTask ClearData(Guid id, Guid requestId)
{
try
{
await AysncTask.Run(() => DoClearData(id, requestId));
}
catch (Exception ex)
{
throw new Exception("Exception in myController.ClearData", ex);
}
}
}
处理异步异常也非常重要。。虽然这适用于windows控制台应用程序,但同样的原则也应适用
资料来源:
}我认为在服务器端使用async/await没有什么好处。您只需对同一事物使用更多线程即可。@I4V:async
服务器端可以显著减少每个请求使用的线程数(假设代码是自然异步的,而不是伪异步的,例如Task.Run
)。因此,异步服务器能够更好地扩展,通常在10-100倍左右。。。我在微软的一个校园参加了一个培训课程,在那里我们被告知,只要将服务器上运行的所有代码异步化,就可以大幅提高相同硬件的容量。纯粹是因为,当一个方法正在等待子调用的响应时,主线程被释放去做其他工作。。。ie处理其他并发的web请求。优点是多任务。这个答案有很多错误信息<此处不需要代码>未观察到的异常(等待
将通过WebAPI方法正确传播GetAllErrorLogs
中的任何异常)HttpContext.Current
在默认情况下被正确地传播到处理异步请求的所有线程(即,返回错误日志
行有一个完全有效的HttpContext.Current
)。关于等待,你说得对,我错读了那部分。它只会在任务的情况下不被传播。运行被用作火,然后忘记。但是,HttpContext.Current在等待后肯定无效,除非WebAPI已覆盖默认的同步上下文行为。WebAPI不提供同步上下文,但ASP.NET提供。因此,HttpContext.Current
在wait
@StephenCleary之后是完全有效的,WebAPI不提供同步上下文-hmm,在任何情况下,它仍然是Web API的AspNetSynchronizationContext
?下面是一个例子,我要求OPDebug.Print(SynchronizationContext.Current.GetType().Name)
,结果是AspNetSynchroniz
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncAndExceptions
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += (s, e) => Log("*** Crash! ***", "UnhandledException");
TaskScheduler.UnobservedTaskException += (s, e) => Log("*** Crash! ***", "UnobservedTaskException");
RunTests();
// Let async tasks complete...
Thread.Sleep(500);
GC.Collect(3, GCCollectionMode.Forced, true);
}
private static async Task RunTests()
{
try
{
// crash
// _1_VoidNoWait();
// crash
// _2_AsyncVoidAwait();
// OK
// _3_AsyncVoidAwaitWithTry();
// crash - no await
// _4_TaskNoWait();
// crash - no await
// _5_TaskAwait();
// OK
// await _4_TaskNoWait();
// OK
// await _5_TaskAwait();
}
catch (Exception ex) { Log("Exception handled OK"); }
// crash - no try
// await _4_TaskNoWait();
// crash - no try
// await _5_TaskAwait();
}
// Unsafe
static void _1_VoidNoWait()
{
ThrowAsync();
}
// Unsafe
static async void _2_AsyncVoidAwait()
{
await ThrowAsync();
}
// Safe
static async void _3_AsyncVoidAwaitWithTry()
{
try { await ThrowAsync(); }
catch (Exception ex) { Log("Exception handled OK"); }
}
// Safe only if caller uses await (or Result) inside a try
static Task _4_TaskNoWait()
{
return ThrowAsync();
}
// Safe only if caller uses await (or Result) inside a try
static async Task _5_TaskAwait()
{
await ThrowAsync();
}
// Helper that sets an exception asnychronously
static Task ThrowAsync()
{
TaskCompletionSource tcs = new TaskCompletionSource();
ThreadPool.QueueUserWorkItem(_ => tcs.SetException(new Exception("ThrowAsync")));
return tcs.Task;
}
internal static void Log(string message, [CallerMemberName] string caller = "")
{
Console.WriteLine("{0}: {1}", caller, message);
}
}