I have included a link on my website to download images. When I click on the link I would like the download to automatically start.
Currently when I click on the link I’m getting back the response message: Example:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.PushStreamContent, Headers: { Content-Type: application/octet-stream Content-Disposition: attachment; filename=895621d7-57a4-47a5-8dc5-ae36a2623826Banneraaaaaaaa.jpg }
How do I modify the code below to start the download automatically. I think I might be returning the wrong type:
Here is my code:
public HttpResponseMessage DownloadImageFile(string filepath)
{
filepath = "https://mysite.com/" + filepath;
try
{
var response = new HttpResponseMessage();
response.Content = new PushStreamContent((Stream outputStream, HttpContent content, TransportContext context) =>
{
try
{
DownloadFile(filepath, outputStream);
}
finally
{
outputStream.Close();
}
});
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = Path.GetFileName(filepath);
return response;
}
catch (Exception ex)
{
}
return null;
}
public void DownloadFile(string file, Stream response)
{
var bufferSize = 1024 * 1024;
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[bufferSize];
var bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, bufferSize)) > 0)
{
response.Write(buffer, 0, bytesRead);
}
response.Flush();
}
}
}
You should use one of the Controller.File overload. The File() helper method provides support for returning the contents of a file. The MediaTypeNames class can be used to get the MIME type for a specific file name extension.
For example:
public FileResult Download(string fileNameWithPath)
{
// Option 1 - Native support for file read
return File(fileNameWithPath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(fileNameWithPath));
// Option 2 - Read byte array and pass to file object
//byte[] fileBytes = System.IO.File.ReadAllBytes(fileName); return
//File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet,
//fileName);
}
Related
Uploading a single image seems to be no problem with retrofit 2.
However,
i cant figure out how to upload 2 images at the same time.
if followed the documentation:
http://square.github.io/retrofit/2.x/retrofit/retrofit2/http/PartMap.html
File file = new File(path, "theimage");
File file2 = new File(path2, "theimage");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
Map<String, RequestBody> params = new HashMap<>();
params.put("image2", requestBody2 );
Call<ResponseBody> call = service.upload(requestBody, params);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
Log.v("Upload", "success");
}
interface:
public interface FileUploadService {
#Multipart
#POST("/upload")
Call<ResponseBody> upload(
//#Part("image_logo\"; filename=\"image.png\" ") RequestBody file,
#Part("file") RequestBody file,
#PartMap Map<String, RequestBody> params
// #Part("description") String description
);
this gives a 'Upload: success' but on the server side i get gibberish:
CONTENT_TYPE: multipart/form-data;
boundary=50fbfeb3-3abc-4f15-b130-cdcb7e3a0e4f
CONTENT POST:Array (
[file] => �PNG IHDR L alotofbinarygibberish.... ... snip
[file2] => �PNG
IHDR L more binary gibberish...
can anyone point me in the right direction?
single upload does work so thats not the problem, i'm trying to upload 2 or more images.
if i change it to this:
HashMap<String, RequestBody> partMap = new HashMap<String, RequestBody>();
partMap.put("file\"; filename=\"" + file.getName(), requestBody);
partMap.put("file\"; filename=\"" + file2.getName(), requestBody);
Call<ResponseBody> call = service.upload(partMap);
#Multipart
#POST("/upload")
Call<ResponseBody> upload(
#PartMap() Map<String, RequestBody> partMap,
i get no gibberish but only the second image is uploaded... !?
UPDATE
i tried this Retrofit(2.0 beta2) Multipart file upload doesn't work solution but get an error that #body can not me used with multipart:
Java.lang.IllegalArgumentException: #Body parameters cannot be used with form or multi-part encoding. (parameter #1)
for (String key : keys) {
Bitmap bm = selectedImages.get(key);
File f = new File(saveToInternalStorage(bm, key), key);
if (f.exists()) {
buildernew.addFormDataPart(key, key + ".png", RequestBody.create(MEDIA_TYPE, f));
}
}
RequestBody requestBody = buildernew.build();
-
Call<ResponseBody> upload(
#Body RequestBody requestBody
This works:
final MediaType MEDIA_TYPE=MediaType.parse("image/png");
HashMap<String,RequestBody> map=new HashMap<>(selectedImages.size());
RequestBody file=null;
File f=null;
Set<String> keys = selectedImages.keySet();
for (String key : keys) {
try {
Bitmap bitmap = selectedImages.get(key);
f = new File(saveToInternalStorage(bitmap, key), key);
FileOutputStream fos = new FileOutputStream(f);
if(bitmap!=null){
bitmap.compress(Bitmap.CompressFormat.PNG, 0 , fos);
fos.flush();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
return;
}
file=RequestBody.create(MEDIA_TYPE, f);
map.put(""+key+"\"; filename=\""+key+".jpg",file);
Log.i("##MYLOG###", "### MAP PUT:" + key + " filename:"+key+".jpg file:" + file.toString() +" type:"+ file.contentType() );
file=null;
f = null;
}
--
Call<ResponseBody> upload(
#PartMap() Map<String,RequestBody> mapFileAndName //for sending multiple images
--
beware: while debugging this with the httpClient.interceptors() i saw only a single upload but when checking the endpoint itself to see what it actually got, it DID get the multiple uploads!
I might be late but my answer might help future visitors
I am asking user to select multiple images like this:
int PICK_IMAGE_MULTIPLE = 1;
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_MULTIPLE);
Then in onActivityResult() I am doing this:
ArrayList<String> filePaths;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_MULTIPLE) {
if (data != null) {
filePaths=new ArrayList<>();
// If data.getData() == null means multiple images selected, else single image selected.
if (data.getData() == null) {
ClipData clipData = data.getClipData();
if (clipData != null) {
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
Uri uri = item.getUri();
filePaths.add(FileUtils.getPath(Activity.this, uri));
}
}
} else {
filePaths.add(FileUtils.getPath(Activity.this,data.getData()));
}
sendToServer();
}
}
}
You can get FileUtils class from this Github link
My sendToServer() method looks like this:
private void sendToServer() {
if(filePaths!=null) {
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
MediaType MEDIA_TYPE_IMG = MediaType.parse("image/jpeg");
MultipartBody.Builder builder=new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
RequestBody requestBody;
try {
for (int i = 0; i < filePaths.size(); i++) {
File file = new File(filePaths.get(i));
requestBody=RequestBody.create(MEDIA_TYPE_IMG,file);
builder.addFormDataPart("photo"+i,file.getName(),requestBody);
}
RequestBody finalRequestBody=builder.build();
Call<YourResponse> call=apiService.addEvent(finalRequestBody);
call.enqueue(new Callback<YourResponse>() {
#Override
public void onResponse(Call<YourResponse> call, Response<YourResponse> response) {
// process response
}
#Override
public void onFailure(Call<YourResponse> call, Throwable t) {
t.printStackTrace();
t.getCause();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
}
Finally my Retrofit endpoint looks like this:
#POST("event/add")
Call<YourResponse> addEvent(#Body RequestBody body);
Note that YourResponse can be your custom model class for handling response, or you can also use raw Response class in you don't want to make your model class.
Hope this helps new visitors.
Try This
For API:
//Multiple Images
#Multipart
#POST(HttpConstants.FILEMULTIPLEUPLOAD)
Call<Result>uploadMultipleImage(#Part MultipartBody.Part files1,#Part MultipartBody.Part files2, #Query("total_images") int total, #Query("stdID") int stdID);
Client
public class RaytaServiceClass {
public RaytaServiceClass() {
}
private static Retrofit getRetroClient(){
Gson gson = new GsonBuilder()
.setLenient()
.create();
return new Retrofit.Builder()
.baseUrl(HttpConstants.baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
public static RaytaApi getApiService(){
return getRetroClient().create(RaytaApi.class);
}
}
The Call
RaytaApi service= RaytaServiceClass.getApiService();
File file1 = new File(selectedPath1);
File file2 = new File(selectedPath2);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
RequestBody requestFile2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
MultipartBody.Part body =
MultipartBody.Part.createFormData("uploaded_file", file1.getName(), requestFile);
MultipartBody.Part body2 =
MultipartBody.Part.createFormData("uploaded_file", file2.getName(), requestFile2);
Call<Result> resultCall=service.uploadMultipleImage(body,body2,2,1);
Log.v("####WWE","REquest "+resultCall.toString());
Log.v("###WWE","Retrofit Request Method = "+resultCall.request().method());
Log.v("###WWE","Retrofit Request Body = "+resultCall.request().body());
Log.v("###WWE","Retrofit Request Url = "+resultCall.request().url());
final Result[] result = {new Result()};
resultCall.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
progressDialog.dismiss();
Log.v("###WWE","Respnse");
result[0] =response.body();
Log.v("###WWE","Response Result "+result[0].getResult());
if(response.isSuccessful()){
Toast.makeText(UploadMultipleImageActivity.this,"Sucess",Toast.LENGTH_SHORT).show();
Toast.makeText(UploadMultipleImageActivity.this,"Press Refresh Button",Toast.LENGTH_LONG).show();
supportFinishAfterTransition();
}
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
progressDialog.dismiss();
Log.v("###WWE","Failure ");
Log.v("###WWE","MEssage "+t.getMessage());
}
});
I'v a pretty simple use case wherein, I need to upload a jpeg & download a pdf from a rest api. I am facing below mentioned problems & I'v done due diligence (to the best of my knowledge) to try to get a solution from SO & google, but I haven't been successful, yet.
questions :
sendPdf method does indeed send multiple fragments of data (confirmed by running a pkt sniffer) but My code in playground recieves response as nil.
Use cases, but to no vain :
1 Tried content-type = application/pdf
2 Tried content-type = application/octet-stream
SaveFile method indeed creates the file viz. img_1 & img_2, but picture viewer is not able to open the photograph, meaning, some mismatch in bits while re-compiling the bytestream as pdf.
Use cases, but to no vain :
1 Tried DataInputStream
2 Tried ImageIO functions alongwith ByteArrayInputStream
rest api :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
createOutput(request, response);
}
private void createOutput(HttpServletRequest request, HttpServletResponse response) {
PrintWriter out_response = null;
response.setHeader("Cache-Control", "no-cache");
saveFile(request);
sendPdf(response);
}
private void sendPdf(HttpServletResponse response) throws IOException {
//response.setContentType("application/pdf");
response.setContentType("application/octet-stream");
FileInputStream fin = new FileInputStream("C:\\Users\\dwalia\\Desktop\\abc.pdf");
if(fin !=null){
BufferedInputStream bin = new BufferedInputStream(fin);
BufferedOutputStream bout = new BufferedOutputStream(response.getOutputStream());
int ch =0;
while((ch=bin.read())!=-1)
{
bout.write(ch);
}
bin.close();
fin.close();
bout.close();
}
}
private void saveFile(HttpServletRequest request) {
byte[] data = new byte[0];
byte[] buffer = new byte[512];
int bytesRead;
try {
DataInputStream din = new DataInputStream(request.getInputStream());
while ((bytesRead = din.read(buffer)) > 0) {
byte[] newData = new byte[data.length + bytesRead];
System.arraycopy(data, 0, newData, 0, data.length);
System.arraycopy(buffer, 0, newData, data.length, bytesRead);
data = newData;
}
FileOutputStream fos = new FileOutputStream("C:\\Users\\dwalia\\Desktop\\img_1.png");
fos.write(data);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
File outputfile = new File("C:\\Users\\dwalia\\Desktop\\img_2.png");
if(img != null) ImageIO.write(img, "png", outputfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My xcode playground code (SRWeb library : https://github.com/sraj/Swift-SRWebClient):
1. Trying to upload a png & download a pdf in a single go :
var image_src = UIImage(named : "India")
var params = ["username":"uname", "password":"pwd"]
var img_data = UIImageJPEGRepresentation(image_src, 100)
SRWebClient.POST("http://169.254.54.114:8080/sample/hello_world_servlet")
.data(img_data, fieldName: "signature", data: params)
.send(
{(response:AnyObject!, status:Int) -> Void in
println(status) <-- 200
if let response_json: AnyObject = response {
println(response as! String) <-- nothing, response == nil
}
}
)
2. Trying to download pdf only :
SRWebClient.GET("http://169.254.54.114:8080/sample/hello_world_servlet",
success:{
(response:AnyObject!, status:Int) -> Void in
println("\(status) \(response)") <-- "Data nil"
if let response_data: AnyObject = response {
println(response_data) <-- nothing, response == nil
}
}, failure:{
(error:NSError!) -> Void in
println(error.localizedDescription) <-- nothing
}
)
I managed to set up modh264 on IIS 7 working just fine, pseudo streaming is working great.
I can't get jwplayer pseudo streaming to work with a httphandler in-between.
I mean the video starts from the beginning whenever you click in a different position!
if I remove the handler the pseudo streaming works as expected.
My problem here is to prevent people gaining direct access to my videos (I don't care if they save the video via browser cache).
I had to load via 10k bytes chunks since videos are big enough to get memory exception
here's my httphandler
public class DontStealMyMoviesHandler : IHttpHandler
{
/// <summary>
/// You will need to configure this handler in the web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
HttpRequest req = context.Request;
string path = req.PhysicalPath;
string extension = null;
string contentType = null;
string fileName = "";
if (req.UrlReferrer == null)
{
context.Response.Redirect("~/Home/");
}
else
{
fileName = "file.mp4";
if (req.UrlReferrer.Host.Length > 0)
{
if (req.UrlReferrer.ToString().ToLower().Contains("/media/"))
{
context.Response.Redirect("~/Home/");
}
}
}
extension = Path.GetExtension(req.PhysicalPath).ToLower();
switch (extension)
{
case ".m4v":
case ".mp4":
contentType = "video/mp4";
break;
case ".avi":
contentType = "video/x-msvideo";
break;
case ".mpeg":
contentType = "video/mpeg";
break;
//default:
// throw new notsupportedexception("unrecognized video type.");
}
if (!File.Exists(path))
{
context.Response.Status = "movie not found";
context.Response.StatusCode = 404;
}
else
{
try
{
//context.Response.Clear();
//context.Response.AddHeader("content-disposition", "attachment; filename=file.mp4");
//context.Response.ContentType = contentType;
//context.Response.WriteFile(path, false);
//if(HttpRuntime.UsingIntegratedPipeline)
// context.Server.TransferRequest(context.Request.Url.ToString(), true);
//else
// context.RewritePath(context.Request.Url.AbsolutePath.ToString(), true);
// Buffer to read 10K bytes in chunk:
byte[] buffer = new Byte[10000];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
using (FileStream iStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
// Total bytes to read:
dataToRead = iStream.Length;
context.Response.Clear();
context.Response.Cache.SetNoStore();
context.Response.Cache.SetLastModified(DateTime.Now);
context.Response.AppendHeader("Content-Type", contentType);
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (context.Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
context.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
context.Response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
}
catch (Exception e)
{
context.Response.Redirect("home");
}
finally
{
context.Response.Close();
}
}
}
#endregion
}
Thank you in advance
I solved creating a httpmodule instead, Because with a httpHandler I had to manage the response myself causing the pseudo stream to fail (the file was loaded entirely to the output stream). While this way if someone is accessing the file directly I just do a simple redirect. I don't get why redirect to "~/" doesn't work.
public class DontStealMyMoviesModule : IHttpModule
{
public DontStealMyMoviesModule()
{
}
public void Init(HttpApplication r_objApplication)
{
// Register our event handler with Application object.
r_objApplication.PreSendRequestContent +=new EventHandler(this.AuthorizeContent);
}
public void Dispose()
{
}
private void AuthorizeContent(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication objApp = (HttpApplication)r_objSender;
HttpContext objContext = (HttpContext)objApp.Context;
HttpRequest req = objContext.Request;
if (Path.GetExtension(req.PhysicalPath).ToLower() != ".mp4") return;
if (req.UrlReferrer == null)
{
objContext.Response.Redirect("/");
}
}
}
I'm having some trouble getting uploaded files to save to S3. My first attempt was:
Result SaveFile(System.Web.HttpPostedFileBase file, string path)
{
//Keys are in web.config
var t = new Amazon.S3.Transfer.TransferUtility(Amazon.RegionEndpoint.USWest2);
try
{
t.Upload(new Amazon.S3.Transfer.TransferUtilityUploadRequest
{
BucketName = Bucket,
InputStream = file.InputStream,
Key = path
});
}
catch (Exception ex)
{
return Result.FailResult(ex.Message);
}
return Result.SuccessResult();
}
This throws an exception with the message: "The request signature we calculated does not match the signature you provided. Check your key and signing method." I also tried copying file.InputStream to a MemoryStream, then uploading that, with the same error.
If I set the InputStream to:
new FileStream(#"c:\folder\file.txt", FileMode.Open)
then the file uploads fine. Do I really need to save the file to disk before uploading it?
This is my working version first the upload method:
public bool Upload(string filePath, Stream inputStream, double contentLength, string contentType)
{
try
{
var request = new PutObjectRequest();
request.WithBucketName(_bucketName)
.WithCannedACL(S3CannedACL.PublicRead)
.WithKey(filePath).InputStream = inputStream;
request.AddHeaders(AmazonS3Util.CreateHeaderEntry("ContentType", contentType));
_amazonS3Client.PutObject(request);
}
catch (Exception exception)
{
// log or throw;
return false;
}
return true;
}
I just get the stream from HttpPostedFileBase.InputStream
(Note, this is on an older version of the Api, the WithBucketName syntax is no longer supported, but just set the properties directly)
Following the comment of shenku, for newer versions of SDK.
public bool Upload(string filePath, Stream inputStream, double contentLength, string contentType)
{
try
{
var request = new PutObjectRequest();
string _bucketName = "";
request.BucketName = _bucketName;
request.CannedACL = S3CannedACL.PublicRead;
request.InputStream = inputStream;
request.Key = filePath;
request.Headers.ContentType = contentType;
PutObjectResponse response = _amazonS3Client.PutObject(request);
return true;
}catch(Exception ex)
{
return false;
}
}
I'm trying to download xml files using httpwebrequest using the code below based on this example here. Now it works partially in that it doesn't download all the xml file's contents. Any idea why?
public void download(String url)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.AllowReadStreamBuffering = false;
request.Method = "GET";
request.BeginGetResponse(a =>
{
StringBuilder data=null;
using (WebResponse response = request.EndGetResponse(a))
{
int expected = (int)response.ContentLength;
try
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
int read = 0;
data = new StringBuilder(expected);
char[] buffer = new char[1024];
while ((read = reader.Read(buffer, 0, buffer.Length)) != 0)
{
data.Append(new string(buffer, 0, read));
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("exception caught: " + ex.Message);
}
}
System.Diagnostics.Debug.WriteLine("Got \n " + data.ToString());
}, null);
}
If all you're getting is XML, you can use XDocument.Load(stream) to load the result to a XDocument instance
Your problem may be with the applied Encoding, and this method should solve any Encoding issue!