Asp.net C# custom file handler - c#

I would like to receive files from an asp.net website but I would like to verify the request with data in a database before serving the file to the client.
For images I would be loading using a standard html image tag like this:
'<img src="/Uploads/RANDOMGUID/img.aspx" alt="The Moon" title="The Moon">
The requests will have a random GUID in the path which maps to a field in the database for the stored image.
I would like to have one entry point for all the requests this could be an aspx or ashx page for example [unless there there is a better way], this would then:
Parse the GUID out of the request path
Verify if the requester has access to the requested image or file using database data
Return an error image or file if not authorized
If authorized return the file contents and set the content type
How should I implement such functionality? Do I need a site wide file extension which is handled in an aspx file and returns a custom file content type?

First, put image files into directory that can't be accessed by user directly.
Then change path like this:
<img src="/Uploads/img.aspx?id=RANDOMGUID" alt="The Moon" title="The Moon">
That way, you can get ID from Request.QueryString["id"] and do the checking.
It's much easier than path you wanted because it will always go to same aspx page. With original path you would have to do path mapping and complicate your life without need.
After checking in database you can use Response.WriteFile to send appropriate file. Check https://msdn.microsoft.com/en-us/library/dyfzssz9%28v=vs.110%29.aspx for details.
EDIT: This was regarding getting ID of image. As #mason pointed out, you should register handler and use .ashx extension as you don't really need view.

Related

Generate in-memory path for a saved XML document and serve to AJAX to be displayed

So, I have been running into all kinds of CORS errors (when using HTTPS) and Not allowed to load local resource: file:///C:/Windows/TEMP/e3ef26_75603_4.xml when saving my file to a temp folder and then trying to serve the request via AJAX to be displayed on my browser.
Basically the scenario is that I am requesting a file from a S3 bucket. Now there are couple of things that I tried:
By directly giving the full file path (HTTPS) with associated bucket and file name to a AJAX call. This is done by first generating the file path on the Controller method and assigning a ViewBag variable. Something like:
ViewBag.currentURL = JsonConvert.SerializeObject(tempfilepath);
And associated AJAX:
$(function executeXML() {
//console.log('#Html.Raw(ViewBag.currentURL)');
$("#myeditor").execute({
ajaxOptions: {
pathtoxml: #Html.Raw(ViewBag.currentURL)
},
});
});
This method works quite well when the S3 bucket has public access and the CORS policies are there for the bucket.
Problem: Using this method on a S3 bucket that has no public access and no CORS policies will result in the No 'Access-Control-Allow-Origin' header is present on the requested resource from any browser.
Sigh! But not yet,
The second method that I was trying to do is to read the file on the server side and save it to a XML document. Now when I want to save this XML document, I use a temp folder to save my file. Something like this:
using (WebClient client = new WebClient())
{
string myXMLString = client.DownloadString(fullpathstory);
XmlDocument xml = new XmlDocument();
xml.LoadXml(myXMLString); // suppose that myXmlString contains "<Names>...</Names>"
//Now save the file to temp folder
tempfilepath = Path.Combine(Path.GetTempPath(), filename);
xml.Save(tempfilepath);
}
This gives me a path like: file:///C:/Windows/TEMP/e3ef26_75603_4.xml
Now when I am sending this path to my AJAX, it gives me the error jquery.min.js:4 Not allowed to load local resource: file:///C:/Windows/TEMP/e3ef26_75603_4.xml which is quite obvious and expected.
Question: I am looking for a way to save my XML document in-memory and generate a path or a stream that can be read by my AJAX call and serve it on the browser.
Is there such a way or do I need to create a proper file sever where I store all my generated XML files and then read from that location. It would basically be a temp server folder but then I would need to keep monitoring the ever increasing size of it.
Thanks in advance
Rather than pre generating the file, i would recommend to generate file on demand. The moment user issues an ajax request for file, file would be generated in memory, converted to byte array, returned to client (as a base64 encoded string) and download would start at client's end.

InsertInlineImage or ReplaceImage URI

