为什么我的 Azure 移动应用程序没有返回任何数据?

Why is my Azure mobile app not returning any data?

我一直在关注有关 Azure 移动应用程序的简易表格的教程 (https://blog.xamarin.com/getting-started-azure-mobile-apps-easy-tables/)。一切进展顺利,我设法开始测试我的应用程序,它似乎没有 return 任何数据,我不知道为什么,我也没有收到任何错误这个问题的追踪比较困难。

好的,首先我有我的 Azure 数据库(配置为允许访问 Azure 服务),我已经创建了 table 并使用 EasyTables 工作。我使用 Postman (https://www.getpostman.com/) 应用程序来测试我的 API 并确保数据是使用 https://myproject.azurewebsites.net/tables/users 从我的数据库中 return 编辑的,return 编辑了我的数据json.

我的数据库 table 称为 users,它的结构非常基本(用于测试),有两列 idFirstName。我已经用虚拟数据填充了我的 table,我已经证明可以使用 Postman 从我的 azure uri returned。

这是获得 运行ning 的基础工作,这是我的项目层次结构的快照。

MyProject/Model/users.cs

这是命名为与数据库中的 table 匹配的实体数据。

using System;
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;

namespace MyProject
{
    public class users
    {

        [JsonProperty(PropertyName = "Id")]
        public string id { get; set; }       

        public string FirstName {get; set; }
    }
}

MyProject/Services/AzureService.cs

至关重要的是,我们这里有 public async Task<IEnumerable<users>> GetUsers() 任务,它会触发初始化任务(这是定义应用程序 url 的地方)。

using System;
using Microsoft.WindowsAzure.MobileServices;
using Microsoft.WindowsAzure.MobileServices.Sync;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.WindowsAzure.MobileServices.SQLiteStore;
using System.Diagnostics;
using Xamarin.Forms;
using MyProject;
using System.IO;
using Plugin.Connectivity;

[assembly: Dependency(typeof(AzureService))]
namespace MyProject
{
    public class AzureService
    {
        public MobileServiceClient Client { get; set; } = null;

        IMobileServiceSyncTable<users> userTable;       
        public async Task Initialize()
        {
            if (Client?.SyncContext?.IsInitialized ?? false)
                return;

            var appUrl = "https://myproject.azurewebsites.net";

            //Create our client

            Client = new MobileServiceClient(appUrl);


            //InitialzeDatabase for path
            var path = "syncstore.db";
            //path = Path.Combine(MobileServiceClient.DefaultDatabasePath, path);

            //setup our local sqlite store and intialize our table
            var store = new MobileServiceSQLiteStore(path);

            //Define table
            store.DefineTable<users>();


            //Initialize SyncContext
            await Client.SyncContext.InitializeAsync(store);

            //Get our sync table that will call out to azure
            userTable = Client.GetSyncTable<users>();


        }

        public async Task SyncUsers()
        {
            try
            {

                await userTable.PullAsync("allUsers", userTable.CreateQuery());

                await Client.SyncContext.PushAsync();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Unable to sync users, that is alright as we have offline capabilities: " + ex);
            }

        }

        //
        //Get Users
        public async Task<IEnumerable<users>> GetUsers()
        {
            await Initialize();
            await SyncUsers();

            return await userTable.ToEnumerableAsync(); ;

        }   
    }
}

MyProject/View/UserList.xaml

出于测试的目的,我保持了简短和简约。一个简单的列表,其源设置为 UsersList(这是 ViewModel 中的一个 Observable 集合)。列表中的每一项都绑定到 FirstName.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MyProject;assembly=MyProject"
             x:Class="MyProject.UserList"
             Title="UserList">
        <ListView x:Name="userList"
                  ItemsSource="{Binding UsersList}"
                  IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                  RefreshCommand="{Binding LoadUsersCommand}"
                  Grid.Row="1">
            <ListView.ItemTemplate>
                <DataTemplate>
                <ViewCell>
                    <StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal" Padding="15,5,0,0">
                            <StackLayout Padding="5,0,0,0" VerticalOptions="StartAndExpand" Orientation="Vertical">
                            <Label Text="{Binding FirstName}"  />
                        </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>        
</ContentPage>

MyProject/View/UserList.xaml.cs

这只是说明 UserList 绑定到视图模型,当列表出现时会从视图模型中触发加载用户命令。

using System;
using System.Collections.Generic;
using Plugin.Connectivity;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyProject
{
    public partial class UserList : ContentPage
    {
        UsersViewModel vm;

        public UserList()
        {
            InitializeComponent();
            BindingContext = vm = new UsersViewModel();
        }

        protected override async void OnAppearing()
        {
            base.OnAppearing();

            vm.LoadUsersCommand.Execute(null);            
        }       
    }
}

MyProject/ViewModel/UsersViewModel.cs

这个文件做的最多,视图模型定义了 observable 和 Load Users 命令。

using System;
using MvvmHelpers;
using System.Windows.Input;
using System.Threading.Tasks;
using System.Diagnostics;
using Xamarin.Forms;
using System.Linq;
using Microsoft.WindowsAzure.MobileServices;

namespace MyProject
{
    public class UsersViewModel : BaseViewModel
    {
        AzureService azureService;
        public UsersViewModel()
        {
            azureService = DependencyService.Get<AzureService>();
        }

        public ObservableRangeCollection<users> UserList { get; } = new ObservableRangeCollection<users>();

        string loadingMessage;
        public string LoadingMessage
        {
            get { return loadingMessage; }
            set { SetProperty(ref loadingMessage, value); }
        }

        ICommand  loadUsersCommand;
        public ICommand LoadUsersCommand =>
            loadUsersCommand ?? (loadUsersCommand = new Command(async () => await ExecuteLoadUsersCommandAsync())); 

        async Task ExecuteLoadUsersCommandAsync()
        {
            try 
            {                
                LoadingMessage = "Loading Users...";
                IsBusy = true;
                var users = await azureService.GetUsers();
                UserList.ReplaceRange(users);
            }
            catch (Exception ex) 
            {
                Debug.WriteLine("OH NO!" + ex);

                await Application.Current.MainPage.DisplayAlert("Sync Error", "Unable to sync users, you may be offline", "OK");
            } 
            finally 
            {
                IsBusy = false;
            }
        }     
    }
}

我在 运行 应用程序时弹出了几个断点,看看我是否能找到问题的根源,没有错误意味着我没有工作的参考框架。

目前事件的触发顺序如下(根据我设置的断点):

  1. public ObservableRangeCollection<users> UserList { get; } = new ObservableRangeCollection<users>(); - UserViewModel
  2. azureService = DependencyService.Get<AzureService>(); - UserViewModel
  3. var users = await azureService.GetUsers(); - UserViewModel
  4. await Initialize(); - AzureService
  5. public async Task Initialize() - AzureService
  6. await SyncUsers(); - Azure服务
  7. public async Task SyncUsers() - AzureService
  8. return await userTable.ToEnumerableAsync(); ; - AzureService
  9. UserList.ReplaceRange(users); - UserViewModel

然后使用模拟器将该列表加载到我的 MacBook pro 上,但它是空的,根本没有数据。任何人都可以帮助我理解为什么我无法获取我的数据吗?我应该设置它们的断点并检查某些项目是否存在吗?

就像我说的那样,没有实际错误,这是一个艰难的过程,但它也可能非常简单,我们将不胜感激。

更新

根据我的初步调查,我在我的代码中添加了一个 if 语句,特别是在 UserList.xaml.cs 中的 OnAppearing 方法中。我在 UserViewModel.cs 中添加的代码检查 UserList 集合是否为 0。

 protected override async void OnAppearing()
 {
     base.OnAppearing();

     if (vm.UserList.Count == 0)
         vm.LoadUsersCommand.Execute(null);
     else
     {
         ...
     }
     vm.LoadUsersCommand.Execute(null);
 }

有趣的是 UserList 总是返回 0。所以问题看起来出在 UsersViewModel.cs

中的这行代码中

public ObservableRangeCollection<users> UserList { get; } = new ObservableRangeCollection<users>();

可能是什么原因造成的?

我唯一能看到的是您将 id 列重命名为 Id - 在客户端上,它需要是 id(小写)。

其中还有一些其他错误,但使用调试器应该很容易找到它们。我看到其中一个已经被指出了。