Reading blob from SQL Server and downloading it - c#

I am updating an asp.net application and saving and retrieving documents from a mssql database. Saving was very simple but is there a way to download a file from an anchor that directly downloads from the database? Lets just say that that blob is bound within a gridview or some other data control, I would like to do this, example: Download Doc. I save the file name as well.

First, you wouldn't assign the image to the href element, you would create an img tag to display the image, then the href tag to download it or embed the image tag directly in the href:
<img src="<%#Eval("blobcolumn")%></img>
Second, displaying the image inline without Url to a file requires a Data URI, which means that a base-64 version of the image is embedded in the web page:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
This approach means a substantial amount of extra traffic on your web server and your end user's machines since the image will not be cached as it would be if you provided an actual URL to the image in your web server (i.e. /images/reddot.png).
I think that you would be much better off saving copies of the image to the web server and providing urls to those images in your page.
If there is concern about the size or number of files, you could create batch jobs to purge files older than a certain number of days or hours from the temporary image cache.

You can create a Handler to download data.
sample.ashx
public void ProcessRequest (HttpContext context)
{
string id = context.Request["id"];
if (!string.IsNullOrEmpty(id))
{
//read byte[] and other data from database based upon given ID
byte []ar=//result from database
string fileName=//filename
context.Response.ContentType = "Application/octet-stream";
context.Response.AddHeader("Content-Length", ar.Length.ToString());
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName );
context.Response.BinaryWrite(ar);
context.Response.Flush();
context.Response.End();
}
}
and request via hyperlinks
Download .zip
<a href='sample.ashx?id=<%#Eval("ID")%>'><%#Eval("Desc")%></a>

Related

How to force view in browser of pdf and word docs

I am required to open various files types such as pdf and word in browser I see that the most accepted solution seems to be the simlar as to what I have done
public string GetDocument(Guid UserId, string Filename)
{
string mimeType = "application/pdf"
Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
return File(doc, mimeType);
}
My quesiton is how do i turn my raw file on the server to something that can be served to the browser I persume I have to change it to byte if so how would one change a pdf to bytes. And for that matter word files
You can use something like:
public void GetDocument(Guid UserId, string Filename)
{
string mimeType = "application/pdf"
Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
Response.WriteFile(fileName);
Response.End();
}
Note, Response.WriteFile expects the FULL path to the file, so if the filename variable isn't the full path, you'll need to map it.
In the case of the PDF, most browsers will open in inside the browser, for other file types your mileage may vary, depending on whether the browser has the capability to display that file type inline.
You cannot force it from the server end.
Some browsers (such as Chrome) can render a PDF just fine, but a PDF rendered from a server will only open in Chrome only if the .pdf file extension is associated with Chrome. You can't change the associations without access to the machine on which the browser is running.
As far as I know, you cannot open a Word doc directly in any browser. You have to use a viewer.
Using a viewer you can display PDF or Word docs within the page-- this is different from downloading the file and displaying it natively, but it may suit your purpose.
A few viewers are freely available. Here's two.
Google docs viewer
Office Web Apps viewer

ASP MVC Getting image from SQLite db vs. file system

