How to download images automatically from database table when it is updated? - mysql

I have this sample code to download images from database table manually by clicking a button.
In Html page:
<asp:Button ID="Button1" runat="server" Text="Convert Byte to All Image " OnClick="Button1_Click" />
Code behind:
protected void Button1_Click(object sender, EventArgs e)
{
string sConn = ConfigurationManager.ConnectionStrings["conString"].ToString();
SqlConnection objConn = new SqlConnection(sConn);
objConn.Open();
string sTSQL = "Select TOP 1500 FileData, FileValue from Demo_Tbl where Active=1 and FileGroup='C_Photo'";
SqlCommand objCmd = new SqlCommand(sTSQL, objConn);
objCmd.CommandType = CommandType.Text;
SqlDataAdapter adapter = new SqlDataAdapter();
DataTable dt = new DataTable();
adapter.SelectCommand = objCmd;
adapter.SelectCommand.CommandTimeout = 10000;
adapter.Fill(dt);
objConn.Close();
for (int i = 0; i < dt.Rows.Count; i++)
{
string FileValue = dt.Rows[i]["FileValue"].ToString();
object FileData = dt.Rows[i]["FileData"];
System.IO.File.WriteAllBytes(Server.MapPath("/Images/" + FileValue), (byte[])FileData);
}
Response.Write("Images has been fetched");
}
I want this download to happen automatically when Demo_Tbl table is updated by some one each time. Also I want the download target folder in cloud database(https.clode.azure.com) blobs.
I need some one to help me on this since I'm clue less.

Yeah, its a good idea to download on the update event.
If you write the download code on the update event, it will need to wait the download method before the update event finished. I would recommend you to insert a queue message to Azure storage queue, then use Azure webjob QueueTrigger to download the file to Azure Blob. Here is a similar scenario that use Azure Webjob QueueTrigger to resize the image. I think it will help with your scenario.

Related

Error Trying To Upload Image File In ASP.NET

I have the following asp.net C# code to upload an image, and when I try to run it and select the file to upload, it does not recognize that I have selected a file to upload, so I get the message "file not uploaded successfully. I get the following error when trying. Object reference not set to an instance of an object.
I believe I have to add code, to instantiate. I am new to this, and I believe I do not have the correct syntax. I have a data entry form where the File Upload. Can someone tell me what I need, I think I need to add a declaration, as in Line 3 (with ******), but what I have may not be correct if it is not setting the file I am trying to upload, the debugger shows no file, although I am selecting one. Thanks.
See code below
protected void ButImg_Click(object sender, EventArgs e)
{
******FileUpload fileImg = (FileUpload)this.FindControl("fileImg");*****
if (fileImg.HasFile)
{
string imgfile = Path.GetFileName(fileImg.PostedFile.FileName);
string savePath = Path.Combine(ConfigurationManager.AppSettings["ImagesFolder"], imgfile);
fileImg.SaveAs(Server.MapPath("UsrImage/"+ imgfile));
_connstr = System.Configuration.ConfigurationManager.ConnectionStrings["Conn"].ConnectionString;
/* Save file to Ticket Attachments folder */
if (System.IO.File.Exists(savePath))
{
System.IO.File.Delete(savePath);
}
SqlConnection sqlconn = new SqlConnection(_connstr);
sqlconn.Open();
SqlCommand sqlcomm = new SqlCommand(_procUpdateImage);
sqlcomm.CommandType = CommandType.StoredProcedure;
sqlcomm.Connection = sqlconn;
sqlcomm.Parameters.AddWithValue("#UsrID", this.txtUsrID.Text);
sqlcomm.Parameters.AddWithValue("#ImageName", imgfile);
sqlcomm.Parameters.AddWithValue("#ImagePath", "Images/" + imgfile);
sqlcomm.Parameters.AddWithValue("#UsrID", _UsrName);
sqlcomm.ExecuteNonQuery();
LitImg.Text = "Image saved successfully";
sqlconn.Close();
fileImg.SaveAs(savePath);
}
else
{
LitImg.Text = "Image not saved successfully";
}
}
.aspx web form for Upload control
<td class="tdSingle">Usr Image</td>
<td class="tdSingle">
<asp:FileUpload ID="fileImg" runat="server"></asp:FileUpload><br/>
<asp:Button ID="ButImg" runat="server" Text="Image Save" OnClick="ButImg_Click" ></asp:Button><br/>
<p>
<asp:Literal ID="LitImg" runat="server"></asp:Literal>
</p>
</td>

