I'm developing a web app which allow the user to upload and view PDF files.
My question is where should I store the file uploaded by the user? They said that it takes a great toll storing it in the database. So if not in the database where should I store the files uploaded by the user? Can you give me a specific or sample path where I should store the files?
By the way I'm using Spring MVC if it would help to clarify my question.
And also this is what I've done with my controller so far:
#RequestMapping( value = "*/uploadPDF", method = RequestMethod.POST )
public String uploadPDF( #RequestParam( defaultValue = "" )
String message, #RequestParam( defaultValue = "" )
String messageType, HttpServletRequest request, ModelMap model, FileBean fileBean, BindingResult result )
{
model.addAttribute( "message", message );
model.addAttribute( "messageType", messageType );
HttpSession session = request.getSession();
String returnVal = Credentials.checkSession( session );
if( returnVal != null )
{
return returnVal;
}
if( result.hasErrors() )
{
for( ObjectError error : result.getAllErrors() )
{
System.err.println( "Error: " + error.getCode() + " - " + error.getDefaultMessage() );
}
return "redirect:*/module?error";
}
return "admin/module";
}
I haven't decided yet of how would I handle the file yet. Please guide me.
When it comes to storing a files, you have many options... It really depends on your use case.
You can store the file in the database as a lob. Generally, it would be slower with more overhead, but you can access it from any application that has a database connection.
You can store your file on your application server FileSystem. this is probably the best solution if you want it to be very effective.
You can put your files in a content repository (Ex Apache Jackrabbit). It can be a good option if you want to share your file across multiple applications.
...
What are your requirements? Confidentiality, performance, files availability...
Related
I have a very unusual problem.
I'm trying to create a simple database (6 tables, 4 of which only have 2 columns).
I'm using an in-house database library which I've used in a previous project, and it does work.
However with my current project there are occasional bugs. Basically the database isn't created correctly. It is added to the sdcard but when I access it I get a DatabaseException.
When I access the device from the desktop manager and try to open the database (with SQLite Database Browser v2.0b1) I get "File is not a SQLite 3 database".
UPDATE
I found that this happens when I delete the database manually off the sdcard.
Since there's no way to stop a user doing that, is there anything I can do to handle it?
CODE
public static boolean initialize()
{
boolean memory_card_available = ApplicationInterface.isSDCardIn();
String application_name = ApplicationInterface.getApplicationName();
if (memory_card_available == true)
{
file_path = "file:///SDCard/" + application_name + ".db";
}
else
{
file_path = "file:///store/" + application_name + ".db";
}
try
{
uri = URI.create(file_path);
FileClass.hideFile(file_path);
} catch (MalformedURIException mue)
{
}
return create(uri);
}
private static boolean create(URI db_file)
{
boolean response = false;
try
{
db = DatabaseFactory.create(db_file);
db.close();
response = true;
} catch (Exception e)
{
}
return response;
}
My only suggestion is keep a default database in your assets - if there is a problem with the one on the SD Card, attempt to recreate it by copying the default one.
Not a very good answer I expect.
Since it looks like your problem is that the user is deleting your database, just make sure to catch exceptions when you open it (or access it ... wherever you're getting the exception):
try {
URI uri = URI.create("file:///SDCard/Databases/database1.db");
sqliteDB = DatabaseFactory.open(myURI);
Statement st = sqliteDB.createStatement( "CREATE TABLE 'Employee' ( " +
"'Name' TEXT, " +
"'Age' INTEGER )" );
st.prepare();
st.execute();
} catch ( DatabaseException e ) {
System.out.println( e.getMessage() );
// TODO: decide if you want to create a new database here, or
// alert the user if the SDCard is not available
}
Note that even though it's probably unusual for a user to delete a private file that your app creates, it's perfectly normal for the SDCard to be unavailable because the device is connected to a PC via USB. So, you really should always be testing for this condition (file open error).
See this answer regarding checking for SDCard availability.
Also, read this about SQLite db storage locations, and make sure to review this answer by Michael Donohue about eMMC storage.
Update: SQLite Corruption
See this link describing the many ways SQLite databases can be corrupted. It definitely sounded to me like maybe the .db file was deleted, but not the journal / wal file. If that was it, you could try deleting database1* programmatically before you create database1.db. But, your comments seem to suggest that it was something else. Perhaps you could look into the file locking failure modes, too.
If you are desperate, you might try changing your code to use a different name (e.g. database2, database3) each time you create a new db, to make sure you're not getting artifacts from the previous db.
The problem with flex applications is that a user can download it and run it on his local machine or possibly host it on another site. Is it possible to lock a flex application to a domain name to prevent such acts?
Sure, you'll do something like this in your application initialization area :
var domainList : String = 'mysite.com,anothersite.com';
var domainCheck : String = this.url.split('/')[2];
var foundValidDomain : Boolean = false;
for each ( var domainChecking : String in domainList.split(',')){
if( domainCheck.toUpperCase().indexOf(domainChecking.toUpperCase()) >= 0 ){
mx.controls.Alert.show( 'check success: "' + domainCheck + '" against: "' + domainChecking );
foundValidDomain = true;
break;
}else{
mx.controls.Alert.show( 'check failed: "' + domainCheck + '" against: "' + domainChecking );
}
}
if( !foundValidDomain ){
// oh noes! mad hax!
this.visible = false; // or however you want to lock it down
return;
}
Make sense? :)
Now, if you want to lock it down more, you can have your app post to a server with a key string and have the server send some encrypted time-sensitive instructions back (send date/time to server and back, etc). This would add another layer of hassle having to implement the server side as well. This is probably overkill for most applications.
You'll have to write the code yourself, but you could access the URL variable of the application tag and disable the app if the domain is not your domain.
I wouldn't call this an unbeatable measure, but I don't think anything is.
I'm not sure why this 'problem' is unique to Flex applications.
Take a look at this link http://www.richardlord.net/blog/protecting-a-swf
Basically, you can solve the problem by locking down the domain as you say, and also you can potentially encrypt your code using commercial solutions - which are discussed in the link. I think the main point is if you publish Flex code externally you want people to run it.
I use ASP.NET
I need to give user temporary link for downloading file from server.
It should be a temporary link (page), which is available for a short time (12 hours for example). How can I generate this link (or temporary web page with link)?
Here's a reasonably complete example.
First a function to create a short hex string using a secret salt plus an expiry time:
public static string MakeExpiryHash(DateTime expiry)
{
const string salt = "some random bytes";
byte[] bytes = Encoding.UTF8.GetBytes(salt + expiry.ToString("s"));
using (var sha = System.Security.Cryptography.SHA1.Create())
return string.Concat(sha.ComputeHash(bytes).Select(b => b.ToString("x2"))).Substring(8);
}
Then a snippet that generates a link with a one week expiry:
DateTime expires = DateTime.Now + TimeSpan.FromDays(7);
string hash = MakeExpiryHash(expires);
string link = string.Format("http://myhost/Download?exp={0}&k={1}", expires.ToString("s"), hash);
Finally the download page for sending a file if a valid link was given:
DateTime expires = DateTime.Parse(Request.Params["exp"]);
string hash = MakeExpiryHash(expires);
if (Request.Params["k"] == hash)
{
if (expires < DateTime.UtcNow)
{
// Link has expired
}
else
{
string filename = "<Path to file>";
FileInfo fi = new FileInfo(Server.MapPath(filename));
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.WriteFile(fi.FullName);
Response.Flush();
}
}
else
{
// Invalid link
}
Which you should certainly wrap in some exception handling to catch mangled requests.
http://example.com/download/document.pdf?token=<token>
The <token> part is key here. If you don't want to involve a database, encrypt link creation time, convert it to URL-safe Base64 representation and give user that URL. When it's requested, decrypt token and compare date stored in there with current date and time.
Alternatively, you can have a separate DownloadTokens table wich will map said tokens (which can be GUIDs) to expiration dates.
Append a timestamp to the URL, in the querystring:
page.aspx?time=2011-06-22T22:12
Check the timestamp against the current time.
To avoid the user changing the timestamp by himself, also compute some secret hash over the timestamp, and also append that to the querystring:
page.aspx?time=2011-06-22T22:12&timehash=4503285032
As hash you can do something like the sum of all fields in the DateTime modulo some prime number, or the SHA1 sum of the string representation of the time. Now the user will not be able to change the timestamp without knowing the correct hash. In your page.aspx, you check the given hash against the hash of the timestamp.
There's a million ways to do it.
The way I did once for a project was to generate a unique key and use a dynamic downloader script to stream the file. when the file request was made the key was generated and stored in db with a creation time and file requested. you build a link to the download script and passed in the key. from there it was easy enough to keep track of expiration.
llya
I'll assume you're not requiring any authentication and security isn't an issue - that is if anyone gets the URL they will also beable to download the file.
Personally I'd create a HttpHandler and then create some unique string that you can append to the URL.
Then within the ProcessRequest void test the encoded param to see if it's still viable (with in your specified time-frame) if so use BinaryWrite to render the File or if not you can render some HTML using Response.Write("Expired")
Something like :
public class TimeHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest ( HttpContext context )
{
if( this.my_check_has_expired( this.Context.Request.Params["my_token"] ) )
{
// Has Expired
context.Response.Write( "URL Has Expired" );
return;
}
// Render the File
Stream stream = new FileStream( File_Name , FileMode.Open );
/* read the bytes from the file */
byte[] aBytes = new byte[(int)oStream.Length];
stream.Read( aBytes, 0, (int)oStream.Length );
stream.Close( );
// Set Headers
context.Response.AddHeader( "Content-Length", aBytes.Length.ToString( ) );
// ContentType needs to be set also you can force Save As if you require
// Send the buffer
context.Response.BinaryWrite( aBytes );
}
}
You need to then setup the Handler in IIS, but that a bit different depending on the version you're using.
... and not by reading it from the config file! Nor inferring it from anyplace other than be reading exactly what the Membership Provider is itself using. Call me paranoid.
The first data access in my application is an access to the membership provider. The vast majority of connectivity issues have been where the application is deployed to staging or production with a connection string from development, so I'd like to change this:
MembershipUser me = Membership.GetUser();
to this:
MembershipUser me;
try
{
me = Membership.GetUser();
}
catch ( SqlException E )
{
Response.Write( "SQL Error " + E.Message + ".<br />" );
Response.Write( "Connection String: " + Membership.Provider.WHAT? + "<br />" );
}
Seems so obvious, but every reference I find instructs me to use the ConfigurationManager, which is what I specifically don't want to do. Although I concede that such may be my only option, and a satisfactory one at that.
I'm perfectly willing to accept the possibility that my question is on par with this:
int i;
try
{
i = 42;
}
catch ( Exception e )
{
Response.Write( "Error assigning literal to integer." );
}
If this is the case, please comment accordingly.
I don't believe there is a direct property that you can use that will give you the connection information. One thing you could do though is subclass your chosen membership provider and implement your own properties to give you the info.
It's generally considered a bad idea to surface connection strings in the UI (i.e. poor security) which is why you won't find readily available properties to pass on the value from classes that have read it from the config file.
You may want to consider addressing the root cause of the problem which is related to deployment. This problem is easily solved by using different configuration files for development, staging and production. Visual Studio has built-in support for automatically managing the deployment of the appropriate config file. Full details here:
http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx
Hi Here is a way to get connection string from or by the specified Provider Name (ex MySQL provider).
using MySql.Data.MySqlClient;
using MySql.Data;
using MySql.Web.Security;
using System.Collections.Specialized;
using System.Reflection;
void SomeFunction()
{
Type t = Membership.Provider.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField("connectionString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
MySql.Web.Security.MySQLMembershipProvider a =(MySql.Web.Security.MySQLMembershipProvider)Membership.Provider;
string Connection_String_Value= fi.GetValue(a).ToString();
}
By replace 'connectionString' with other Non-Public field name You
can Access its Value too.
By replacing Provider(default) with
Membership.Providers["Name_Of_Your_Provider"] you can get its
connection string too.
My ASP.NET MVC application will take a lot of bandwidth and storage space. How can I setup an ASP.NET upload page so the file the user uploaded will go straight to Amazon S3 without using my web server's storage and bandwidth?
Update Feb 2016:
The AWS SDK can handle a lot more of this now. Check out how to build the form, and how to build the signature. That should prevent you from needing the bandwidth on your end, assuming you need to do no processing of the content yourself before sending it to S3.
If you need to upload large files and display a progress bar you should consider the flajaxian component.
It uses flash to upload files directly to amazon s3, saving your bandwidth.
The best and the easiest way to upload files to amazon S3 via asp.net . Have a look at following blog post by me . i think this one will help. Here i have explained from adding a S3 bucket to creating the API Key, Installing Amazon SDK and writing code to upload files. Following are are the sample code for uploading files to amazon S3 with asp.net C#.
using System
using System.Collections.Generic
using System.Linq
using System.Web
using Amazon
using Amazon.S3
using Amazon.S3.Transfer
///
/// Summary description for AmazonUploader
///
public class AmazonUploader
{
public bool sendMyFileToS3(System.IO.Stream localFilePath, string bucketName, string subDirectoryInBucket, string fileNameInS3)
{
// input explained :
// localFilePath = we will use a file stream , instead of path
// bucketName : the name of the bucket in S3 ,the bucket should be already created
// subDirectoryInBucket : if this string is not empty the file will be uploaded to
// a subdirectory with this name
// fileNameInS3 = the file name in the S3
// create an instance of IAmazonS3 class ,in my case i choose RegionEndpoint.EUWest1
// you can change that to APNortheast1 , APSoutheast1 , APSoutheast2 , CNNorth1
// SAEast1 , USEast1 , USGovCloudWest1 , USWest1 , USWest2 . this choice will not
// store your file in a different cloud storage but (i think) it differ in performance
// depending on your location
IAmazonS3 client = new AmazonS3Client("Your Access Key", "Your Secrete Key", Amazon.RegionEndpoint.USWest2);
// create a TransferUtility instance passing it the IAmazonS3 created in the first step
TransferUtility utility = new TransferUtility(client);
// making a TransferUtilityUploadRequest instance
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest();
if (subDirectoryInBucket == "" || subDirectoryInBucket == null)
{
request.BucketName = bucketName; //no subdirectory just bucket name
}
else
{ // subdirectory and bucket name
request.BucketName = bucketName + #"/" + subDirectoryInBucket;
}
request.Key = fileNameInS3 ; //file name up in S3
//request.FilePath = localFilePath; //local file name
request.InputStream = localFilePath;
request.CannedACL = S3CannedACL.PublicReadWrite;
utility.Upload(request); //commensing the transfer
return true; //indicate that the file was sent
}
}
Here you can use the function sendMyFileToS3 to upload file stream to amazon S3.
For more details check my blog in the following link.
Upload File to Amazon S3 via asp.net
I hope the above mentioned link will help.
Look for a javascript library to handle the client side upload of these files. I stumbled upon a javascript and php example Dojo also seems to offer a clientside s3 file upload.
ThreeSharp is a library to facilitate interactions with Amazon S3 in a .NET environment.
You'll still need to host the logic to upload and send files to s3 in your mvc app, but you won't need to persist them on your server.
Save and GET data in aws s3 bucket in asp.net mvc :-
To save plain text data at amazon s3 bucket.
1.First you need a bucket created on aws than
2.You need your aws credentials like
a)aws key b) aws secretkey c) region
// code to save data at aws
// Note you can get access denied error. to remove this please check AWS account and give //read and write rights
Name space need to add from NuGet package
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
var credentials = new Amazon.Runtime.BasicAWSCredentials(awsKey, awsSecretKey);
try`
{
AmazonS3Client client = new AmazonS3Client(credentials, RegionEndpoint.APSouth1);
// simple object put
PutObjectRequest request = new PutObjectRequest()
{
ContentBody = "put your plain text here",
ContentType = "text/plain",
BucketName = "put your bucket name here",
Key = "1"
//put unique key to uniquly idenitify your data
// you can pass here any data with unique id like primary key
//in db
};
PutObjectResponse response = client.PutObject(request);
}
catch(exception ex)
{
//
}
Now go to your AWS account and check the bucket you can get data with "1" Name in the AWS s3 bucket.
Note:- if you get any other issue please ask me a question here will try to resolve it.
To get data from AWS s3 bucket:-
try
{
var credentials = new Amazon.Runtime.BasicAWSCredentials(awsKey, awsSecretKey);
AmazonS3Client client = new AmazonS3Client(credentials, RegionEndpoint.APSouth1);
GetObjectRequest request = new GetObjectRequest()
{
BucketName = bucketName,
Key = "1"// because we pass 1 as unique key while save
//data at the s3 bucket
};
using (GetObjectResponse response = client.GetObject(request))
{
StreamReader reader = new
StreamReader(response.ResponseStream);
vccEncryptedData = reader.ReadToEnd();
}
}
catch (AmazonS3Exception)
{
throw;
}