I'm writing a WinForms application. I created a Google Doc template file that contains placeholders like {{name}} for various text elements. I can successfully make a copy of this document and use the BatchUpdateDocumentRequest to modify them just fine.
However, I also have an embedded image in the document. I can obtain the objectId for this image just fine. I either want to replace this image with another or remove it from my template and then append my new image to the end of the document. In both cases, the InsertInlineImage or ReplaceImage classes require a URI of the image to insert or replace with. This is where I have an issue.
The image itself has been captured from a control on the WinForms. Its actually a chart. I've saved the image in PNG format since I know that is one of the formats supported by Google drive/docs. I figured in order to use it in the batch update, I would need to upload it first, so I did and got its file id and webcontentlink back in the response.
I'm not locked into any particular way of doing this. I originally tried creating an HTML file, uploading but then it would strip the image from it, so became useless, so I switched gears to using a Google Doc as my template and just try to replace elements in it instead. This went well until I got to the image.
Essentially no matter what I try to specify as the URI, it says the file in not in a supported format.
As far as I can tell, Google expects the URI to actually end in .png or be a real link versus a download URL you'd get from Google Drive.
Here is an example of the code I'm using to attempt to replace the image. The strImageObjectId is the objectId of the Embedded Object image in the template document copy that I want to replace. The Uri is what Google needs to pull the new image from. I'm happy to pull it from my local computer or Google Drive if only I could get it to accept it somehow.
BatchUpdateDocumentRequest batchUpdateRequest = new BatchUpdateDocumentRequest {
Requests = new List<Google.Apis.Docs.v1.Data.Request>()
};
request = new Google.Apis.Docs.v1.Data.Request {
ReplaceImage = new ReplaceImageRequest() {
ImageObjectId = strImageObjectId,
Uri = strChartWebContentLink
}
};
batchUpdateRequest.Requests.Add(request);
DocumentsResource.BatchUpdateRequest updateRequest =
sDocsService.Documents.BatchUpdate(batchUpdateRequest, strCopyFileId);
BatchUpdateDocumentResponse updateResponse = updateRequest.Execute();
I'm happy to use whatever method will get me to a point where I an end up with a Google Doc on Google Drive that was based on a template in which I can replace various text elements, but most importantly add/replace an image.
Thanks so much for the advice.
I got to the point were I believe I was specifying the URI correctly, but then I started getting an access forbidden error instead.
I didn't have time to hunt this one down, so I went back to creating an HTML template with my image, uploading as a Google Doc, exporting to PDF, and then uploading as a PDF. This ended up working because originally I was using a BMP as the file format and that is not supported by Google Docs, so I changed to a PNG instead and it worked just fine.
I think Google Docs needs to add the ability to add an image using a MemoryStream or some other programmatic base64 resource instead of purely being based on URIs and running into temporary upload or permission issues.
Hey I'm doing the same thing with you,
and I got this, by modify the download link format.
from this:
https://docs.google.com/uc?export=download&id={{YOUR GDRIVE IMAGE
ID}
to this
https://docs.google.com/uc?export=view&id={{YOUR GDRIVE IMAGE ID}
e.g :
uri: "https://docs.google.com/uc?export=view&id=1cjgyHqtYSgS0CBT4x-9eQIHRzOIfGgv-"
but the image should be set for public privilege

Create image from "src" coming from html in c#

I want to know how to create an image object having the "src info from an email". I already manage to get read the inbox, and to parse the html of it, and get out all of the "src = foo" from all the images in the email. My question is how do I then proceed to create an image using the information taken out from "src" in the of the html. I need this object in order to store it in a sharepoint picture library. Just want to know how to create the image object of the image stored in the html of the email.
Not sure about how to put it in SharePoint, but assuming you have a src in an extractedSrc variable:
WebClient webClient = new WebClient();
webClient.DownloadFile(extractedSrc, localFileName)
I guess there are two basic cases you have to consider, 1. The src attribute points to an external image (ie. image stored on a web site), 2. Src points to an image attached in the email.
For case 1. You need to download the image from the external server and then you can save it in your share point
For case 2. You have to decode the attachment sections of the email to extract the file data and then you can save it to your library

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.

Render image from byte[] that is not in the DB in ASP.NET MVC3

This is a variation on a question that has been asked here several times. One example: Display an image contained in a byte[] with ASP.Net MVC3. The question is how to render an image from a byte array.
In all those questions, there is an Action similar to one of the answers in the link I provided above:
public FileContentResult Display(string id) {
byte[] byteArray = GetImageFromDB(id);
return new FileContentResult(byteArray, "image/jpeg");
}
With an image tag similar to this:
<img src="#Url.Action("Display", new { id = Model.Id })" />
This is done because it's not possible to send a byte array through a GET request, so just the id is sent allowing a lookup in the Action method. I get this part, it's not the problem. What I'm trying to do is create a 'Preview' page, where they can check their work before saving in the database. They can see the layout of the Title, Text and Image and decide whether to save, or go back and Edit some more. Therefore, the 'GetImageFromDB(id)' part won't work, since the object has not been saved yet to the database.
Is there any way to accomplish this, or do I just have to save the byte array temporarily in the database and access it that way for the Preview page?
You need to store the uploaded file somewhere on the server if you want to show it later (as a preview or full size image). Whether it is the database or the file system it is up to you. So once the file is uploaded you could store it as a temporary file on some location on the server by renaming it using some unique Guid and return this Guid to the client so that it can create an action link to a preview controller action passing the Guid which will fetch the file from the temporary location and stream it to the client.

Categories

Resources