I am trying to send data to a .NET web service that accepts three parameters whose types are (String, String, QBUser Class). In Javascript, I would send the parameters in JSON like so:
{sKey: "key", sUpdatetype: "edit", oQbUser: QBUser}
I have never had any issue with that method before and .NET would be able to sort it right into a class object on the server. With Swift, I have achieved success sending almost every type in the book so far as JSON but I am having issues sending custom classes/struct as a parameter. Here is my current code:
func updateQbUser(k: String, t: String, oUser: QBUUser, completion: @escaping (_ oVisits: AnyObject) -> ()) {
let params: [String: Any] = ["sKey": k, "sUpdateType": t, "iObjectId": oUser]
let url = URL(string: "myWebService.asmx/updateQbUser")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
do { request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) } catch let error { print(error.localizedDescription) }
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else { return }
DispatchQueue.main.async { completion(response!) }
})
task.resume()
}
The error as shown in the console is as follows:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (QBUUser)'
The QBUUser class is not an instance of NSString, NSNumber, NSArray, NSDictionary, or NSNull so I am stuck on how to get this across to the server.
Is there a way to convert the QBUUser class to Any Object type listed above before attempting to send? I tried to run a loop over the class and that was a whole different bag of hammers but got some error about could not AnyHashable over Array Literal or some such. Is there a better way I have not discovered?
The parameters have to be in that way so I am stuck there. I just need to get the class sent over to the other side as what is essentially just in a key/value pair.
here is what the class looks like printed in the console:
[QBUUser]:
ID:20786
created at:2017-05-03 15:05:56 +0000
updated at:2017-05-03 20:16:52 +0000
externalUserID:2456369827
blobID:0
facebookID:(null)
twitterID:(null)
twitterDigitsID:(null)
full name:Erik Grosskurth
email:erik@webgraphicsatlanta.com
login:Erik_2456369827
phone:(null)
tags:(
""
)
lastRequestAt:2017-05-03 20:20:16 +0000
customData:(null)
website:(null)
You, most likely, just need to convert your QBUUser
object into a dictionary. You could do it inline, though if you're planning to reuse that functionality you may as well make a helper function to do it.
The dictionary should just look something like this:
let qbuUser = QBUUser() //presumably you already have a reference to the user in question
let user: [String : Any] = ["id" : qbuUser.ID, "createdAt" : qbuUser.createdAt, "updatedAt" : qbuUser.updatedAt, ...]
If you want to create a helper method in your QBUUser
class you could do something like:
extension QBUUser {
func toDictionary() -> [String : Any] {
return ["id", self.ID, "createdAt", self.createdAt, ...]
}
}
And that'd allow you to change your existing function to look like this:
let params: [String: Any] = ["sKey": k, "sUpdateType": t, "iObjectId": oUser.toDictionary()]
It also might be worth pointing out that the key for that QBUUser
object in your parameters is "iObjectId", which (to me) implies that all they need is the ID
from your user, which makes this entire solution moot.