如何调试具有异步数据访问和没有调用堆栈的WPF应用程序?

时间:2013-03-27 16:47:58

标签: c# wpf debugging asynchronous data-access

我有一个使用MVVM设计模式和异步数据访问方法的大型WPF应用程序。它使用带有回调处理程序的旧式异步代码和IAsyncResult接口......这是一个典型的例子:

function.BeginInvoke(callBackMethod, asyncState);

然后,在视图模型中,我有以下回调处理程序:

private void GotData(GetDataOperationResult<Genres> result)
{
    UiThreadManager.RunOnUiThread((Action)delegate
    {
        if (result.IsSuccess) DoSomething(result.ReturnValue);
        else FeedbackManager.Add(result);
    });
}

RunOnUiThread方法基本上如下:

public object RunOnUiThread(Delegate method)
{
    return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}

此问题仅影响一个视图模型,即允许用户编辑Release对象的视图模型。在相关视图中,首次加载时会从数据库中请求填充ComboBox es的某些集合。让我们简化一下,说只有一个名为Genres的集合。数据到达视图模型后,处理方式如下:

private void GotGenres(GetDataOperationResult<Genres> result)
{
    UiThreadManager.RunOnUiThread((Action)delegate
    {
        if (result.IsSuccess) Genres.AddEmptyItemBefore(result.ReturnValue);
        else FeedbackManager.Add(result);
    });
}

当集合存在并且在UI中选择了Release对象时,我有以下代码从集合中选择当前的Release.Genre值:

if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id)) 
    Release.Genre = Genres.GetItemWithId(Release.Genre);

此时,我应该注意这一切都正常,这是 only 行,它引用了视图模型中的Release.Genre属性。

我的特殊问题是,有时Release.Genre属性设置为null,我无法弄清楚如何或从哪里开始。 &GT;&GT;编辑&gt;&gt;当我在属性设置器上设置断点时,&lt;&lt;编辑&lt;&lt; Call Stack没有提供关于设置null值的真实线索,因为只有[Native to Managed Transition]行。从Show External Code窗口中选择Call Stack选项后,我可以看到基本的异步代码调用:

Call Stack

现在,我可以确认在尝试解决此问题时发现的以下事实:

  1. 引用Release.Genre属性的一行将其设置为null
  2. 对Genres.AddEmptyItemBefore(result.ReturnValue)的调用将其设置为null ...这只是在添加后将结果集合添加到Genres集合中一个'空'Genre
  3. 在调用Genres.AddEmptyItemBefore(result.ReturnValue)时或之后Release.Genre属性有时会设置为null,但因为它...在某些情况下单步执行它,执行已经(以不相关的方式)跳转到我在Release.Genre属性设置器上设置的断点,其中value输入参数是null,但这每次都会发生。
  4. 从相关视图模型到Release视图模型时,通常会发生这种情况,但每次都
  5. 相关视图模型没有引用Release.Genre属性。
  6. 要清楚,我并不是要求任何人从我提供的稀疏信息中调试我的问题。我也不是在寻求关于进行异步数据调用的建议。相反,我真的想找到我尚未想到的新方法。我理解某些代码(几乎可以肯定是我的代码)将属性设置为null ...我的问题是如何检测此代码的位置?它似乎不在Release视图模型中。如何在没有更多线索的情况下继续调试此问题?

1 个答案:

答案 0 :(得分:0)

我通常使用平面文件,XML或数据库日志记录进行调试。我为记录目的创建了这些Log类,以便我可以从我开发的每个应用程序中调用它。

对于数据库日志记录,您可以这样做:

void WriteLog(string log){
  // Your database insert here
}

也许您需要日期时间和其他支持信息,但这取决于开发人员。对于简单的平面文件记录是:

void WriteLog(string log){
  using(TextWriter tx = new StreamWriter("./Log/" + DateTime.Now.ToString() + ".txt", false)){
    tx.WriteLine(log);
  }
}

您可以通过以下两种方式使用应用程序中的日志记录:

1:方法调用

WriteLog((Release.Genre == null).ToString());
if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id)) 
    Release.Genre = Genres.GetItemWithId(Release.Genre);

2:将其添加到您的Release.Genre set(或get)属性

public class Release{
  private Genre _genre=null;
  public Genre Genre{
    get{
      WriteLog((_genre == null).ToString());
      return _genre;
    }
    set{
      WriteLog((_genre == null).ToString());
      _genre = value;      
    }
  }
}

有了这个,您可以尝试获取呼叫顺序,无论是在呼叫期间,呼叫期间是否在其他地方设置了Release.Genre。

请注意我只是给出了建筑物测井的一般图像。请指望错误。但是,开发人员有责任开发Logging acitivities以满足要求。