I'm trying to pass an object over a StreamSocket, so i need to serialize it before i can do that.
I looked at the BinaryFormatter, but that doesn't seem to be available in UWP?
Any suggestions on how to serialize an object, and preferably in the most compact way.
You can serialize your own .NET objects; JSON.NET is a very popular choice, but the built-in DataContractSerializer should also work if you don't want any dependencies.
You cannot serialize any WinRT objects.
If you want to serialize an object to json, at first you have to add Newtonsoft.Json to your project.
To install Json.NET, run the following command in the Package Manager Console:
PM> Install-Package Newtonsoft.Json
Then use this code to pass your object :
(Note: In this sample I suppose your server and client are the same and the port that you are using is: 1800.)
try
{
Windows.Networking.Sockets.StreamSocket socket = new Windows.Networking.Sockets.StreamSocket();
Windows.Networking.HostName serverHost = new Windows.Networking.HostName("127.0.0.1");
string serverPort = "1800";
socket.ConnectAsync(serverHost, serverPort);
var json = JsonConvert.SerializeObject(object);
byte[] buffer = Encoding.UTF8.GetBytes(json);
Stream streamOut = socket.OutputStream.AsStreamForWrite();
StreamWriter writer = new StreamWriter(streamOut);
var request = json;
writer.WriteLine(request);
writer.Flush();
Stream streamIn = socket.InputStream.AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string response = reader.ReadLine();
}
catch (Exception e)
{
var err = e.Message;
//Handle exception here.
}
Inform me if you have any other question.
Related
I am an intern now. I'm just learning coding processes. I am returning a data as json object. My developer manager said that a query or operation should be done so that there is no problem when parsing the Json object. What action can be taken?
He said it should be done before the parcel process. I thought of the try catch method. But I don't think this is the definitive result. What kind of query or code should I write before the parse operation? Here I am returning the data in excel as json.
My code:
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(_appSetting.ExcelLicense);
byte[] excelData = System.IO.File.ReadAllBytes(fileName);
MemoryStream uploadExcelStream = new MemoryStream(excelData);
//Stream uploadExcelStream = data.File.OpenReadStream();
ExcelEngine excelEngine = new ExcelEngine();
IApplication application = excelEngine.Excel;
application.DefaultVersion = Path.GetExtension(fileName) == "xlsx" ? ExcelVersion.Xlsx : ExcelVersion.Excel97to2003;
IWorkbook book = application.Workbooks.Open(uploadExcelStream);
uploadExcelStream.Close();
MemoryStream jsonStream = new MemoryStream();
book.SaveAsJson(jsonStream, true);
excelEngine.Dispose();
byte[] json = new byte[jsonStream.Length];
jsonStream.Position = 0;
jsonStream.Read(json, 0, (int)jsonStream.Length);
string jsonString = Encoding.UTF8.GetString(json, 0, json.Length);
JObject jsonObject = JObject.Parse(jsonString);
var json2 = JsonConvert.SerializeObject(jsonObject);
return Json(json2, "application/json");
When converting from Excel to json, I was told that sometimes there may be a problem with the parse process and I need to write a query just above it. How can I do something so that there is no problem?
First up I think you could simplify the top part a little bit:
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
var jsonString = reader.ReadToEnd();
//OR
var jsonString = await reader.ReadToEndAsync(); //If you want to read async
As to your question, it´s a bit unclear what you are trying/supposed to do.
Since you are first desirializing your incoming json and then serialize it again to return, I can only assume you are supposed to do some kind of check on the object in between those two actions.
In the following code i want to use a predefined protobuf message in c#. I found that I was able to write and use the method to take a method that has been created and make a byte[]:
ContainerMessage containerMessage = new ContainerMessage();
containerMessage.Type = CommandType.Connect;
containerMessage.Connect = new Connect();
containerMessage.Connect.ClientName = "TemporaryClientName";
byte[] stream = new byte[containerMessage.CalculateSize()];
using (Google.Protobuf.CodedOutputStream outstream = new Google.Protobuf.CodedOutputStream(stream))
{
containerMessage.WriteTo(outstream);
}
This works as expected and i can inspect the message and the values are as expected as are the values in the byte[]. But if I try to Deserialize even this simple byte[] that i have just created:
using (Google.Protobuf.CodedInputStream instream = new Google.Protobuf.CodedInputStream(stream))
{
instream.ReadMessage(containerMessage);
}
It fails with:
An unhandled exception of type 'Google.Protobuf.InvalidProtocolBufferException' occurred in Google.Protobuf.dll
Additional information: Protocol message contained an invalid tag (zero).
Is this way of deserializing from a byte[] correct for protobuf?
The Protobuf Definition is:
message ContainerMessage {
CommandType type = 1;
bool commandSuccess = 2;
oneof message {
Connect connect = 3;
}
}
enum CommandType {
START = 0;
CONNECT = 2;
}
message Connect {
string ClientName = 1;
uint32 PushPullPort = 2;
}
And the CS file is generated with the command line:
protoc.exe -I=%CD% --csharp_out=..\GeneratedCsMessaging\ Connect.proto
The CodedOutputStream and CodedInputStream are mainly intended to be used by the compiled proto classes. The API for CodedOutputStream states such and mentions that if you want to have manually-written code calling either of both classes you need to use their WriteTag method before each value.
However, since you want to use the Google Protobuf for serializing and parsing any System.IO.Stream will do the job just like intended. This is very well documented and described in the Parsing and serialization section of the Protocol Buffer Basics for C#. The examples which can be found in Google Protobuf's Github can be quite helpful for getting the hang of Google Protobuf quickly. There you can see that a MemoryStream is used to serialize the object while the Parse.ParseFrom method can be used to parse an object out of the serialized data.
As you've mentioned in the comments to your question using Google.Protobuf; is an essential part to be able to use Google Protobuf's features.
EDIT: A sample usage in your case could look something like this
byte[] serializedBytes;
ContainerMessage containerMessage = new ContainerMessage()
{
Connect = new Connect()
{
ClientName = "TemporaryClientName",
},
Type = CommandType.Connect,
};
using( MemoryStream stream = new MemoryStream())
{
containerMessage.WriteTo(stream);
serializedBytes = stream.ToArray();
}
ContainerMessage parsedCopy = ContainerMessage.Parser.ParseFrom(serializedBytes);
I'm accessing the tomtom json api, and the api either returns me an array of objects, or a single object, when an error has happen.
Example:
[{"driverno": "...
Error Example:
{"errorCode": "8011","errorMsg": "request quota reached, error code: 8011"}
The data is accessed WebRequest, WebResponse and they return a stream, which can then be passed to a DataContractJsonSerializer. However, I can't create a serialization class, which accepts both forms of JSON, and the stream can't be passed twice, because the seek function is not supported.
Is there a way, to create a serialization class which supports both types of JSON input?
I found a workaround, where I copy the Stream to a MemoryStream, which enables seeking. I'm not completly settisfied with th solution, becuase it does a Stream copying and the DataContractJsonSerializer twice.
Sample:
string text = File.ReadAllText(PAHT);
text = Regex.Replace(text, "\\{[\\n\\r ]*\"__type", "{\"__type");
// copy to MemoryStream
using (MemoryStream dataStream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
DataContractJsonSerializer errorDeserializer = new DataContractJsonSerializer(typeof(RequestError));
RequestError errorSerilaized = (RequestError)errorDeserializer.ReadObject(dataStream);
// check if an error happened
if (errorSerilaized.errorCode == null)
{
// seek the stream to position 0
dataStream.Position = 0;
DataContractJsonSerializer _deserializer = new DataContractJsonSerializer(typeof(NoneErrorSerializationClass));
NoneErrorSerializationClass tripReportsSerialized = (NoneErrorSerializationClass)_deserializer.ReadObject(dataStream);
// ...
}
else
{
MessageBox.Show(errorSerilaized.errorMsg);
}
}
I can't get the DataContractJsonSerializer object to swallow my stream. When I execute the code with the commented-out line active, I get to see the text provided (and it is a parsable JSON object), so I know that the stream is working fine.
However, for some reason, the compiler complains that the streamReader I'm trying to shove down its throat in ReadObject isn't a Stream. Well, isn't it?!
Argument 1: cannot convert from 'System.IO.StreamReader' to 'System.IO.Stream'
What am I missing and how do I resolve it?
using (StreamReader streamReader = new StreamReader(...))
{
//String responseText = reader.ReadToEnd();
MyThingy thingy = new MyThingy();
DataContractJsonSerializer serializer
= new DataContractJsonSerializer(thingy.GetType());
thingy = serializer.ReadObject(streamReader);
}
I'm adapting this example to work with my stream. Should I approach it from a different angle? If so - how?
You're trying to put in a reader of a stream instead of an actual stream. Skip the using and whatever hides behind the ellipsis (i.e. whatever you put in as an argument when you create an instance of StreamReader), you can probably put that into the ReadObject.
Also, you'll get into problems when reading the data because ReadObject will return an instance of type Object and you'll need to convert it into MyThingy. Since it's a nullable (I'm assuming), you don't have to type cast but rather as-ify it.
MyThingy thingy = new MyThingy();
DataContractJsonSerializer serializer
= new DataContractJsonSerializer(thingy.GetType());
Stream stream = ...;
thingy = serializer.ReadObject(stream) as MyThingy;
You could of course skip the next-to-last line and put the stream directly into the last line.
Courtesy of #JohanLarsson (all Swedes are great, especially those from Stockholm, like me):
In case you can't or don't want to omit the StreamReader declaration in your using statement, I'd suggest that you take a look at BaseStream property to get to it.
You can try this:
using (StreamReader streamReader = new StreamReader(...))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(MyThingy));
MyThingy thingy = (MyThingy) serializer.ReadObject(streamReader.BaseStream);
}
I've been always using this:
// get stuff here
String json = GetJSON();
List<T> result;
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(typeof(List<T>));
result = (List<T>)serializer.ReadObject(ms);
}
I have a CookieContainer extracted from a HttpWebRequest/HttpWebResponse session named CookieJar. I want my application to store cookies between runs, so cookies collected in the CookieContainer on one run of the program will be used the next run, too.
I think the way to do this would be to somehow write the contents of a CookieContainer to disk. My question is:
How can you write a CookieContainer to the disk? Are there built-in functions for this, or, if not, what are the approaches people have taken? Are there any classes available for simplifying this?
Once you've written a CookieContainer to the disk, how do you load it back in for use?
UPDATE: The first answer has suggested serialization of the CookieContainer. However, I am not very familiar with how to serialize and deserialize such complex objects. Could you provide some sample code? The suggestion was to utilise SOAPFormatter.
This problem was bugging me for ages, nothing I could find worked. I worked it out, so putting that information out into the world.
Answer using BinaryFormatter:
public static void WriteCookiesToDisk(string file, CookieContainer cookieJar)
{
using(Stream stream = File.Create(file))
{
try {
Console.Out.Write("Writing cookies to disk... ");
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, cookieJar);
Console.Out.WriteLine("Done.");
} catch(Exception e) {
Console.Out.WriteLine("Problem writing cookies to disk: " + e.GetType());
}
}
}
public static CookieContainer ReadCookiesFromDisk(string file)
{
try {
using(Stream stream = File.Open(file, FileMode.Open))
{
Console.Out.Write("Reading cookies from disk... ");
BinaryFormatter formatter = new BinaryFormatter();
Console.Out.WriteLine("Done.");
return (CookieContainer)formatter.Deserialize(stream);
}
} catch(Exception e) {
Console.Out.WriteLine("Problem reading cookies from disk: " + e.GetType());
return new CookieContainer();
}
}
I Haven't tried it but it has the attribute Serializable and so can be [de]serialized with .net binary serialization, e.g. SoapFormatter.
Here is the code snippet you asked for.
var formatter = new SoapFormatter();
string file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "cookies.dat");
using (Stream s = File.Create (file))
formatter.Serialize(s, cookies);
...
CookieContainer retrievedCookies = null;
using (Stream s = File.OpenRead (file))
retrievedCookies = (CookieContainer) formatter.Deserialize(s);
Looking at msdn it seems SoapFormatter is now deprecated in .net 3.5 and it recommends you use Binaryformatter. In the past I have found SoapFormatter useful as the file is readable which helps with diagnosis when deserialization fails! These formatters are sensitive to version changes even in the assembly version (so if you deserialize with one version of the framework upgrade the framework, then it might not deserialize, not sure), but there are ways around this with the Binder property if this becomes a problem. I believe they are primarily designed for short term persistance / remoting, but they might be good enough for you here.
The new DataContractSerializer does not seem to work with it so that is out.
An alternative would be to write a CookieContainerData class to [de]serialize with XmlSerializer and manually convert between this and CookieContainer.
It is interesting to have cookies in text format. Besides being able to be used to write to disk, it can be used for other purposes.
WORKS FOR ME!
Use the LoadCookiesFromFile and SaveCookiesToFile functions to load and write the cookies to the disk respectively.
Or use the GetCookies and SetCookies functions to do the same thing, but to manipulate it as a string.
CookieContainer cookieContainer = new CookieContainer();
void LoadCookiesFromFile(string path)
{
SetCookies(cookieContainer, File.ReadAllText(path));
}
void SaveCookiesToFile(string path)
{
File.WriteAllText(path, GetCookies(cookieContainer));
}
string GetCookies(CookieContainer cookieContainer)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, cookieContainer);
var bytes = new byte[stream.Length];
stream.Position = 0;
stream.Read(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes);
}
}
void SetCookies(CookieContainer cookieContainer, string cookieText)
{
try
{
var bytes = Convert.FromBase64String(cookieText);
using (MemoryStream stream = new MemoryStream(bytes))
{
cookieContainer = (CookieContainer)new BinaryFormatter().Deserialize(stream);
}
}
catch
{
//Ignore if the string is not valid.
}
}
All of the previous answers are outdated since serializing using IFormatter classes was deprecated https://aka.ms/binaryformatter
So the correct method now is serializing it using something else that supports IEnumerable<T>.
Here's an example using System.Text.Json
Serialize
await using var fs = File.OpenWrite("cookies.json");
// Beware: GetAllCookies is available starting with .NET 6
JsonSerializer.Serialize(fs, cookieContainer.GetAllCookies());
Deserialize
var cookieContainer = new CookieContainer();
await using var fs = File.OpenRead("cookies.json");
var cookieCollection = JsonSerializer.Deserialize<CookieCollection>(fs);
cookieContainer.Add(cookieCollection);