I have two identical images. One is saved as a .png in a folder, the other is saved as a SQLite blob in a database. I'm trying to figure out a good way to persist these images and show them in my view when needed.
I have two methods for trying to get these images into my view. The first one is reading the image files directly from the file system, converting them into a base64 string which I shove into a ViewBag. This method works fine.
The other method is trying to load the image blob directly from the database and then fetch the image from the Model in the view. This doesn't work so well.
Through a couple of breakpoints I've found out that there's a huge different between the base64 strings, depending on my method. I'm not sure why and what the difference between the SQLite image blob and the .png in my file system is, and any help would be appreciated since saving images in a folder seems like extra work, when I could just keep them in my database.
Loading from the file system:
public string FirstImagePath(string slideid, int well)
{
var firstPath = HttpContext.Current.Server.MapPath(slideid);
byte[] firstImageByteData = File.ReadAllBytes(firstPath + "_first" + well + ".png");
string firstImageBase64Data = Convert.ToBase64String(firstImageByteData);
string firstImageDataUrl = string.Format("data:image/png;base64,{0}", firstImageBase64Data);
return firstImageDataUrl;
}
Loading from SQLite db:
public byte[] FirstImage { get; set; }
public string FirstBase64Image
{
get { return ConvertImage(FirstImage);}
}
public string ConvertImage(byte[] imageBytes)
{
byte[] imageArray = imageBytes;
string imageBase64String = Convert.ToBase64String(imageBytes);
string imageDataString = string.Format("data:image/png;base64,{0}", imageBase64String);
return imageDataString;
}
Both methods have their advantages and disadvantages.
If you store your images in a DB it's very easy to move the application across different platforms without having to copy a lot of images. On the other hand your DB is going to get very large over time.
Storing images on disk allows you to overwrite them easily with a copy / paste job etc. However, if you have multiple web servers, you're going to have to make this change several times.
However, this isn't the main issue that I have with your approach. The problem is that you get the images, convert them to base64 and embed them in your output. This is bad practice for many reasons. Firstly, browsers are smart enough to load in multiple resources at a time. For instance, your browser can download multiple images at a time which will drastically increase page load speed. If you have the images embeded it becomes the responsibility of the html parser to render these images which in turn slows the overall download of the html document as it's larger.
I would recommend a hybrid of the two. Upload images to your database. Create an image handler in your application that retrieves an image from the DB and attempts to save it to the file system. If it's successful return this image. The next time you try to get this image (and it's not cached on the users machine) your handler can check the file system to see if it has already been created and return it.
This method gives you the advantages of both the DB and file structure methods. If you decide you need 10 web servers, all of your images will be stored in the DB, and the file system will be automatically populated with your images as and when you need them depending on which server receives the request. I recommend using a GUID or some unique id for your images.
You could even extend this further and pass height and width parameters to the image handler that will resize the image for you before sending it back to the client.

How to save/retrieve images from disk in windows form application?

What I am trying to do is, I want to save an image ("scanned image of receipt") upon each ticket generation and store its reference(image name) in mssql database.
Scenario:
The user will select the image from a source through OpenDialogBox & will click save button. Now what I want my application to do is, copy the file from source, change its file name to TicketID (TicketID will be unique everytime so the image name will always remain unique) and then save to a specific folder (which will store all images) and store the filename in database.
I have never used images in C# before, so I have no idea on how to actually do it. So I would really appreciate if someone could link me to a tutorial or something...
P.S. I am using visual studio 2012 and MQ SQL Server 2012.
you can do the following
1- on the save event assuming that your scanned Image called image
var ticketID=Guid.NewGuid().ToString(); // this method will ensure that the name of image will be unique all the time
var path="savingPath" + "/" + ticketID + ".jpg";
// the image path you can save it in the database
image.Save(path);
2- when you want to load the image
// retrieve the image path from database
var image=Image.FromFile(path);
hope that this will help you
If you don't need anything overly fancy in terms of processing the System.Drawing library should meet your needs.
Depending on how you want to architect your app you can pass a directory path directly into the constructor of your Image implementation. e.g.
var myImage = new Bitmap("C:\\somepath\\filename.jpg");
Or you could abstract away the location access you can just pass in a stream (which comes from a byte array, file operation, web request, whatever)
var myImage = new Bitmap(stream);
Saving an image is easy. The image class has a save method
image.Save("C:\\somepath\\filename2.jpg")
http://msdn.microsoft.com/en-us/library/9t4syfhh(v=vs.110).aspx

Displaying pdf files in a web page from a sql database directly without needing to save them to the server file system

