Expose url to webservice - c#

In our project we want to query a document management system for a specific document or movie. The dms returns a URL with the document location (for example: http://mydomain.myserver1.share/mypdf.pdf or http://mydomain.myserver2.share/mymovie.avi).
We want to expose the document to internet users and intranet users. The requested file can be large (large video files).
Our architecture is like:
request goes like: webapp1 -> webapp2 -> webapp3 -> dms
response goes like: dms -> webapp3 -> webapp2 -> webapp1
webapp1 could be on the internet.
I have have been thinking how we can obfuscate the real url from the dms, due to security issues. I have seen implementations from other webapps where the pdf URL was obfusicated by creating a temp file for the requested document that is specific for the session and user. So other users cannot easily guess the documentname of other users.
My question: is there a pattern that deals with exposing company/user vulernable data to the public ?
Our development is in C# 3.5.

The easiest way to handle it is to create a ashx file (or some other way of creating a URL) and have it serve the pdf. Since WCF supports REST you could always do it through that too. Just load the pdf into memory and push the byte contents into the response stream.
Alternatively, you might want to look into these:
http://www.microsoft.com/forefront/edgesecurity/isaserver/en/us/
http://www.isapirewrite.com/

Related

How to store & retrieve uploaded images across Load Balanced servers with ASP.NET?

My ASP.NET MVC application will be deployed to a series of load-balanced web servers. One problem I'm still working out is how to handle dynamically-uploaded file content, such as user-uploaded images -- obviously, saving them on the server where they were uploaded won't allow them to be accessed from the other servers in the load balanced group.
Currently I'm planning to save these to a shared storage location, specifically a UNC path referring to a directory on our NAS; but I'm not sure how best to retrieve these files to display them to the client. I'm thinking I'll need to write a custom route handler of some kind to retrieve them from the non-web-accessible storage location on the server side and then stream them back to the client. This seems relatively straightforward to do, yet I'm struggling with how to begin to approach this in ASP.NET.
Another solution I've considered is creating a Virtual Directory in each application directory which points to the network directory.
I've even considered uploading the files to Amazon S3 (via the file upload handling code) and using CloudFront to delivery them, but I'd rather avoid the external service dependency.
Which approach do you recommend, and are there established best practices or even existing components/libraries available for accomplishing this sort of thing?
In ASP.NET MVC you can handle this with a controller action, like so:
public class SharedImageController : Controller {
public ActionResult GetImage(String imageId) {
String uncPath = GetImageUncLocationFromId( imageId );
Response.ContentType = "image/jpeg"; // change as appropriate
return new FileResult( uncPath );
}
}
and in your HTML:
<img src="<%= Url.Action("GetImage", "SharedImage", new { imageId = "SomeImage.jpg" } %>" alt="Some descriptive text" />
You could make a custom HtmlHelper extension method to make this less error-prone if you'll be using this a lot.
i think there are 2 ways to fix it
1.use a tool synchronous files between machines
it makes duplicate files,per machine has same file
2.upload file to a net address like //192.168.1.1/upload,and host a website on iis like img.domain.com,than img url use this domain
file not duplicate,so you should make sure the browser can find it.the img domain not balance
or upload file to a cloud service

PDF binary data output in .NET

I have a question about outputting PDF files. Currently I'm storing the PDF in the database in binary form. I'm outputting the PDF file via a URL such as:
http://myhost.com/FileManager.aspx?FileId=8465b2f9-b64e-4a9a-a449-94b5adb3b278
so from what I could deduce, to the browser this is an .aspx page that is loading and not a PDF. Firefox and IE interpret this correctly and launch Adobe Acrobat, however since Chrome (12.0.742.112) has its own implementation of a PDF reader, it will open the file correctly, but then when someone goes to save the file in chrome, it wants to save it as a .aspx. If I simply rename the .aspx to .pdf, the file downloads correctly. However, I"m trying to avoid telling my customer that s/he may have to take that extra step.
When I chose to look at the headers that loaded in Chrome via Web Inspector, I see this:
FileManager.aspx:-1 Resource interpreted as Document but transferred
with MIME type application/pdf
I can completely understand why Chrome would say this.
Furthermore, I get a save as box upon page load when I add:
Response.AddHeader("content-disposition", "attachment;filename=blah.pdf");
However, I was hoping to just keep the file in a browser. So aside from using some URL Rewrite, is there a way I can manipulate the HTTP Headers to simply open the page as a PDF and save correctly in Chrome?
Lastly, I tried using a WebService, but I can't seem to write the binary data to the page.
this.Context.Response.BinaryWrite(bytes);
Any help is appreciated!
In the web application's top-level web.config, add the following <add> element to the <httpHandlers> section:
<httpHandlers>
<add verb="*" path="FileManager.pdf" type="ProjectName.FileManager" />
...where ProjectName.FileManager is the full name (namespace and classname) of the FileManager class in FileManager.aspx.cs.
This tells ASP.NET to handle the path /FileManager.pdf using the handler defined by ProjectName.FileManager. (System.Web.UI.Page implements the IHttpHandler interface, so every webform is a handler.)
Now you can serve the PDFs via a URL with a .pdf extension like so:
http://myhost.com/FileManager.pdf?FileId=8465b2f9-b64e-4a9a-a449-94b5adb3b278
You do not need to rename the physical FileManager.aspx file. When the user enters /FileManager.pdf?FileId=foo in the browser, ASP.NET will handle the request with the ProjectName.FileManager class defined in FileManager.aspx.
Note:
The above should work on Cassini (the Visual Studio "mini" webserver) with no further changes. However IIS by default only sends *.aspx, *.asmx, *.ashx requests to ASP.NET. Therefore, for the above to work on IIS, you need to tell it to send requests for /FileManager.pdf to ASP.NET. That is, you need to configure a "mapping".
With IIS 6 you need to configure the mapping using IIS manager.
With IIS 7 you can configure a mapping from your web.config--this makes deployment easier, but it depends on how your hosting is set up.
Something that worked for me was to add the intended filename between the application page name (in your case, FileManager.aspx) and the query mark (the ? mark).
So, in the end, you'd have something like this:
http://myhost.com/FileManager.aspx/myfile.pdf?FileId=8465b2f9-b64e-4a9a-a449-94b5adb3b278
Surprisingly, the correct application will run (Filemanager.aspx), the variables will be passed unharmed (FileId), the result will be treated as inline (if you didn't change it to attachment, that is) but the browser will think that the filename to use, in case the user wants to save the page, is myfile.pdf.

ASMX file upload

Is there a way to upload a file from local filesystem to a folder in a server using ASMX web services(no WCF, don't ask why:)?
UPD
P.S.file size can be 2-10 GB
Sure:
[WebMethod]
public void Upload(byte[] contents, string filename)
{
var appData = Server.MapPath("~/App_Data");
var file = Path.Combine(appData, Path.GetFileName(filename));
File.WriteAllBytes(file, contents);
}
then expose the service, generate a client proxy from the WSDL, invoke, standard stuff.
--
UPDATE:
I see your update now about handling large files. The MTOM protocol with streaming which is built into WCF is optimized for handling such scenarios.
When developing my free tool to upload large files to a server, I am also using .NET 2.0 and web services.
To make the application more error tolerant for very large files, I decided to not upload one large byte[] array but instead do a "chuncked" upload.
I.e. for uploading a 1 MB file, I do call my upload SOAP function 20 times, each call passing a byte[] array of 50 KB and concating it on the server together again.
I also count the packages, when one drops, I try to upload it again for several times.
This makes the upload more error tolerant and more responsive in the UI.
If you are interested, this is a CP article of the tool.
For very large files, the only efficient way to send them to web services is with MTOM. And MTOM is only supported in WCF, which you have ruled out. The only way to do this with old-style .asmx web services is the answer that #Darin Dimitrov gave. And with that solution, you'll have to suffer the cost of the file being base64 encoded (33% more bandwidth).
We had the same requirement, basically uploading a file via HTTP POST using the standard FileUpload controls on the client side.
In the end we just added an ASPX page to the ASMX web service project (after all its just a web project) - this allowed us to upload to i.e. http://foo/bar/Upload.aspx when the web service was at http://foo/bar/baz.asmx. This kept the functionality within the web service, even though it was using a separate web page.
This might or might not fit your requirements, #Darins approach would work as a workaround as well but you would have to make modifications on the client side for that, which wasn't an option for us.
You can try to convert the file to Base64 and pass it as a string to the service and then convert back to a byte array.
https://forums.asp.net/t/1980031.aspx?Web+Service+method+with+Byte+array+parameter+throws+ArgumentException
How to convert file to base64 in JavaScript?
The input is not a valid Base-64 string as it contains a non-base 64 character

How can you configure or extend BITS (Background Intelligent Transfer Service) to read files from a Sql Server Database

I have a ASP .NET load balanced application (webservice and website). It runs on SQL server. I need to be able to provide large files for download. However, because of the load balancing situation, the files are stored in the SQL database as opposed to the file system. BITS seems to be the best approach. I have full control of the client. However, i don't know how to configure BITS to read the file from the database. I know how to write the C# code for that, but i don't know how to get BITS to hook into it as opposed to reading the file from the file system.
Any ideas?
You can create a custom http handler by implementing System.Web.IHttpHandler. The ProcessRequest(HttpContext context) method is where you will write your file retrieval code from the database. Since BITS operates with range requests you will need to parse the value of context.Request.Headers["Range"] to get the start and end bytes requested. In the ProcessRequest you can read the binary from the database using the SqlCommand.ExecuteReader(CommandBehavior.SequentialAccess) method and set the resulting binary in context.Response.OutputStream. Remember to call context.Response.Flush() at the end.
The custom HttpHandler will serve a particular file extension (e.g. '.file'). This is what needs to be done in IIS:
Both IIS Versions
Add to section in in web.config:
IIS 6.0
Add .file (application/x-zip-compressed) extension as MIME type for the website.
Add Application Extension (Website Properties  Virtual Directory  Configuration  Mappings)
Extension: .file
Executable Path(s): %windir%\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll
%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll
IIS 7.0
Add to section in in web.config:
Add to section in in web.config:
<mimeMap fileExtension=".file" mimeType="application/x-zip-compressed" />
Hope that's enough to get you started.
Have a look at 2008 Books Online OpenSqlFilestream. That API has examples that may help you.

Static files and authentication in ASP.net

Say I have a virtual folder /topFolder/ in IIS7, and in that folder there can be any file that can be displayed in a browser (xml, html, swf, doc etc - typically "unmanaged" resources from the IIS perspective).
Before giving the request permission to open any file below the folder, I need to check some session variables in order to see if the user has a "license" for the subfolder and file in question.
I've tried implementing a module with IHttpModule and IReadOnlySessionState interfaces, but the Session is always null on the AcquireRequestState event when the file is "static" and not IIS managed (like aspx, ashx etc).
If I use a custom HttpHandler, I get the session, but then I also need to implement how the content is sent to response. Edit: Since the user isn't downloading the file, I just want IIS to serve the file like it does with its StaticFileModule. The Handler/Module should really be a StaticFileModuleWithAuthorizationHook...
So I really want to do the following:
1. For request /topFolder/* : check session and licenses etc
a) If ok, continue serving file
b) If not ok, interrupt request, or just send FORBIDDEN in response.
Hope someone can help.
You should be able to handle this via the httphandler, the simple way is to use the built in methods to send the file down to the user if they have access.
This article (at the bottom) shows an example of how to do this.

Categories