await client.GetStringAsync毫无例外地退出

时间:2014-04-22 15:56:32

标签: c# asp.net .net async-await asp.net-web-api2

我关注如何在ASP.NET Web API 2中使用批处理支持blog post。服务器代​​码似乎可以工作并侦听端口12345。

当我运行客户端代码时,它会到达这一行:

dynamic listOfCustomers = JToken.Parse(await client.GetStringAsync("http://localhost:12345/api/WebCustomers"));

并退出,不会抛出任何异常。这是调试输出:

'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'c:\users\documents\visual studio 2013\Projects\client_batch\client_batch\bin\Debug\client_batch.vshost.exe'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 0x1b80 has exited with code 259 (0x103).
The thread 0x1fec has exited with code 259 (0x103).
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'c:\users\mryan.asavie\documents\visual studio 2013\Projects\client_batch\client_batch\bin\Debug\client_batch.exe'. Symbols loaded.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'c:\users\mryan.asavie\documents\visual studio 2013\Projects\client_batch\client_batch\bin\Debug\Newtonsoft.Json.dll'. Cannot find or open the PDB file.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'c:\users\mryan.asavie\documents\visual studio 2013\Projects\client_batch\client_batch\bin\Debug\System.Net.Http.Formatting.dll'. Cannot find or open the PDB file.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'c:\users\mryan.asavie\documents\visual studio 2013\Projects\client_batch\client_batch\bin\Debug\Ploeh.AutoFixture.dll'. Cannot find or open the PDB file.
'client_batch.vshost.exe' (CLR v4.0.30319: client_batch.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 0x1920 has exited with code 259 (0x103).
The thread 0x14ac has exited with code 259 (0x103).
The program '[7268] client_batch.vshost.exe' has exited with code 0 (0x0).

这是服务器的代码:

namespace MyWebApp
{
    class Program {

        static void Main(string[] args)
        {
            string serviceUrl = "http://localhost:12345";
            using (WebApp.Start(serviceUrl, Configuration))
            {

                Console.WriteLine("Service listening at {0}", serviceUrl);
                Console.WriteLine("Press any key to stop the service and exit the application");
                Console.ReadKey();
            }
        }

        private static void Configuration(IAppBuilder builder)
        {
            HttpConfiguration configuration = new HttpConfiguration();
            HttpServer server = new HttpServer(configuration);
            configuration.Routes.MapHttpRoute(
                name: "api",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional });
            builder.UseWebApi(server);
        }

        public class Customer
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

        public class WebCustomersController : ApiController
        {
            CustomersContext context = new CustomersContext();
            [Queryable(PageSize = 10, MaxExpansionDepth = 2)]
            public IHttpActionResult Get()
            {
                return Ok(context.Customers);
            }

            public async Task<IHttpActionResult> Post([FromBody] Customer entity)
            {
                if (entity == null)
                {
                    return BadRequest(ModelState);
                }
                context.Customers.Add(entity);
                await context.SaveChangesAsync();
                return CreatedAtRoute("api", new { controller = "ApiCustomers" }, entity);
            }

            public async Task<IHttpActionResult> Put(int id, [FromBody] Customer entity)
            {
                if (entity == null)
                {
                    return BadRequest(ModelState);
                }
                else if (id != entity.Id)
                {
                    return BadRequest("The key from the url must match the key of the entity in the body");
                }
                var originalCustomer = await context.Customers.FindAsync(id);
                if (originalCustomer == null)
                {
                    return NotFound();
                }
                else
                {
                    context.Entry(originalCustomer).CurrentValues.SetValues(entity);
                    await context.SaveChangesAsync();
                }
                return Content(HttpStatusCode.OK, entity);
            }

            public async Task<IHttpActionResult> Delete(int id)
            {
                Customer entity = await context.Customers.FindAsync(id);
                if (entity == null)
                {
                    return NotFound();
                }
                else
                {
                    context.Customers.Remove(entity);
                    await context.SaveChangesAsync();
                    return StatusCode(HttpStatusCode.NoContent);
                }
            }
        }

        public class CustomersContext : DbContext
        {
            static CustomersContext()
            {
                Database.SetInitializer<CustomersContext>(new CustomersContextInitializer());
            }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
            }

            private class CustomersContextInitializer : DropCreateDatabaseAlways<CustomersContext>
            {
                protected override void Seed(CustomersContext context)
                {
                    Fixture fixture = new Fixture();
                    IEnumerable<Customer> customers = fixture.CreateMany<Customer>(20).ToList();
                    context.Customers.AddRange(customers);
                }
            }

            public DbSet<Customer> Customers { get; set; }
        }
    }
}

