Inserting many records while reloading the page - c#

I have a form. I am inserting data to my database and sending those inserted details to mail.
After clicking the submit button I'm clearing all the variables but my problem is when I reload the page once again data inserting as a new record and anther mail is sending. I don't want to insert new record and send another mail.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Data.SqlClient;
namespace SupportPortal
{
public partial class Support : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void clearallfields()
{
ProblemName.Value = "";
ImpactDropDown.SelectedIndex = 0;
SeverityDropDown.SelectedIndex = 0;
ProblemDescription.Value = "";
}
protected void Submitsupportform_Click(object sender, EventArgs e)
{
//string ticketNumber = string.Empty;
string Problem = ProblemName.Value;
string impact = ImpactDropDown.Value;
string Priority = SeverityDropDown.Value;
string problemdescription = ProblemDescription.Value;
Byte[] bytImage = new byte[] { 1 };
Byte[] bytImage1 = new byte[] { 1 };
Byte[] bytImage2 = new byte[] { 1 };
string FileName = "";
try
{
// Get the HttpFileCollection
HttpFileCollection hfc = Request.Files;
for (int i = 0; i < hfc.Count; i++)
{
HttpPostedFile hpf = hfc[i];
FileName = System.IO.Path.GetFullPath(hpf.FileName);
HttpPostedFile objHttpPostedFile = Request.Files[Request.Files.AllKeys[i]];
int intContentlength = objHttpPostedFile.ContentLength;
if (i == 0)
{
bytImage = new Byte[intContentlength];
objHttpPostedFile.InputStream.Read(bytImage, 0, intContentlength);
}
if (i == 1)
{
bytImage = new Byte[intContentlength];
objHttpPostedFile.InputStream.Read(bytImage1, 0, intContentlength);
}
if (i == 2)
{
bytImage = new Byte[intContentlength];
objHttpPostedFile.InputStream.Read(bytImage2, 0, intContentlength);
}
}
}
catch (Exception ex)
{
throw ex;
}
// inserting into database
SqlConnection con = new SqlConnection("Server=localhost;Database=ViveSupport;Integrated Security=SSPI");
SqlCommand cmd = new SqlCommand("CreateTicket", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Product", ProductName.Value);
cmd.Parameters.AddWithValue("#Version", ProductVersionDropDown.Value);
cmd.Parameters.AddWithValue("#Module", ModuleDropDown.Value);
cmd.Parameters.AddWithValue("#OperatingSystem", OSDropDown.Value);
cmd.Parameters.AddWithValue("#DataSource", Datasource.Value);
cmd.Parameters.AddWithValue("#Browser", BrowserDropDown.Value);
cmd.Parameters.AddWithValue("#Attachment1", bytImage);
cmd.Parameters.AddWithValue("#Attachment2", bytImage1);
cmd.Parameters.AddWithValue("#Attachment3", bytImage2);
con.Open();
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
String ticketNumber = ds.Tables[0].Rows[0]["ticketNumber"].ToString();
con.Close();
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[6] {
new DataColumn("Product", typeof(string)),
new DataColumn("Module",typeof(string)),
new DataColumn("Product version", typeof(string)),
new DataColumn("OS",typeof(string)),
new DataColumn("Datasource", typeof(string)),
new DataColumn("Browser",typeof(string))});
dt.Rows.Add(ProductName, ModuleDropDown, ProductVersionDropDown, OSDropDown, Datasource, BrowserDropDown);
StringBuilder sb = new StringBuilder();
// Table start
sb.Append("<table cellpadding='5' cellspacing='0' style='border: 1px solid #ccc;font-size: 9pt;font-family:Arial'>");
// Adding HeaderRow
sb.Append("<tr>");
foreach (DataColumn column in dt.Columns)
{
sb.Append("<th style='background-color: #f5f5f5;border: 1px solid #ccc;text-align: left;'>" + column.ColumnName + "</th>");
}
sb.Append("</tr>");
// Adding DataRow
foreach (DataRow row in dt.Rows)
{
sb.Append("<tr>");
foreach (DataColumn column in dt.Columns)
{
sb.Append("<td style='width:100px;border: 1px solid #ccc'>" + row[column.ColumnName].ToString() + "</td>");
}
sb.Append("</tr>");
}
// Table end
sb.Append("</table>");
StringBuilder problemtable = new StringBuilder();
problemtable.Append("<div><div><table style='font-size: 9pt;font-family:Arial'><tr><td>Problem: </td><td>" + Problem + "</td></tr><tr><td>Impact: </td><td>" + impact + "</td></tr><tr><td>Priority: </td><td>" + Priority + "</td></tr><tr><td>ProblemDescription: </td><td>" + problemdescription + "</td></tr></table></div></div>");
StringBuilder footersignature = new StringBuilder();
string to = ""; //To address
string from = ""; //From address
MailMessage message = new MailMessage(from, to);
string mailbody = sb.ToString() + problemtable.ToString();
message.Subject = "Generated ticket Number is" + ticketNumber;
message.Body = mailbody;
message.BodyEncoding = Encoding.UTF8;
message.IsBodyHtml = true;
for (var x = 0; x < Request.Files.AllKeys.Length; x++)
{
string file = System.IO.Path.GetFullPath(upload_file1.PostedFile.FileName);
// HttpPostedFile file = Request.Files[Request.Files.AllKeys[x]];
if (file != null && file.Length > 0)
{
try
{
message.Attachments.Add(new Attachment(Path.GetFileName(System.IO.Path.GetFileName(file))));
}
catch (Exception ex)
{
throw ex;
}
}
}
SmtpClient client = new SmtpClient("smtp.gmail.com", 587); //Gmail smtp
System.Net.NetworkCredential basicCredential1 = new System.Net.NetworkCredential("", "");
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = basicCredential1;
try
{
client.Send(message);
}
catch (Exception ex)
{
throw ex;
}
// method to clear all the fields
clearallfields();
}
}
}

