How to Manage Sessions with Afnetworking

How to manage sessions with AFNetworking?

Yes, your session ID should be sent automatically once you are logged in, as long as the cookie does not expire before the next request is sent (important detail to be sure of). NSURLConnection, which AFNetworking uses, takes care of the details for this for you.

On the backend AFNetworking is using NSURLConnection which in turn automatically updates NSHTTPCookieStorage to store the session. You can manipulate or delete the cookies as you see fit by messing with the cookie storage.

Like if you wanted to appear to the service as not logged in, you could just delete the session cookie associated to that domain. Some services I have worked with will error if you are already logged in and attempt to login again. Additionally there was no way to check login status. Quick fix, get the cookies from URL and delete them :

NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}

From the developer himself

How do i set multiple http header using sessionManager (AFNetworking)

The Accept header takes a comma separated list, so something like this should work:

[_sessionManager.requestSerializer setValue:@"application/json, application/xml" forHTTPHeaderField:@"Accept"];

Obviously replace application/xml with whatever you need.

How to use AFNetworking in this situation?

Idea is to make use of blocks or delegates to inform other classes about the changes rather then putting the thread to sleep. Because am very much comfirtable with blocks lemme use blocks here.

The code provided here is only meant for explaining the concept and copy pasting may never work.

What to do :

  1. I prefere creating a singleton class for web services though its completely optional and depends on your coding practices.

  2. Have an array either in singleton model class that you will create to hold the array of currently running server or have a variable in app delegate so that it can be accessed by all the classes (preferably have a private variable and write setter and getter for it and make them public but then its up to you to declare property in .h as well)

  3. Have a method in singleton class or in appdelegate that takes the completionblock as parameter and which will hit the master server get all the currently active servers and populate the array in model class and then invoke the completion block.

  4. In ViewDidLoad or ViewWillAppear of your firstViewController check if array is nil or not if yes make call to the above declared method and pass a completion block to it when done your completion block will be involved and by the time it is invoked you will have the aray of urls as well.

  5. Whenever url fails and server seems to be down call the same method again and pass the completion block to it repeat the same method as explained above.

Code

Assuming you are using AFNetworking updated version and making use of blocks here is the code. Even if you are using delegate approcah will be same.

Lets assume you have written a method named getActiveServers in appDelegate,

-(void)getActiveServers:(void(^)(NSError *)) completionBlock {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:@"http://myURL.com/user" parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) {
//process the response get the array
//save it in array variable
self.activeServerArray = [responseObject valueForKey:@"serverArray"];
if (completionBlock) {
completionBlock(nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(error);
}];
}

In viewDidLoad of yourViewControllers that makes the webservice call or at the beginning of any class that makes the webService class for that matter,

considering the example of ViewController here,

- (void)viewDidLoad {
[super viewDidLoad];
appdelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
if(appDelegate.activeServerArray) {
//get the url you want and call your method to make webservice call
}
else {
[appdelegate getActiveServers:^(NSError *) {
if(error) {
//show alert fetching active server failed
}
else {
//call your method to make webservice call
}
}];
}

Finally in your method that calls the webservice if it finds out that server is down,

-(void)myMethodToMakeWebServiceCall {
//realised server down
appdelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
[appdelegate getActiveServers:^(NSError *) {
if(error) {
//show alert fetching active server failed
}
else {
//call the same method to fetch the data now with updated url
[self myMethodToMakeWebServiceCall];
}
}];
}

Sharing session between AFNetworking and UIWebView

Actually, AFNetworking and UIWebView share the same cookies storage. So we don't need any special technique to let UIWebView "share" a session initialized by AFNetworking, or any native session-based request which uses NSHTTPCookieStorage to store cookie. In my situation, the UIWebView did not find shared session to be useful, just because the session initialized by AFNetworking has lacked of a cookie which was sent only when browsing the site with a browser.

And here is what I did to solve the problem:

// Open a request to remote server with a User-Agent string set to the request header.
// We'll have browser-specific cookies in NSHTTPCookieStorage
NSString *userAgent = @"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager.requestSerializer setValue:userAgent forHTTPHeaderField:@"User-Agent"];
[manager GET:kRemoteServerUrl parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"Done");
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Failure");
}];

Above code will ensure that we have all browser-specific cookies in NSHTTPCookieStorage, hence let the UIWebView share any session initialized by native login routine.

AFNetworking 2 custom session manager

Well, the whole problem was that kMyBaseURL was:

#define kMGBaseURL @"http://example.com/api"

instead of

#define kMGBaseURL @"http://example.com/api/"

and later I've used links as @"/something" instead of @"something".



Related Topics



Leave a reply



Submit