In my C# app I access a NetApp REST API. I am using RestSharp to access the API. No problem with Get requests. However when I try a Put request I alwas get: "Invalid JSON input. Unexpected character in stream: r around 0:0."
Added: I'm stuck with RestSharp version 105.2.3 because of other dependencies. Its a huge application and moving to a newer version of RestSharp would need changes in several modules as well as moving to another .Net version. AddStringBody method would maybe help, but is not present in the version I am using.
The method called, prepares and sends the request, as well as checks the result.
internal bool CreateQtree(Pool pool, BaseStorageConf storageConf, RestClientCustom server) {
bool isOk = false;
// Prepare request query parameters.
var request = new RestRequest("storage/qtrees");
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json;
request.AddParameter("return_records", "false");
request.AddParameter("return_timeout", 15);
// Prepare body.
PostCreateQTree CreateQTreePost = new PostCreateQTree();
CreateQTreePost.Name = pool.Name;
CreateQTreePost.SecurityStyle = "unix";
CreateQTreePost.Svm = new Svm();
CreateQTreePost.Svm.Name = storageConf.FileServer;
CreateQTreePost.Volume = new Volume();
CreateQTreePost.Volume.Name = storageConf.FileSystem;
// Assure that null values are not serialized.
JsonSerializerSettings setting = new JsonSerializerSettings();
setting.NullValueHandling = NullValueHandling.Ignore;
// Using this serializer makes sure that the JsonProperty are honored.
string body = JsonConvert.SerializeObject(CreateQTreePost, setting);
request.AddParameter("application/json", body, ParameterType.RequestBody);
// Execute request.
var response = server.Execute(request);
// Handle results.
if (response.StatusCode == HttpStatusCode.OK) {
// Creation of the qtree was successfull.
TheLogger.Instance.Error(string.Format("Qtree could be created. Pool: {0}", pool.Name));
isOk = true;
} else {
// There was an error, dump.
ResponseError ErrorResponse = JsonConvert.DeserializeObject<ResponseError>(response.Content);
TheLogger.Instance.Error(string.Format("Qtree could not be created. Pool: {0}, code: {1}, message: {2}", pool.Name, ErrorResponse.Error.Code, ErrorResponse.Error.Message));
}
return isOk;
}
The RestClientCustom is only to allow debugging, when working against the productive system.
using Logging;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Devices.NetAppREST {
internal class RestClientCustom:RestClient {
private readonly bool mIsDebugMode;
internal RestClientCustom(string baseUrl, bool isDebugMode): base(baseUrl) {
mIsDebugMode = isDebugMode;
}
internal RestClientCustom(Uri baseUrl, bool isDebugMode) : base(baseUrl) {
mIsDebugMode = isDebugMode;
}
public IRestResponse Execute(RestRequest request) {
IRestResponse response;
TheLogger.Instance.Debug(string.Format("REST URI:\r\n{0}", base.BuildUri(request)));
TheLogger.Instance.Debug(string.Format("Parameters:\r\n{0}", ParameterToString(request)));
if (mIsDebugMode) {
response = new RestResponse();
response.StatusCode = HttpStatusCode.OK;
return response;
} else {
response = base.Execute(request);
}
TheLogger.Instance.Debug(string.Format("StatusCode:\r\n{0}", response.StatusCode));
TheLogger.Instance.Debug(string.Format("Content:\r\n{0}", response.Content));
TheLogger.Instance.Debug(string.Format("Headers:\r\n{0}", response.Headers));
TheLogger.Instance.Debug(string.Format("ResponseURI:\r\n{0}", response.ResponseUri));
TheLogger.Instance.Debug(string.Format("ErrorMessage:\r\n{0}", response.ErrorMessage));
return response;
}
internal String ParameterToString(RestRequest request) {
var sb = new StringBuilder();
foreach (var param in request.Parameters) {
sb.AppendFormat("Name: {0}, Value: {1}, Type: {2}\r\n", param.Name, param.Value, param.Type.ToString());
}
return sb.ToString();
}
}
}
The Post JSON is created with the following class.
using Newtonsoft.Json;
namespace Devices.NetAppREST {
public class PostCreateQTree {
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("security_style")]
public string SecurityStyle { get; set; }
[JsonProperty("svm")]
public Svm Svm { get; set; }
[JsonProperty("volume")]
public Volume Volume { get; set; }
}
}
I use a Newtonsoft.Json serializer in order to get the correct naming in the body JSON, as well als filter null values. An example looks as follows ...
{"name":"G-IPH-TestPoolCreate","security_style":"unix","svm":{"name":"sy-fs-301"},"volume":{"name":"g"}}
I can take this JSON string and post it via curl, powershell or test it on the target system directly and it works. However when I use the RestSharp implementation, I get above error.
I tried the normal serializer. But it does not generate the correct JSON (capitals). I added the JSON string directly as parameter in the code, no luck. Now I use the Newtonsoft.Json serializer. But I do not think the serialization is the problem. In the debugger I see the parameters and the URI passed in the request object. They seem ok.
I suppose I am missing something. A hint would be appreciated.
If found the solution ... In the method CreateQtree I used to add to query parameters.
request.AddParameter("return_records", "false");
request.AddParameter("return_timeout", 15);
When I add them more sprecific ...
request.AddParameter("return_records", "false", ParameterType.QueryString);
request.AddParameter("return_timeout", 15, ParameterType.QueryString);
It works. It seems the two parameters are not added correctly if I do not specify them as query parameters.