Async GetAwaiter() 抛出一个奇怪的异常
Async GetAwaiter() throwing an odd exception
下面我粘贴了一些代码。在正文的第一行,我调用了一个等待调用 Task<IEnumerable<SkuGcn>> GetSkuGcnList();
在最后一行,在 mapPromise.GetAwaiter()
中,它在获取结果时抛出此异常:
An exception of type 'System.IO.FileNotFoundException' occurred in System.Private.CoreLib.ni.dll but was not handled in user code
Additional information: Could not load file or assembly 'System.Runtime.Serialization.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
我知道 GetSkuGcnList()
调用正在调用我的服务,因为我可以设置一个断点并在调用时中断它。然后服务好像return.
此代码在 ASP.NET 5 RC1 中运行良好,但在 ASP.Net Core 1.0 版本中效果不佳。
任何帮助将不胜感激!
public ProductItemsCacheStore(IItemsProductCacheRepository itemsRepo, IProductAvailabilityPricing proxyGoliathApi,
IProductItemListRepo itemsListsRepo, IItemPricesCacheRepo itemPricesRepo)
{
var mapPromise = proxyGoliathApi.GetSkuGcnList();
_items = itemsRepo.GetAllProductOrderListForCache();
_itemsLists = itemsListsRepo.GetItemListsForCache();
_priceZones = itemPricesRepo.GetAllPriceZonesAndItemPrices();
MergeProductsWithGcn(_items, mapPromise.GetAwaiter().GetResult());
}
我的 project.json 看起来像这样:
{
"version": "1.0.0-alpha.1",
"description": "AvailabilityPricingClient Class Library",
"authors": [ "irving.lennert" ],
"packOptions": {
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": ""
},
"tooling": {
"defaultNamespace": "AvailabilityPricingClient"
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.AspNet.WebApi.Client": "5.2.3"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
}
}
GetSkuGcnList()
的实现是这样的:
public async Task<IEnumerable<SkuGcn>> GetSkuGcnList()
{
HttpResponseMessage response = _client.GetAsync("/api/skuGcnList").Result;
if (response.IsSuccessStatusCode)
{
var skuGcns = await response.Content.ReadAsAsync<IEnumerable<SkuGcn>>();
return skuGcns;
}
return null;
}
正如@DaniDev 在评论中提到的,不建议混合使用同步和异步代码。关于此主题的规范文章是 Stephen Cleary 的 Don't Block on Async Code.
让你的代码异步有点棘手,因为你在构造函数中调用异步操作,constructors can't be async。
重组代码的一种方法是拆分构造函数(依赖注入)和初始化(异步调用)代码:
public class ProductItemsCacheStore
{
private readonly IItemsProductCacheRepository _itemsProductCacheRepo;
private readonly IProductAvailabilityPricing _productAvailabilityPricing;
private readonly IProductItemListRepo _productItemListRepo;
private readonly IItemsPricesCacheRepo _itemsPricesCacheRepo;
private bool _initialized = false;
public ProductItemsCacheStore(
IItemsProductCacheRepository itemsRepo,
IProductAvailabilityPricing proxyGoliathApi,
IProductItemListRepo itemsListsRepo,
IItemPricesCacheRepo itemPricesRepo)
{
_itemsProductCacheRepo = itemsRepo;
_productAvailabilityPricing = proxyGoliathApi;
_productItemListRepo = itemsListsRepo;
_itemsPricesCacheRepo = itemsPricesRepo
}
public async Task Initialize()
{
// Could possibly move these to the constructor as well
var _items = itemsRepo.GetAllProductOrderListForCache();
var _itemsLists = itemsListsRepo.GetItemListsForCache();
var _priceZones = itemPricesRepo.GetAllPriceZonesAndItemPrices();
MergeProductsWithGcn(_items, await _productAvailabilityPricing.GetSkuGcnList());
_initialized = true;
}
}
您的消费代码(无论您之前在哪里构建 new ProductItemsCacheStore(...)
)现在看起来像:
var productItemsCacheStore = new ProductItemsCacheStore(/* dependencies */);
await productItemsCacheStore.Initialize();
当然,这意味着您的消费代码也必须是异步的。这是 .
我确定我正在调用的程序集在 ASP.Net 核心版本中无法正常工作。如果你看上面的 project.json 就是这一行:
"Microsoft.AspNet.WebApi.Client": "5.2.3"
我已将该行更改为此行:
"System.Net.Http": "4.1.0"
这个程序集没有公开相同的 API 所以我不得不将我的实现代码更改为:
public async Task<IEnumerable<SkuGcn>> GetSkuGcnList()
{
HttpResponseMessage response = _client.GetAsync("/api/skuGcnList").Result;
if (response.IsSuccessStatusCode)
{
var skuGcns = await response.Content.ReadAsStringAsync()
.ContinueWith<IEnumerable<SkuGcn>>(getTask =>
{
return JsonConvert.DeserializeObject<IEnumerable<SkuGcn>>(getTask.Result);
});
return skuGcns;
}
return null;
}
此解决方案运行良好。重要的是要注意我在 post 上也遇到了同样的问题,它们有点复杂,所以我会提供另一个我打的电话 post 给任何感兴趣的人。
public async Task<IEnumerable<Availablity>> GetAvailabilityBySkuList(IEnumerable<string> skuList)
{
var output = JsonConvert.SerializeObject(skuList);
HttpContent contentPost = new StringContent(output, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = _client.PostAsync("/api/availabilityBySkuList", contentPost).Result;
if (response.IsSuccessStatusCode)
{
var avail = await response.Content.ReadAsStringAsync()
.ContinueWith<IEnumerable<Availablity>>(postTask =>
{
return JsonConvert.DeserializeObject<IEnumerable<Availablity>>(postTask.Result);
});
return avail;
}
return null;
}
感谢所有的贡献!
下面我粘贴了一些代码。在正文的第一行,我调用了一个等待调用 Task<IEnumerable<SkuGcn>> GetSkuGcnList();
在最后一行,在 mapPromise.GetAwaiter()
中,它在获取结果时抛出此异常:
An exception of type 'System.IO.FileNotFoundException' occurred in System.Private.CoreLib.ni.dll but was not handled in user code
Additional information: Could not load file or assembly 'System.Runtime.Serialization.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
我知道 GetSkuGcnList()
调用正在调用我的服务,因为我可以设置一个断点并在调用时中断它。然后服务好像return.
此代码在 ASP.NET 5 RC1 中运行良好,但在 ASP.Net Core 1.0 版本中效果不佳。
任何帮助将不胜感激!
public ProductItemsCacheStore(IItemsProductCacheRepository itemsRepo, IProductAvailabilityPricing proxyGoliathApi,
IProductItemListRepo itemsListsRepo, IItemPricesCacheRepo itemPricesRepo)
{
var mapPromise = proxyGoliathApi.GetSkuGcnList();
_items = itemsRepo.GetAllProductOrderListForCache();
_itemsLists = itemsListsRepo.GetItemListsForCache();
_priceZones = itemPricesRepo.GetAllPriceZonesAndItemPrices();
MergeProductsWithGcn(_items, mapPromise.GetAwaiter().GetResult());
}
我的 project.json 看起来像这样:
{
"version": "1.0.0-alpha.1",
"description": "AvailabilityPricingClient Class Library",
"authors": [ "irving.lennert" ],
"packOptions": {
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": ""
},
"tooling": {
"defaultNamespace": "AvailabilityPricingClient"
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.AspNet.WebApi.Client": "5.2.3"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
}
}
GetSkuGcnList()
的实现是这样的:
public async Task<IEnumerable<SkuGcn>> GetSkuGcnList()
{
HttpResponseMessage response = _client.GetAsync("/api/skuGcnList").Result;
if (response.IsSuccessStatusCode)
{
var skuGcns = await response.Content.ReadAsAsync<IEnumerable<SkuGcn>>();
return skuGcns;
}
return null;
}
正如@DaniDev 在评论中提到的,不建议混合使用同步和异步代码。关于此主题的规范文章是 Stephen Cleary 的 Don't Block on Async Code.
让你的代码异步有点棘手,因为你在构造函数中调用异步操作,constructors can't be async。
重组代码的一种方法是拆分构造函数(依赖注入)和初始化(异步调用)代码:
public class ProductItemsCacheStore
{
private readonly IItemsProductCacheRepository _itemsProductCacheRepo;
private readonly IProductAvailabilityPricing _productAvailabilityPricing;
private readonly IProductItemListRepo _productItemListRepo;
private readonly IItemsPricesCacheRepo _itemsPricesCacheRepo;
private bool _initialized = false;
public ProductItemsCacheStore(
IItemsProductCacheRepository itemsRepo,
IProductAvailabilityPricing proxyGoliathApi,
IProductItemListRepo itemsListsRepo,
IItemPricesCacheRepo itemPricesRepo)
{
_itemsProductCacheRepo = itemsRepo;
_productAvailabilityPricing = proxyGoliathApi;
_productItemListRepo = itemsListsRepo;
_itemsPricesCacheRepo = itemsPricesRepo
}
public async Task Initialize()
{
// Could possibly move these to the constructor as well
var _items = itemsRepo.GetAllProductOrderListForCache();
var _itemsLists = itemsListsRepo.GetItemListsForCache();
var _priceZones = itemPricesRepo.GetAllPriceZonesAndItemPrices();
MergeProductsWithGcn(_items, await _productAvailabilityPricing.GetSkuGcnList());
_initialized = true;
}
}
您的消费代码(无论您之前在哪里构建 new ProductItemsCacheStore(...)
)现在看起来像:
var productItemsCacheStore = new ProductItemsCacheStore(/* dependencies */);
await productItemsCacheStore.Initialize();
当然,这意味着您的消费代码也必须是异步的。这是
我确定我正在调用的程序集在 ASP.Net 核心版本中无法正常工作。如果你看上面的 project.json 就是这一行:
"Microsoft.AspNet.WebApi.Client": "5.2.3"
我已将该行更改为此行:
"System.Net.Http": "4.1.0"
这个程序集没有公开相同的 API 所以我不得不将我的实现代码更改为:
public async Task<IEnumerable<SkuGcn>> GetSkuGcnList()
{
HttpResponseMessage response = _client.GetAsync("/api/skuGcnList").Result;
if (response.IsSuccessStatusCode)
{
var skuGcns = await response.Content.ReadAsStringAsync()
.ContinueWith<IEnumerable<SkuGcn>>(getTask =>
{
return JsonConvert.DeserializeObject<IEnumerable<SkuGcn>>(getTask.Result);
});
return skuGcns;
}
return null;
}
此解决方案运行良好。重要的是要注意我在 post 上也遇到了同样的问题,它们有点复杂,所以我会提供另一个我打的电话 post 给任何感兴趣的人。
public async Task<IEnumerable<Availablity>> GetAvailabilityBySkuList(IEnumerable<string> skuList)
{
var output = JsonConvert.SerializeObject(skuList);
HttpContent contentPost = new StringContent(output, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = _client.PostAsync("/api/availabilityBySkuList", contentPost).Result;
if (response.IsSuccessStatusCode)
{
var avail = await response.Content.ReadAsStringAsync()
.ContinueWith<IEnumerable<Availablity>>(postTask =>
{
return JsonConvert.DeserializeObject<IEnumerable<Availablity>>(postTask.Result);
});
return avail;
}
return null;
}
感谢所有的贡献!