Background Transfer Service download with multiple task

abhishekkabhishekk USMember
edited December 2016 in Xamarin.iOS

I have written this code to run API's in background session. This code runs very well when API returns success (statuscode 200), but gives confusing out put when API fails.
Second observation is this issue occurs only for POST request.

`public class BackgroundService
{

    String bundleID = "com.bg.demo";
    NSUrlSession backgroundSession;
    NSOperationQueue queue;
    SessionDelegate sessionDelegate;
    Dictionary<String,IBackgroundServiceDelegate> taskDelegates;
    Dictionary<string, string> values = new Dictionary<string, string>();

    //Using the lockObject executes perfectly
    //static object lockObject = new object();
    public BackgroundService()
    {

        NSUrlSessionConfiguration bgConfig = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(bundleID);
        queue = new NSOperationQueue();
        queue.MaxConcurrentOperationCount = 8;

        sessionDelegate = new SessionDelegate(this);

        backgroundSession = NSUrlSession.FromConfiguration(bgConfig,sessionDelegate,queue);
        backgroundSession.SessionDescription = string.Format("{0}", bundleID);
        taskDelegates = new Dictionary<string, IBackgroundServiceDelegate>();
    }

    public NSUrlSessionDownloadTask getDownloadTask(NSMutableUrlRequest request, NSString task)
    {
        NSUrlSessionDownloadTask downloadTask = backgroundSession.CreateDownloadTask(request);
        downloadTask.TaskDescription = task;
        return downloadTask;
    }

    public void registerDelegate(NSString task, IBackgroundServiceDelegate that)
    {
        taskDelegates[(String)task] = that;
    }

    public void clearValuesDict()
    {
        values.Clear();
    }

    class SessionDelegate : NSUrlSessionDownloadDelegate
    {
        private BackgroundService _bgService;
        public SessionDelegate(BackgroundService bgService)
        {
            _bgService = bgService;
        }

        public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError error)
        {
            //Using lock executes perfectly
            //lock(lockObject)
            {
                var bgNet = (IBackgroundServiceDelegate)_bgService.taskDelegates[task.TaskDescription];
                if (bgNet != null)
                {
                    if (!_bgService.values.ContainsKey(task.TaskDescription))
                    {
                        _bgService.values.Add(task.TaskDescription, task.TaskDescription);
                    }
                    else
                    {
                        Console.WriteLine("Magic");
                    }
                    Console.WriteLine("Passion {0} : {1} : {2}", task.TaskDescription, String.Join(",", _bgService.values.Values), (int)((NSHttpUrlResponse)task.Response).StatusCode);
                }
            }
        }
    }
}

public class Caller{

    main(){

        for (int i = 0; i < 10; i++)
        {
            String url = "http://domainname/url";
            Dictionary<string, object> data = new Dictionary<string, object>();

            postReq(url,data,i.ToString(),null);
        }

    }

    public void postReq(String url, Dictionary<string, object> data, String taskDescription, IBackgroundServiceDelegate bgServiceDelegate){

        NSMutableUrlRequest request = new NSMutableUrlRequest(new NSUrl(url), NSUrlRequestCachePolicy.ReloadIgnoringCacheData, 120);

        if (data != null)
        {
            var nsObject = Utils.Convert(data);
            NSError error = null;
            NSData jsonData = NSJsonSerialization.Serialize(nsObject, 0, out error);
            request.Body = jsonData;
            request.HttpMethod = "POST";
            var headers = new NSMutableDictionary();
            headers.SetValueForKey((NSString)"application/json", (NSString)"Content-type");
            request.Headers = headers;
        }
        else {
            request.HttpMethod = "GET";
        }

        NSUrlSessionDownloadTask downloadTask = appDelegate.bgService.getDownloadTask(request, (NSString)taskDescription);
        if (downloadTask != null && bgServiceDelegate != null)
        {
            appDelegate.bgService.registerDelegate((NSString)taskDescription, bgServiceDelegate);
        }

        downloadTask.Resume();
}   
}

public static class Utils
{
    public static NSDictionary Convert(this Dictionary<string, object> dict)
    {
        if (dict == null)
            throw new ArgumentNullException("dict");

        var nativeDict = new NSMutableDictionary();

        foreach (var item in dict)
        {
            NSObject value = null;
            if (IsDictionary(item.Value))
            {
                value = Utils.Convert((Dictionary<string, object>)item.Value);
            }
            else {
                value = item.Value.ToNSObject();
            }
            if (value != null)
            {
                nativeDict.Add((NSString)item.Key, value);
            }
        }

        return nativeDict;
    }
}
`

Output without lock:

2016-12-29 18:22:55.193 CRM.iOS[7626:114479] Passion 0 : 0 : 401
2016-12-29 18:22:55.211 CRM.iOS[7626:114388] Passion 4 : 0,4 : 401
2016-12-29 18:22:55.219 CRM.iOS[7626:114480] Passion 4 : 0,4 : 401
Passion 5 : 0,4,5 : 401
2016-12-29 18:22:55.225 CRM.iOS[7626:114402] Passion 6 : 0,4,5,6 : 401
2016-12-29 18:22:55.408 CRM.iOS[7626:114388] Passion 7 : 0,4,5,6,7 : 401
2016-12-29 18:22:55.415 CRM.iOS[7626:114402] Passion 8 : 0,4,5,6,7,8 : 401
2016-12-29 18:22:55.419 CRM.iOS[7626:114482] Passion 8 : 0,4,5,6,7,8 : 401
Passion 9 : 0,4,5,6,7,8,9 : 401
2016-12-29 18:22:55.433 CRM.iOS[7626:114483] Passion 1 : 0,4,5,6,7,8,9,1 : 401
2016-12-29 18:22:55.608 CRM.iOS[7626:114480] Passion 2 : 0,4,5,6,7,8,9,1,2 : 401
2016-12-29 18:22:55.624 CRM.iOS[7626:114479] Passion 3 : 0,4,5,6,7,8,9,1,2,3 : 401

To fix this issue i thought of using lock and it worked but am surprised. In above output "Output without lock" the taskdescription 4 got executed again with taskDescription 5 and this is in single thread then how come lock resolved the issue.

Output with lock:

2016-12-29 18:18:57.597 CRM.iOS[7601:113249] Passion 0 : 0 : 401
2016-12-29 18:18:57.619 CRM.iOS[7601:113366] Passion 4 : 0,4 : 401
2016-12-29 18:18:57.638 CRM.iOS[7601:113249] Passion 5 : 0,4,5 : 401
2016-12-29 18:18:57.654 CRM.iOS[7601:113305] Passion 6 : 0,4,5,6 : 401
2016-12-29 18:18:57.793 CRM.iOS[7601:113366] Passion 7 : 0,4,5,6,7 : 401
2016-12-29 18:18:57.815 CRM.iOS[7601:113364] Passion 8 : 0,4,5,6,7,8 : 401
2016-12-29 18:18:57.835 CRM.iOS[7601:113249] Passion 9 : 0,4,5,6,7,8,9 : 401
2016-12-29 18:18:57.991 CRM.iOS[7601:113305] Passion 2 : 0,4,5,6,7,8,9,2 : 401
2016-12-29 18:18:58.013 CRM.iOS[7601:113366] Passion 3 : 0,4,5,6,7,8,9,2,3 : 401
2016-12-29 18:19:00.441 CRM.iOS[7601:113364] Passion 1 : 0,4,5,6,7,8,9,2,3,1 : 401

Sign In or Register to comment.