ProtoBuf-net Deserialize does not work - serialization

code is here:
var responseMsg = new ResponseMessage()
{
code = ErrorCode.OK,
type = MsgType.LOGIN,
responseStr = "this is local server"
};
var serverStream = new MemoryStream();
ProtoBuf.Serializer.Serialize(serverStream, responseMsg);
Console.WriteLine($"responseMsg {responseMsg?.responseStr ?? "failed"}\n");
var response =ProtoBuf.Serializer.Deserialize<ResponseMessage>(serverStream);
Console.WriteLine($"response {response?.responseStr ?? "failed"}\n");
result is
responseMsg this is local server
response
ProtoBuf-net can not Deserialize what it Serialized. it's really a strange thing

You need to rewind the stream to the beginning by resetting its Position before you can read from it:
serverStream.Position = 0;
var response = ProtoBuf.Serializer.Deserialize<ResponseMessage>(serverStream);
Sample fiddle.

Related

How to call API method that accepts XML in ASP.NET Core Web APIs?

The API Method I am calling is:
[HttpPost("PostXml")]
[Consumes("application/xml")]
[Produces("application/xml")]
public Reservation PostXml([FromBody] Reservation res) =>
repository.AddReservation(new Reservation
{
Name = res.Name,
StartLocation = res.StartLocation,
EndLocation = res.EndLocation
});
The client code:
[HttpPost]
public async Task<IActionResult> AddReservationByXml(Reservation reservation)
{
Reservation receivedReservation = new Reservation();
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(ConvertObjectToXMLString(reservation), Encoding.UTF8, "application/xml");
using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation/PostXml", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
}
}
return View(receivedReservation);
}
string ConvertObjectToXMLString(object classObject)
{
string xmlString = null;
XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, classObject);
memoryStream.Position = 0;
xmlString = new StreamReader(memoryStream).ReadToEnd();
}
return xmlString;
}
I am failing to call the API method and getting the error:
400One or
more validation errors
occurred.https://tools.ietf.org/html/rfc7231#section-6.5.1|f5452728-4c49abe4d88e559e.1.8095e7c1_An
error occurred while deserializing input
data.
What is wrong here?
You got error from this line
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
Please check the validation of your Reservation Model and detail the values you past
and the content of error you got.
Your XML request should be with the correct case as the c# class. XML is case sensitive.
Try this code.
XmlSerializer xsSubmit = new XmlSerializer(typeof(Reservation));
System.IO.StringWriter sww = new System.IO.StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, reservation);
var xml = sww.ToString();

Getting Swagger API response error StatusCode 404, when called from code

While making an API call from swagger-ui, with content type "application/json", it is working fine. But when the same API is being called from below specified code, shows 404 StatusCode . What could be the possible reasons for it? Also, few other APIs from the same swagger-ui, are when being called from the code, they work from this same code.
var serialized = JsonConvert.SerializeObject(data);
String uri = GetEndpointUrl(path);
String responseData = "";
var buffer = System.Text.Encoding.UTF8.GetBytes(serialized);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.Timeout = TimeSpan.FromSeconds(120);
var response = client.PostAsync(uri, byteContent).Result;
responseData = await response.Content.ReadAsStringAsync();

Posting GZip content using RestSharp

