异步正在成为背后的痛苦,因为我正在尝试制作一个不糟糕的可重用库
本文关键字:一个 痛苦 背后 因为 异步 | 更新日期: 2023-09-27 18:32:08
因为对API的Post请求需要在Windows Phone上异步运行,所以我正在努力创建一个精简的易于使用的库来与API交互。
问题是使用该库的人总是需要提供一个回调函数。
让我们看一些伪代码:
发布请求类来帮助我处理 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; }
}
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);
}
//...
}
您会注意到,我必须一直传递一个回调函数,以便一旦我的 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 );
//...
问题是我想创建某种存储库样式模式...假设 API 返回了不同的 json 模型,一次调用返回了一系列产品......问题是我想创建一个可爱的存储库调用,例如:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
但是我也必须在其中放置一些 GOSH DARN 回调函数,这意味着 API 返回的任何对象类型的每个存储库方法都将具有此 MemoryStream 回调......如果我想更改该功能,我必须在任何地方更新这些东西哟。:(有没有人见过更好的方法来做这种废话。
这开始变得过于复杂
--哭
使用较新的语言结构的更简单的答案是:
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);
}
在 4.0 项目中,您可以使用TaskCompletionSource
将非任务异步模型转换为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;
}
调用方现在有一个表示此异步操作结果的Task<string>
。 他们可以同步等待它并使用 Result
属性获取结果,他们可以添加一个回调,该回调将在操作完成后使用 ContinueWith
执行,或者他们可以在 async
方法中await
任务,该方法在后台将连接该方法的其余部分作为该任务的延续, 但没有创建新方法甚至新范围,即
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
这将启动异步任务,向该任务添加回调(或延续),以便在它运行时继续从中断的地方执行代码,此时它将结果写入控制台并将此方法返回的Task
标记为已完成,以便随后将执行此方法的任何延续(允许组合async
方法)。