Xamarin:如何从 Xamarin iOS 项目的 NSUrlSession 任务 return 数据到共享项目?
Xamarin: How to return data to Shared Project from NSUrlSession task from Xamarin iOS Project?
我在 Xamarin iOS 项目中有一个 class,例如:
public class NetworkUtility : INetworkUtility
{
public void GetData()
{
NSUrl url = new NSUrl("https://reqres.in/api/users?page=2");
NSUrlRequest request = new NSUrlRequest(url);
NSUrlSession session = null;
NSUrlSessionConfiguration myConfig = NSUrlSessionConfiguration.DefaultSessionConfiguration;
myConfig.MultipathServiceType = NSUrlSessionMultipathServiceType.Handover;
session = NSUrlSession.FromConfiguration(myConfig);
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
Console.WriteLine(data);
});
task.Resume();
}
}
而且我在一些 Xaml 后面的代码中从共享项目中调用它,例如:
DependencyService.Get<INetworkUtility>().GetStringData();
现在在GetData()
函数中,我在匿名函数部分从web服务获取数据:
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
Console.WriteLine(data);
});
我怎样才能 return 将此数据发送给调用者(即发送给后面的 Xaml 代码)?
如果我将 GetData()
函数的 return 类型更改为字符串或 Task 并尝试在 lambda 表达式中 return,则会出现编译错误。
我读到各种论坛都说我需要实施 NSUrlDelegate 来处理响应。我为此尝试了多种变体,但没有成功。请指教
此外,(我认为这是不可能的或正确的方法)但是有没有办法 return 整个 NSUrlSession 到共享项目并从共享项目本身调用数据任务方法?
有一个简单的解决方案。在您的 INetworkUtility
接口中声明 GetData()
方法,如下所示:
Task<string> GetData();
在您的 iOS NetworkUtility class 中创建一个 TaskCompletionSource 和 return 任务。然后,在您的 lambda 表达式中,当所有设置和完成后,您可以设置任务结果。
public Task<string> GetData()
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
NSUrl url = new NSUrl("https://reqres.in/api/users?page=2");
NSUrlRequest request = new NSUrlRequest(url);
NSUrlSession session = null;
NSUrlSessionConfiguration myConfig = NSUrlSessionConfiguration.DefaultSessionConfiguration;
myConfig.MultipathServiceType = NSUrlSessionMultipathServiceType.Handover;
session = NSUrlSession.FromConfiguration(myConfig);
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
//Console.WriteLine(data);
//tell the TaskCompletionSource that we are done here:
tcs.TrySetResult(data); //assuming data is a string but i guess you can convert it if not
});
task.Resume();
return tcs.Task;
}
在您的共享代码中,您可以创建一个等待结果任务的异步函数:
public async Task ReceiveDataShared() {
string yourData = await DependencyService.Get<INetworkUtility>().GetData();
}
编辑:我想可能存在一种极端情况,即 lambda 表达式和 TrySetResult(...)
永远不会被调用。在这种情况下,您的共享代码将永远等待。为防止这种情况,您可以像这样设置超时:
Task<string> dataTask = DependencyService.Get<INetworkUtility>().GetData();
await Task.WhenAny(dataTask, Task.Delay(10000)); // 10.000ms timeout
if(dataTask.IsCompletedSuccessfully) {
//all good:
string dataString = dataTask.Result;
}else{
//we hit the time limit
}
我在 Xamarin iOS 项目中有一个 class,例如:
public class NetworkUtility : INetworkUtility
{
public void GetData()
{
NSUrl url = new NSUrl("https://reqres.in/api/users?page=2");
NSUrlRequest request = new NSUrlRequest(url);
NSUrlSession session = null;
NSUrlSessionConfiguration myConfig = NSUrlSessionConfiguration.DefaultSessionConfiguration;
myConfig.MultipathServiceType = NSUrlSessionMultipathServiceType.Handover;
session = NSUrlSession.FromConfiguration(myConfig);
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
Console.WriteLine(data);
});
task.Resume();
}
}
而且我在一些 Xaml 后面的代码中从共享项目中调用它,例如:
DependencyService.Get<INetworkUtility>().GetStringData();
现在在GetData()
函数中,我在匿名函数部分从web服务获取数据:
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
Console.WriteLine(data);
});
我怎样才能 return 将此数据发送给调用者(即发送给后面的 Xaml 代码)?
如果我将 GetData()
函数的 return 类型更改为字符串或 Task 并尝试在 lambda 表达式中 return,则会出现编译错误。
我读到各种论坛都说我需要实施 NSUrlDelegate 来处理响应。我为此尝试了多种变体,但没有成功。请指教
此外,(我认为这是不可能的或正确的方法)但是有没有办法 return 整个 NSUrlSession 到共享项目并从共享项目本身调用数据任务方法?
有一个简单的解决方案。在您的 INetworkUtility
接口中声明 GetData()
方法,如下所示:
Task<string> GetData();
在您的 iOS NetworkUtility class 中创建一个 TaskCompletionSource 和 return 任务。然后,在您的 lambda 表达式中,当所有设置和完成后,您可以设置任务结果。
public Task<string> GetData()
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
NSUrl url = new NSUrl("https://reqres.in/api/users?page=2");
NSUrlRequest request = new NSUrlRequest(url);
NSUrlSession session = null;
NSUrlSessionConfiguration myConfig = NSUrlSessionConfiguration.DefaultSessionConfiguration;
myConfig.MultipathServiceType = NSUrlSessionMultipathServiceType.Handover;
session = NSUrlSession.FromConfiguration(myConfig);
NSUrlSessionTask task = session.CreateDataTask(request, (data, response, error) => {
//Console.WriteLine(data);
//tell the TaskCompletionSource that we are done here:
tcs.TrySetResult(data); //assuming data is a string but i guess you can convert it if not
});
task.Resume();
return tcs.Task;
}
在您的共享代码中,您可以创建一个等待结果任务的异步函数:
public async Task ReceiveDataShared() {
string yourData = await DependencyService.Get<INetworkUtility>().GetData();
}
编辑:我想可能存在一种极端情况,即 lambda 表达式和 TrySetResult(...)
永远不会被调用。在这种情况下,您的共享代码将永远等待。为防止这种情况,您可以像这样设置超时:
Task<string> dataTask = DependencyService.Get<INetworkUtility>().GetData();
await Task.WhenAny(dataTask, Task.Delay(10000)); // 10.000ms timeout
if(dataTask.IsCompletedSuccessfully) {
//all good:
string dataString = dataTask.Result;
}else{
//we hit the time limit
}