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
}