C# 带JSON反序列化的Windows Phone 8 MVVM

C# 带JSON反序列化的Windows Phone 8 MVVM,c#,windows-phone-8,windows-phone,.net-4.5,c#-5.0,C#,Windows Phone 8,Windows Phone,.net 4.5,C# 5.0,(需要关于恐怖代码的建议) 我试图通过合并MVVM和一个适用于所有视图模型的通用DataService类来调用相应的web服务处理程序,为我的旧Windows Phone应用程序代码带来一些优雅 例如,在notification ViewModel中,我有: private ObservableCollection<Notification> _notifications; public ObservableCollection<Notification> Notific

(需要关于恐怖代码的建议)

我试图通过合并MVVM和一个适用于所有视图模型的通用DataService类来调用相应的web服务处理程序,为我的旧Windows Phone应用程序代码带来一些优雅

例如,在notification ViewModel中,我有:

private ObservableCollection<Notification> _notifications;
public ObservableCollection<Notification> Notifications
{
    get
    {
        return _notifications;
    }
}

public void GetNotifications()
{
    new DataService().DownloadViewModelData<ObservableCollection<Notification>>(GetNotificationsCallback, "getnotificationslist.ashx");
    this.IsDataLoaded = true;
}

public void GetNotificationsCallback(ObservableCollection<Notification> notificationsList)
{
    _notifications = notificationsList;
       
    Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
        NotifyPropertyChanged("Notifications");
    });
    this.IsDataLoaded = true;
}
private observedcollection\u通知;
公开收集通知
{
得到
{
返回通知;
}
}
public void GetNotifications()
{
new DataService().DownloadViewModelData(GetNotificationsCallback,“getnotificationslist.ashx”);
this.IsDataLoaded=true;
}
public void GetNotificationsCallback(ObservableCollection notificationsList)
{
_通知=通知列表;
Deployment.Current.Dispatcher.BeginInvoke(()=>
{
NotifyPropertyChanged(“通知”);
});
this.IsDataLoaded=true;
}
在DataService类中,我尝试创建一个与服务通信的通用方法:

public static string ServerUrl = "http://<ip-address>:<port>/";

public void DownloadViewModelData<T>(Action<T> callbackFunction, string handlerName, bool methodIsPOST = false, List<KeyValuePair<string, string>> querySet = null) where T : class
{
    var queryString = "";

    if(null != querySet)
    {
        foreach (KeyValuePair<string, string> tuple in querySet)
        {
            queryString += tuple.Key + "=" + tuple.Value + "&";
        }

        queryString = queryString.Remove(queryString.Length - 1, 1);
    }

    var urlQueryString = ServerUrl + handlerName;

    if (!methodIsPOST)
        urlQueryString += queryString;

    var webRequest = HttpWebRequest.CreateHttp(urlQueryString);

    webRequest.ContentType = "application/x-www-form-urlencoded";

    Func<AsyncCallback, object, IAsyncResult> requestingMethod = null;

    if (methodIsPOST)
    {
        webRequest.Method = "POST";
        webRequest.ContentLength = queryString.Length;
        webRequest.BeginGetRequestStream(
            a =>
            {

                System.IO.Stream postStream = webRequest.EndGetRequestStream(a);
                byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(queryString);
                postStream.Write(byteArray, 0, queryString.Length);
                postStream.Close();
                webRequest.BeginGetResponse(
                    b =>
                    {
                        using (WebResponse response = webRequest.EndGetResponse(b))
                        {
                            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                            {
                                callbackFunction(new DataContractJsonSerializer(typeof(T)).ReadObject(response.GetResponseStream()) as T);
                            }
                        }
                    },
                    null
                );
            },
            null
        );
    }
    else
    {
        webRequest.Method = "GET";
        webRequest.BeginGetResponse(
            a =>
            {
                using (WebResponse response = webRequest.EndGetResponse(a))
                {
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        callbackFunction(new DataContractJsonSerializer(typeof(T)).ReadObject(response.GetResponseStream()) as T);
                    }
                }
            },
            null
        );
    }
}
publicstaticstringserverurl=“http://:/”;
public void DownloadViewModelData(Action callbackFunction,string handlerName,bool methodIsPOST=false,List querySet=null),其中T:class
{
var queryString=“”;
if(null!=querySet)
{
foreach(querySet中的KeyValuePair元组)
{
queryString+=tuple.Key+“=”+tuple.Value+“&”;
}
queryString=queryString.Remove(queryString.Length-1,1);
}
var urlQueryString=ServerUrl+handlerName;
如果(!methodIsPOST)
urlQueryString+=查询字符串;
var webRequest=HttpWebRequest.CreateHttp(urlQueryString);
webRequest.ContentType=“application/x-www-form-urlencoded”;
Func


在我看来,有一种更好的方法可以做到这一点,这样您的ViewModel就不会知道任何有关数据服务实现的信息

我会考虑做几件事

  • 开始使用依赖项注入框架,如。这将允许您不知道ViewModel使用的数据服务类型。您可以使用DI框架为代码注入特定的实现
  • 创建一个表示数据服务的接口。为了便于讨论,我将调用我的示例
    IDataService
    。此接口的主要目标是抽象出检索数据的方法。因此,可以从数据库、Web服务或文件中访问数据,而viewmodel具有任何知识(或关心)
  • 对于您的代码,我会给它签名:

    public interface IDataService
    {
        Task<IEnumerable<Notification>> ListNotifications();
    }
    
    公共接口IDataService
    {
    任务列表通知();
    }
    
    您会注意到,我正在使用
    任务
    ,它允许我使用.Net 4.5异步框架。因此,现在我们提供了一个界面,上面只说,
    我有一种方法可以异步
    返回通知列表。这是您的viewmodel所需的信息

  • 不要重新创建您的
    ObservableCollection
    。如果您需要更改集合的内容,
    清除()
    它,然后重新填充,但不要重新绑定或重新创建集合本身。这也有许多性能优势

  • 如果将接口定义放在可移植库中,那么如果您需要特定平台的特定实现(例如WP8与Win8),那么由于您仅在ViewModels中引用接口,那么您可能只需要更改非常小的数量来支持不同的实现

  • 希望一切都有意义