How do I call a SOAP web service in Swift 2? - swift

I want to call web service for Swift 2. But it never works. This is my code.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, NSURLConnectionDelegate, NSXMLParserDelegate {
var mutableData:NSMutableData = NSMutableData.init()
var currentElementName:NSString = ""
#IBOutlet var txtCelsius : UITextField!
#IBOutlet var txtFahrenheit : UITextField!
#IBAction func actionConvert(sender : AnyObject) {
let celcius = txtCelsius.text
let soapMessage = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><CelsiusToFahrenheit xmlns='http://www.w3schools.com/xml/'><Celsius>\(celcius)</Celsius></CelsiusToFahrenheit></soap:Body></soap:Envelope>"
let urlString = "http://www.w3schools.com/xml/tempconvert.asmx"
let url = NSURL(string: urlString)
let theRequest = NSMutableURLRequest(URL: url!)
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue((soapMessage), forHTTPHeaderField: "Content-Length")
theRequest.HTTPMethod = "POST"
theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) // or false
let connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: true)
connection!.start()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
mutableData.length = 0;
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
mutableData.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
let xmlParser = NSXMLParser(data: mutableData)
xmlParser.delegate = self
xmlParser.parse()
xmlParser.shouldResolveExternalEntities = true
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if currentElementName == "CelsiusToFahrenheit" {
txtFahrenheit.text = string
}
}

NSURLConnection is deprecated, use NSURLSession instead.
Here's an example of a function doing what you want with NSURLSession and a callback:
func getFarenheit(celsius celsius: Int, completion: (result: String) -> Void) {
let soapMessage = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><CelsiusToFahrenheit xmlns='http://www.w3schools.com/xml/'><Celsius>\(celsius)</Celsius></CelsiusToFahrenheit></soap:Body></soap:Envelope>"
let urlString = "http://www.w3schools.com/xml/tempconvert.asmx"
if let url = NSURL(string: urlString) {
let theRequest = NSMutableURLRequest(URL: url)
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue((soapMessage), forHTTPHeaderField: "Content-Length")
theRequest.HTTPMethod = "POST"
theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
NSURLSession.sharedSession().dataTaskWithRequest(theRequest) { (data, response, error) in
if error == nil {
if let data = data, result = String(data: data, encoding: NSUTF8StringEncoding) {
completion(result: result)
}
} else {
print(error!.debugDescription)
}
}.resume()
}
}
Use it like this with a "trailing closure":
getFarenheit(celsius: 42) { (result) in
print(result)
}
It prints the data containing the XML and the converted value:
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CelsiusToFahrenheitResponse xmlns="http://www.w3schools.com/xml/"><CelsiusToFahrenheitResult>107.6</CelsiusToFahrenheitResult></CelsiusToFahrenheitResponse></soap:Body></soap:Envelope>

Related

Download PDF from API

