I have searched through various stackoverflow questions and I got answer but using NSMutableURLRequest as there is one method - (void)addValue:(NSString *)value forHTTPHeaderField:(NSString *)field; which can be called over requestObject only.
How do I add value using _sessionManager.requestSerializer ?Or any work around. Here is the code which I am using for session configuration.
- (void)configureSesionManager {
_sessionManager = [AFHTTPSessionManager manager];
_sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
_sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
_sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/json"];
_sessionManager.requestSerializer.timeoutInterval = 360;
if ([GSCommonUtil isUserLoggedIn]) {
authenticationHeader = [NSString stringWithFormat:#"Bearer %#",[GSCommonUtil retriveValueFromUserDefaults:kNSUserAuthenticationToken]];
[_sessionManager.requestSerializer setValue:authenticationHeader forHTTPHeaderField:#"Authorization"];
}
[_sessionManager.requestSerializer setValue:#"text/plain" forHTTPHeaderField:#"Content-Type"];
[_sessionManager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
// I have to add one more HTTPHeader for #"Accept". How could I achieve it.
NSLog(#"Done with Session Manager Configuration!");
}
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.
Related
How do I set an expectation on a property of an instance?
Let's say I have the following code:
id request = OCMClassMock([NSMutableURLRequest class]);
And I want to make sure that, in my implementation, the HTTPMethod property is set to #"Get", how would my test verify this?
Try something like this:
- (void)testNSURLConnection
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com"]];
[request setHTTPMethod:#"POST"];
id connectionMock = OCMClassMock([NSURLConnection class]);
OCMStub([connectionMock connectionWithRequest:[OCMArg checkWithBlock:^BOOL(NSMutableURLRequest *request) {
XCTAssertTrue([request.HTTPMethod isEqualToString:#"GET"]);
return YES;
}] delegate:OCMOCK_ANY]);
[NSURLConnection connectionWithRequest:request delegate:nil];
}
This test will fail until your change #"POST" to #"GET" which is, I believe, what you want.
I am in the process of switching over some of my code from AFNetworking 1.0 to 2.0.
Before when doing a POST, I was creating an AFHTTPClient, and an AFHTTPRequestOperation like so:
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:reqUrl];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
httpClient.operationQueue.maxConcurrentOperationCount = 1;
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
req.viewName, #"viewName",
req.json, #"JSON",
req.dateAdded.description, #"dateTime",
req.latitude, #"latitude",
req.longitude, #"longitude",
req.heading, #"heading",
req.user, #"requestUser",
nil];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[op setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation,
id responseObject) {
.......convert responseObject (string) to NSDictionary.....
});
This worked fine, and my POSTs went through and I received a successful text response from the server. (which I then converted to a NSDictionary)
I now am using an AFHTTPSessionManager singleton, and calling the POST method from that. When initializing my AFHTTPSessionManager, I am doing the following:
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
[self setResponseSerializer:responseSerializer];
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"text/html", nil];
Then in my other class, I am calling the POST like so:
NSDictionary *params = #{
#"viewName":req.viewName,
#"JSON":req.json,
#"dateTime":req.dateAdded.description,
#"latitude":req.latitude,
#"longitude":req.longitude,
#"heading":req.heading,
#"requestUser":req.user
};
[netManager POST:path parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
.....
} failure:^(NSURLSessionDataTask *task, NSError *error) {
//failing here
});
My data has not changed at all, but the POSTs always fail with the error:
Error Domain=AFNetworkingErrorDomain Code=-1011 "Request failed: bad request (400)" UserInfo=0x1704675c0 {AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x178234660> { URL: ... } { status code: 400, headers {
"Content-Length" = 2738;
"Content-Type" = "text/html";
Date = "Thu, 15 May 2014 16:13:51 GMT";
Server = "Microsoft-IIS/7.0";
"X-Powered-By" = "ASP.NET";
Whats different that is causing the new AFNetworking 2.0 POST code to not work with this now? Is there anything I need to be setting? The URL and Parameters I am passing are the same as they were with the old way I was sending the POST.
Thanks
My solution ended up being a pretty simple one
In my AFHTTPSessionManager's init, I was not setting the RequestSerializer along with the ResponseSerializer.
After setting it correctly, my POSTs are going through fine again. Heres what I set:
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", nil];
[self setRequestSerializer:[AFJSONRequestSerializer serializer]];
EDIT
Aaron Brager stated that those first 2 lines are defaults and not needed. All I needed was to set the RequestSerializer. I tested and can verify this.
I am trying to implement this code in Objective C:
Public Shared Function Login(ByVal Username As String, ByVal Password As String) As Boolean
Dim str As String = Func.ConvertToHex(Username)
Http.GetResponse("http://www.website.com/forum/login.php?do=login", String.Concat(New String() { "vb_login_username=", str, "&vb_login_password=", Password, "&cookieuser=1&s=&securitytoken=guest&do=login&vb_login_md5password=&vb_login_md5password_utf=" }))
If Http.ResponseValue.Contains(("Thank you for logging in, " & Username)) Then
Http.GetResponse("http://www.website.com/forum/usercp.php")
Return True
End If
Return False
End Function
This is what I've already done:
- (IBAction)loginButton:(id)sender {
NSURL *loginURL = [NSURL URLWithString:#"http://www.website.com/forum/login.php?do=login"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:loginURL];
[request setRequestMethod:#"POST"];
[request setUseKeychainPersistence:YES];
[request addPostValue:[self.usernameField stringValue] forKey:#"vb_login_username="];
[request addPostValue:[self.passwordField stringValue] forKey:#"&vb_login_password="];
[request setDelegate:self];
[request setTimeOutSeconds:60];
[request startSynchronous];
[request setUseSessionPersistence:YES];
}
- (void)requestFailed:(ASIHTTPRequest *)request {
NSLog(#"Request failed: %#",[request error]);
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"Submitted form successfully");
NSLog(#"Response was:");
NSLog(#"%#",[request responseString]);
}
But it does not work..
I get a reply back but not as a member.
P.S. It's about a vBulletin Forum
Sorry for my bad english..
Thanks in advance!
Hard to try to reproduce with no server to test. However two things:
lib which you use is depreciated, consider moving for other (for example AFNetworking)
in second parameter you have "&vb_login_password=" I believe there should be no '&' character. Also try to remove '=' at end.
If there is no HTTPS you can use wireshark to check packets from program which work, and from your version. Then compare both request and seek for differences.
It now works. I've added some more entries.
[request addPostValue:#"1" forKey:#"cookieuser"];
[request addPostValue:#"login" forKey:#"do"];
[request addPostValue:#"" forKey:#"s"];
[request addPostValue:#"guest" forKey:#"securitytoken"];
[request addPostValue:#"" forKey:#"vb_login_md5password"];
[request addPostValue:#"" forKey:#"vb_login_md5password_utf"];
[request addPostValue:[self.passwordField stringValue] forKey:#"vb_login_password"];
[request addPostValue:[self.usernameField stringValue] forKey:#"vb_login_username"];
I now get the HTML code from the forum back to a point where it says "Thank you for logging in, Username".
I need to pass information from the application to the server, specifically a and b in text format. Here is the code the WCF service:
public class iOSService
{
// To use HTTP GET, add [WebGet] attribute. (Default ResponseFormat is WebMessageFormat.Json)
// To create an operation that returns XML,
// add [WebGet(ResponseFormat=WebMessageFo rmat.Xml)],
// and include the following line in the operation body:
// WebOperationContext.Current.Outgoin gResponse.ContentType = "text/xml";
[OperationContract]
public void DoWork()
{
// Add your operation implementation here
return;
}
// Add more operations here and mark them with [OperationContract]
[OperationContract]
public string iOSTest2(string a, string b)
{
string res = "";
try
{
res=(int.Parse(a) + int.Parse(b)).ToString();
}
catch (Exception exp)
{
res = "Not a number";
}
return res;
}
}
After receiving a and b, the server adds them, and sends back their sum.
And here is my code to send parameters to the server of an iOS application:
- (IBAction)test:(id)sender {
NSArray *propertyNames = [NSArray arrayWithObjects:#"23", #"342", nil];
NSArray *propertyValues = [NSArray arrayWithObjects:#"a", #"b", nil];
NSDictionary *properties = [NSDictionary dictionaryWithObjects:propertyNames forKeys:propertyValues];
NSMutableArray * arr;
arr=[[NSMutableArray alloc]initWithObjects:properties, nil];
NSLog(#"%#",arr);
NSError * error;
NSData *jsonData2 = [NSJSONSerialization dataWithJSONObject:arr options:NSJSONWritingPrettyPrinted error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.mathforyou.net/iOSservice.svc/iOSTest2"]];
NSString *jsonString = [[NSString alloc] initWithData:jsonData2 encoding:NSUTF8StringEncoding];
[request setValue:#"appliction/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:jsonData2];
NSLog(#"JSON String: %#",jsonString);
NSError *errorReturned = nil;
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&errorReturned];
if (errorReturned) {
//...handle the error
NSLog(#"error");
}
else {
NSString *retVal = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",retVal);
}
}
But the server answers me the following message:
"ExceptionDetail":null,"ExceptionType":null,"Message":"The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.","StackTrace":null
And here is the logs from Xcode:
2013-03-01 17:38:28.657 2231233122[3442:c07] (
{
a = 23;
b = 342;
}
)
2013-03-01 17:38:28.659 2231233122[3442:c07] JSON String: [
{
"a" : "23",
"b" : "342"
}
]
2013-03-01 17:38:29.054 2231233122[3442:c07] {"ExceptionDetail":null,"ExceptionType":null,"Message":"The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.","StackTrace":null}
P.S. I asked a friend to help me, but since he does not know objective-c wrote a program just for C++ and the code works, so the problem is not in the server. Here is the code:
string data = "{\"a\":\"560\",\"b\":\"90\"}";
byte[] bd = Encoding.UTF8.GetBytes(data);
HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create("http://www.mathforyou.net/IOSService.svc/iOSTest2");
wr.ContentType = "application/json";
wr.Method = "POST";
wr.ContentLength = bd.Length;
Stream sw = wr.GetRequestStream();
sw.Write(bd, 0, bd.Length);
sw.Close();
HttpWebResponse resp = (HttpWebResponse)wr.GetResponse();
Stream s = resp.GetResponseStream();
byte[] bres = new byte[resp.ContentLength];
s.Read(bres, 0, bres.Length);
string ans = Encoding.UTF8.GetString(bres);
Console.WriteLine(ans);
Please help, I'm worn out.
If you copied and pasted the code, it looks like you might have misspelled your Content-Type value. It should be application/json, you have it as appliction/json.
Also, I'm not sure if this matters, but you're also not setting the content length explicitly. I am not sure if setHTTPBody: does that for you.
I'm not sure if you still need this, but try the following:
[request addValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:jsonString forHTTPHeaderField:#"json"]; //<-- I added this line
[request setHTTPMethod:#"POST"];
[request setHTTPBody:jsonData2];
So I have this url that leads to a .php
So far I managed to retrieve every single thing except the actual XML that I want. the XML is stored in a variable called _xml.
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
$_POST["_xml"] = $_xml;
}
So I've already set the outMethod to POST but I don't understand how to retrieve the value within _xml.
- (void)grabURLInBackground
{
NSLog(#"grab url in background");
NSURL *url = [NSURL URLWithString:#"xxxxxxxxxxx"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"POST" forKey:#"outMethod"];
[request setPostValue:#"1" forKey:#"Entity_ID"];
[request setDelegate:self];
[request startAsynchronous];
NSLog(#"end of grabUrlInBackgroun");
}
don't worry the URL is right I just don't want to post it.
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"A");
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
if(responseString)
{
NSLog(#"responseData is not null");
}
NSLog(#"response string: %#", responseString);
//NSLog(#"%#", responseString);
}
What I get back is that the request is good, but there is no response in responseString. This is because my php does not want to print out any of the XML on screen in HTML but it stores the result in the variable _xml sent via post "$_POST["_xml"] = $_xml
My question is, how do I get back that xml variable? Isn't there a method available within the ASIHTTPRequest library? I am using ASIFormDataRequest class not ASIHTTPRequest.
You have to print you variable in the php-file:
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
echo $_xml;
}
A HTTPRequest (and the ASIFormDataRequest as well) isn't interested in any variables you declare in your *.php file. It only returns the string you actually print.