Generally doing bulk changes or comits like this is not a good design. You want to have the user only Add, Edit or Delete one specific entry. And comit the moment the user is finished with that one. Gathering changes like this is not generally a good idea. It raises the danger of data loss and update race conditions exponentially. It barely works for IMAP, and IIRC that one is designed more like a proper, multi-insert Distributed Database.
If you want to still use this design, you have to memorize if one specific row has been comited already. You want to know wich row has "unsaved changes". A simple boolean value for each row would do this. With WebApplications persisting the data is a problem. In this specific case - as the data has very low security impact - you can have it send to the client and retreive it back from them as part of the Formular data.
Very important rule: No mater how much they look like a Desktop applications, Web Applications are still a 1980 HTML Webformular. All the old design decisions still apply. But luckily that old design did include a hidden formular field. Something send to and send back from the user, that is not displayed. How to use such a field from ASP.Net is a bit outside my knowledge however.

Related

How to remove the top rows of an Excel Spreadsheet on Import to a SQL Server Database

Hello Stack Overflow community. I'm writing a small application in C# that can import an excel file directly into a SQL Database. I can import files with the current headers that are in the Excel File as they match the column names (See 2nd Image link below) in my Database, however I am looking to add some flexibility to the excel files that I can Import. Ex: Some of the excel files i need to import have a legend at the top, and this legend does not match the column headers in my database (See 1st image link)
In this Image you can see the portion of the excel sheet I want to remove with code
The Files that do not contain that Legend at the top are easily imported
Without the legend this is where the import can occur at line row 10 in the excel file
I'm looking for a way to remove the top 9 rows (The legend at the top of the file) on import.
Here is all the source code. Any help would be greatly appreciated.
using ExcelDataReader;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ProviderBreakfastExcelReader
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void BtnOpen_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog() { Filter = "Excel Workbook|*.xlsx", ValidateNames = true })
{
if (ofd.ShowDialog() == DialogResult.OK)
{
var ExcelData = ExcelFileRead(ofd.FileName);
cboSheet.Items.Clear();
foreach (DataTable dt in ExcelData.Tables)
{
cboSheet.Items.Add(dt.TableName);
}
}
}
}
private void CboSheet_SelectedIndexChanged(object sender, EventArgs e)
{
string path = #"C:\Desktop\Dir\filename.xlsx";
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
IExcelDataReader reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
DataSet result = reader.AsDataSet();
dataGridView.DataSource = result.Tables[cboSheet.SelectedIndex];
}
private DataSet ExcelFileRead(string path)
{
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
using (IExcelDataReader reader = ExcelReaderFactory.CreateOpenXmlReader(fs))
{
var result = reader.AsDataSet(new ExcelDataSetConfiguration()
{
UseColumnDataType = true,
ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
{
EmptyColumnNamePrefix = "Column",
UseHeaderRow = true,
}
});
return result;
}
}
private void SendExcelToDatabase(string Filename)
{
var data = ExcelFileRead(Filename);
using (var db = new ProviderBreakfastDBEntities())
{
foreach (DataRow record in data.Tables[0].Rows)
{
int rank;
var isValidRank = int.TryParse(record["Ranking"].ToString(), out rank);
db.ProviderBreakfastExcels.Add(new ProviderBreakfastExcel
{
Ranking = isValidRank ? rank : new int?(),
Contact = record["Contact"].ToString(),
LastName = record["LastName"].ToString(),
FirstName = record["FirstName"].ToString(),
// Bedsize = isValidBedsize ? beds : new int?(),
Bedsize = Convert.ToInt32(record["Bedsize"].ToString()),
City = record["City"].ToString(),
Company = record["Company"].ToString(),
JobTitle = record["JobTitle"].ToString(),
State = record["State"].ToString()
});
}
db.SaveChanges();
}
}
private void import_Click(object sender, EventArgs e)
{
OpenFileDialog ofd2 = new OpenFileDialog();
if (ofd2.ShowDialog() == DialogResult.OK)
{
string stringFileName = ofd2.FileName;
textBox1.Text = stringFileName;
SendExcelToDatabase(stringFileName);
}
}
}
}
static void GetDataTableFromCsv(string path, bool isFirstRowHeader)
{
string header = isFirstRowHeader ? "Yes" : "No";
string pathOnly = Path.GetDirectoryName(path);
string fileName = Path.GetFileName(path);
string sql = #"SELECT [ColumnNamesFromExcelSpreadSheet] FROM [" + fileName + "]";
using (OleDbConnection connection = new OleDbConnection(
#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + pathOnly +
";Extended Properties=\"Text;HDR=" + header + "\""))
using (OleDbCommand command = new OleDbCommand(sql, connection))
using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
{
DataTable dt = new DataTable();
dt = CultureInfo.CurrentCulture
adapter.Fill(dt);
StringBuilder sb = new StringBuilder();
foreach (DataRow dataRow in dt)
{
foreach (var item in dataRow.ItemArray)
{
sb.Append(item);
sb.Append(',');
}
}
}
}
This is a great little function for moving an excel spreadsheet into a datatable you can then insert the datatable into your sql db. Only thing you need to change is removing x amount of rows.
EDIT:
private void SendExcelToDatabase(string Filename)
{
int rowThread = HowManyRowsYouWouldLikeToSkipInExcel;
var data = ExcelFileRead(Filename);
using (var db = new ProviderBreakfastDBEntities())
{
foreach (DataRow record in data.Tables[0].Rows)
{
if (!(rowThreshold >= x))
{
int rank;
var isValidRank = int.TryParse(record["Ranking"].ToString(), out rank);
db.ProviderBreakfastExcels.Add(new ProviderBreakfastExcel
{
Ranking = isValidRank ? rank : new int?(),
Contact = record["Contact"].ToString(),
LastName = record["LastName"].ToString(),
FirstName = record["FirstName"].ToString(),
// Bedsize = isValidBedsize ? beds : new int?(),
Bedsize = Convert.ToInt32(record["Bedsize"].ToString()),
City = record["City"].ToString(),
Company = record["Company"].ToString(),
JobTitle = record["JobTitle"].ToString(),
State = record["State"].ToString()
});
}
}
db.SaveChanges();
x++
}
}
See if something like this works.

