How to make use of memorystream instead of filestream - c#

So what im trying to do is read a Select store procedure from my database save the data in a csv file and make it that the user is able to download it through the web application. I was able to get the requested result by saving the file temporary into my program foldel and using filestream. What i want to do now is skip the part where the file is saved onto my computer and temporary save it in the RAM memory instead. From what i understood i have to make use of memory stream instead of file stream but i dont really understand how i can do that. From what i understood from what i read is that instead of me making use of a file i need to convert my data to bytes make a memorystream out of it and then use it in my FileStreamResult. Am i correct here?
Method when i read from procedure and save to a csvfile:
public static String StoreApproved ()
{
string path1 = HttpRuntime.AppDomainAppPath + "Report.csv";
SqlConnection sqlConnection1 = new SqlConnection("CONNECTIONSTRING");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "ExportApproved";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
reader = cmd.ExecuteReader();
List<ModelStoreProcedureApproved> TestList = new List<ModelStoreProcedureApproved>();
ModelStoreProcedureApproved test ;
while (reader.Read())
{
test = new ModelStoreProcedureApproved();
// test.Id = int.Parse(reader["IdTimeTracker"].ToString());
test.Month = reader["Month"].ToString();
test.EmailUser = reader["Email"].ToString();
test.Project = reader["Name"].ToString();
test.Approved = reader["Description"].ToString();
test.Month = reader["Month"].ToString();
test.Year = reader["Year"].ToString();
TestList.Add(test);
}
File.Create(path1).Close();
var i = TestList.FirstOrDefault();
using (TextWriter fileReader = new StreamWriter(path1))
{
var csv = new CsvWriter(fileReader);
csv.Configuration.Encoding = Encoding.UTF8;
foreach (var value in TestList)
{
csv.WriteRecord(value);
}
fileReader.Close();
}
sqlConnection1.Close();
return path1;
}
Controller code:
public ActionResult ExportToCSV()
{
string path = Repositories.UserRepository.StoreApproved();
var fileStream = new FileStream(path,
FileMode.Open,
FileAccess.Read);
return new FileStreamResult(fileStream, "text/csv") { FileDownloadName = "export.csv" };
}
Can someone explain me what the best way to do this is?
Other posts i have read
Serialize and Deserialize using BinaryFormatter
BinaryFormatter and Deserialization Complex objects
Using CSVHelper to output stream to browser

You can make it like this:
public static byte[] StoreApproved ()
{
string path1 = HttpRuntime.AppDomainAppPath + "Report.csv";
SqlConnection sqlConnection1 = new SqlConnection("CONNECTIONSTRING");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "ExportApproved";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
reader = cmd.ExecuteReader();
List<ModelStoreProcedureApproved> TestList = new List<ModelStoreProcedureApproved>();
ModelStoreProcedureApproved test ;
while (reader.Read())
{
test = new ModelStoreProcedureApproved();
// test.Id = int.Parse(reader["IdTimeTracker"].ToString());
test.Month = reader["Month"].ToString();
test.EmailUser = reader["Email"].ToString();
test.Project = reader["Name"].ToString();
test.Approved = reader["Description"].ToString();
test.Month = reader["Month"].ToString();
test.Year = reader["Year"].ToString();
TestList.Add(test);
}
var i = TestList.FirstOrDefault();
var mem = new MemoryStream();
using (TextWriter fileReader = new StreamWriter(mem))
{
var csv = new CsvWriter(fileReader);
csv.Configuration.Encoding = Encoding.UTF8;
foreach (var value in TestList)
{
csv.WriteRecord(value);
}
}
sqlConnection1.Close();
return mem.ToArray();
}
public ActionResult ExportToCSV()
{
byte[] bytes = Repositories.UserRepository.StoreApproved();
Stream stream = new MemoryStream(bytes);
return new FileStreamResult(stream, "text/csv") { FileDownloadName = "export.csv" };
}

I suggest you make clean separation of concerns since you are also using Asp.Net MVC. Instead of reading and creating memory stream inside same method, first read/get the data collection you need and just return the data out of the method. Then inside the action method you can decorate it with required format(binding to UI or returning a file etc.) based on your requirement
Though this is not be a straight answer to your question, and if all that you are looking for is using a memory stream, there are plenty of examples available to use for example as shown here and the answer you accepted etc.
Hope this help you.

