I'm developing a Windows 8/WinRT App and i encounter a problem to retrieve crypted data by using the DataProtectionProvider. To serialize data I'm using this:
internal static async Task SerializeFileEncrypted<T>(T type, StorageFile file)
{
using (Stream stream = await file.OpenStreamForWriteAsync())
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
dcs.WriteObject(ms, type);
ms.Seek(0, SeekOrigin.Begin);
DataProtectionProvider dpp = new DataProtectionProvider("Local=User");
await dpp.ProtectStreamAsync(ms.AsInputStream(), stream.AsOutputStream());
await stream.FlushAsync();
}
}
}
And to deserialize data I'm using this:
internal static async Task<T> DeserializeEncryptedFile<T>(StorageFile file)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
DataProtectionProvider dpp = new DataProtectionProvider();
await dpp.UnprotectStreamAsync((await file.OpenStreamForReadAsync()).AsInputStream(), ms.AsOutputStream());
ms.Seek(0, SeekOrigin.Begin);
return (T)dcs.ReadObject(ms);
}
}
Serializing process seems to works well but when I try to deserialize the file I have the following error: "Unexpected end of file."
I suspect the problem to be linked to the encoding of the file. When I don't crypt data and only use DataContractSerializer I have an UTF8 file whereas otherwise I have an ANSI file. Can someone help me to figure out where is my problem and how to solve it?
Related
My initial requirement is to let the user download a file from object list for that I found this solution https://stackoverflow.com/a/49207997/11178128,
But the problem is when it comes to this line
bin = stream.ToArray();
there are no streams written to it. So the bin comes as an empty array.
What could be the problem?
Also, I'm making my web API available through a windows service. And for some reason System.Web.HttpContext.Current.Response gives me null. any idea why it can be?
Thanks in advance.
This is the code i have so far
List<Device> devices;
using (StreamReader r = new StreamReader(String.Format(#"{0}\deviceList.json", savefilePath)))
{
string json = r.ReadToEnd();
devices = JsonConvert.DeserializeObject<List<Device>>(json);
}
byte[] bin;
//String.Format(#"{0}\devices.csv", savefilePath)
using (MemoryStream stream = new MemoryStream())
using (TextWriter textWriter = new StreamWriter(stream))
using (CsvWriter csv = new CsvWriter(textWriter))
{
csv.Configuration.ShouldQuote = (field, context) => false;
csv.WriteRecords(devices);
bin = stream.ToArray();
}
This is related to another question, CsvHelper not writing anything to memory stream.
You just need to change your using statements so that the StreamWriter gets flushed before calling stream.ToArray();
List<Device> devices;
using (StreamReader r = new StreamReader(String.Format(#"{0}\deviceList.json", savefilePath)))
{
string json = r.ReadToEnd();
devices = JsonConvert.DeserializeObject<List<Device>>(json);
}
byte[] bin;
//String.Format(#"{0}\devices.csv", savefilePath)
using (MemoryStream stream = new MemoryStream())
{
using (TextWriter textWriter = new StreamWriter(stream))
using (CsvWriter csv = new CsvWriter(textWriter))
{
csv.Configuration.ShouldQuote = (field, context) => false;
csv.WriteRecords(devices);
}
bin = stream.ToArray();
}
Actually, after a bit of struggling, Found that i was missing this line.
textWriter.Flush();
As mentioned in the below reply I had to flush the textWriter object in order to write to the file. Here is the working code.
byte[] data;
using (MemoryStream stream = new MemoryStream())
using (TextWriter textWriter = new StreamWriter(stream))
using (CsvWriter csv = new CsvWriter(textWriter))
{
csv.Configuration.RegisterClassMap<DeviceMap>();
csv.Configuration.ShouldQuote = (field, context) => false;
csv.WriteRecords(values);
textWriter.Flush();
data = stream.ToArray();
}
return data;
using (var ms = new MemoryStream())
{
using (var writer = new StreamWriter(ms))
using (var csv = new CsvWriter(writer))
{
csv.WriteRecords(dbresponse);
} // the closing tag here is important!!It flush the streamwriter
ms.ToArray(); // or ms.GetBuffer()
}
Now the ms.ToArray() will contain the data from csvHelper
For a field variant - for example a list, which won't work using the writerecords method - you will need to use writefield. I am just submitting this here as this trifling issue caused me none too little pain.
Here is an async example:
var result = await GetListOfString();
using (var ms = new MemoryStream())
{
using (var writer = new StreamWriter(ms))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
foreach (var value in result)
{
csv.WriteField(value);
await csv.NextRecordAsync();
}
await writer.FlushAsync();
return ms.ToArray();
}
}
I read data from printer like this:
using (Stream stream = client.GetStream())
{
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
client.Close();
byte[] result = ms.ToArray();
...
using (var memoryStream = new MemoryStream(result))
{
using (var package = Package.Open(memoryStream, FileMode.Open))
{
var packageUri = new Uri("memorystream://printstream");
PackageStore.AddPackage(packageUri, package);
var xpsDocument = new XpsDocument(package, CompressionOption.Fast, packageUri.OriginalString);
return xpsDocument.GetFixedDocumentSequence() // NULL
I tried also saving stream directly to the file and then read as File.ReadAllBytes(filePath), but result is the same.
After I save stream to the file I can open it via XpsViewer without any problem.
Strange but it's working. I have to used XpsConverter.exe and convert .xps file to .xps. Here is #AXMIM solution
I am trying to use the WCF DataContractSerializer to serialize a DataContract object into a memoryStream.
Then I use the memoryStream.ToArray to get the serialized content.
Finally, I persist the memoryStream into a file using anther fileStream.
My initial implement is like this. I am missing bytes at the end of the persisted File.
public virtual string SerializeTransient(DataObject data, string targetPath)
{
string securityCode;
using (var memoryStream = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings {Indent = true}))
{
_serializer.WriteObject(xmlWriter, data);
using (var fileStream = new FileStream(targetPath, FileMode.Create))
{
securityCode = CalculateSecurityCode(memoryStream.ToArray());
memoryStream.WriteTo(fileStream);
}
}
}
return securityCode;
}
If I move the persist logic out of the inner using{} block (see below), the output is correct. It almost feels like the WriteObject function didnt finish what it is doing. Could someone please explain to me what is happening there? Thanks.
public virtual string SerializeTransient(DataObject data, string targetPath)
{
string securityCode;
using (var memoryStream = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings {Indent = true}))
{
_serializer.WriteObject(xmlWriter, data);
}
using (var fileStream = new FileStream(targetPath, FileMode.Create))
{
securityCode = CalculateSecurityCode(memoryStream.ToArray());
memoryStream.WriteTo(fileStream);
}
}
return securityCode;
}
XmlWriter has an internal buffer. You should either Close/Dispose XmlWriter or call the XmlWriter.Flush() to force all content to be written to underlying stream (memoryStream).
If memoryStream.ToArray() is called before writer.Flush() then some bytes will possibly remain in internal writer buffer.
I'm having trouble when creating a StreamWriter object in windows-8, usually I just create an instance just passing a string as a parameter, but in Windows 8 I get an error that indicates that it should recieve a Stream, but I noticed that Stream is an abstract class, Does anybody knows how will be the code to write an xml file?, BTW I'm using .xml because I want to save the serialized object, or does anyone knows how to save to a file a serialized object in Windows 8?.
Any ideas?
Currently using Windows 8 Consumer Preview
Code:
StreamWriter sw = new StreamWriter("person.xml");
Error:
The best overloaded method match for 'System.IO.StreamWriter.StreamWriter(System.IO.Stream)' has some invalid arguments
Instead of StreamWriter you would use something like this:
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync();
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
//TODO: Replace "Bytes" with the type you want to write.
dataWriter.WriteBytes(bytes);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
You can look at the StringIOExtensions class in the WinRTXamlToolkit library for sample use.
EDIT*
While all the above should work - they were written before the FileIO class became available in WinRT, which simplifies most of the common scenarios that the above solution solves since you can now just call await FileIO.WriteTextAsync(file, contents) to write text into file and there are also similar methods to read, write or append strings, bytes, lists of strings or IBuffers.
You can create a common static method which you can use through out application like this
private async Task<T> ReadXml<T>(StorageFile xmldata)
{
XmlSerializer xmlser = new XmlSerializer(typeof(List<myclass>));
T data;
using (var strm = await xmldata.OpenStreamForReadAsync())
{
TextReader Reader = new StreamReader(strm);
data = (T)xmlser.Deserialize(Reader);
}
return data;
}
private async Task writeXml<T>(T Data, StorageFile file)
{
try
{
StringWriter sw = new StringWriter();
XmlSerializer xmlser = new XmlSerializer(typeof(T));
xmlser.Serialize(sw, Data);
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteString(sw.ToString());
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
catch (Exception e)
{
throw new NotImplementedException(e.Message.ToString());
}
}
to write xml simply use
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("data.xml",CreationCollisionOption.ReplaceExisting);
await writeXml(Data,file);
and to read xml use
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("data.xml");
Data = await ReadXml<List<myclass>>(file);
I'm trying to do custom serialization/deserialization of an object as well as compressing/decompressing the serialized data with DeflateStreams. I originally did this for more complex objects but cut it down to try and figure out the problem, however it just became more puzzling as it is still there. Here is the class to be serialized/deserialized:
[Serializable]
public class RandomObject : ISerializable
{
public String Name { get; set; }
public String SavePath { get; set; }
public RandomObject()
{
}
public RandomObject(String name, String savepath)
{
Name = name;
SavePath = savepath;
}
public RandomObject(SerializationInfo info, StreamingContext context)
: this(info.GetString("name"), info.GetString("savepath"))
{
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("name", Name);
info.AddValue("savepath", SavePath);
}
}
And here is the code that is supposed to serialize it(which seems to work):
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, profile);
using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress))
{
try
{
using (FileStream fs = File.Create(path))
{
ds.Flush();
Miscellaneous.CopyStream(ds.BaseStream, fs);
fs.Flush();
fs.Close();
}
}
catch (IOException e)
{
MessageBox.Show(e.Message);
success = false;
}
ds.Close();
}
ms.Close();
}
And here is the deserialization:
RandomObject profile = null;
using (FileStream fs = File.OpenRead(path))
{
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress))
{
BinaryFormatter bf = new BinaryFormatter();
ds.Flush();
using (MemoryStream ms = new MemoryStream())
{
Miscellaneous.CopyStream(ds.BaseStream, ms);
profile = bf.Deserialize(ms) as RandomObject;
profile.SavePath = path;
ms.Close();
}
ds.Close();
}
fs.Close();
}
Now, to the problem. Deserialization throws a SerializationException with the message {"No map for object '201326592'."} I have no idea how to troubleshoot or figure out what exactly is causing the problem. Very basic serialization works when I just run BinaryFormatter's Serialize and Deserialize methods on the same MemoryStream.
I tried removing the DeflateStream stuff from both methods, but it's still the same problem. When I look at the examples at MSDN and other places it looks like I'm doing it just right, and googling for the exception message doesn't give any meaningful results(or perhaps I'm just bad at searching).
PS. As you can see I use Miscellaneous.CopyStream(src, dest) which is a basic stream copier, as I can't get src.CopyTo(dest) to work at all, so any hints on that is welcome as well.
Below is a link to the whole VS2010 project if you would like to look at it more closely:
http://www.diredumplings.com/SerializationTesting.zip
UPDATE:
The_Smallest: I tried using the Compress method you posted on my serialization:
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
bf.Serialize(stream, profile);
byte[] array = Compress(stream);
using (MemoryStream ms = new MemoryStream(array))
{
using (FileStream fs = File.Create(path))
{
ms.WriteTo(fs);
fs.Flush();
}
}
}
However, it seems to give me the same problems that I had with srcStream.CopyTo(destStream) earlier, which is that it doesn't seem to get written to the stream. The result is a 0 kb file when I try to save it to disk. Any ideas?
Pieter: I removed the MemoryStream from the deserialization method and it seems have the same functionality as before. However I'm not sure how to implement the serialization the way you suggested. Is this what you had in mind?
BinaryFormatter bf = new BinaryFormatter();
using (FileStream fs = File.Create(path))
{
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
{
bf.Serialize(ds, profile);
fs.Flush();
ds.Close();
}
fs.Close();
}
Thanks to both of you!
I dowloaded you example and digged a little in there. See changes for your project below:
Replace LoadFromFile in Loader.cs
private static RandomObject LoadFromFile(string path)
{
try
{
var bf = new BinaryFormatter();
using (var fileStream = File.OpenRead(path))
using (var decompressed = new MemoryStream())
{
using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Decompress))
deflateStream.CopyTo(decompressed);
decompressed.Seek(0, SeekOrigin.Begin);
var profile = (RandomObject)bf.Deserialize(decompressed);
profile.SavePath = path;
return profile;
}
}
catch (IOException e)
{
MessageBox.Show(e.Message);
return null;
}
}
Replace Save in Saver.cs as follows:
public static bool Save(RandomObject profile, String path)
{
try
{
var bf = new BinaryFormatter();
using (var uncompressed = new MemoryStream())
using (var fileStream = File.Create(path))
{
bf.Serialize(uncompressed, profile);
uncompressed.Seek(0, SeekOrigin.Begin);
using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Compress))
uncompressed.CopyTo(deflateStream);
}
return true;
}
catch (IOException e)
{
MessageBox.Show(e.Message);
return false;
}
}
You should serialize into the DeflateStream, not the base (MemoryStream) stream.
For serializing: begin with the File.Create. Then around that stream, create the DeflateStream. Then to the DefaulteStream, serialize your objects.
For deserializing: do not create the MemoryStream and deserialize directly from the DeflateStream.
I believe there is no need for the added MemoryStream. If however you do have problems writing directly to/reading directly from the file streams, just change the serialize routine to write to the DeflateStream instead of the MemoryStream.
That should solve your issues.
There is error in streams logics, while compressing you should write to CompressStream, which writes to MemoryStream, after this you will have result in MemoryStream (not in CompressStream)
Here is example how to compress and decompress bytes
private static byte[] Compress(Stream stream)
{
using (var resultStream = new MemoryStream())
{
using (var gzipStream = new DeflateStream(resultStream, CompressionMode.Compress))
stream.CopyTo(gzipStream);
return resultStream.ToArray();
}
}
private static byte[] Decompress(byte[] bytes)
{
using (var readStream = new MemoryStream(bytes))
using (var resultStream = new MemoryStream())
{
using (var gzipStream = new DeflateStream(readStream, CompressionMode.Decompress))
gzipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}