2014-09-27 46 views
1

我有一个主要方法从另一个类中调用方法,这些方法都是异步任务方法,但不返回任何内容。他们正在向REST API客户端发送获取请求。 这里有一个方法,在一个名为DbRequestHandler类的例子:试图在c#控制台应用程序中运行多个异步任务

public static async Task ReadRooms(HttpClient client) 
{ 
    // HTTP GET all rooms 
    HttpResponseMessage response = await client.GetAsync("api/v1/rooms"); 

    if (response.IsSuccessStatusCode) 
    { 
     StreamWriter file = new StreamWriter("xmlRooms.xml", false); 

     string rooms = await response.Content.ReadAsStringAsync(); 
     file.Write(rooms); 
     file.Flush(); 

     Console.Out.Write(rooms); 
     Console.ReadKey(); 
    } 
} 

下面是通过调用DbRequestHandler运行的程序的主要方法:

static void Main(string[] args) 
{ 
    var url = System.Configuration.ConfigurationManager.AppSettings["CentrisURL"]; 

    if (url == null) 
    { 
     Console.WriteLine("Failed to load API url"); 
    } 

    var client = new HttpClient(); 
    client.BaseAddress = new Uri(url); 
    client.DefaultRequestHeaders.Accept.Clear(); 
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); 

    //DbRequestHandler.ReadRooms(client).Wait(); 
    //DbRequestHandler.ReadRoomsType(client).Wait(); 
    //DbRequestHandler.ReadCourses(client).Wait(); 
    DbRequestHandler.ReadTeachers(client).Wait(); 
} 

我的问题是,我似乎无法弄清楚如何调用所有这些独立方法,这些方法都是异步任务方法,我知道它与.Wait()有关,但我一直无法找到正确的解决方案,我尝试了一些。如果我取消注释对DbRequestHandler方法的所有调用,则第一行是唯一被执行的行。有没有人有建议如何解决这个问题?我很难理解异步任务。希望我的问题很明确。我会读你建议阅读的任何链接,但我不能保证我就明白了:P

回答

1
static async void Main(string[] args) 
{ 
    var url = System.Configuration.ConfigurationManager.AppSettings["CentrisURL"]; 

    if (url == null) 
    { 
     Console.WriteLine("Failed to load API url"); 
    } 

    var client = new HttpClient(); 
    client.BaseAddress = new Uri(url); 
    client.DefaultRequestHeaders.Accept.Clear(); 
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); 

    await Task.WhenAll(
     new Task[] { 
      DbRequestHandler.ReadRooms(client), 
      DbRequestHandler.ReadRoomsType(client), 
      DbRequestHandler.ReadCourses(client), 
      DbRequestHandler.ReadTeachers(client), 
     } 
    ); 
} 
+0

这看起来非常好,我虽然这会工作,但我得到了与另一个解决方案相同的错误,那就是:“'await'操作符只能在异步方法中使用,请考虑使用' async'修饰符并将其返回类型更改为'Task' – 2014-09-27 17:39:51

+0

@MargretKristjansdottir对不起...再试一次... – Aron 2014-09-27 17:40:50

+5

@Aron你不能使'Main'异步,如果你正在编写一个控制台应用程序,你必须调用'。 Wait()'。如果这是一个事件中的WCF或winforms项目,你的解决方案将是正确的。 – 2014-09-27 17:47:05

-1

解决这将是创建任务的数组,然后等待所有完成的最好方法有关运行多个任务

if (url == null) 
     { 
      Console.WriteLine("Failed to load API url"); 
     } 

     var client = new HttpClient(); 
     client.BaseAddress = new Uri(url); 
     client.DefaultRequestHeaders.Accept.Clear(); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); 
     Task[] taskArray = new Task[4]; 
     taskArray[0] = Task.Factory.StartNew(await DbRequestHandler.ReadRooms(client)); 
     taskArray[1] = Task.Factory.StartNew(DbRequestHandler.ReadRoomsType(client)); 
     taskArray[2] = Task.Factory.StartNew(DbRequestHandler.ReadCourses(client)); 
     taskArray[3] = Task.Factory.StartNew(DbRequestHandler.ReadTeachers(client)); 
     Task.WaitAll(taskArray); 

的更多信息可以在MSDN上找到enter link description here

+2

-1错误地使用'Task.Factory.StartNew'。因为它被使用。完全可以。 – Aron 2014-09-27 17:42:16

+0

You对了。我的错。 – CrazyBernie 2014-09-27 17:43:56

+0

OP的问题是异步编程而非线程编程。此外,你不应该写'Task.Factory.StartNew(await ...)'。 – Aron 2014-09-27 17:45:24

0

async-await和控制台应用程序打交道时,你总是最终做的事情,你在的地方不会做,你有一个自定义SynchronizationContext(如Winforms或WPF)。

在你的榜样,您可以使用在主要执行的所有任务Task.WaitAll简单地等待,直到他们都完成:

Task readRoomsTask = DbRequestHandler.ReadRooms(client); 

Task readRoomTypeTask = DbRequestHandler.ReadRoomsType(client); 
Task readCoursesTask = DbRequestHandler.ReadCourses(client); 
Task readTeachersTask = DbRequestHandler.ReadTeachers(client); 

Task.WaitAll(readRoomsTask, readRoomTypeTask, reachCoursesTask, reqdTeachersTask); 
2

如果我取消注释所有DbRequestHandler方法的调用第一行是唯一被执行的一个。

这听起来像您的实际应用一个控制台应用程序像您发布的一个。我没有看到你的原始代码无法工作的原因。我刚刚运行了你的代码,它执行了两种方法。

如果你想要做的异步工作方式串行(一个接一个),那么你应该使用await

await DbRequestHandler.ReadRoomsAsync(client); 
await DbRequestHandler.ReadRoomsTypeAsync(client); 
... 

如果你想同时做所有的异步工作方式,那么你应该使用await Task.WhenAll

await Task.WhenAll(DbRequestHandler.ReadRoomsAsync(client), 
    DbRequestHandler.ReadRoomsTypeAsync(client), ...); 

无论哪种方式,如果你把这个变成一个控制台应用程序,我建议你Main改为只调用另外一种方式和Wait就可以了,就像这样:

static void Main(string[] args) 
{ 
    MainAsync().Wait(); 
} 

static async Task MainAsync() 
{ 
    var url = System.Configuration.ConfigurationManager.AppSettings["CentrisURL"]; 
    ... 
} 

这可以帮助您的代码保持干净,方法是将代码保留在Main所在的位置,而无需其他位置。

相关问题