using (var ms = new MemoryStream())
{
using (var writer = new StreamWriter(ms))
using (var csv = new CsvWriter(writer))
{
csv.WriteRecords({A list here});
}
ms.ToArray() // here is your actual data in memory stream
}

Related

How to process uploaded files in ASP.NET core 2.0

We are trying to migrate our code from ASP.NET that was written some time ago to ASP.NET Core 2.0.
This piece of code stores a document in SQL Server and retrieves it.
***Original Code:***
protected void btnUpload_Click(object sender, EventArgs e)
{
foreach (HttpPostedFile postedFile in multipleUpload.PostedFiles)
{
string filename = Path.GetFileName(postedFile.FileName);
string contentType = postedFile.ContentType;
using (Stream fs = postedFile.InputStream)
{
using (BinaryReader br = new BinaryReader(fs))
{
byte[] bytes = br.ReadBytes((Int32)fs.Length);
string constr = ConfigurationManager.ConnectionStrings["ab"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
string query = "insert into ftr_UploadMultiple (name,contentType,data) values (#Name, #ContentType, #Data)";
using (SqlCommand cmd = new SqlCommand(query))
{
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Name", filename);
cmd.Parameters.AddWithValue("#ContentType", contentType);
cmd.Parameters.AddWithValue("#Data", bytes);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
We did try with the following code, it only stores 0 bytes in the DB:
Any suggestions around this should be really helpful.
Our Code in ASP.NET Core 2.0
if (file.Length > 0)
{
using (var stream = new
FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
using (BinaryReader br = new BinaryReader(stream))
{
byte[] bytes = br.ReadBytes((Int32)stream.Length);
string constr = "<Connection String";
using (SqlConnection con = new SqlConnection(constr))
{
string query = "insert into ftr_UploadMultiple (data) values (#Data)";
using (SqlCommand cmd = new SqlCommand(query))
{
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Data", bytes);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
I have deliberately removed the closing }s. Also, facing an issue in Downloading already uploaded file as Response.Binarywrite() is not available in ASP.NET Core 2.0.
After you call CopyToAsync to copy the bytes from the upload file to the filestream, the filestream's position is at the end. When you then attempt to read from the filestream, you're only reading the null byte at the end, resulting in 0 bytes being read.
The simplest solution is to just add the following before you read:
stream.Position = 0;
However, unless you actually need to write the file to the filesystem as well, this is just extraneous work. It would be better to copy the upload file's stream to a MemoryStream and then simply use ToArray to get the bytes from that: no need for additional reader.
Try get bytes array from InputStream
// Read bytes from http input stream
BinaryReader b = new BinaryReader(file.InputStream);
byte[] binData = b.ReadBytes(file.ContentLength);
ASP.NET Core
if (file.Length > 0)
{
using (BinaryReader br = new BinaryReader(file.InputStream))
{
/* ... use file.Length or file.ContentLength */
byte[] bytes = br.ReadBytes(file.Length);
/* ... File Processing (bytes) */
}
}
.

Retrieve C# object from binary that saved in SQL Server database

I want save and retrieve an object from a database. I write C# code to save it as below, and it worked fine. Now I can save an object into the database.
ReportObject ro = new ReportObject()
{
Name = ctrl.Name,
BackColor = ctrl.BackColor,
ForeColor = ctrl.BackColor,
Fonts = ctrl.Font,
TypeofControl = ctrl.GetType()
};
MemoryStream memStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memStream);
sw.Write(ro);
string sql = "INSERT INTO [TemplateDetails] ([Object]) VALUES (#Object)";
SqlCommand cmd = new SqlCommand(sql, con, tran);
cmd.Parameters.Add("#Object", SqlDbType.VarBinary, Int32.MaxValue);
cmd.Parameters["#Object"].Value = memStream.GetBuffer();
cmd.ExecuteNonQuery();
I am already saved a C# object ReportObject in SQL Server database. I want to retrieve it back to a C# object.
string sql = "SELECT [Object] FROM [TemplateDetails]"
SqlDataReader dr = db.Reader(sql);
if (dr.Read())
{
byte[] arrays = (byte[])dr["Object"];
}
I Solved problem myself.
first Serialize to a byte array and save in database.
enter ReportObject ro = new ReportObject()
{
Name = ctrl.Name,
BackColor = ctrl.BackColor,
ForeColor = ctrl.BackColor,
Fonts = ctrl.Font,
TypeofControl = ctrl.GetType()
};
MemoryStream memorystream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(memorystream, ro);
byte[] yourBytesToDb = memorystream.ToArray();
after retrieving from the database as a byte array. Deserialize and convert to object.
MemoryStream memorystreamd = new MemoryStream(arrBytes);
BinaryFormatter bfd = new BinaryFormatter();
ReportObject deserializedReportObject = bfd.Deserialize(memorystreamd) as ReportObject;

xml file to mysql database

I am converting 3D objects to one xml file, write it to hard drive, then read it from hard drive and upload to Mysql database as a blob. Then I delete created xml.file from my hard drive. Is it somehow possible to do this (create xml file/upload to database) so that I don't have to write it to drive at first, then read it, then delete it? If I could somehow create xml file and pass it directly without the need to save it on drive. Any ideas?
Here I write xml file to drive (EDITED):
public Stream WriteXml(List<object> gridEntities, string fileName)
{
XDocument doc = new XDocument();
XElement root = new XElement("ViewportLayout");
XElement xEntities = new XElement("Entities");
xEntities.Add(...);
root.Add(xEntities);
doc.Add(root);
//var path = string.Format("C:\\Users\\NP\\Desktop\\Saves\\{0}", fileName);
//doc.Save(path);
Stream stream = new MemoryStream(); // Create a stream
doc.Save(stream); // Save XDocument into the stream
stream.Position = 0; // Rewind the stream ready to read from it elsewhere
return stream;
}
Here I upload it to data base:
public static void SaveGridXmlFileToDataBase(Stream stream, string projectName, string filePath, string gridName, string gridGuid)
{
if (OpenConnection() == true)
{
byte[] file;
using (stream)
{
using (var reader = new BinaryReader(stream))
{
file = reader.ReadBytes((int)stream.Length);
}
}
string project = string.Concat(projectName, "_grids");
string query = String.Format("INSERT INTO {0} SET name=#name, guid=#guid, xml=#File;", project);
using (var sqlWrite = new MySqlCommand(query, connection))
{
sqlWrite.Parameters.Add("#name", MySqlDbType.VarChar).Value = gridName;
sqlWrite.Parameters.Add("#guid", MySqlDbType.VarChar).Value = gridGuid;
sqlWrite.Parameters.Add("#File", MySqlDbType.LongBlob).Value = file;
sqlWrite.ExecuteNonQuery();
}
CloseConnection();
}
}

Binary stream '0' does not contain a valid BinaryHeader error while Deserialization custom object

I faced this error while deserialization a custom object
I am trying to insert a collection of custom class into sql database & retrieve it the insertion going well but retrieving the data & deserialize give me this error
My code sample:
private void InsertObject()
{
ReceiptCollection items = SqlDataRepository.ReceiptProvider.GetAll();
string connectionString = "my connection";
System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(connectionString);
string sql = "INSERT INTO [dbo].[LogHeader]([MasterObject]) VALUES (#MasterObject)";
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
binaryFormatter.Serialize(memoryStream, items);
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sql, connection))
{
byte[] bytes = new byte[memoryStream.Length];
memoryStream.Write(bytes, 0, bytes.Length);
connection.Open();
cmd.Parameters.AddWithValue("#MasterObject", bytes);
cmd.ExecuteNonQuery();
}
}
private void RetrieveObjects()
{
string connectionString = "my connection";
System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(connectionString);
string sql = "Select MasterObject From [dbo].[LogHeader] WHERE LogHeaderID=2";
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sql, connection))
{
connection.Open();
byte[] bytes = (byte[])cmd.ExecuteScalar();
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(bytes);
memoryStream.Position = 0;
ReceiptCollection items = (ReceiptCollection)binaryFormatter.Deserialize(memoryStream); // the error happened here
}
}
I was facing the same problem in the serialization and deserialization of a custom class. Everywhere I looked around, they have the same code marked as the solution (as your code presented on the top) but I couldn't make it run correctly. All I was recieving after the memoryStream.Write() method, was an array of zeroes. I changed my code and got it to work.
What I did was (implemented in your code):
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
binaryFormatter.Serialize(memoryStream, items);
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sql, connection))
{
byte[] bytes = new byte[memoryStream.Capacity];
bytes = memoryStream.GetBuffer();
connection.Open();
cmd.Parameters.AddWithValue("#MasterObject", bytes);
cmd.ExecuteNonQuery();
}
This is for sending a byte array to the data base. For retrieving it, I did the following:
connection.Open();
byte[] bytes = (byte[])cmd.ExecuteScalar();
BinaryFormatter binaryFormatter = new BinaryFormatter();
using (MemoryStream memoryStream = new MemoryStream(bytes))
{
memoryStream.Position = 0;
ReceiptCollection items = (ReceiptCollection)binaryFormatter.Deserialize(memoryStream);
}
Try it! It really worked for me.
Start by checking what actually got stored in that column, and also check if the column's type is varbinary or similar. The error suggests that the serialized object's data stream got badly corrupted or truncated. If the row/column does not contain a long "hexstring", then there's a write problem with inserting/updating and search further there.

Persist a DataContract as XML in a database

I'm working on a kind of "store and forward" application for WCF services. I want to save the message in a database as a raw XML blob, as XElement. I'm having a bit of trouble converting the datacontract into the XElement type I need for the database call. Any ideas?
this returns it as a string, which you can put into the db into an xml column. Here is a good generic method you can use to serialize datacontracts.
public static string Serialize<T>(T obj)
{
StringBuilder sb = new StringBuilder();
DataContractSerializer ser = new DataContractSerializer(typeof(T));
ser.WriteObject(XmlWriter.Create(sb), obj);
return sb.ToString();
}
btw, are you using linq to sql? The reason i ask is because of the XElement part of your question. if thats the case, you can modify this in the .dbml designer to use a string as the CLR type, and not the default XElement.
The most voted on answer (Jason W. posted) did not work for me. I dont know why that answer got the most votes. But after searching around I found this
http://billrob.com/archive/2010/02/09/datacontractserializer-converting-objects-to-xml-string.aspx
Which worked for my project. I just had a few classes and put the datacontract and datamemeber attributes on classes and properties and then wanted to get an XML string which I could write to the database.
Code from the link above incase it goes 404:
Serializes:
var serializer = new DataContractSerializer(tempData.GetType());
using (var backing = new System.IO.StringWriter())
using (var writer = new System.Xml.XmlTextWriter(backing))
{
serializer.WriteObject(writer, tempData);
data.XmlData = backing.ToString();
}
Deserializes:
var serializer = new DataContractSerializer(typeof(T));
using (var backing = new System.IO.StringReader(data.XmlData))
using (var reader = new System.Xml.XmlTextReader(backing))
{
return serializer.ReadObject(reader) as T;
}
If your database is SQL Server 2005 or above, you can use the XML data type:
private readonly DataContractToSerialize _testContract =
new DataContractToSerialize
{
ID = 1,
Name = "One",
Children =
{
new ChildClassToSerialize {ChildMember = "ChildOne"},
new ChildClassToSerialize {ChildMember = "ChildTwo"}
}
};
public void SerializeDataContract()
{
using (var outputStream = new MemoryStream())
{
using (var writer = XmlWriter.Create(outputStream))
{
var serializer =
new DataContractSerializer(_testContract.GetType());
if (writer != null)
{
serializer.WriteObject(writer, _testContract);
}
}
outputStream.Position = 0;
using (
var conn =
new SqlConnection(Settings.Default.ConnectionString))
{
conn.Open();
const string INSERT_COMMAND =
#"INSERT INTO XmlStore (Data) VALUES (#Data)";
using (var cmd = new SqlCommand(INSERT_COMMAND, conn))
{
using (var reader = XmlReader.Create(outputStream))
{
var xml = new SqlXml(reader);
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#Data", xml);
cmd.ExecuteNonQuery();
}
}
}
}
}
I'm not sure about the most efficient way to get it to an XElement, but to get it to a string just run:
DataContractSerializer serializer = new DataContractSerializer(typeof(Foo));
using (MemoryStream memStream = new MemoryStream())
{
serializer.WriteObject(memStream, fooInstance);
byte[] blob = memStream.ToArray();
}
I tried to use Jason w'Serialize function that uses StringBuilder , but it returns empty string for LingToSQL Designer generated table class
with [DataContract()] attribute
However if I serialze to byte array as suggested by AgileJon
and then use UTF7Encoding to convert to string , it creates readable XML string.
static string DataContractSerializeUsingByteArray<T>(T obj)
{
string sRet = "";
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
using (MemoryStream memStream = new MemoryStream())
{
serializer.WriteObject(memStream, obj);
byte[] blob = memStream.ToArray();
var encoding= new System.Text.UTF7Encoding();
sRet = encoding.GetString(blob);
}
return sRet;
}
Not sure why stringBuilder solution not working.

Categories