1
public ActionResult OpenDocument(int documentID)
{
   Document doc = Model.DocumentServiceHelper.GetSingleDocument(documentID);

   if (doc != null)
   {
       return File(doc.Data, MimeMapping.GetMimeMapping(doc.Name) , doc.Name);
   }
   return Json("No File", JsonRequestBehavior.AllowGet);
}

JS:

 $('#btnOpenDocument').click(function () {
   var documentID = $('#hidDocumentID').val();

window.location.href = '/Documents/OpenDocument?documentID=' + documentID;

 });

Html:

<input type="hidden" id="hidDocumentID" 
       name="DocumentID" value="ViewData["DocumentId"]" />

I tried many documents on stackoverflow.Whatever i tried file return (downloads) without "xls,doc etc.." and i can not open document because of path.

How can i correct this for return file or another solution

Thanks.

Kjartan
  • 18,591
  • 15
  • 71
  • 96
Alan Richard
  • 13
  • 1
  • 4
  • how you are invoking `OpenDocument` method? – Kartikeya Khosla Dec 19 '14 at 08:17
  • 1
    The second parameter expects the content type, eg `application\octet-stream` or `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` yet it looks like you are trying to put the name there? Did you type `+` by mistake? – Panagiotis Kanavos Dec 19 '14 at 08:19
  • @PanagiotisKanavos I typed + in my code and changed it as "," now.I tried with , however same problem occurs.. – Alan Richard Dec 19 '14 at 08:27
  • Please specify what you are doing. Is `Data` a byte array or a string? What content type are you using exactly? What is the value of `doc.Name`? Does `Data` contain any data? Have you tried navigating to the action URL directly (ie type it in the browser? – Panagiotis Kanavos Dec 19 '14 at 08:30
  • doc.Name is string and doc.Data is byte[] . – Alan Richard Dec 19 '14 at 08:31
  • What does `doc.Name` contain? Does it contain a valid name including the extension? Neither the server nor the browser are going to guess the type and add their own extension – Panagiotis Kanavos Dec 19 '14 at 08:34
  • BTW if a file doesn't exist, the proper response is a 404 error. – Panagiotis Kanavos Dec 19 '14 at 08:35

2 Answers2

2

The second parameter in any Controller.File should be the content type, yet is seems the code tries to pass both the type and the file name. Perhaps this is a typo and the intent was to type:

return File(doc.Data, MimeMapping.GetMimeMapping(doc.Name), doc.Name)

doc.Data should be either a byte array or a Stream to avoid confusion with the Controller.File(string,string,string) overload which expects the first argument to be the path to a server file.

Moreover, GetMimeMapping should return a valid MIME type like application\octet-stream or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for .xlsx files, etc.

The browser can open the correct program on the client by checking first the content type, then the file extension. This means that an Excel file can be sent as application\octet-stream but the target name (doc.Name in this case) must include the proper extension.

Finally, to ensure the Javascript code isn't messing anything up, either Fiddler or the Network capture functionality of Chrome or IE should be used to check exactly what is sent to the server and what is returned.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • application/vnd.openxmlformats-officedocument.spreadsheetml.sheet works for xls thanks for it.I need it for all types (xls , rar pdf , word etc ) What do i need change ? – Alan Richard Dec 19 '14 at 08:47
  • It's in the 4th paragraph. Just make it `application\octet-stream` and make sure you add an extension – Panagiotis Kanavos Dec 19 '14 at 08:50
  • Thanks so much it works only a problem.. string destinationPath = "." + doc.FileExtension; return File(doc.Data, MimeMapping.GetMimeMapping(doc.Name), doc.Name + Path.GetFileName(destinationPath));when i return file path adds "--" to last why ? i have syntax problem for path right now – Alan Richard Dec 19 '14 at 09:12
0

Returning a file should be done like that:

byte[] file = ...
return File(file, System.Net.Mime.MediaTypeNames.Application.Octet, "name");

However throwing error where no file is returned may not be so easy. Please delete following line:

return Json("NoFile", JsonRequestBehavior.AllowGet);

...(and of course if condition) and then test whether you can download a file. If download will be successful you could experiment with case when no file is returned.

Ensure also whether doc.Data is a byte array.

EDIT:

According to your update change:

window.location.href = '/Documents/OpenDocument?documentID=' + documentID;

to

var url = '@Url.Action("OpenDocument","Documents")';
window.location = url + '?documentID=' + documentID;

You shouldn't use paths like '/Documents/OpenDocument' because it can vary depends on routing configuration.

Moreover perfect would be if you use overloaded method Url.Action which takes array of arguments and place there documentID parameter.

Please change also:

public ActionResult OpenDocument(int documentID)
{
   Document doc = Model.DocumentServiceHelper.GetSingleDocument(documentID);

   if (doc != null)
   {
       return File(doc.Data, MimeMapping.GetMimeMapping(doc.Name) + doc.Name);
   }
   return Json("No File", JsonRequestBehavior.AllowGet);
}

to

public FileResult OpenDocument(int documentID)
{
   Document doc = Model.DocumentServiceHelper.GetSingleDocument(documentID);
   return File(doc.Data, System.Net.Mime.MediaTypeNames.Application.Octet, doc.Name);
}

And test solution.

Then think about a scenario when no file is returned.

Arkadiusz Kałkus
  • 17,101
  • 19
  • 69
  • 108