等待client.GetStringAsync毫无例外地退出

汤姆塞立克

我正在关注此博客文章,内容涉及如何在ASP.NET Web API 2中使用批处理支持。服务器代​​码似乎可以正常工作,并在端口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#的新手,所以任何指针都将不胜感激!

尤瓦尔·伊茨恰科夫(Yuval Itzchakov)

当您在异步方法中的代码中使用await关键字时,您真正告诉的程序是“听着,继续进行工作,完成后给我回电(当然,这不是那样很简单,编译器为我们做了很多开销,我们看不到,您可以在这里阅读))“。

所以代码中实际发生的是

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

将控制权交还给调用方,在这种情况下,调用方是一个称为start()的方法,由于它是Main方法,因此无法等待。start重新获得了控件,并且没有等待它,因此下一行代码继续执行,这将导致您的程序结束。

您需要做的是在开始时使用Wait(),这样在将控制权交还给您时它就不会结束:

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..
  }

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章