The API I am using has 3 parameters year month and salaryType.
When I enter those parameters to my URL
if let url = URL(string: "https://rip.rtuk.gov.tr/workplacebackend/api/Employee/GetPayroll?yil=\(year)&ay=\(month)&maasturu=\(salaryType)")
URL becomes
"https://rip.rtuk.gov.tr/workplacebackend/api/Employee/GetPayroll?yil=2020&ay=2&maasturu=1"
When I enter this URL with Auth and Token it returns a pdf file. How should I modify my getPayroll so that I can download pdf after the request?
func getPayroll(year: Int, month: Int, salaryType: Int, completion: #escaping (String) -> ()) {
if let url = URL(string: "https://rip.rtuk.gov.tr/workplacebackend/api/Employee/GetPayroll?yil=\(year)&ay=\(month)&maasturu=\(salaryType)") {
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("Basic \(authToken)", forHTTPHeaderField: "Authorization")
request.addValue(workingToken, forHTTPHeaderField: "token")
let task = URLSession.shared.downloadTask(with: request) { (localURL, urlResponse, error) in
if let localURL = localURL {
if let string = try? String(contentsOf: localURL) {
completion(string)
}
}
}
task.resume()
}
}
So when I tap on a cell I want to show an alert, download and then open pdf
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch cellType(rawValue: selected.title) {
case .salary:
selectedPayment = (payment?[indexPath.row])!
RtukNetworkManager.shared.getPayroll(year: selectedPayment.year, month: selectedPayment.month, salaryType: selectedPayment.paymentType) { filePath in
DispatchQueue.main.async {
self.displayDownloadAlert(filePath)
}
}
func downloadFile(path: String) {
let donwloadManager = FileDownloadManager()
donwloadManager.downloadFile(path: path, viewController: self)
}
When I tap on a cell getting an error as an alert
Error
The document can not be shown
this will save pdf file to url and also check if already downloaded
func getPayroll(year: Int, month: Int, salaryType: Int, completion: #escaping ((URL?) -> ())) {
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let parameters: [String: Int] = ["yıl": year, "ay": month, "maasturru": salaryType]
if let url = URL(string: "https://rip.rtuk.gov.tr/workplacebackend/api/Employee/GetPayroll?yil=\(year)&ay=\(month)&maasturu=\(salaryType)") {
let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
if FileManager().fileExists(atPath: destinationUrl.path) {
print("File already exists [\(destinationUrl.path)]")
completion(destinationUrl)
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("Basic \(authToken)", forHTTPHeaderField: "Authorization")
request.addValue(workingToken, forHTTPHeaderField: "token")
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request) { (data, response, error) in
if error == nil {
if let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
if let data = data {
if let _ = try? data.write(to: destinationUrl, options: Data.WritingOptions.atomic)
{
completion(destinationUrl)
}
else
{
completion(destinationUrl)
}
}
}
}
} else {
print(error?.localizedDescription)
completion(nil)
}
}
task.resume()
}
}
after that call your to download
RtukNetworkManager.shared.getPayroll(year: selectedPayment.year, month: selectedPayment.month, salaryType: selectedPayment.paymentType) { filePath in
if let url = filePath {
self.displayDownloadAlert(url.lastPathComponent)
showPdf(url:url)
}
}
to show pdf
func showPdf(url:URL) {
let pdfView = PDFView(frame: CGRect(x:100,y:100,width:200,height:200))
let pdfDocument = PDFDocument(url: url))
pdfView.autoresizesSubviews = true
pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleLeftMargin]
pdfView.displayDirection = .vertical
pdfView.autoScales = true
pdfView.displayMode = .singlePage
pdfView.displaysPageBreaks = true
pdfView.document = pdfDocument
pdfView.maxScaleFactor = 4.0
pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
pdfView.usePageViewController(true, withViewOptions: [:])
view.addSubview(pdfView)
}
also import PDFKit
PDFView use for displaying pdf

Swift XML Parser not firing properly