I'm currently using an html embed tag to display a pdf file that is saved on the local server. Is there a wayo to display a pdf file on my page without having to save it to the local file system of the server? I just wand to pass it to the view from the controller in such a way that it can be displayed as a pdf in the page without having it stored on the file system directly.
Alternatively, is there a way to call a method to delete the pdf file from the server once the user has navigated away from the page they are viewing? How do I tell if th euser has navicated away from the page and how do i cause that to trigger a method that will delete the file?
I created a MVC class called PdfResult that returns a byte array as a PDF file.
The purpose is as follows (can't upload the source code, sorry):
PdfResult inherits from FileStreamResult
Set the Content-Type header to application/pdf
Set the Content-Disposition to either attachment or inline, and set an appropriate file name
Convert your data to a Stream -- if your data is a byte array, then write it to a MemoryStream.
See https://stackoverflow.com/a/16673120/272072 for a good example of how to do this.
Then, your embed code just needs to point to the action method, as if it was a PDF file.
Here's an example:
public ActionResult ShowPdf() {
// Note: the view should contain a tag like <embed src='MyController/GetPdf'>
return View();
}
public ActionResult GetPdf() {
byte[] pdfBytes = dataRepo.GetPdf(...);
return new PdfResult(pdfBytes, "Filename.pdf", false) ;
}
Here is a link to a CodeProject article and code sample titled Download and Upload Images from SQL Server via ASP.NET MVC. This gives an example of an efficient method to stream content to and from SQL Server via MVC.
You can easily adapt the code to stream your PDF file downloads.
UPDATE
The article uses a DataReader, but it can easily be adapted to Linq2Sql or EF. As an example, here is the Read method where I am reading from the database and copying to the stream:
public override int Read(byte[] buffer, int offset, int count)
{
result = _attachments.ExecuteStoreQuery<byte[]>(
"SELECT SUBSTRING(AttachmentBytes, " + position.ToString() +
", " + count.ToString() + ") FROM Attachments WHERE Id = {0}",
id).First();
var bytesRead = result.Length;
Buffer.BlockCopy(result, 0, buffer, 0, bytesRead);
position += bytesRead;
return (int)bytesRead;
}
You can read the PDF as a bytestream from the database and save it to the http response stream. If you have set the content type correctly to application/pdf, then the browser will load the document in the PDF plugin.
Update (14/Oct/2011): You need to write the bytestream to the Response.OutputStream object. How you create and write the byte stream is dependent on how you have stored in the database and how you are retrieving it. The following code snippet is from an article we have on our website - Generate PDF Forms In ASP.NET Using PDFOne .NET v3.
// Get the page's output stream ready
Response.Clear();
Response.BufferOutput = true;
// Make the browser display the forms document
// using a PDF plug-in. (If no plug in is available,
// the browser will show the File -> Save As dialog box.
Response.ContentType = "application/pdf";
// Write the forms document to the browser
doc.Save(Response.OutputStream);
doc.Close();
doc.Dispose();
The doc object is from our component. You need not use that. This code snippet is only for your understanding. For your requirement, you may have to something like bytestream.save(Response.OutputStream) I guess. BTW, this code is for ordinary ASP.NET, not MVC.
DISCLAIMER: I work for Gnostice.
If you want to create the PDF 100% dynamically, you would generate it completely in memory then stream it out directly to the requesting web browser without saving it as a file. This is very easy to do with the right tools. I would recommend AspPDF from Persits.com as a way to do this very easily. Take a look at their online documentation to see how simple this is to do without creating a bunch of rendered PDF files all over your server.
If you cannot do something like that, then simply incorporate a process to cleanup your "expired" PDF files from your server's filesystem based on their age. For example, after you have created your local PDF file, you just look through the folder containing your temporary PDF's and delete any you find over a certain age. You cannot reliably tell if or when a user has navigated away from your page or site.
For the first part of your question, like mentioned in the comments, use some type of stream object to pass the PDF data around. Right now, you are streaming the file to the local file system, then streaming it once again to the embedded tag for display. Just do away with the intermediate step of saving to the file system, and do the whole thing in memory (although, that's not really a model of efficiency, and might not scale well).
Regarding the second part of your question, that's not as straightforward. MVC really has no concept of state (viewstate, etc.), so it doesn't have events that can be fired from a state change (say, navigating away from a page).
You could use Javascript to detect a user navigating away from your page (windows.onunload), that calls a (C#/VB) method to remove the file from the file system. You would probably have to use AJAX to communicate back to the server, using an HTTP POST method, and have something listening at that URL endpoint to fire your method that removes the file.

How to display html email with embedded images (cid)?

I store emails and their attachments in a database. I'm using a WPF WebBrowser and the NavigateToString method to display the html body of emails. It works but when emails use embedded images with a content id (cid), i can't display them. I saved all embedded images as attachments when i save emails in database. I could create and store images in temporary files of the current user and replace cid references with an absolute path on user's disk but i think it's not the best way...
Have you got some ideas ?
I finally found a good way :
I replaced the cid references of all images with base64 image data (RFC 2557) like this :
<img src="data:image/png;base64,RAAAtuhhx4dbgYKAAA7...more data....." alt="test">
You can use the following code to generate the base64 string :
string base64Str = Convert.ToBase64String(File.ReadAllBytes(#"C:\Temp\test.png"));
Remarks : doesn't work with IE6

Categories

Resources