我有一个web服务,可以加载一些插件(dll)并调用它们的Process方法。其中一个插件获取成员列表,并确保它们都包含在MailChimp列表中。
以下是将用户添加到MailChimp组的代码。
private async Task AddMCUsers(List<Member> _memberList)
{
using (var http = new HttpClient())
{
var creds = Convert.ToBase64String(Encoding.ASCII.GetBytes("user:password");
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", creds);
string memberURI = string.Format(@"{0}lists/{1}/members", _baseURI, _memberGroupId);
var jss = new JavaScriptSerializer();
foreach (var user in _memberlist)
{
var _addStatus = "";
try
{
var content = jss.Serialize(new MCPost()
{
email_address = user.Email,
status = "subscribed",
merge_fields = new MCMergeFields()
{
FNAME = user.Firstname,
LNAME = user.Lastname
}
});
using(var result = await http.PostAsync(memberURI, new StringContent(content,Encoding.UTF8, "application/json")))
{
var resultText = await result.Content.ReadAsStringAsync();
if(result.IsSuccessStatusCode)
{
_addStatus = "Success";
var _returnedUser = jss.Deserialize<MCMember>(resultText);
//Store new user's id
user.ServiceId = _returnedUser.id;
}
else
{
_addStatus = "Fail";
}
}
}
catch {
_addStatus = "Error";
}
LogEvent("Add User - " + _addStatus, string.Format("Id: {0} - {1} {2} (Account: {3}) : {4}", user.Id, user.Firstname, user.Lastname, user.AccountId, user.Email));
}
}
}
在正常的程序代码中,这不会成为问题。但是,httpClient上唯一可用的Post方法是PostAsync。作为async / await东西的新手,我不确定其余代码的后果......特别是因为它与我尝试重用httpClient而不是为每个http调用实例化一个新代码有关。
我不确定当它被包裹在像我一样的foreach中时会发生什么。在异步运行时重新使用httpClient进行重复调用会遇到问题吗?
我的另一个问题是,实际上会返回什么。 IOW,我的理解是await返回一个Task。但是,在这里,我循环遍历列表并进行多次调用以等待PostAsync。我的方法返回一个Task。但哪个任务返回?如果我的调用方法需要在继续之前等待完成,它的调用是什么样的?
private void Process()
{
//Get List
var task = AddMCUsers(list);
task.Wait();
//Subsequent processing
}
我已经读过你应该一直使用Async。这是否意味着我的调用方法应该更像这样?
public async Task Process()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
感谢您提供的任何帮助。
答案 0 :(得分:4)
在正常的程序代码中,这不是问题。
WHERE line.`The #` IS NOT NULL AND line.`Person's First/Last Name` IS NOT NULL
/ async
的重点是以与“普通”同步代码几乎完全相同的方式编写异步代码。
对async / await东西相当新,我不确定其余代码的后果......特别是因为它与我尝试重用httpClient而不是为每个http调用实例化一个新的
await
旨在重复使用;实际上,它可以同时用于任意数量的呼叫。
我不确定当它像我一样包裹在foreach中时会发生什么。
考虑它的一种方法是HttpClient
“暂停”该方法直到其操作完成。当操作完成时,该方法继续执行。我有一个更详细的async
intro。
在异步运行时,重新使用httpClient重复调用会遇到问题吗?
不,那很好。
IOW,我的理解是等待返回一个任务。
await
await
。它“解开”该任务并返回任务的结果(如果有的话)。如果任务以异常完成,则Task
会引发该异常。
我的方法返回一个Task。但是哪个任务会被返回?
await
方法返回的Task
由async
状态机创建。你不必担心它。有关详细信息,请参阅我的介绍。
如果我的调用方法需要在继续之前等待完成,它的调用是什么样的? ...我已经读过你应该一直使用Async。这是否意味着我的调用方法应该更像这样?
是的,它看起来应该是你的第二个片段:
async
我唯一更改的是public async Task ProcessAsync()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
后缀,Task-based Asynchronous Pattern推荐使用。{/ p>
答案 1 :(得分:0)
在您的代码中,您应该可以重用HttpClient。 async / await允许代码释放执行线程以防止在等待Web响应时锁定cpu线程。它还将控制权释放回调用者。将代码发回给调用方时,意味着如果您的Process
函数没有等待AddMCUsers
,Process
可能会在AddMCUsers
之前完成(在火灾和忘记情况下有用)等待方法)。
async/await
不做的是影响单个方法的逻辑流程。当您等待异步Web调用时,执行暂停,然后在Web调用返回后在同一点恢复。还有线程上下文跟踪,默认情况下代码在相同的上下文中恢复(即UI线程或后台线程,具体取决于父级),但如果需要,可以更改。
在您的代码中的某个时刻,您可能希望有一个阻塞的方法,直到您的异步代码竞争,并且您希望Task.Wait()调用阻止执行。如果您正在等待,那么您的程序可能会在您的任务竞争之前结束。请参阅下面的代码示例。
class Program
{
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
}
static async Task waitAsync()
{
await Task.Delay(5000);
}
}
在没有Task.Wait
调用阻止Main方法的示例中,程序将在5秒等待完成之前结束。拥有以下主要方法将导致程序在退出前等待5秒钟:
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
waitForMe.Wait();
}