c# Base64 in email attachment

I know that i'm stuck in a silly problem...and now i am here with hope, that you can help me. Simple situation: I need to send email with attachment from database. I have done it by myself, but...i don't know why, but attachment in email what was send is incorrect. Preciously attachment contents code, what i get from my database.
My code:
static void IncomeMessage()
{
SqlConnection conn = new SqlConnection("Data Source=xxx;Initial Catalog=xxx;User ID=xxx;Password=xxx");
SqlCommand cmd = new SqlCommand("Here is my SQL SELECT", conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
try
{
var AID = dr["ID"].ToString();
var Ids = dr["MessageID"].ToString();
var SuperOrganizationTitle = dr["SuperOrganizationTitle"].ToString();
var Date = dr["Date"].ToString();
var Title = dr["Title"].ToString();
var Description = dr["Description"].ToString();
var DBFile = dr["File"].ToString();
var Filename = dr["FileName"].ToString();
MailMessage oMail = new MailMessage("test#test.com", "guntisvindels#gmail.com", "New message with theme: " + Title, "Message Income: " + Date + " From " + SuperOrganizationTitle + ". Message Content: " + Description);
DBFile = GetBase64(DBFile);
var bytes = Encoding.ASCII.GetBytes(DBFile);
MemoryStream strm = new MemoryStream(bytes);
Attachment data = new Attachment(strm, Filename);
ContentDisposition disposition = data.ContentDisposition;
data.ContentId = Filename;
data.ContentDisposition.Inline = true;
oMail.Attachments.Add(data);
SmtpClient oSmtp = new SmtpClient();
SmtpClient oServer = new SmtpClient("test.test.com");
oServer.Send(oMail);
}
catch (Exception ex)
{
//TraceAdd("Error=" + ex.Message.ToString());
}
}
}
For removing unnessessary data ( tags) from database File field i use this code
public static string GetBase64(string str)
{
var index1 = str.IndexOf("<content>");
index1 = index1 + "<content>".Length;
var index2 = str.IndexOf("</content>");
var kek = Slice(str, index1, index2);
return kek;
}
public static string Slice(string source, int start, int end)
{
if (end < 0)
{
end = source.Length + end;
}
int len = end - start;
return source.Substring(start, len);
}
When launching my code I can send email to me, and I'll recieve it. But message content attachment with my Base64 code from database File field. Here is a question - Where I got wrong, and how can I recieve email with correct attachment that has been written into database. Thank you for your attention
P.S Attachment in database is written correctly, because K2 integration platform can correctly display it
Here is example what database contain in File column (DBFile)
<file><name>zinojums.html</name><content>PGh0bWw+PGhlYWQ+PG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiIC8+PHN0eWxlPmh0bWwsYm9keXtmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjtmb250LXNpemU6MTBwdDt9aDF7Zm9udC1zaXplOjE0cHQ7fWgye2ZvbnQtc2l6ZToxMnB0O31we2JhY2tncm91bmQtY29sb3I6I0Y3RUVEQTttYXJnaW46MDtwYWRkaW5nOjhweDt9aHJ7aGVpZ2h0OjFweDsgYm9yZGVyOjAgbm9uZTsgY29sb3I6ICM1RjlCRDQ7IGJhY2tncm91bmQtY29sb3I6ICM1RjlCRDQ7fTwvc3R5bGU+PC9oZWFkPjxib2R5PjxoMT5JbmZvcm3EgWNpamEgbm8gVmFsc3RzIGllxYbEk211bXUgZGllbmVzdGE8L2gxPjxoMj5Eb2t1bWVudHMgcGllxYZlbXRzPC9oMj48cD5Ob2Rva8S8dSBtYWtzxIF0xIFqYSBOci4gPGI+TEFUVklKQVMgVkFMU1RTIFJBRElPIFVOIFRFTEVWxKpaSUpBUyBDRU5UUlMgQVMgKDQwMDAzMDExMjAzKTwvYj4gaWVzbmllZ3RhaXMgZG9rdW1lbnRzICI8Yj5aacWGYXMgcGFyIGRhcmJhIMWGxJNtxJNqaWVtPC9iPiIgTnIuIDxiPjU1NDYyNTY5PC9iPiBwaWXFhmVtdHMgdW4gaWVrxLxhdXRzIFZJRCBkYXR1YsSBesSTLjxiciAvPjwvcD48IS0tY29udGVudC0tPjxociAvPsWgaXMgZS1wYXN0cyBpciBpenZlaWRvdHMgYXV0b23EgXRpc2tpLCBsxatkemFtIHV6IHRvIG5lYXRiaWxkxJN0LjxiciAvPlBpZXNsxJNndGllcyBWSUQgRWxla3Ryb25pc2vEgXMgZGVrbGFyxJPFoWFuYXMgc2lzdMSTbWFpOiA8YSBocmVmPSJodHRwczovL2Vkcy52aWQuZ292Lmx2Ij5lZHMudmlkLmdvdi5sdjwvYT4uPC9ib2R5PjwvaHRtbD4=</content></file>
Right now the method you're using to create binary data from your string takes no account of the fact the string is base64-encoded specifically.
You need to replace
var bytes = Encoding.ASCII.GetBytes(DBFile);
with
var bytes = Convert.FromBase64String(DBFile);

