SerializeObject and DeserializeObject - wcf

I use this following code but it gives error
Service1.svc.cs
public static byte[] SerializeObject<T>(T obj)
{
using (MemoryStream ms = new MemoryStream())
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(ms))
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
dcs.WriteObject(writer, obj); writer.Flush();
return ms.ToArray();
}
}
}
client code Windows phone
public static T DeserializeObject<T>(byte[] xml)
{
using (MemoryStream memoryStream = new MemoryStream(xml))
{
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(memoryStream, XmlDictionaryReaderQuotas.Max))
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
return (T)dcs.ReadObject(reader);
}
}
}
I call this DeserializeObject from below code
void svc_Get_Conn(object send, GetConnCompletedEventArgs e)
{
CookieContainer con =DeserializeObject<CookieContainer>(e.Result);
}
This gives following error
Message = "Type 'System.Net.PathList' with data contract name 'PathList:http://schemas.datacontract.org/2004/07/System.Net' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using...
How to solve this?

CookieContainer can't be serializable. Check this workaround
cheers

Related

How does C# know the length of string using Binary Writer?

Please look at the code below. This program simply saves a 33-character-length string "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" with an additional byte value of "33".
using System.Text;
namespace Test
{
internal class Program
{
static void Main(string[] args)
{
string filepath = args[0];
using (var stream = File.Open(filepath, FileMode.Create))
{
using (var writer = new BinaryWriter(stream, Encoding.UTF8, false))
{
writer.Write(new string('!', 33));
writer.Write((byte)33);
}
}
using (var stream = File.Open(filepath, FileMode.Open))
{
using (var reader = new BinaryReader(stream, Encoding.UTF8, false))
{
Console.WriteLine(reader.ReadString());
Console.WriteLine(reader.ReadByte());
}
}
Console.ReadKey();
}
}
}
And here is the binary representation of it:
Apparently, the first starting "ox21" is the length of the string - but how on earth does C# know?

Blazor Server create link to download file from byte array

I have a method in my code behind to retrieve a get a pdf file from an API and return the byte[]
byte[] byteArray = response.Content.ReadAsByteArrayAsync().Result; ;
using (MemoryStream pdfStream = new MemoryStream())
{
pdfStream.Write(byteArray, 0, byteArray.Length);
pdfStream.Position = 0;
return new FileStreamResult(pdfStream, "application/pdf");
}
How in Blazor server to I create a link in my .razor component to consume this byte[] so that when the user clicks the link, it triggers the file download?
Your solution is close because you're creating the appropriate result, but you simply need the method that returns it.
Set up your API controller like the following:
[ApiController]
public class DownloadController : ControllerBase {
[HttpGet]
public ActionResult Get() {
byte[] byteArray = response.Content.ReadAsByteArrayAsync().Result; ;
using (MemoryStream pdfStream = new())
{
pdfStream.Write(byteArray, 0, byteArray.Length);
pdfStream.Position = 0;
var result = FileStreamResult(pdfStream, "application/pdf");
result.FileDownloadName = "sample.txt";
return result;
}
}
}

Save XDocument issue