How do I post GZip data using RestSharp. I have the following code but it isn't working as I would expect:
var restRequest = new RestRequest(url, Method.POST)
{
Timeout = Constants.DefaultTimeoutMilliseconds
};
var dataStream = new MemoryStream();
using (var zipStream = new GZipStream(dataStream, CompressionMode.Compress))
{
using (var writer = new StreamWriter(zipStream))
{
writer.Write(new DotNetXmlSerializer().Serialize(content));
}
}
var compressedBytes = dataStream.ToArray();
restRequest.AddParameter("application/x-gzip", compressedBytes, ParameterType.RequestBody);
return _restClient.Execute<TResponseData>(restRequest);
When I run this and check the wireshark trace, the compressedBytes variable is posted as
'System.Byte[]' - as if ToString() has been called on it despite the parameter being a system.object.
If I pass the compressed byte array through as a string using both Convert.ToBase64String() and Encoding.Utf8.GetString() then I am unable to decompress the GZip at the server. I simply get 'System.IO.InvalidDataException: The magic number in GZip header is not correct. Make sure you are passing in a GZip'.
Is there any way of posting Gzipped data using RestSharp?
Make sure you've updated to the latest version of RestSharp (like 104.4.0) as this was a bug in a previous version.
I think this was fixed in 104.2 where the PUT or POST of binary data ended up with the System.Byte[] being represented as the string.
Update your NuGet reference and try it again. Good luck!
var body = "some string";
var dataStream = new MemoryStream();
byte[] dataToCompress = Encoding.UTF8.GetBytes(body);
using (var memoryStream = new MemoryStream())
{
using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
{
gzipStream.Write(dataToCompress, 0, dataToCompress.Length);
}
dataStream = memoryStream;
}
var client = new RestClient("url");
var request = new RestRequest("", Method.POST);
var compressedBytes = dataStream.ToArray();
request.AddHeader("Content-Encoding", "gzip");
request.AddParameter("application/x-gzip", compressedBytes, ParameterType.RequestBody);
//client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
IRestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);

WinRT No mapping for the Unicode character exists in the target multi-byte code page

I am trying to read a file in my Windows 8 Store App. Here is a fragment of code I use to achieve this:
if(file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
var size = stream.Size;
using(var inputStream = stream.GetInputStreamAt(0))
{
DataReader dataReader = new DataReader(inputStream);
uint numbytes = await dataReader.LoadAsync((uint)size);
string text = dataReader.ReadString(numbytes);
}
}
However, an exeption is thrown at line:
string text = dataReader.ReadString(numbytes);
Exeption message:
No mapping for the Unicode character exists in the target multi-byte code page.
How do I get by this?
I managed to read file correctly using similar approach to suggested by duDE:
if(file != null)
{
IBuffer buffer = await FileIO.ReadBufferAsync(file);
DataReader reader = DataReader.FromBuffer(buffer);
byte[] fileContent = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(fileContent);
string text = Encoding.UTF8.GetString(fileContent, 0, fileContent.Length);
}
Can somebody please elaborate, why my initial approach didn't work?
Try this instead of string text = dataReader.ReadString(numbytes):
dataReader.ReadBytes(stream);
string text = Convert.ToBase64String(stream);
If, like me, this was the top result when search for the same error regarding UWP, see the below:
The code I had which was throwing the error (no mapping for the unicode character exists..):
var storageFile = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
using (var stream = await storageFile.OpenAsync(FileAccessMode.Read))
{
using (var dataReader = new DataReader(stream))
{
await dataReader.LoadAsync((uint)stream.Size);
var json = dataReader.ReadString((uint)stream.Size);
return JsonConvert.DeserializeObject<T>(json);
}
}
What I changed it to so that it works correctly
var storageFile = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
using (var stream = await storageFile.OpenAsync(FileAccessMode.Read))
{
T data = default(T);
using (StreamReader astream = new StreamReader(stream.AsStreamForRead()))
using (JsonTextReader reader = new JsonTextReader(astream))
{
JsonSerializer serializer = new JsonSerializer();
data = (T)serializer.Deserialize(reader, typeof(T));
}
return data;
}

Encoding with HttpClient

I am using the HttpClient class in Windows 8. With Windows Phone, I use
the WebClient class in combination with encoding to get the right encoding.
WebClient xml = new WebClient();
xml.Encoding = Encoding.GetEncoding("ISO-8859-1");
In Windows 8 it is looks like this:
HttpClient xml = new HttpClient();
HttpResponseMessage response = await xml.GetAsync(uri);
responsetext = await response.Content.ReadAsStringAsync();
How can I add a encoding to support German (umlaute)?
I don't have time to test right now, but have you tried using the HttpContent.ReadAsByteArrayAsync method (rather than ReadAsStringAsync) and encoding the resulting byte[] into ISO-8859-1 separately?
Change ReadAsStringAsync to ReadAsBufferAsync and parse result with required encoding
var buffer = await response.Content.ReadAsBufferAsync();
byte [] rawBytes = new byte[buffer.Length];
using (var reader = DataReader.FromBuffer(buffer))
{
reader.ReadBytes(rawBytes);
}
var res = Encoding.UTF8.GetString(rawBytes, 0, rawBytes.Length);