I'm using MVC 3 and SQL Server 2008 R2.
I'm building a File Management tool for my client, so they can store images and pdfs, and then insert them onto pages.
I've been looking into FILESTREAM in SQL Server, and it looks great. It allows me to store the files, as well as keep a backup of them in case something goes wrong.
But I also want the files stored physically somewhere, so that my client can send a link to someone, like: http://www.mysite.com/files/mydoc.pdf
What's the best practice here? Is it safe and/or smart to use both?
If serving up the files via URL is your only reason for storing on the server too, I'd say that you don't want to do this.
In MVC it's trivial to create a controller action that handles that URL, looks up the file in the DB and returns it to the user. The filename is simply an action parameter in this case, your action logic takes that parameter retrieves the file from the database and return it with a FileStreamResult
return File(fileStream, contentType, fileName);
Here's some more info. About half way down the page shows an example of using FileStreamResult
http://www.mikesdotnetting.com/Article/125/ASP.NET-MVC-Uploading-and-Downloading-Files
Related
The ASP.NET MVC website I'm working on has some (Controller-derived) "user" pages and some (ApiController-derived) "api" pages.
The site uses MiniProfiler to instrument the "user" pages, and I really like what it does. I'd like to have the same or similar functionality in the "api" pages - specifically, a record of the SQL statements that were executed, and how long everything took.
I saw this link which looked promising, where the URL of the entry point is simply entered into the browser address bar, but that's using the default view that comes out of the box with ASP.NET MVC WebApi. My own URLs return an XML document (or JSON response).
Also, I'd prefer something that will allow me to get away from the browser, since my real-life API calls are initiated by another program, and I'd like to be able to record information about a whole session rather than just a single request.
Any advice?
You can have MiniProfiler log it's results to a database instead of disposing of the results. At that point you'll be able to look back at the performance over time (against a session or an end point).
Add:
MiniProfiler.Settings.Storage = new SqlServerStorage("connection string here");
to your settings and it should start logging to the database.
I have a web application running under Windows/IIS that includes some reports via SSRS.
I would like to be able to render a report, somehow save it on the web or SSRS file system, create an encrypted version, and deliver that encrypted file to the user.
I've considered creating a zip file with a password, but not sure about how well that would work.
What would be the best way to do this?
There are a couple of issues in this - and I have to work on the assumption that the purpose of encryption is that you want to be able to distribute the report in a way that only authorized users can view it.
The simplest way of achieving this goal would be to have a login scheme, and serve the report over HTTPS. This means only those who have a log-in can download the report, and it can't be intercepted using network sniffing.
In the past, a client insisted that they wanted to avoid allowing users to download unencrypted files, because they might forward the (unencrypted) report to un-authorized users. To meet this requirement, we created a windows service which created encrypted ZIP files; we used a service because performance tests showed that creating the ZIP in the context of a web request created a serious scalability issue.
The major problem you have with this scheme is distributing decryption keys; making sure everyone has the right key for their report is a huge pain in the backside.
It also didn't prevent users from decrypting the ZIP file and emailing on the unencrypted report - but this was a clear breach of IT policies, which was a harder point to make with unencrypted reports.
Maybe 7-zip or TrueCrypt?
Both require the installation of additional software however. I'm really not sure how strong ZIP file password protection is, so I would be hesitant to go that route without some research.
TrueCrypt is pretty secure, from my understanding.
You'll need a reference in your project to http://<Server Name>/ReportServer/ReportExecution2005.asmx. See the example included in ReportExecutionService.Render Method for how to execute and render a report. You can then take the returned byte array from the render method and create a MemoryStream based on it.
You can perform simple compression using thing in the System.IO.Compression Namespace like this:
public void CompressData(Stream uncompressedSourceStream, Stream compressedDestinationStream)
{
using (DeflateStream compressionStream = new DeflateStream(compressedDestinationStream, CompressionMode.Compress))
{
uncompressedSourceStream.CopyTo(compressionStream);
}
}
public void DecompressData(Stream compressedSourceStream, Stream uncompressedDestinationStream)
{
using (DeflateStream decompressionStream = new DeflateStream(uncompressedDestinationStream, CompressionMode.Decompress))
{
compressedSourceStream.CopyTo(decompressionStream);
}
}
using (FileStream sourceStream = File.OpenRead(#"C:\MyDir\MyFile.txt))
using (FileStream destinationStream = File.OpenWrite(#"C:\MyDir\MyCompressedFile.txt.cp"))
{
CompressData(sourceStream, destinationStream)
}
See the AesCryptoServiceProvider Class for information on how to encrypt data. It shouldn't be hard to modify the example to encrypt a stream instead of a string.
It's also possible to issue certificates to users and perform encryption/decryption based on that but it's more complicated. For that you'll need to look at the System.Security.Cryptography.X509Certificates Namespace.
i'm on a task where I need to create a file serverside and move this file to an USB key.
Is it possible to copy a file from a webserver to an USB Key ?
(any security issues)
Furthermore the user needs to indicate to which path the file needs to be saved on. Is there a control like the asp upload control, where the user can browse to the right directory or is the simple solution to use a textbox, where the user can write e.g. "E:\mygeneratedfiles"
The USB key is on the users local machines
From the ASP.NET perspective, you can return the file in HTTP response, but once the file is sent to the client web browser, you're pretty much out of luck.
There might be something you can do with javascript to streamline the saving process (not my area of expertise), but accessing the client's filesystem directly, especially writing to it, is out of the question. If you want to do that you'll have to write an ActiveX control or similar type of plugin.
Edit:
For returning the file in the HTTP response, load your file in to a 1-dimensional byte array and use the following code pattern:
context.Response.Clear()
context.Response.AddHeader("content-disposition", "attachment;filename=" & objFile.FileName)
context.Response.BinaryWrite(objFile.FileImage)
context.Response.End()
In this example objFile.FileName is the file name string and objFile.FileImage is a Byte array containing the file. context is the current HttpContext.
Use this Code samples on this FileUpload control page
I'm currently using Spring MVC.
What I'm looking to do is have a web page where once the user submits a form, the controller writes a file to the output stream then flushes it, so the user may save the file. But I would then like the contoller to return a modelview, taking the user to another page.
At the moment once the output stream has been flushed, when the modelview get's returned, I end up with a "getOutputStream() has already been called for this response" error. (Normally I would return null after flushing the output stream to avoid this error).
So what I'm asking is, is there a way I can flush the output stream so the user can download the file and then return a modelview so the user is taken to another page?
Cheers.
I don't think what you're looking for is exactly possible, no matter what web framework you use. Best alternative I can think of is doing it the way Sourceforge.net processes downloads, e.g. a page with 'your download will start shortly', here's an example. (click the download link on the page)
You definitely can't redirect to a 2nd page if you've already begun writing to the output stream; this is part of the servlet spec rather than any one MVC framework
I need to export a large amount of data (~100mb) from a sql table to a user via the web. What would be the best solution for doing so? One thought was to export the data to a folder on the db server, compress it (by some means) and then provide a download link for the user. Any other methods for doing so? Also, can we compress data from within sql server?
Any approaches are welcome.
I wouldn't tie up the database waiting for the user to download 100Mb, even for a high speed user. When the user requests the file have them specify an email address. Then call an asynch process to pull the data, write it to a temp file (don't want > 100mb in memory after all), then zip the temp file to a storage location, then send the user an email with a link to download the file.
You can respond to a page request with a file:
Response.AddHeader("Content-Disposition",
"attachment; filename=yourfile.csv");
Response.ContentType = "text/plain";
Be sure to turn buffering off, so IIS can start sending the first part of the file while you are building the second:
Response.BufferOutput = false;
After that, you can start writing the file like:
Response.Write("field1,field2,field3\r\n");
When the file is completely written, end the response, so ASP.NET doesn't append a web page to your file:
Response.End();
This way, you don't have to write files on your web servers, you just create the files in memory and send them to your users.
If compression is required, you can write a ZIP file in the same way. This is a nice free library to create ZIP files.
Your approach works fine. SSIS + 7zip might be useful for automating the process if you need to do it more than a couple times.
If XML is OK, one approach would be to select the data "FOR XML" like this:
http://www.sqljunkies.ddj.com/Article/296D1B56-8BDD-4236-808F-E62CC1908C4E.scuk
And then spit out the raw XML directly to the browser as content-type: text/xml. Also be sure to set up Gzip compression on your web server for files with XML extensions. http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/502ef631-3695-4616-b268-cbe7cf1351ce.mspx?mfr=true
This will shrink the XML file down to 1/3 or maybe 1/4 the size as it's transferred. This wouldn't be the highest performance option because of the inherent wasted space in XML files, but a lot depends on what format you're looking for in the end.
Another option would be to use the free CSharpZipLib to compress the XML (or whatever format you want) into a zip file that the user would download. Along those lines, if this is something that will be used frequently you might want to look into caching and storing the zip file on the web server with some sort of expiration so it's not regenerated for every single request.
The download link is a perfectly valid and reasonable solution. Another would be to automatically redirect the user to that file so they didn't need to click a link. It really depends on your workflow and UI experience.
I would suggest against implementing compression in the SQL Server engine. Instead look at the DotNetZip library (Or System.IO.Conpression if you think your users have the capability of uncompressing gzip archives) and implement the compression within the web application.