这对于客户来说:

namespace client_batch
{
    class Program
    {
        static void Main(string[] args)
        {
            start();
        }

        private async static void start()
        {
            Fixture fixture = new Fixture();
            HttpClient client = new HttpClient();

            dynamic listOfCustomers = JToken.Parse(await client.GetStringAsync("http://localhost:12345/api/WebCustomers"));
            dynamic firstCustomer = listOfCustomers[0];
            firstCustomer.Name = "Peter";
            dynamic secondCustomer = listOfCustomers[1];
            JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter();

            //Create a request to query for customers
            HttpRequestMessage queryCustomers = new HttpRequestMessage(HttpMethod.Get, "http://localhost:12345/api/WebCustomers");
            //Create a message to add a customer
            HttpRequestMessage addCustomer = new HttpRequestMessage(HttpMethod.Post, "http://localhost:12345/api/WebCustomers");
            addCustomer.Content = new ObjectContent<Customer>(fixture.Create<Customer>(), formatter);
            //Create a message to update a customer
            HttpRequestMessage updateCustomer = new HttpRequestMessage(HttpMethod.Put, string.Format("http://localhost:12345/api/WebCustomers/{0}", firstCustomer.Id));
            updateCustomer.Content = new ObjectContent<dynamic>(firstCustomer, formatter);
            //Create a message to remove a customer.
            HttpRequestMessage removeCustomer = new HttpRequestMessage(HttpMethod.Delete, string.Format("http://localhost:12345/api/WebCustomers/{0}", secondCustomer.Id));

            //Create the different parts of the multipart content
            HttpMessageContent queryContent = new HttpMessageContent(queryCustomers);
            HttpMessageContent addCustomerContent = new HttpMessageContent(addCustomer);
            HttpMessageContent updateCustomerContent = new HttpMessageContent(updateCustomer);
            HttpMessageContent removeCustomerContent = new HttpMessageContent(removeCustomer);

            //Create the multipart/mixed message content
            MultipartContent content = new MultipartContent("mixed", "batch_" + Guid.NewGuid().ToString());
            content.Add(queryContent);
            content.Add(addCustomerContent);
            content.Add(updateCustomerContent);
            content.Add(removeCustomerContent);

            //Create the request to the batch service
            HttpRequestMessage batchRequest = new HttpRequestMessage(HttpMethod.Post, "http://localhost:12345/api/batch");
            //Associate the content with the message
            batchRequest.Content = content;
        }

        public class Customer
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }
}

我是c#的新手,所以任何指针都会受到赞赏!

1 个答案:

答案 0 :(得分:4)

当你在异步方法的代码中使用等待关键字时,你真正告诉程序的是&#34;听,你继续工作,当你完成时给我回电(当然,这不是那么简单,编译器为我们做了很多开销,我们没有看到,你可以阅读它{ {3}})&#34;

所以代码中实际发生的是

dynamic listOfCustomers = JToken.Parse(await client.GetStringAsync("http://localhost:12345/api/WebCustomers"));

将控制权交还给调用者,在这种情况下,调用者是一个名为start()的方法,由于它是一个Main方法,因此无法等待。开始得到控制权并且没有等待,所以下一行代码继续执行,这导致程序结束。

你需要做的是启动时等待(),这样当控制权被收回时它就不会结束:

class Program
{
  static void Main(string[] args)
  {
    start().Wait();
  }

  private async static void start()
  {
    Fixture fixture = new Fixture();
    HttpClient client = new HttpClient();

    dynamic listOfCustomers = JToken.Parse(await client.GetStringAsync("http://localhost:12345/api/WebCustomers").ConfigureAwait(false));
     // Rest Of Code..
  }