Jim*_*988 2 c# api asynchronous windows-phone-8
因为对API的Post请求需要在Windows Phone上异步运行,所以我很难创建一个易于使用的精简库来与API进行交互.
问题是使用库的人总是需要提供回调函数.
我们来看看一些伪代码:
PostRequest类帮助我处理POST请求:
class PostRequest
{
private Action<MemoryStream> Callback;
public PostRequest(string urlPath, string data, Action<MemoryStream> callback)
{
Callback = callback;
// Form the URI
UriBuilder fullUri = new UriBuilder(urlPath);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
// Initialize a new WebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
request.Method = "POST";
// Set up the state object for the async request
DataUpdateState dataState = new DataUpdateState();
dataState.AsyncRequest = request;
// Start the asynchronous request
request.BeginGetResponse(new AsyncCallback(HandleResponse),
dataState);
}
private void HandleResponse(IAsyncResult asyncResult)
{
// Get the state information
DataUpdateState dataState = (DataUpdateState)asyncResult.AsyncState;
HttpWebRequest dataRequest = (HttpWebRequest)dataState.AsyncRequest;
// End the async request
dataState.AsyncResponse = (HttpWebResponse)dataRequest.EndGetResponse(asyncResult);
if (dataState.AsyncResponse.StatusCode.ToString() == "OK")
{
// Create a stream from the response
Stream response = dataState.AsyncResponse.GetResponseStream();
TextReader textReader = new StreamReader(response, true);
string jsonString = textReader.ReadToEnd();
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// Send the stream through to the callback function
Callback(stream);
}
}
}
public class DataUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
API访问对象类:
class APIAuthenticationCredentials
{
public String Username { get; set; }
public String Password { get; set; }
}
class APIAO
{
private String AuthUrl = "http://api.example.com/";
public static Auth Auth = new Auth();
//...
public static void Authenticate( String data, APIAuthenticationCredentials credentials, Action<MemoryStream> callback )
{
PostRequest request = new PostRequest(AuthURL, data, callback);
}
//...
}
Run Code Online (Sandbox Code Playgroud)
你会注意到我必须一直传递一个回调函数,这样一旦我的PostRequest类中的HandleResponse方法返回数据,数据就被转发到某个控制器上,使屏幕对数据做一些事情.目前,使用它并不是非常可怕:
private void DisplayData(MemoryStream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Auth));
APIAO.Auth = (Auth)serializer.ReadObject(stream);
}
//...
APIAuthenticationCredentials credentials = new APIAuthenticationCredentials {
Username = "whatever",
Password = "whatever"
}
APIAO.Authenticate( credentials, DisplayData );
//...
Run Code Online (Sandbox Code Playgroud)
问题是我想创建某种存储库样式模式...假设API返回了不同的json模型,一个调用返回了一个产品数组...问题是我想创建一个可爱的存储库调用,例如:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
Run Code Online (Sandbox Code Playgroud)
但是我也必须在其中放置一些GOSH DARN回调函数,这意味着API返回的任何对象类型的每个存储库方法都将具有此MemoryStream回调...如果我想要更改该功能,我'我必须到处更新那些东西哟.:(有没有人看到更好的方式做这个废话.
这开始变得太复杂了
--crying
使用较新的语言结构的更简单的答案是:
public static Task<string> GetData(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
return client.DownloadStringTaskAsync(fullUri.Uri);
}
Run Code Online (Sandbox Code Playgroud)
在4.0项目中,您可以使用a TaskCompletionSource将非Task异步模型转换为Task:
public static Task<string> GetData2(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (s, args) =>
{
if (args.Error != null)
tcs.TrySetException(args.Error);
else if (args.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(args.Result);
};
client.DownloadStringAsync(fullUri.Uri);
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
调用者现在有一个Task<string>表示此异步操作的结果.他们可以同步等待它并使用Result属性获得结果,他们可以添加一个将在操作完成使用时执行的回调ContinueWith,或者他们可以await在一个async方法中的任务,该方法在引擎盖下将连接该方法的其余部分作为该任务的延续,但没有创建新方法甚至是新范围,即
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
Run Code Online (Sandbox Code Playgroud)
这将启动异步任务,添加的回调(或延续)到该任务,以便在运行时,它会继续执行代码离开的地方,在这一点上,然后将结果写到控制台和纪念Task那这个方法返回完成后,将继续执行此方法的任何延续(允许async方法的组合).