I'm reasonably new to Swift and I'm trying to read data from a web service. The data is returned and according to the parser it was parsed successfully. All I have at the moment is when the data is returned it's to be placed in a textview and it does do this successfully. But the returned XML is not being parsed. I have breakpoints in all 4 parser functions but none of them are being hit. It's as though they are not being fired. Here's my code (this is just playing at the moment so please be nice :) )
import UIKit
import Foundation
class ViewController: UIViewController, XMLParserDelegate{
var currentElementName:String = ""
var foundCharacters = ""
var parser = XMLParser()
var is_SoapMessage: String = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body></soap:Body></soap:Envelope>"
override func viewDidLoad() {
super.viewDidLoad()
parser.delegate = self
//clear all arrays
let Emp = EmployeeDetails()
Emp.ID.removeAll()
Emp.Name.removeAll()
Emp.Mobile.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func GetServiceBtn(_ sender: Any) {
Test1()
}
//Text box to see what's returned
#IBOutlet weak var OutputTxt: UITextView!
//First test of using web services
func Test1(){
let URL: String = "http://192.168.1.106:8080/Service.asmx"
let WebRequ = NSMutableURLRequest(url: NSURL(string: URL)! as URL)
let session = URLSession.shared
WebRequ.httpMethod = "POST"
WebRequ.httpBody = is_SoapMessage.data(using: String.Encoding.utf8)
WebRequ.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
WebRequ.addValue(String(is_SoapMessage), forHTTPHeaderField: "Content-Length")
WebRequ.addValue("MyServices/GetEmployeesFullNames", forHTTPHeaderField: "SOAPAction")
var Str: String = ""
let task = session.dataTask(with: WebRequ as URLRequest, completionHandler: {data, response, error -> Void in
let strData = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
Str = String(strData!) as String
if Str != ""{
self.PopulateTxt(Detail: Str)
self.ReadEmployeeResults(Data: data!)
print(Str)
}
if error != nil
{
print("Error: " + error.debugDescription)
}
})
task.resume()
}
//Process returned data
func ReadEmployeeResults(Data: Data){
self.parser = XMLParser(data: Data)
let success:Bool = parser.parse()
if success {
print("parse success!")
let Emp = EmployeeDetails()
print("Employee Name count \(Emp.Name.count)")
print("Employee ID count \(Emp.ID.count)")
print("Employee Mobile count \(Emp.ID.count)")
print(Emp.Name[0])
} else {
print("parse failure!")
}
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
print("In Parser")
currentElementName = elementName
if(elementName=="Table")
{
let Emp = EmployeeDetails()
for string in attributeDict {
let strvalue = string.value as NSString
switch string.key {
case "Emp_ID":
Emp.ID.append(Int(strvalue as String)!)
break
case "Emp_FullName":
Emp.Name.append(strvalue as String)
break
case "Emp_Mobile":
Emp.Mobile.append(strvalue as String)
break
default:
break
}
}
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
print("In didEndElement Parser")
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if currentElementName == "Emp_ID" {
print(string)
}
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print("failure error: ", parseError)
}
func PopulateTxt(Detail: String){
DispatchQueue.main.async {
self.OutputTxt.text = Detail //code that caused error goes here
}
}
}
class EmployeeDetails {
var Name = [String()]
var ID = [Int()]
var Mobile = [String()]
}
You are not setting the parser's delegate in your ReadEmployeeResults function. The XMLParser instance you create there is not the same one you create initially.
There is no need for your parser property or setting its delegate in viewDidLoad. Simply create the one you need in the function.
func ReadEmployeeResults(Data: Data){
let parser = XMLParser(data: Data)
parser.delegate = self
let success = parser.parse()
if success {
print("parse success!")
let Emp = EmployeeDetails()
print("Employee Name count \(Emp.Name.count)")
print("Employee ID count \(Emp.ID.count)")
print("Employee Mobile count \(Emp.ID.count)")
print(Emp.Name[0])
} else {
print("parse failure!")
}
}
Also note that variable and function names should start with lowercase letters.

Consume SOAP API

I want to consume a SOAP API but I am facing problem.
My delegate methods are not called and URL variable shows unable to read data which is of NSURL type.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, NSURLConnectionDelegate, XMLParserDelegate {
var mutableData:NSMutableData = NSMutableData.init()
var currentElementName:NSString = ""
#IBOutlet var txtCelsius : UITextField!
#IBOutlet var txtFahrenheit : UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let celcius = "24"
let soapMessage = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='https://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='https://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><CelsiusToFahrenheit xmlns='https://www.w3schools.com/xml/'><Celsius>\(String(describing: celcius))</Celsius></CelsiusToFahrenheit></soap:Body></soap:Envelope>"
let urlString = "https://www.w3schools.com/xml/tempconvert.asmx"
print(urlString)
if let url = NSURL(string: urlString)
{
print(url)
let theRequest = NSMutableURLRequest(url: url as URL)
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue((soapMessage), forHTTPHeaderField: "Content-Length")
theRequest.httpMethod = "POST"
theRequest.httpBody = soapMessage.data(using: String.Encoding.utf8, allowLossyConversion: false)
let connection = NSURLConnection(request: theRequest as URLRequest, delegate: self, startImmediately: true)
connection!.start()
}
}
private func connection(connection: NSURLConnection!, didReceiveResponse response: URLResponse!) {
mutableData.length = 0;
}
private func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
mutableData.append(data as Data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
let xmlParser = XMLParser(data: mutableData as Data)
xmlParser.delegate = self
xmlParser.parse()
xmlParser.shouldResolveExternalEntities = true
}
func parser(_ parser: XMLParser, foundCharacters string: String)
{
if currentElementName == "CelsiusToFahrenheit"
{
txtFahrenheit.text = string
}
}
}

http request with consumer key in swift 3.0

I am really new to Swift and I'm trying to make a http request to a URL with consumer key and consumer secret and honestly I'm not sure that is even possible to do in Swift.
I've been trying to make this work with authentication method but it only gives me an error.
My code (Hope this helps you to understand what I'm trying to do..)
let baseUrl = "my url"
let consumer_key = "consumer_key"
let consumer_secret = "consumer_secret"
let loginString = NSString(format:"%#:%#", consumer_key, consumer_secret)
let loginData = loginString.data(using: String.Encoding.utf8.rawValue)!
let base64LoginString = loginData.base64EncodedString()
let url = URL(string: baseUrl)
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
let config = URLSessionConfiguration.default
let authString = "Basic \(base64LoginString)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
session.dataTask(with: url!) {
(data, response, error) in
if (response as? HTTPURLResponse) != nil {
print("in session")
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("data please...",dataString!)
}
}.resume()
If this http call with consumer key and consumer secret is totally unacceptable in Swift or if there is any other way that I can get by this, please let me know.
Thank you in advanced.
EDIT------------------------------------------------------
import UIKit
class OrdersViewController: UIViewController {
#IBOutlet weak var orderView: UITableView!
var orderData = [[String: AnyObject]]()
var selectedIndex = -1
override func viewDidLoad() {
super.viewDidLoad()
print("in")
// Do any additional setup after loading the view.
let baseUrl = "my url"
let consumer_key = "consumer_key"
let consumer_secret = "consumer_secret"
let loginString = NSString(format:"%#:%#", consumer_key, consumer_secret)
let loginData = loginString.data(using: String.Encoding.utf8.rawValue)!
let base64LoginString = loginData.base64EncodedString()
let url = URL(string: baseUrl)
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
let config = URLSessionConfiguration.default
let authString = "Basic \(base64LoginString)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
session.dataTask(with: url!) {
(data, response, error) in
if (response as? HTTPURLResponse) != nil {
print("in session")
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("data please...",dataString!)
}
}.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return orderData.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if (selectedIndex == indexPath.row) {
return 100
} else {
return 40
}
}
func tableView(tableView: UITableView, cellforRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! orderCell
let obj = orderData[indexPath.row]
print("obj", obj)
return cell
}
}
Based on your response, it looks as if you are running into ATS issues - the network code does not run at all since the URL is an http:// URL and not an https:// one.
If you have a secure URL with https:// I would suggest you use it. Otherwise, you can add an ATS exception as detailed in the following SO thread:
Transport security has blocked a cleartext HTTP
I figured this out by changing my URLsession function.
session.dataTask(with: url!, completionHandler: {
(data, response, error) in
if (error != nil) {
print("in session error", error.debugDescription)
} else {
do {
print("in session")
self.orderData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
OperationQueue.main.addOperation {
self.orderView.reloadData()
print("data", self.orderData)
}
} catch let error as NSError {
print(error)
}
}
}).resume()
Now I see "in session" in my console which means it making http call properly but I'm facing a new problem which it says Cannot assign value of type 'NSDictionary' to type '[[String: AnyObect]]'. But I'm still happy that my http call works and finally I can start banging my head to a different problem.
Thank you all for helping and I hope this answer can help others as well.

Moving from NSURLConnection to NSURLSession for SOAP POST in Swift

I am trying to move over from NSURLConnection over to NSURLSession for a SOAP post, but seem to have issues with the NSURLSessionDataDelegate.
Here is the old code in NSURLConnection that works fine:
let soapMessage = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ns1='http://tempuri.org/'><SOAP-ENV:Body><ns1:get_Countries/></SOAP-ENV:Body></SOAP-ENV:Envelope>"
print("Soap Packet is \(soapMessage)")
let urlString = "https://example.com/Service.svc"
let url = NSURL(string: urlString)
let theRequest = NSMutableURLRequest(URL: url!)
let msgLength = String(soapMessage.characters.count)
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
theRequest.addValue("http://tempuri.org/IService/get_Countries", forHTTPHeaderField: "SoapAction")
theRequest.HTTPMethod = "POST"
theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
print("Request is \(theRequest.allHTTPHeaderFields!)")
let connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: false)
connection?.start()
This code then uses NSURLConnectionDelegate, and works fine as follows:
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
MutableData.length = 0;
let httpresponse = response as? NSHTTPURLResponse
print("status \(httpresponse?.statusCode)")
//print("headers \(httpresponse?.allHeaderFields)")
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
MutableData.appendData(data)
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
NSLog("Error with Soap call: %#", error)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
let xmlParser = NSXMLParser(data: MutableData)
xmlParser.delegate = self
xmlParser.parse()
xmlParser.shouldResolveExternalEntities = true
}
func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust && challenge.protectionSpace.host == "example.com" {
NSLog("yep")
let credential = NSURLCredential(trust: challenge.protectionSpace.serverTrust!)
challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
} else {
NSLog("nope")
challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge)
}
}
So that code all works fine, and is just for reference so you can see what I have done in the past, and the fact that the API actually does work! However, if I move over to using NSURLSession and NSURLSessionDataDelegate instead then I cannot get it working correctly.
So here is the new code:
let soapMessage = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ns1='http://tempuri.org/'><SOAP-ENV:Body><ns1:get_Countries/></SOAP-ENV:Body></SOAP-ENV:Envelope>"
print("Soap Packet is \(soapMessage)")
let urlString = "https://example.com/Service.svc"
let url = NSURL(string: urlString)
let theRequest = NSMutableURLRequest(URL: url!)
let msgLength = String(soapMessage.characters.count)
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
theRequest.addValue("http://tempuri.org/IService/get_Countries", forHTTPHeaderField: "SoapAction")
theRequest.HTTPMethod = "POST"
theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
print("Request is \(theRequest.allHTTPHeaderFields!)")
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration:config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(theRequest)
task.resume()
My delegates I am using are NSURLSessionDelegate, NSURLSessionDataDelegate:
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
print("Am in NSURLSessionDelegate didReceiveChallenge")
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust && challenge.protectionSpace.host == "example.com" {
NSLog("yep authorised")
let credential = NSURLCredential(trust: challenge.protectionSpace.serverTrust!)
challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
} else {
NSLog("nope")
challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge)
}
}
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
print("Am in URLSessionDidFinishEventsForBackgroundURLSession")
let xmlParser = NSXMLParser(data: MutableData)
xmlParser.delegate = self
xmlParser.parse()
xmlParser.shouldResolveExternalEntities = true
}
func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
print("error of \(error)")
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
print("Am in didReceiveResponse")
MutableData.length = 0
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
print("Am in didReceiveData")
MutableData.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
print("error of \(error)")
}
So, when I run the code, I get output:
"Am in NSURLSessionDelegate didReceiveChallenge"
"yep authorised"
So it's getting to didReceiveChallenge fine, and it appears to be authorising the HTTPS secure certificate fine, but then nothing further happens, it doesn't do anything else, I'd expect it to go into didReceiveResponse then didReceiveData, but nothing further happens at all.
So I am stuck, I could of course continue and use NSURLConnection as it all works fine, but I'd like to understand the NSURLSession, and particulary where I am going wrong. So if anyone can help that would be great.
Thanks
In case anyone else has the same issue, I sorted this out. The issue was I was not using the completionHandler in the didReceiveChallenge and didReceiveResponse delegates
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
completionHandler(NSURLSessionResponseDisposition.Allow) //.Cancel,If you want to stop the download
}