How can I prompt the user for a save location from

2019-09-03 14:44发布

问题:

I have a related question here, where I was trying to create a link to the location of the saved file (where the location and filename are taken care of for the user). Unfortunately, the link won't open the file, due to path access denial (as described in Update 4 in the link above).

What I really would rather do, if possible, is prompt the user for a save location (without requiring them to enter into an input text element something like "C:\Bla\Blee"); I don't think, though, that the tried-and-not-so-true (in this case) FileSaveDialog is available to me from a Sharepoint page.

Are there any alternatives or workarounds so that I can prompt the user for a location?

UPDATE

I don't think this will work to try to save the generated file client-side, because it is generated (via iTextSharp) server-side.

UPDATE 2

By creating a link to the file (as I have done, as hown here), I can right-click said link and select "Save Taget As..." and do so (a "Save As" dialog appears, and I can save the file wherever I want). This being the case, there must be a way to invoke that same dialog programatically so that, instead of the user having to right-click, and then select a menu item ("Save Target As..."), they can simply mash the link and up pops, weasel-like, the "Save As" dialog.

So how can I invoke that obviously invokable dialog in response to a link click?

If see "Total and Payment Total do not match; Please enter the same amount for both values and try again." must redisplay the form (make a "show_sections()" function and call it after the save button runs)?

回答1:

I browsed through your other questions and I just want to make sure that we're clear on a couple of things. (If anything here is blindly obvious please forgive me, I don't intend to be insulting, I just want to make sure we're on the same page.)

First, client and server. Anything server-side runs under the context of a user account and is relative to the machine that it runs on. If you say "save this to the desktop" using server-side code, then this is the server's local process's desktop which almost never makes any sense. If you are impersonating the logged in user, however, this might work except that you are saving it to the logged in user's desktop on the server. If the client and the server are running on the same machine and you are impersonating the client then this might actually completely work. Maybe.

Second, Right-click, Save As. When you right-click a link you are invoking a browser's built-in proprietary menu system. That system is browser and/or OS-specific and is not defined in any specification out there. In the 90's you might have been able to use VBScript to "send keys" and have Internet Explorer "click" that link but those days are long gone. The closest modern equivalent to this would be to write a plugin which I imagine you don't want to do (and would be browser and/or OS-specific).

Third, MIME types. Generally speaking, every HTTP response includes a MIME type which specifies the server's intent for the bytes being sent. These include things like text/html and application/pdf. When server-side code (ASP.Net) doesn't get invoked, for instance static files like images and CSS or even pre-generated files like your PDF, the server (IIS) looks up the file extension in a list to determine what MIME type to send. On the client side the browser uses the MIME type to determine what action to take. If it is text/html it (probably) renders the HTML. If it is application/pdf then the browser looks at its list of MIME types to see if any application has that MIME type registered. Most modern browsers have a built-in PDF renderer so the browser just passes the bytes on to that to render. If the browser isn't aware of that MIME it might ask the OS if it knows about it and has a registered handler available and if so it passes that through. If that all fails (possibly because a user such as me has disabled that specific MIME type) then either the browser just puts those bytes into the "Downloads" folder, it tries to interpret those bytes as text or it prompts to save.

Going a little deeper into this last one, per the HTTP spec (19.5.1 paragraph 3), if you send a MIME type of application/octet-stream in addition to a header of Content-Disposition: attachment; filename="fname.ext" then

the implied suggestion is that the user agent should not display the response, but directly enter a `save response as...' dialog.

This is what you are ultimately trying to achieve, right?

In your case, clicking the PDF link bypasses ASP.Net and IIS just looks up the file and sends the application/pdf MIME type along with it. One fix is to de-register the PDF file extension from the system. This probably isn't the most portable solution, however. Similarly you could also just change the file extension to be application/octet-stream and you (might) get the Save As dialog.

What I would consider the best option for forcing the Save As dialog would be to create a handler of some sort server-side that forces the MIME type and Content Disposition headers into the stream and then passes the file's raw bytes. You could do this in a couple of ways, maybe with an IHttpHandler (maybe even better here) or possibly with just a single ASPX page that inspects the Query String. You'll want to perform some extra security and definitely make sure you don't allow path-like characters and commands in file names.