繁体   English   中英

Xamarin:如何将数据从 Xamarin iOS 项目的 NSUrlSession 任务返回到共享项目?

[英]Xamarin: How to return data to Shared Project from NSUrlSession task from Xamarin iOS Project?

我在 Xamarin iOS 项目中有一个类,例如:

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);

            });

如何将此数据返回给调用者(即返回到后面的 Xaml 代码)?

如果我将GetData()函数的返回类型更改为 string 或 Task 并尝试在 lambda 表达式内部返回,则会出现编译错误。

我读过并且各种论坛都说我需要实现一个 NSUrlDelegate 来处理响应。 我为此尝试了多种变体,但没有成功。 请指教。

另外,(我认为这是不可能的或正确的方法)但是有没有办法将整个 NSUrlSession 返回到共享项目并从共享项目本身调用数据任务方法?

有一个简单的解决方案。 在您的INetworkUtility接口中,像这样声明GetData()方法:

Task<string> GetData();

在您的 iOS NetworkUtility 类中创建一个 TaskCompletionSource 并返回任务。 在您的 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();
}

编辑:我想可能存在一个TrySetResult(...)情况,即 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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM