API 的异步方法调整变量,然后变量处于其原始状态

本文关键字:变量 于其 原始 原始状 状态 异步方法 调整 API 然后 | 更新日期: 2023-09-27 18:36:14

好吧,所以我使用eID读卡器从ID卡中获取姓名等,然后使用以下方法要查看数据库中是否已有人具有完全相同的信息,请执行以下操作:

    private async void GetCustomer()
    {
        using (HttpClient client = new HttpClient())
        {
            HttpResponseMessage response = await client.GetAsync("http://localhost:32576/api/customer?name=" + EIDCustomer.CustomerName + "&address=" + EIDCustomer.Address);
            if(response.IsSuccessStatusCode)
            {
                string json = await response.Content.ReadAsStringAsync();
                ApplicationVM.customer = JsonConvert.DeserializeObject<Customer>(json);
            }
            else
            {
                Console.Write("api fail");
            }
        }
    }

好的,ApplicationVM.customer如下:"public static Customer customer = null;" GetCustomer()正在通过以下方法调用:

private Customer GetCustomerFromIDReader()
{
    Customer c = new Customer();
    try
    {
        //BEID_ReaderSet.initSDK();
        BEID_ReaderSet readerSet = BEID_ReaderSet.instance();
        BEID_ReaderContext reader = readerSet.getReader();
        if(reader.isCardPresent())
        {
            BEID_EIDCard card = reader.getEIDCard();
            BEID_EId doc = card.getID();
            string firstName = doc.getFirstName();
            string lastName = doc.getSurname();
            int postCode = Int32.Parse(doc.getZipCode());
            string straatEnNr = doc.getStreet().Trim();
            string gemeente = doc.getMunicipality();
            c.CustomerName = firstName + "" + lastName;
            c.Address = straatEnNr + ";" + postCode + ";" + gemeente;
            c.Picture = card.getPicture().getData().GetBytes();
        }
        else
        {
            c = null;
        }
        BEID_ReaderSet.releaseSDK();
    }
    catch (BEID_Exception ex)
    {
        Console.Write("Er is iets misgelopen bij het inlezen van de eID");
        return null;
    }
    EIDCustomer = c;
    GetCustomer();
    return c;
}

EIDCustomer 是"客户"类型的属性。好吧,那么程序应该检查c是否为空,如果不是,那么它检查ApplicationVM.customer是否为空。如果是这样,您将被重定向到要求您创建新帐户的窗口。如果ApplicationVM.customer不为空,则可以转到下一个窗口。这是代码:

public ICommand LoginCommand
{
    get
    {
        return new RelayCommand(Login);
    }
}
public void Login()
{
    ApplicationVM appvm = App.Current.MainWindow.DataContext as ApplicationVM;
    Customer c = new Customer();
    c = GetCustomerFromIDReader();
    if(c == null)
    {
        Console.Write("Er is iets fout gelopen bij het inlezen van de e-IDkaart");
    }
    else if (ApplicationVM.customer == null)
    {
        appvm.ChangePage(typeof(KlantNieuwVM));
    }
    else
    {
        appvm.ChangePage(typeof(KlantenInterfaceVM));
    }
}

(我与UserControls合作更改页面,我总是在MainWindow上,但我认为这对这个问题没有任何意义。

这是在 API 中调用的方法:

public Customer Get(string name, string address)
{
    return CustomerDA.CheckCustomerLogin(name, address);
}

CustomerDA.CheckCustomerLogin只是一个SQL语句,用于检查数据库中是否有具有完全相同名称和地址的人。

API 的异步方法调整变量,然后变量处于其原始状态

您遇到的问题是您的GetCustomer()方法是异步的,并且您没有等待它。因此,当您点击HttpResponseMessage行时:

HttpResponseMessage response = await client.GetAsync("");

控制权将返回到您的命令,并且在请求返回之前继续执行。

您可以通过使命令异步来解决此问题。

当您使用 async/await 模式时,整个调用链需要是可等待的,否则您将遇到此问题。

GetCustomerFromIDReader

private async Task<Customer> GetCustomerFromIDReader()
{
    Customer c = new Customer();
    // .... redacted for clarity
    await GetCustomer();
    return c;
}

命令用法

public ICommand LoginCommand
{
    get
    {
        return new RelayCommand(async () => await Login());
    }
}
public async Task Login()
{
    ApplicationVM appvm = App.Current.MainWindow.DataContext as ApplicationVM;
    Customer c = new Customer();
    c = await GetCustomerFromIDReader();
    if(c == null)
    {
        Console.Write("Er is iets fout gelopen bij het inlezen van de e-IDkaart");
    }
    else if (ApplicationVM.customer == null)
    {
        appvm.ChangePage(typeof(KlantNieuwVM));
    }
    else
    {
        appvm.ChangePage(typeof(KlantenInterfaceVM));
    }
}

最后,更改您的GetCustomer以返回任务并且不会无效。

获取客户

private async Task GetCustomer()
{
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync("");
        if(response.IsSuccessStatusCode)
        {
            string json = await response.Content.ReadAsStringAsync();
            ApplicationVM.customer = JsonConvert.DeserializeObject<Customer>(json);
        }
        else
        {
            Console.Write("api fail");
        }
    }
}

正如我在有关异步最佳实践的 MSDN 文章中解释的那样,请避免async void

因此,您的async void方法应async Task

private async Task GetCustomerAsync()
{
  ...
}

当它被调用时,它应该被await ed,这反过来又使调用方法async

private async Task<Customer> GetCustomerFromIDReaderAsync()
{
  ...
  EIDCustomer = c;
  await GetCustomerAsync();
  return c;
}

调用该方法的方法也是如此:

public async Task LoginAsync()
{
  ApplicationVM appvm = App.Current.MainWindow.DataContext as ApplicationVM;
  Customer c = new Customer();
  c = await GetCustomerFromIDReaderAsync();
  if(c == null)
  {
    Console.Write("Er is iets fout gelopen bij het inlezen van de e-IDkaart");
  }
  else if (ApplicationVM.customer == null)
  {
    appvm.ChangePage(typeof(KlantNieuwVM));
  }
  else
  {
    appvm.ChangePage(typeof(KlantenInterfaceVM));
  }
}

最后,您最终得到ICommand实现,您可以在其中使用async void因为它在逻辑上是一个事件处理程序):

public ICommand LoginCommand
{
  get
  {
    return new RelayCommand(async () => { await LoginAsync(); });
  }
}
但是,在

处理异步命令时,您需要考虑几点。这个简单的示例不会在执行时禁用ICommand,也不会干净地处理异常。我有另一篇专门介绍异步 MVVM 命令的 MSDN 文章。