I'm loading my document like so:
WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.OpenReadAsync(new Uri("Rolls.xml", UriKind.Relative));
Then on the Read Completed:
XDocument doc = XDocument.Load(XmlReader.Create(e.Result));
using (Stream stream = e.Result)
{
{
foreach (var roll in _rollsToAddStudentTo)
{
doc.Element("rolls").Add(new XElement("rollid", roll));
}
doc.Save(stream);
}
}
The problem is when it gets to the save I get the error
"Specified method is not supported."
Help will be much appreciated.
Cheers
Thanks Jehof,
So, how would I incorporate my document into that async method?
foreach (var roll in _rollsToAddStudentTo)
{
doc.Element("rolls").Add(new XElement("rollid", roll));
}
WebClient client = new WebClient();
client.OpenWriteCompleted += new OpenWriteCompletedEventHandler(client_OpenWriteCompleted);
client.OpenWriteAsync(new Uri("Rolls.xml", UriKind.Relative));
I have resolved this by changing my logic to below.
using (IsolatedStorageFile isoStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
// Create new file
using (IsolatedStorageFileStream isoStream =
new IsolatedStorageFileStream("Rolls.xml",
FileMode.Create, isoStore))
{
// Write to the Isolated Storage for the user.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
// Create an XmlWriter.
using (XmlWriter writer = XmlWriter.Create(isoStream, settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("Rolls");
foreach (var roll in _rollsToAddStudentTo)
{
writer.WriteStartElement("roll");
writer.WriteAttributeString("rollid", roll);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}
The stream you try to save the XDocument is readonly. Cause it is the stream you get passed as argument to your method client_OpenReadCompleted that is registered to the event OpenReadCompleted.
If you want to save your XDocument back via WebClient you need to call one of the OpenWriteAsync-methods.

C# extension method to objects with specific attribute

I created an extension method that will tell me the size of every object I create
like this:
public static int CalculateKilobytes(this object notSuspectingCandidate)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, notSuspectingCandidate);
return stream.ToArray().Count() / 1000;
}
}
Since I'm using serializaion, not all objects will be able to return answer, only the serializble ones. Is there a way to attach this method to an object that can be serialized?
you can use Type.IsSerializable Property.
public static int CalculateKilobytes(this object notSuspectingCandidate)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
if (notSuspectingCandidate.GetType().IsSerializable) {
formatter.Serialize(stream, notSuspectingCandidate);
return stream.ToArray().Count() / 1000;
}
return 0;
}
}
It's a really bad practice to serialize a object only to get its size, if you plan to serialize it again later.
Use with caution.
The extension method will be applied to all objects, you must check if it has the custom property in it.
This check can do the job.
if (notSuspectingCandidate.GetType().GetCustomAttributes(typeof(SerializableAttribute), true).Length == 0)
{
return -1; // An error
}
Another way is to put a extension method to ISerializable and use the interface in all your required types.
public static int CalculateKilobytes(this ISerializable notSuspectingCandidate)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, notSuspectingCandidate);
return stream.ToArray().Count() / 1000;
}
}

Protobuf-net Extension interfaces

I have a problem understanding protobuf-net extensions and how they exactly work. I need to serialize a 2D custom class array and so I decited to wrap it into a class something like:
class CustomData : IExtension
{
private CustomClass[,] data;
public CustomClass this[int index_X, int index_Y]
{
get
{
return data[index_X, index_Y];
}
set
{
data[index_X, index_Y] = value;
}
}
public Stream BeginQuery()
{
var stream = new MemoryStream();
int pos = 0;
byte[] packedData = SomeStaticClass.ConvertToByteArray(data)
using(var writer = new ProtoWriter(stream, null, null))
{
ProtoWriter.WriteFieldHeader(1, WireType.String, writer);
ProtoWriter.WriteBytes(packedData, writer);
}
return stream;
}
public void EndQuery(Stream stream)
{
stream.Close();
}
//... and the other 3 implemented funcs from IExtension
}
So this ofcourse is in a custom IExtensible which has GetExtensionObject() returning an instance of the CustomData object. The problem comes when I try to append extension data to an instance. Here is what I'm doing:
public void DoAppend()
{
var stream = new MemoryStream();
using (ProtoWriter writer = new ProtoWriter(stream, null, null))
{
var test = new CustomExtensibleClass(300, 300);
ProtoWriter.AppendExtensionData(test, writer);
}
var result = stream.ToArray();
}
The problem is that "result" contains no data. I expected that the data I appended and written via BeginQuery() will be transfered to the stream of the ProtoWriter but I suppose this is not the case.
Can somebody explaing what I am doing wrong or at least how can use the appended data?