MySQL Connector/Net Bulk Uploader not finding file on remote server

I have pored through many pages trying to find an answer but have had no luck. I have a .NET page built in C# that has been working fine until a few days ago. Now it isn't working and I'm pulling my hair out to find out why.
The page has a file uploader that uploads a .csv file and saves it to a folder on the web server. Then it uses the MySQL Bulk Uploader to insert the records into the database on another server.
I have confirmed the file is uploading to the correct folder, but when MySQL tries to insert the records, it fails with the message "File 'E:\inetpub\wwwroot\training\data_uploads\filename.csv' not found (Errcode: 2 - No such file or directory)"
This page has worked for several years without any problem, but I updated some of the NuGet packages and removed some that were not being used, and now it's stopped working. What am I missing? Is there a package or a .dll I need to add back in? Unfortunately, I don't remember what I removed.
Here's the code I'm using:
protected void btnGo_Click(object sender, EventArgs e)
{
try
{
//if file is selected for upload
if (btnSelectFile.HasFile)
{
//upload data file to server
string path = string.Concat(Server.MapPath("~/data_uploads/" + btnSelectFile.FileName));
btnSelectFile.SaveAs(path);
string conString = ConfigurationManager.ConnectionStrings["nameOfConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(conString);
conn.Open();
//get rid of old data
MySqlCommand truncateTerms = new MySqlCommand("TRUNCATE terms_temp;", conn);
truncateTerms.ExecuteNonQuery();
//create bulk uploader and set parameters
var bl = new MySqlBulkLoader(conn);
bl.TableName = "terms_temp";
bl.FieldTerminator = ",";
bl.FieldQuotationCharacter = '"';
bl.LineTerminator = "\r\n";
bl.FileName = path;
bl.NumberOfLinesToSkip = 2;
//insert data
var inserted = bl.Load(); //This is where it fails
conn.Close();
//do some other stuff
catch (Exception ex)
{
Label1.ForeColor = System.Drawing.Color.Red;
Label1.Text = ex.Message.ToString();
}
}
If you're bulk-loading a file that's stored on the web server, not the database server, you need to set MySqlBulkLoader.Local = true, to indicate that the file is local to the database client. Otherwise, the server will give an error that the file isn't found.
For security reasons you will also need to set AllowLoadLocalInfile=true in your connection string to enable this feature.

Best way to turn sql selected data into a table on excel using asp.net

I have an sql statements that selects a table of data that i want to export to excel in the .xls format,
i added this table to a grid view then rendered that grid view to create an html writer and write it on excel file using asp.net.
But i keep having this warning that the file format and extension does not match.
The issue is that the file you are creating is not a genuine Excel file. It's HTML with a .xls extension.
Please, i need to know what is the best way to export these selected data to the xls file without the warning.
I Have also tried exporting from the dataTable directly, but i still get the warning when tying to open the excel.
// these namespaces need to be added to your code behind file
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
namespace MySpot.UserPages
{
public partial class Journal : System.Web.UI.Page
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySpotDBConnStr"].ConnectionString);
DataTable dt = new DataTable();
// regular page_load from .aspx file
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
// added a button with ID=btnDownload and double clicked it's onclick event to auto create method
protected void btnDownload_Click(object sender, EventArgs e)
{
string queryStr = "SELECT * from table";
SqlDataAdapter sda = new SqlDataAdapter(queryStr, conn);
sda.Fill(dt);
ExportTableData(dt);
}
// this does all the work to export to excel
public void ExportTableData(DataTable dtdata)
{
string attach = "attachment;filename=journal.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attach);
Response.ContentType = "application/ms-excel";
if (dtdata != null)
{
foreach (DataColumn dc in dtdata.Columns)
{
Response.Write(dc.ColumnName + "\t");
//sep = ";";
}
Response.Write(System.Environment.NewLine);
foreach (DataRow dr in dtdata.Rows)
{
for (int i = 0; i < dtdata.Columns.Count; i++)
{
Response.Write(dr[i].ToString() + "\t");
}
Response.Write("\n");
}
Response.End();
}
}
}
}
http://blogs.msdn.com/b/vsofficedeveloper/archive/2008/03/11/excel-2007-extension-warning.aspx
The current design does not allow you to open HTML content from a web site in Excel unless the extension of the URL is .HTM/.HTML/.MHT/.MHTML. So ASP pages that return HTML and set the MIME type to something like XLS to try to force the HTML to open in Excel instead of the web browser (as expected) will always get the security alert since the content does not match the MIME type. If you use an HTML MIME type, then the web browser will open the content instead of Excel. So there is no good workaround for this case because of the lack of a special MIME type for HTML/MHTML that is Excel specific. You can add your own MIME type if you control both the web server and the client desktops that need access to it, but otherwise the best option is to use a different file format or alert your users of the warning and tell them to select Yes to the dialog.

Creating CycleTile with remote images

I have seen a number of examples showing the CycleTile in action, but these have all used local images. Is it possible to set these images once the app is first run and point the CycleTile to the remote images? Or if I do need to save these to the phone first, how can I get the CycleTile to reference them?
CycleTileTemplate & CycleTileData only support local URIs and don't support remote web URIs. Meaning that you can only set the source of a cycle image from files installed from the XAP or from files in IsoStore.
In order to support remote images in CycleTileData, you'll need to download the images in a periodic background agent, save them to IsoStore and then update the CycleTileData with those images. Push notifications won't work here since the images need to be local and neither will ShellTileSchedule.
Make sure to save the images to IsoStore under the "/Shared/ShellContent" and set their URIs as "isostore:/Shared/Shellcontent/myImage.png" or they won't be accessible to the start screen tiles.
Let's see an example of that. First we start off by writing up a parallelized threaded algorithm that launches 9 download threads, waits for the results and then updates tiles:
private IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var threadFinishEvents = new List<WaitHandle>();
DownloadImages(threadFinishEvents);
new Thread(()=>
{
Mutex.WaitAll(threadFinishEvents.ToArray());
UpdateTiles();
isoStore.Dispose();
}).Start();
}
Next, we'll download the 9 images into IsoStore "/Shared/ShellContent". We'll take special note to add the new threading flags for each web download, and set the flag as done once the file is in IsoStore.
private void DownloadImages(List<WaitHandle> threadFinishEvents)
{
for (int i = 0; i < 9; i++)
{
var localI = i;
var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
threadFinishEvents.Add(threadFinish);
var request = WebRequest.CreateHttp("http://www.justinangel.net/storage/691x336.png");
request.BeginGetResponse(ir =>
{
var result = request.EndGetResponse(ir);
using (var isoStoreFile = isoStore.OpenFile("shared/shellcontent/myImage" + localI + ".png",
FileMode.Create,
FileAccess.ReadWrite))
using (var response = result.GetResponseStream())
{
var dataBuffer = new byte[1024];
while (response.Read(dataBuffer, 0, dataBuffer.Length) > 0)
{
isoStoreFile.Write(dataBuffer, 0, dataBuffer.Length);
}
}
threadFinish.Set();
}, null);
}
}
Finally, we'll update the live tile to use the new images in IsoStore.
private void UpdateTiles()
{
ShellTile.ActiveTiles
.First()
.Update(new CycleTileData()
{
Title = "Cyclical",
CycleImages = new Uri[]
{
new Uri("isostore:/Shared/ShellContent/myImage0.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage1.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage2.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage3.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage4.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage5.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage6.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage7.png", UriKind.Absolute),
new Uri("isostore:/Shared/ShellContent/myImage8.png", UriKind.Absolute),
}
});
}
There's a couple of interesting things to consider:
Periodic background agents only have 25 seconds to complete their operation, so it might make sense to add timer thresehold when activating Mutex.WaitAll and have it fail gracefully.
Downloading 9 images in 25 seconds might not work at all under some network conditions so it might be best to optimize for that. You can either use less images, or update only a few images every 30 minutes.
Updating the CycleTileData to the same file URIs won't trigger an update of the tile (AFAIK). So you'll need better filenames then myImage0, but rather have unique file names for the images.
For CycleTile, the images have to be local. You could set up a periodic task to refresh the images though, then store those images in the shared/shellcontent special folder in local/isolated storage (e.g., ms-appdata:///local/shared/shellcontent/image01.png)
Session 7 of the Windows Phone 8 Jumpstart is a good reference for this - specifically about 25:30 in.

Calling wkhtmltopdf to generate PDF from HTML

I'm attempting to create a PDF file from an HTML file. After looking around a little I've found: wkhtmltopdf to be perfect. I need to call this .exe from the ASP.NET server. I've attempted:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = HttpContext.Current.Server.MapPath("wkhtmltopdf.exe");
p.StartInfo.Arguments = "TestPDF.htm TestPDF.pdf";
p.Start();
p.WaitForExit();
With no success of any files being created on the server. Can anyone give me a pointer in the right direction? I put the wkhtmltopdf.exe file at the top level directory of the site. Is there anywhere else it should be held?
Edit: If anyone has better solutions to dynamically create pdf files from html, please let me know.
Update:
My answer below, creates the pdf file on the disk. I then streamed that file to the users browser as a download. Consider using something like Hath's answer below to get wkhtml2pdf to output to a stream instead and then send that directly to the user - that will bypass lots of issues with file permissions etc.
My original answer:
Make sure you've specified an output path for the PDF that is writeable by the ASP.NET process of IIS running on your server (usually NETWORK_SERVICE I think).
Mine looks like this (and it works):
/// <summary>
/// Convert Html page at a given URL to a PDF file using open-source tool wkhtml2pdf
/// </summary>
/// <param name="Url"></param>
/// <param name="outputFilename"></param>
/// <returns></returns>
public static bool HtmlToPdf(string Url, string outputFilename)
{
// assemble destination PDF file name
string filename = ConfigurationManager.AppSettings["ExportFilePath"] + "\\" + outputFilename + ".pdf";
// get proj no for header
Project project = new Project(int.Parse(outputFilename));
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = ConfigurationManager.AppSettings["HtmlToPdfExePath"];
string switches = "--print-media-type ";
switches += "--margin-top 4mm --margin-bottom 4mm --margin-right 0mm --margin-left 0mm ";
switches += "--page-size A4 ";
switches += "--no-background ";
switches += "--redirect-delay 100";
p.StartInfo.Arguments = switches + " " + Url + " " + filename;
p.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none
p.StartInfo.WorkingDirectory = StripFilenameFromFullPath(p.StartInfo.FileName);
p.Start();
// read the output here...
string output = p.StandardOutput.ReadToEnd();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
// if 0 or 2, it worked (not sure about other values, I want a better way to confirm this)
return (returnCode == 0 || returnCode == 2);
}
I had the same problem when i tried using msmq with a windows service but it was very slow for some reason. (the process part).
This is what finally worked:
private void DoDownload()
{
var url = Request.Url.GetLeftPart(UriPartial.Authority) + "/CPCDownload.aspx?IsPDF=False?UserID=" + this.CurrentUser.UserID.ToString();
var file = WKHtmlToPdf(url);
if (file != null)
{
Response.ContentType = "Application/pdf";
Response.BinaryWrite(file);
Response.End();
}
}
public byte[] WKHtmlToPdf(string url)
{
var fileName = " - ";
var wkhtmlDir = "C:\\Program Files\\wkhtmltopdf\\";
var wkhtml = "C:\\Program Files\\wkhtmltopdf\\wkhtmltopdf.exe";
var p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = wkhtml;
p.StartInfo.WorkingDirectory = wkhtmlDir;
string switches = "";
switches += "--print-media-type ";
switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
switches += "--page-size Letter ";
p.StartInfo.Arguments = switches + " " + url + " " + fileName;
p.Start();
//read output
byte[] buffer = new byte[32768];
byte[] file;
using(var ms = new MemoryStream())
{
while(true)
{
int read = p.StandardOutput.BaseStream.Read(buffer, 0,buffer.Length);
if(read <=0)
{
break;
}
ms.Write(buffer, 0, read);
}
file = ms.ToArray();
}
// wait or exit
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
return returnCode == 0 ? file : null;
}
Thanks Graham Ambrose and everyone else.
OK, so this is an old question, but an excellent one. And since I did not find a good answer, I made my own :) Also, I've posted this super simple project to GitHub.
Here is some sample code:
var pdfData = HtmlToXConverter.ConvertToPdf("<h1>SOO COOL!</h1>");
Here are some key points:
No P/Invoke
No creating of a new process
No file-system (all in RAM)
Native .NET DLL with intellisense, etc.
Ability to generate a PDF or PNG (HtmlToXConverter.ConvertToPng)
Check out the C# wrapper library (using P/Invoke) for the wkhtmltopdf library: https://github.com/pruiz/WkHtmlToXSharp
There are many reason why this is generally a bad idea. How are you going to control the executables that get spawned off but end up living on in memory if there is a crash? What about denial-of-service attacks, or if something malicious gets into TestPDF.htm?
My understanding is that the ASP.NET user account will not have the rights to logon locally. It also needs to have the correct file permissions to access the executable and to write to the file system. You need to edit the local security policy and let the ASP.NET user account (maybe ASPNET) logon locally (it may be in the deny list by default). Then you need to edit the permissions on the NTFS filesystem for the other files. If you are in a shared hosting environment it may be impossible to apply the configuration you need.
The best way to use an external executable like this is to queue jobs from the ASP.NET code and have some sort of service monitor the queue. If you do this you will protect yourself from all sorts of bad things happening. The maintenance issues with changing the user account are not worth the effort in my opinion, and whilst setting up a service or scheduled job is a pain, its just a better design. The ASP.NET page should poll a result queue for the output and you can present the user with a wait page. This is acceptable in most cases.
You can tell wkhtmltopdf to send it's output to sout by specifying "-" as the output file.
You can then read the output from the process into the response stream and avoid the permissions issues with writing to the file system.
My take on this with 2018 stuff.
I am using async. I am streaming to and from wkhtmltopdf. I created a new StreamWriter because wkhtmltopdf is expecting utf-8 by default but it is set to something else when the process starts.
I didn't include a lot of arguments since those varies from user to user. You can add what you need using additionalArgs.
I removed p.WaitForExit(...) since I wasn't handling if it fails and it would hang anyway on await tStandardOutput. If timeout is needed, then you would have to call Wait(...) on the different tasks with a cancellationtoken or timeout and handle accordingly.
public async Task<byte[]> GeneratePdf(string html, string additionalArgs)
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = #"C:\Program Files\wkhtmltopdf\wkhtmltopdf.exe",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = "-q -n " + additionalArgs + " - -";
};
using (var p = Process.Start(psi))
using (var pdfSream = new MemoryStream())
using (var utf8Writer = new StreamWriter(p.StandardInput.BaseStream,
Encoding.UTF8))
{
await utf8Writer.WriteAsync(html);
utf8Writer.Close();
var tStdOut = p.StandardOutput.BaseStream.CopyToAsync(pdfSream);
var tStdError = p.StandardError.ReadToEndAsync();
await tStandardOutput;
string errors = await tStandardError;
if (!string.IsNullOrEmpty(errors)) { /* deal/log with errors */ }
return pdfSream.ToArray();
}
}
Things I haven't included in there but could be useful if you have images, css or other stuff that wkhtmltopdf will have to load when rendering the html page:
you can pass the authentication cookie using --cookie
in the header of the html page, you can set the base tag with href pointing to the server and wkhtmltopdf will use that if need be
Thanks for the question / answer / all the comments above. I came upon this when I was writing my own C# wrapper for WKHTMLtoPDF and it answered a couple of the problems I had. I ended up writing about this in a blog post - which also contains my wrapper (you'll no doubt see the "inspiration" from the entries above seeping into my code...)
Making PDFs from HTML in C# using WKHTMLtoPDF
Thanks again guys!
The ASP .Net process probably doesn't have write access to the directory.
Try telling it to write to %TEMP%, and see if it works.
Also, make your ASP .Net page echo the process's stdout and stderr, and check for error messages.
Generally return code =0 is coming if the pdf file is created properly and correctly.If it's not created then the value is in -ve range.
using System;
using System.Diagnostics;
using System.Web;
public partial class pdftest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private void fn_test()
{
try
{
string url = HttpContext.Current.Request.Url.AbsoluteUri;
Response.Write(url);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName =
#"C:\PROGRA~1\WKHTML~1\wkhtmltopdf.exe";//"wkhtmltopdf.exe";
startInfo.Arguments = url + #" C:\test"
+ Guid.NewGuid().ToString() + ".pdf";
Process.Start(startInfo);
}
catch (Exception ex)
{
string xx = ex.Message.ToString();
Response.Write("<br>" + xx);
}
}
protected void btn_test_Click(object sender, EventArgs e)
{
fn_test();
}
}