Dumping SQL table to .csv C#

I am trying to implement a script in my application that will dump the entire contents (for now, but I am trying to write the code so that I can easily customize it to only grab certain columns) of a sql db (running ms sql server express 2014) to a .csv file.
Here is the code I have written currently:
public void doCsvWrite(string timeStamp){
try {
//specify file name of log file (csv).
string newFileName = "C:/TestDirectory/DataExport-" + timeStamp + ".csv";
//check to see if file exists, if not create an empty file with the specified file name.
if (!File.Exists(newFileName)) {
FileStream fs = new FileStream(newFileName, FileMode.CreateNew);
fs.Close();
//define header of new file, and write header to file.
string csvHeader = "ITEM1,ITEM2,ITEM3,ITEM4,ITEM5";
using (FileStream fsWHT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swT = new StreamWriter(fsWHT))
{
swT.WriteLine(csvHeader.ToString());
}
}
//set up connection to database.
SqlConnection myDEConnection;
String cDEString = "Data Source=localhost\\NAMEDPIPE;Initial Catalog=db;User Id=user;Password=pwd";
String strDEStatement = "SELECT * FROM table";
try
{
myDEConnection = new SqlConnection(cDEString);
}
catch (Exception ex)
{
//error handling here.
return;
}
try
{
myDEConnection.Open();
}
catch (Exception ex)
{
//error handling here.
return;
}
SqlDataReader reader = null;
SqlCommand myDECommand = new SqlCommand(strDEStatement, myDEConnection);
try
{
reader = myDECommand.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if(reader["Column1"].ToString() == "") {
//does nothing if the current line is "bugged" (containing no values at all, typically happens after reboot of 3rd party equipment).
}
else {
//grab relevant tag data and set the csv line for the current row.
string csvDetails = reader["Column1"] + "," + reader["Column2"] + "," + String.Format("{0:0.0}", reader["Column3"]) + "," + String.Format("{0:0.000}", reader["Column4"]) + "," + reader["Column5"];
using (FileStream fsWDT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swDT = new StreamWriter(fsWDT))
{
//write csv line to file.
swDT.WriteLine(csvDetails.ToString());
}
}
}
}
}
catch (Exception ex)
{
//error handling here.
myDEConnection.Close();
return;
}
myDEConnection.Close();
}
catch (Exception ex)
{
//error handling here.
MessageBox.Show(ex.Message);
}
}
Now, this was working fine when I was using it with a 3rd party SQLite-based database, but the output I'm getting after modifing this to my MSSQL db looks something like this (ITEM1 is the primary key, a standard auto-incrementing ID-field):
ITEM1,ITEM2,ITEM3,ITEM4,ITEM5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
....
So it seems that it writes several entries of the same row, where I would just like one single line each row. Any suggestions?
Thanks in advance.
edit: Thanks everyone for your answers!
The for loop isn't needed in the section below. Because it loops from 0 to FieldCount I assume the loop was originally meant to append the text from each column together but inside the loop there's a single line that concatenates the text and assigns it to csvDetails.
try
{
reader = myDECommand.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if(reader["Column1"].ToString() == "") {
//does nothing if the current line is "bugged" (containing no values at all, typically happens after reboot of 3rd party equipment).
}
else {
//grab relevant tag data and set the csv line for the current row.
string csvDetails = reader["Column1"] + "," + reader["Column2"] + "," + String.Format("{0:0.0}", reader["Column3"]) + "," + String.Format("{0:0.000}", reader["Column4"]) + "," + reader["Column5"];
using (FileStream fsWDT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swDT = new StreamWriter(fsWDT))
{
//write csv line to file.
swDT.WriteLine(csvDetails.ToString());
}
}
}
}
}
Usually, we use specialy designed export/import utilites for dumping data.
However, if you have to implement you own routine I suggest decomposing.
private static IEnumerable<IDataRecord> SourceData(String sql) {
using (SqlConnection con = new SqlConnection(ConnectionStringHere)) {
con.Open();
using (SqlCommand q = new SqlCommand(sql, con)) {
using (var reader = q.ExecuteReader()) {
while (reader.Read()) {
//TODO: you may want to add additional conditions here
yield return reader;
}
}
}
}
}
private static IEnumerable<String> ToCsv(IEnumerable<IDataRecord> data) {
foreach (IDataRecord record in data) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < record .FieldCount; ++i) {
String chunk = Convert.ToString(record .GetValue(0));
if (i > 0)
sb.Append(',');
if (chunk.Contains(',') || chunk.Contains(';'))
chunk = "\"" + chunk.Replace("\"", "\"\"") + "\"";
sb.Append(chunk);
}
yield return sb.ToString();
}
}
Having SourceData and ToCsv you can easily implement
private static void WriteMyCsv(String fileName) {
var source = SourceData("SELECT * FROM table");
File.WriteAllLines(fileName, ToCsv(source));
}
You have a for loop which is looping over the fieldcount.
for (int i = 0; i < reader.FieldCount; i++)
I think it will work if you remove the loop as you don't need to iterate through the columns.
it happens because output placed inside for-loop
for (int i = 0; i < reader.FieldCount; i++)
and every record repeats FieldCount-times
Complete example. Verified working .NET 4.8, May 22. Code simplified for demo.
Why the DataTable ? Under circumstances it is useful. If you converting hundreds of files at once and multi threading - it works as large buffer + you can do pretty complex data mangling at the same time - should you need it.
UNFORTUNATELY - Microsoft trying to detect the column types and if your data not comply with the mechanism it ends with hard to correct errors. In that case use the second solution.
// Get the data from SQLite
SqliteConnection SQLiDataCon = new SqliteConnection(#"Data Source=c:\sqlite.db3");
SQLiDataCon.Open();
SqliteDataReader SQLiDtaReader = new SqliteCommand(#"SELECT * FROM stats;", SQLiDataCon).ExecuteReader();
// Load data to DataTable
DataTable csvTable = new DataTable();
csvTable.Load(SQLiDtaReader);
// Get "one" string with column names
string csvFields = #"""" + String.Join(#""",""",csvTable.Columns.Cast<DataColumn>().Select(dc => dc.ColumnName).ToArray()) + #"""";
// Prep "in memory the entire content of the CSV"
StringBuilder csvString = new StringBuilder();
// Write the header in
csvString.AppendLine(csvFields);
// Write the rows in
foreach (DataRow dr in csvTable.Rows)
{
csvString.AppendLine(#"""" + String.Join(#""",""", dr.ItemArray) + #"""");
}
// Save to file
StreamWriter csvFile = new StreamWriter(#"c:\stats.csv");
csvFile.Write(csvString);
Without DataTable.
// SQLITE
SqliteConnection SQLiDataCon = new SqliteConnection(#"Data Source=c:\sqlite.db3");
SQLiDataCon.Open();
StringBuilder csvString = new StringBuilder();
StreamWriter csvFile;
Object[] csvRow;
SqliteDataReader SQLiDtaReader = new SqliteCommand(#"SELECT * FROM sometable;", SQLiDataCon).ExecuteReader();
// CSV HEADER
csvString.AppendLine(#"""" + String.Join(#""",""", SQLiDtaReader.GetSchemaTable().AsEnumerable().Select(dr => dr.Field<string>("ColumnName")).ToArray<string>()) + #"""");
// CSV BODY
while (SQLiDtaReader.Read())
{
SQLiDtaReader.GetValues(csvRow = new Object[SQLiDtaReader.FieldCount]);
csvString.AppendLine(#"""" + String.Join(#""",""",csvRow ) + #"""");
}
// WRITE IT
csvFile = new StreamWriter(#"C:\somecsvfile.csv");
csvFile.Write(csvString);

how to send the gridview in email with formatting

I am developing an online ordering web application in which I have to email with perches product details to customer. I have maintain all the data in a data table and then generated the grid view pragmatically as follows
public GridView makeGridview(DataTable Dt)
{
GridView GV = new GridView();
GV.DataSource = Dt;
GV.DataBind();
return GV;
}
then adding this grid view to email
body = body.Replace("{Product_Details}", GridViewToHtml(makeGridview(Dt)));
private string GridViewToHtml(GridView gv)
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(sw);
gv.RenderControl(hw);
return sb.ToString();
}
This is working fine but the problem is then am unable to design it in our predefine format. This mail will be received by the customer of my website, so I need to convert in to our them.
Please guide me how to format in our them.
If there is an another way to do this then I'm open to that as well.
I would suggest you to not trust the GridView as your rendered html, but instead to use your current data-source for that (DataTable):
public GridView CreateHtmlTable(DataTable dt)
{
//Do your HTML work here, like the following:
string tab = "\t";
StringBuilder sb = new StringBuilder();
sb.AppendLine("<html>");
sb.AppendLine(tab + "<body>");
sb.AppendLine(tab + tab + "<table>");
// headers.
sb.Append(tab + tab + tab + "<tr>");
foreach (DataColumn dc in dt.Columns)
{
sb.AppendFormat("<td>{0}</td>", dc.ColumnName);
}
sb.AppendLine("</tr>");
// data rows
foreach (DataRow dr in dt.Rows)
{
sb.Append(tab + tab + tab + "<tr>");
foreach (DataColumn dc in dt.Columns)
{
string cellValue = dr[dc] != null ? dr[dc].ToString() : "";
sb.AppendFormat("<td>{0}</td>", cellValue);
}
sb.AppendLine("</tr>");
}
sb.AppendLine(tab + tab + "</table>");
sb.AppendLine(tab + "</body>");
sb.AppendLine("</html>");
}
Follow follwing code:
public void SendHTMLMail()
{
MailMessage Msg = new MailMessage();
MailAddress fromMail = new MailAddress("administrator#aspdotnet-suresh.com");
// Sender e-mail address.
Msg.From = fromMail;
// Recipient e-mail address.
Msg.To.Add(new MailAddress("suresh#gmail.com"));
// Subject of e-mail
Msg.Subject = "Send Gridivew in EMail";
Msg.Body += "Please check below data <br/><br/>";
Msg.Body += GetGridviewData(gvUserInfo);
Msg.IsBodyHtml = true;
string sSmtpServer = "";
sSmtpServer = "10.2.160.101";
SmtpClient a = new SmtpClient();
a.Host = sSmtpServer;
a.EnableSsl = true;
a.Send(Msg);
}
// This Method is used to render gridview control
public string GetGridviewData(GridView gv)
{
StringBuilder strBuilder = new StringBuilder();
StringWriter strWriter = new StringWriter(strBuilder);
HtmlTextWriter htw = new HtmlTextWriter(strWriter);
gv.RenderControl(htw);
return strBuilder.ToString();
}
Refer below doccument:
http://www.aspdotnet-suresh.com/2012/09/how-to-send-gridview-in-email-body-in.html
Honestly what you have done here (rendering a Web Forms control to an email string) seems like a bit of an unintended trick. Honestly it's not that hard to iterate through a collection and build an HTML table using a StringBuilder.
I believe that for email HTML the convention is often to use inline styles to guarantee the best compatibility with email clients. So you'd want to style your elements like so:
<table>
<tbody>
<tr style="background-color: #EE0000">
<td style="text-transform: uppercase"></td>
...
</tr>
</tbody>
</table>
In the past I've done this by creating an HTML file with everything how I want it and using placeholders like {VariableName} and then doing a string replace on the variables with their values. This way you separate your HTML view from the C# code. It'd be a little tricky with a list of items, in that case you'd have at least two HTML templates: one for the entire document and one for the item rows.
I ran into a similar issue like yours, and I got it done like this:
encapsulated the functionality in a separate HelperClass for ease of use. Used static variables and methods to keep it simple
write the HTML code to format the content of the GridView to a nice table (with zebra stripes and stuffs)
public static StringBuilder gridViewToHTML(GridView gv)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<html>");
sb.AppendLine("<body>");
sb.AppendLine(#"<table style='padding: 10px; font-family: Verdana; font-size:11px;
border-style:solid;border-width:1px;border-color:grey;'> ");
sb.AppendLine("<tr>");
/* *** Build header of the HTML table *** */
for (int i = 0; i < gv.Columns.Count; i++)
{
sb.AppendLine("<td style='font-weight:bold;background-color:black;color:white;'>" + gv.Columns[i].HeaderText + "</td>");
}
sb.AppendLine("</tr>");
/* *** Build body of the HTML table *** */
for (int i = 0; i < gv.Rows.Count; i++)
{
sb.AppendLine("<tr>");
foreach (DataControlFieldCell gvcell in gv.Rows[i].Cells)
{
sb.AppendLine("<td style='text-align;left;'>" + gvcell.ToString() + "</td>");
}
sb.AppendLine("</tr");
}
sb.AppendLine("</table>");
sb.AppendLine("</body>");
sb.AppendLine("</html>");
return sb;
}
send the email message using the StringBuilder object as html formatting of the content, and the casual parameters (to Whom, and Subject)
public static void sendEmailMessage(StringBuilder stringBuilder, string email_ToAddress, string email_Subject)
{
DateTime now = DateTime.Now;
DateTime yesterday = DateTime.Now.AddDays(-1);
MailMessage mail = new MailMessage();
//SomeEmailAccount#yourOrganization.com must be set by your Sysadmin before using it.
mail.From = new MailAddress("SomeEmailAccount#yourOrganization.com");
mail.To.Add(email_ToAddress);
mail.Subject = $"{email_Subject} . Date #{now.ToShortDateString()}";
mail.Body = stringBuilder.ToString();
mail.IsBodyHtml = true;
NetworkCredential autentificare = new NetworkCredential();
autentificare.UserName = "SomeEmailAccount#yourOrganization.com"";
autentificare.Password = "yourPassw0rd";
SmtpClient smtp = new SmtpClient();
smtp.Host = "mail.yourOrganization.com";
smtp.UseDefaultCredentials = true;
smtp.Credentials = autentificare;
smtp.Port = 25;
smtp.EnableSsl = false;
smtp.Send(mail);
}

Add header and footer row flat file in SSIS

I have a SSIS package which exports data from a query into a flat file, which will be used to import into a data warehouse. One of my requirements is to add a header row with the current date, and a footer row with total row count.
I would like to do this ideally in one script component or task using C# for tidiness in the package. I'm a noob when it comes to writing code. How can this be done? I've looked around on the net but can't seem to find anything close enough to what I want.
Here's the code you could use for a script task that would allow you to output a CSV with a header and a footer:
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
namespace ST_80294de8b8dd4779a54f707270089f8c.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
public void Main()
{
int ErrorFlag = 0;
// Try-Catch block
try
{
int RowCount = 0;
bool fireAgain = true;
string SQLCommandText = "SELECT ColumnA = 1, ColumnB = 'A' UNION SELECT ColumnA = 2, ColumnB = 'B' UNION SELECT ColumnA = 3, ColumnB = 'C';";
SqlConnection SQLConnection = new SqlConnection("Data Source=LocalHost;Initial Catalog=master;Integrated Security=SSPI;Application Name=SSIS-My Package Name;Connect Timeout=600");
SqlCommand SQLCommand = new SqlCommand(SQLCommandText, SQLConnection);
SQLCommand.CommandTimeout = 60 * 60;
SqlDataAdapter SQLDataAdapter = new SqlDataAdapter(SQLCommand);
DataTable dt = new DataTable();
SQLDataAdapter.Fill(dt);
SQLConnection.Close();
RowCount = dt.Rows.Count;
Dts.Events.FireInformation(0, "DataTable Rows", RowCount.ToString(), "", 0, ref fireAgain);
StreamWriter sw = new StreamWriter("C:\\Test.csv", false);
// Write the header.
sw.Write("Today's date is " + DateTime.Now.ToLongDateString());
// Write the column headers.
sw.Write(sw.NewLine);
int iColCount = dt.Columns.Count;
for (int i = 0; i < iColCount; i++)
{
sw.Write(dt.Columns[i]);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
// Write the details.
sw.Write(sw.NewLine);
foreach (DataRow dr in dt.Rows)
{
for (int i = 0; i < iColCount; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
sw.Write(dr[i].ToString());
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
// Write the footer.
sw.Write("Row count: " + RowCount.ToString());
sw.Close();
}
catch (SqlException e)
{
Dts.Events.FireError(0, "SqlException", e.Message, "", 0);
ErrorFlag = 1;
}
catch (IOException e)
{
Dts.Events.FireError(0, "IOException", e.Message, "", 0);
ErrorFlag = 1;
}
catch (Exception e)
{
Dts.Events.FireError(0, "Exception", e.Message, "", 0);
ErrorFlag = 1;
}
// Return results.
if (ErrorFlag == 0)
{
Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
}
}
You could also do this without resorting to C#, but it would be a little ugly:
Variable 1: An Int variable used to assign the number of rows from Data Flow 2.
Variable 2: A string variable with an expression that generates a SQL command. If Variable 1's named RowCount, then here's a sample set of code for it:
"SELECT ColumnA = '" + (DT_WSTR, 1252)(#[User::RowCount]) + "', ColumnB = NULL"
Data Flow 1: Executes a SQL command to generate the header of the file and outputs to a flat file destination. Set the "overwrite data in the file" to true.
Data Flow 2: Executes a SQL command to generate the details of the flat file. Set the "overwrite data in the file" to false. Include a Row Count transformation and assign the value to Variable 1.
Data Flow 3: Executes a SQL command to generate the footer of the flat file. The source should "Set command from variable" and it should execute Variable 2. Set the "overwrite data in the file" to false.
Hi These will help you...
http://www.bidn.com/blogs/KeithHyer/bidn-blog/1990/adding-a-header-or-footer-row-to-a-fixed-width-file-using-ssis
http://agilebi.com/jwelch/2008/02/08/adding-headers-and-footers-to-flat-files/
Regards,
Jason
This is what I eventually came up with! It is the cleanest, most simple way I can find of doing this task. It basically just builds up the header and trailer rows then appends to the dataset. Seems so simple once you've done it! It takes a bit of knowledge of C#, however it is well worth it than trying to do it in SQL.
Microsoft SQL Server Integration Services Script Task
Write scripts using Microsoft Visual C# 2008.
The ScriptMain is the entry point class of the script.
using System;
using System.Text;
using System.IO;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
namespace ST_db04adc927b941d19b3817996ff885c2.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
/*
The execution engine calls this method when the task executes.
To access the object model, use the Dts property. Connections, variables, events,
and logging features are available as members of the Dts property as shown in the following examples.
To reference a variable, call Dts.Variables["MyCaseSensitiveVariableName"].Value;
To post a log entry, call Dts.Log("This is my log text", 999, null);
To fire an event, call Dts.Events.FireInformation(99, "test", "hit the help message", "", 0, true);
To use the connections collection use something like the following:
ConnectionManager cm = Dts.Connections.Add("OLEDB");
cm.ConnectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;Provider=SQLNCLI10;Integrated Security=SSPI;Auto Translate=False;";
Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
To open Help, press F1.
*/
public void Main()
{
const string dirPath = #"C:\SSIS\Dev\";
DateTime minusoneweek = DateTime.Today.AddDays(-7);
DateTime minusoneday = DateTime.Today.AddDays(-1);
var headerRecord = ("0|" + DateTime.Today.ToString("ddMMyyyy") + "|" + Dts.Variables["LastSequenceNumber"].Value + "|"
+ Dts.Variables["FileName"].Value) + "|" + minusoneweek.ToString("ddMMyyyy") + "|" + minusoneday.ToString("ddMMyyyy");
var fileBody = AddHeaderAndFooter.GetFileText(dirPath + "blank.txt");
var trailerRecord = "9|" + AddHeaderAndFooter.CountRecords(dirPath + "blank.txt").ToString();
var outPutData = headerRecord + "\r\n" + fileBody + trailerRecord + "\r\n";
AddHeaderAndFooter.WriteToFile(dirPath + "blank.txt", outPutData);
}
}
public static class AddHeaderAndFooter
{
public static int CountRecords(string filePath)
{
return (File.ReadAllLines(filePath).Length + 2);
}
public static string GetFileText(string filePath)
{
var sr = new StreamReader(filePath, Encoding.Default);
var recs = sr.ReadToEnd();
sr.Close();
return recs;
}
public static void WriteToFile(string filePath, string fileText)
{
var sw = new StreamWriter(filePath, false);
sw.Write(fileText, Encoding.ASCII);
sw.Close();
}
}
}

Categories

Resources