重构 api 调用以使用 await
Refactoring api calls to use await
想要更新 C# Winforms 应用程序以使用 await。
该应用程序通过 SDK 调用 MYOB Accountright API。
我正在使用 Dot Net Framework 4.5.1
旧代码是这样的
public void GetItems( CompanyFile companyFile )
{
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(MyCompanyFile, pageFilter, MyCredentials, OnComplete, OnError);
}
/// <summary>
/// Method called on Async complete
/// </summary>
/// <param name="statusCode"></param>
/// <param name="items"></param>
/// <remarks></remarks>
private void OnComplete(System.Net.HttpStatusCode statusCode,
PagedCollection<Item> items)
{
myItems = items;
}
/// <summary>
/// Callback if there is an error
/// </summary>
/// <param name="uri"></param>
/// <param name="ex"></param>
/// <remarks></remarks>
private void OnError(Uri uri, Exception ex)
{
Trace.WriteLine("In OnError");
MessageBox.Show(ex.Message);
}
我想要这样的代码
private async Task FetchItemsAsync()
{
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(MyCompanyFile, pageFilter, MyCredentials, OnComplete, OnError);
var totalPages = (int)Math.Ceiling((double)(myItems.Count / PageSize));
while (_currentPage < totalPages)
{
await LoadMore(); // how do I write this?
}
}
我该怎么做?
[更新5]
我试过了
private const double PageSize = 400;
protected CancellationTokenSource MyCancellationTokenSource;
protected CompanyFile MyCompanyFile;
protected IApiConfiguration MyConfiguration;
protected ICompanyFileCredentials MyCredentials;
protected ItemService MyItemService;
protected IOAuthKeyService MyOAuthKeyService;
private int _currentPage = 1;
private int _totalPages;
public void FetchItems(CompanyFile companyFile, IApiConfiguration configuration, ICompanyFileCredentials credentials)
{
MyCompanyFile = companyFile;
MyConfiguration = configuration;
MyCredentials = credentials;
MyCancellationTokenSource = new CancellationTokenSource();
MyItemService = new ItemService(MyConfiguration, null, MyOAuthKeyService);
FetchAllItemsAsync();
}
private async void FetchAllItemsAsync()
{
try
{
var items = new List<Item>();
int totalPages = 0;
do
{
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize, PageSize * (_currentPage - 1));
CancellationToken ct = MyCancellationTokenSource.Token;
Log("About to Await GetRange");
Task<PagedCollection<Item>> tpc = MyItemService.GetRangeAsync(MyCompanyFile, pageFilter, MyCredentials, ct, null);
Log("About to Await GetRange B");
PagedCollection<Item> newItems = await tpc; // fails here
Log("Page {0} retrieved {1} items", _currentPage, newItems.Count);
if (totalPages == 0)
{
totalPages = (int)Math.Ceiling((items.Count / PageSize));
}
items.AddRange(newItems.Items.ToArray());
_currentPage++;
}
while (_currentPage < totalPages);
MessageBox.Show(string.Format("Fetched {0} items", items.Count));
}
catch (ApiCommunicationException ex)
{
Log(ex.ToString());
throw;
}
catch (Exception exception)
{
Log(exception.ToString());
throw;
}
}
但是我得到一个 ValidationException
{"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
[MYOB.AccountRight.SDK.ApiValidationException]: {"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
base: {"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
ErrorInformation: "Warning, error messages have not been finalised in this release and may change"
Errors: Count = 1
RequestId: "e573dfed-ec68-4aff-ac5e-3ffde1c2f943"
StatusCode: BadRequest
URI: {http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc}
我已经交叉发布这个问题到
MYOB Support
您可以使用可以通过结果或错误回调解析的 TaskCompletionSource 对象。我不确定错误回调的签名是什么,所以该部分可能无法正常工作。
private Task<PagedCollection<Item>> FetchItemsAsync()
{
var taskSource = new TaskCompletionSource<PagedCollection<Item>>();
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(
MyCompanyFile,
pageFilter,
MyCredentials,
(statusCode, items) => taskSource.TrySetResult(items),
(error) => taskSource => taskSource.TrySetException(error) // Not sure if this is correct signature
);
return taskSource.Task;
}
然后您可以 return 它创建的 Task 对象,您可以将其用于异步操作。我不太确定您要实现的逻辑是什么,因为您的问题不是很详细,但是您可以将方法与 await 命令一起使用,因为它 return 是一个如下所示的任务对象。
private async void FetchAllItemsAsync()
{
int totalPages;
do
{
items = await FetchItemsAsync()
totalPages = (int)Math.Ceiling((double)(items.Count / PageSize));
_currentPage++;
} while (_currentPage < totalPages)
}
支持 .NET4、.NET45 和 PCL 上的 async/await 的最新版本 MYOB.AccountRight.API.SDK you are referencing already has overloads。
Sample code was created as an example for someone using .NET 3.5 (hence no async/await). Another sample (windows phone) shows async/await in action using the SDK
[更新]
您可能遇到了与 OData 相关的异常,因为 Item
实体没有您可以过滤的 Date
字段(参见 docs)。
当您捕捉到 ApiCommunicationException
(其中 ApiValidationException
是一个子类)时,会有一个 Errors 属性 提供更多详细信息。
还有一个 RequestId
(和其他一些属性),如果您在与托管 API 的云通信时遇到问题,需要与支持人员交谈,这将非常有用。
想要更新 C# Winforms 应用程序以使用 await。 该应用程序通过 SDK 调用 MYOB Accountright API。 我正在使用 Dot Net Framework 4.5.1
旧代码是这样的
public void GetItems( CompanyFile companyFile )
{
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(MyCompanyFile, pageFilter, MyCredentials, OnComplete, OnError);
}
/// <summary>
/// Method called on Async complete
/// </summary>
/// <param name="statusCode"></param>
/// <param name="items"></param>
/// <remarks></remarks>
private void OnComplete(System.Net.HttpStatusCode statusCode,
PagedCollection<Item> items)
{
myItems = items;
}
/// <summary>
/// Callback if there is an error
/// </summary>
/// <param name="uri"></param>
/// <param name="ex"></param>
/// <remarks></remarks>
private void OnError(Uri uri, Exception ex)
{
Trace.WriteLine("In OnError");
MessageBox.Show(ex.Message);
}
我想要这样的代码
private async Task FetchItemsAsync()
{
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(MyCompanyFile, pageFilter, MyCredentials, OnComplete, OnError);
var totalPages = (int)Math.Ceiling((double)(myItems.Count / PageSize));
while (_currentPage < totalPages)
{
await LoadMore(); // how do I write this?
}
}
我该怎么做?
[更新5]
我试过了
private const double PageSize = 400;
protected CancellationTokenSource MyCancellationTokenSource;
protected CompanyFile MyCompanyFile;
protected IApiConfiguration MyConfiguration;
protected ICompanyFileCredentials MyCredentials;
protected ItemService MyItemService;
protected IOAuthKeyService MyOAuthKeyService;
private int _currentPage = 1;
private int _totalPages;
public void FetchItems(CompanyFile companyFile, IApiConfiguration configuration, ICompanyFileCredentials credentials)
{
MyCompanyFile = companyFile;
MyConfiguration = configuration;
MyCredentials = credentials;
MyCancellationTokenSource = new CancellationTokenSource();
MyItemService = new ItemService(MyConfiguration, null, MyOAuthKeyService);
FetchAllItemsAsync();
}
private async void FetchAllItemsAsync()
{
try
{
var items = new List<Item>();
int totalPages = 0;
do
{
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize, PageSize * (_currentPage - 1));
CancellationToken ct = MyCancellationTokenSource.Token;
Log("About to Await GetRange");
Task<PagedCollection<Item>> tpc = MyItemService.GetRangeAsync(MyCompanyFile, pageFilter, MyCredentials, ct, null);
Log("About to Await GetRange B");
PagedCollection<Item> newItems = await tpc; // fails here
Log("Page {0} retrieved {1} items", _currentPage, newItems.Count);
if (totalPages == 0)
{
totalPages = (int)Math.Ceiling((items.Count / PageSize));
}
items.AddRange(newItems.Items.ToArray());
_currentPage++;
}
while (_currentPage < totalPages);
MessageBox.Show(string.Format("Fetched {0} items", items.Count));
}
catch (ApiCommunicationException ex)
{
Log(ex.ToString());
throw;
}
catch (Exception exception)
{
Log(exception.ToString());
throw;
}
}
但是我得到一个 ValidationException
{"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
[MYOB.AccountRight.SDK.ApiValidationException]: {"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
base: {"Encountered a validation error (http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc)"}
ErrorInformation: "Warning, error messages have not been finalised in this release and may change"
Errors: Count = 1
RequestId: "e573dfed-ec68-4aff-ac5e-3ffde1c2f943"
StatusCode: BadRequest
URI: {http://localhost:8080/AccountRight/ab5c1f96-7663-4052-8360-81004cfe8598/Inventory/Item/?$top=400&$skip=0&$orderby=Date desc}
我已经交叉发布这个问题到 MYOB Support
您可以使用可以通过结果或错误回调解析的 TaskCompletionSource 对象。我不确定错误回调的签名是什么,所以该部分可能无法正常工作。
private Task<PagedCollection<Item>> FetchItemsAsync()
{
var taskSource = new TaskCompletionSource<PagedCollection<Item>>();
var itemSvc = new ItemService(MyConfiguration, null, MyOAuthKeyService);
string pageFilter = string.Format("$top={0}&$skip={1}&$orderby=Date desc", PageSize,
PageSize * (_currentPage - 1));
itemSvc.GetRange(
MyCompanyFile,
pageFilter,
MyCredentials,
(statusCode, items) => taskSource.TrySetResult(items),
(error) => taskSource => taskSource.TrySetException(error) // Not sure if this is correct signature
);
return taskSource.Task;
}
然后您可以 return 它创建的 Task 对象,您可以将其用于异步操作。我不太确定您要实现的逻辑是什么,因为您的问题不是很详细,但是您可以将方法与 await 命令一起使用,因为它 return 是一个如下所示的任务对象。
private async void FetchAllItemsAsync()
{
int totalPages;
do
{
items = await FetchItemsAsync()
totalPages = (int)Math.Ceiling((double)(items.Count / PageSize));
_currentPage++;
} while (_currentPage < totalPages)
}
支持 .NET4、.NET45 和 PCL 上的 async/await 的最新版本 MYOB.AccountRight.API.SDK you are referencing already has overloads。
Sample code was created as an example for someone using .NET 3.5 (hence no async/await). Another sample (windows phone) shows async/await in action using the SDK
[更新]
您可能遇到了与 OData 相关的异常,因为 Item
实体没有您可以过滤的 Date
字段(参见 docs)。
当您捕捉到 ApiCommunicationException
(其中 ApiValidationException
是一个子类)时,会有一个 Errors 属性 提供更多详细信息。
还有一个 RequestId
(和其他一些属性),如果您在与托管 API 的云通信时遇到问题,需要与支持人员交谈,这将非常有用。