我正在构建Windows 8应用程序,并遇到异步调用问题。我会尽量提供尽可能多的细节,可能是因为我觉得我2分的结果,以这样的:窗口8应用程序:嵌套的异步调用
- 我做的东西完全错误的,当它涉及到异步调用
- 还是我做错了而且,这也可能是我错误的架构,使我不能摆在首位的问题上。
我是一个牛逼到Windows Azure和MVVM但这里的情况...
该应用现已内置于Windows 8,但我也希望能够使用其他平台,所以我做了什么首先是创建一个发布到Windows Azure网站的WebAPI项目。这样,我可以使用JSON传输数据,并且WebAPI控制器连接到正在处理和来自Window Azure表存储的数据请求的存储库。第二部分是从Azure网站请求数据的MVVM Light Windows 8应用程序。
那么让我们来更详细地看一下WebAPI项目。在这里,我有一个类别模型开始。
public class Category : TableServiceEntity
{
[Required]
public string Name { get; set; }
public string Description { get; set; }
public string Parent { get; set; }
}
类型模型只包含一个名称和描述(id是 TableServiceEntity的RowKey)。在类别嵌套的情况下,还会向父类别添加字符串引用。第一个问题出现了:父类应该是类型类别而不是字符串,并且后端侧的类别模型是否应包含子类别的集合?
然后我有我的IRepository接口来定义存储库。 (正在进行中;-))它也使用规范模式来传递查询范围。这是所有的工作,你可以测试使用浏览器,浏览到:http://homebudgettracker.azurewebsites.net/api/categories
public interface IRepository<T> where T : TableServiceEntity
{
void Add(T item);
void Delete(T item);
void Update(T item);
IEnumerable<T> Find(params Specification<T>[] specifications);
IEnumerable<T> RetrieveAll();
void SaveChanges();
}
现在,仓库是明确的,让我们来看看控制器。我有一个CategoriesController,它只是一个包含IRepository存储库的ApiController。 (与Ninject但这里无关紧要注入)
public class CategoriesController : ApiController
{
static IRepository<Category> _repository;
public CategoriesController(IRepository<Category> repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
_repository = repository;
}
控制器包含了一些方法,如,例如:
public Category GetCategoryById(string id)
{
IEnumerable<Category> categoryResults =_repository.Find(new ByRowKeySpecification(id));
if(categoryResults == null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
if (categoryResults.First<Category>() == null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
return categoryResults.First<Category>();
}
到现在为止,我们已经看到了后端,让我们转移到这里的实际问题: MvvmLight客户端和对WebAPI控制器的异步http请求。
在客户端项目中,我也有一个类别模型。
public class Category
{
[JsonProperty("PartitionKey")]
public string PartitionKey { get; set; }
[JsonProperty("RowKey")]
public string RowKey { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("Timestamp")]
public string Timestamp { get; set; }
[JsonProperty("Parent")]
public string ParentRowKey { get; set; }
public ObservableCollection<Category> Children { get; set; }
}
不介意PartitionKey和RowKey属性,因为它不涉及Azure的餐桌服务entitiy性能存在哪些应用程序分区键应该被排除在外。 RowKey实际上可以重命名为Id。但在这里没有实际意义。
主要看的视图模型是这样的:
public class MainViewModel : CategoryBasedViewModel
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IBudgetTrackerDataService budgetTrackerDataService)
: base(budgetTrackerDataService)
{
PageTitle = "Home budget tracker";
}
}
它从我创建共享的逻辑包含一个类别观察的集合页面视图模型延伸。在此视图模型重要的东西:
- 甲IBudgetTrackerDataService被注入的视图模型,其是高电平数据服务
- 含有类别 - 视图模型包裹类别的集合
- 一些性质为一个ObservableCollection绑定(fe:IsLoadingCategories在视图上处理ProgressRing)
- 由IBudgetTrackerDataService在 之后调用的getCategoriesCompleted回调方法将完成异步调用
因此,代码如下:
public abstract class CategoryBasedViewModel : TitledPageViewModel
{
private IBudgetTrackerDataService _dataService;
private ObservableCollection<CategoryViewModel> _categoryCollection;
private Boolean isLoadingCategories;
public const string CategoryCollectionPropertyName = "CategoryCollection";
public const string IsLoadingCategoriesPropertyName = "IsLoadingCategories";
public Boolean IsLoadingCategories
{
get
{
return isLoadingCategories;
}
set
{
if (isLoadingCategories != value)
{
isLoadingCategories = value;
RaisePropertyChanged(IsLoadingCategoriesPropertyName);
}
}
}
public ObservableCollection<CategoryViewModel> CategoryCollection
{
get
{
return _categoryCollection;
}
set
{
_categoryCollection = value;
RaisePropertyChanged(CategoryCollectionPropertyName);
}
}
public CategoryBasedViewModel(IBudgetTrackerDataService budgetTrackerDataService)
{
wireDataService(budgetTrackerDataService);
}
public CategoryBasedViewModel(IBudgetTrackerDataService budgetTrackerDataService, string pageTitle)
{
PageTitle = pageTitle;
wireDataService(budgetTrackerDataService);
}
private void wireDataService(IBudgetTrackerDataService budgetTrackerDataService)
{
_dataService = budgetTrackerDataService;
CategoryCollection = new ObservableCollection<CategoryViewModel>();
IsLoadingCategories = true;
_dataService.GetCategoriesAsync(GetCategoriesCompleted);
}
private void GetCategoriesCompleted(IList<Category> result, Exception error)
{
if (error != null)
{
throw new Exception(error.Message, error);
}
if (result == null)
{
throw new Exception("No categories found");
}
IsLoadingCategories = false;
CategoryCollection.Clear();
foreach (Category category in result)
{
CategoryCollection.Add(new CategoryViewModel(category, _dataService));
// Added the dataService as a parameter because the CategoryViewModel will handle the search for Parent Category and Children catagories
}
}
}
这是所有工作,但现在我想父/子关系的类别的运作。对于这一点,我已经 添加逻辑来CategoryViewModel使其获取子类构造时...
public CategoryViewModel(Category categoryModel, IBudgetTrackerDataService
budgetTrackerDataService)
{
_category = categoryModel;
_dataService = budgetTrackerDataService;
// Retrieve all the child categories for this category
_dataService.GetCategoriesByParentAsync(_category.RowKey,
GetCategoriesByParentCompleted);
}
所以一个CategoryBasedViewModel的建设获取类别和调用回调方法GetCategoriesCompleted:
_dataService.GetCategoriesAsync(GetCategoriesCompleted);
该回调方法也调用了CategoryViewModel的构造函数。在那里,使用另一个异步方法来获取类别的子项。
public CategoryViewModel(Category categoryModel, IBudgetTrackerDataService
budgetTrackerDataService)
{
_category = categoryModel;
_dataService = budgetTrackerDataService;
// Retrieve all the child categories for this category
_dataService.GetCategoriesByParentAsync(_category.RowKey,
GetCategoriesByParentCompleted);
}
还有我的问题! GetCategoriesByParentAsync是另一个异步调用中发生的异步调用,代码刚刚脱离调用并且什么也不做。筑巢时
- 为什么这些调用失败:
数据服务实现的接口:
public interface IBudgetTrackerDataService { void GetCategoriesAsync(Action<IList<Category>, Exception> callback); void GetCategoriesByParentAsync(string parent, Action<IList<Category>, Exception> callback); }
异步方法包含下面的代码:
public async void GetCategoriesAsync(Action<IList<Category>, Exception> callback) { // Let the HTTP client request the data IEnumerable<Category> categoryEnumerable = await _client.GetAllCategories(); // Invoke the callback function passed to this operation callback(categoryEnumerable.ToList<Category>(), null); } public async void GetCategoriesByParentAsync(string parent, Action<IList<Category>, Exception> callback) { // Let the HTTP client request the data IEnumerable<Category> categoryEnumerable = await _client.GetCategoriesWithParent(parent); // Invoke the callback function passed to this operation callback(categoryEnumerable.ToList<Category>(), null); }
长话短说来电?
- 其次,我是愚蠢的,我应该处理父母/子女 关系笼子的不同?
只是一个提示:如果您发布较短的问题,人们可能更有可能帮助您。如果您有不止一个问题,请单独询问。 – svick