What is the MVC way of simultaneously sending a file and redirecting to a new page? - asp.net-mvc

I have a form which users must fill out and submit. The controller action does some work and decides the user can have a file and so redirects to another action which is a FilePathResult.
[CaptchaValidator]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection collection)
{
// do some stuff ...
return RedirectToAction("Download");
}
[AcceptVerbs(HttpVerbs.Get)]
public FilePathResult Download()
{
var fileName = "c:\foo.exe";
return File(fileName, "application/octet-stream", "installer.exe");
}
What I would like to do is redirect the user to another page which thanks the user for downloading the file but I'm not sure how to accomplish that in a "MVC-like" way.
The only way I can think of off the top of my head is to skip the Download action and instead redirect to the ThankYou action, and have the ThankYou view use javascript to send the file. But this just doesn't seem very MVC to me. Is there a better approach?
Results:
The accepted answer is correct enough but I wanted to show I implemented it.
The Index action changes where it redirects to:
return RedirectToAction("Thankyou");
I added this controller (and view) to show the user any "post download information" and to say thanks for downloading the file. The AutoRefresh attribute I grabbed from link text which shows some other excellent uses.
[AutoRefresh(ControllerName="Download", ActionName="GetFile", DurationInSeconds=3)]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Thankyou()
{
return View();
}
The action which get redirected to is this same as it was before:
[AcceptVerbs(HttpVerbs.Get)]
public FilePathResult GetFile()
{
var fileName = "c:\foo.exe";
return File(fileName, "application/octet-stream", "installer.exe");
}

Just add a header to your response, in the action for your redirected page.
Googling came up with this header:
Refresh: 5; URL=http://host/path
In your case the URL would be replaced with the URL to your download action
As the page I was reading says, the number 5 is the number of seconds to wait before "refreshing" to the url.
With the file being a download, it shouldn't move you off your nice redirect page :)

Related

Request.UrlReferrer.ToString() Not reload in IE only

I'm trying to redirect page on previous page when i click on currency menu. In this menu set selected currency in cookies and redirect to Request.UrlReferrer.ToString() so Request page automatic read cookies and apply currency.
Here is my code
public ActionResult Index(string currency)
{
HttpCookie cookie = new HttpCookie("Cookie");
cookie.Values["CODE"] = currency;
cookie.Values["sym"] = Currencies[currency];
cookie.Values["Name"] = CurrenciesName[currency];
string currencyname = GetCurrencySymbol(currency);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
return Redirect(Request.UrlReferrer.ToString());
//return RedirectToRoute(Request.UrlReferrer.ToString());
}`
for example page1 have some item with amount in USD now user change currency then i send request to CurrencyController with above Action then return to same page1.
Above code working fine in all browsers but not working in IE 11.
give me some idea where I'm doing wrong.
Thanks
First and foremost, you should never rely on UrlReferrer. Its value comes from an HTTP header that is not guaranteed to be sent, and even if it is sent, it can be tampered with. By using it in the way you are, you're opening yourself up to CSRF and man-in-middle attacks.
The correct way to do something like this is to pass along the URL you want to return to. For example, if a user is on a URL like /foo/ and then clicks a link where you want to redirect them back to /foo/ afterwards, then the URL of the link should be something like: /bar/?returnUrl=/foo/.
Then, the action responding to /bar/ would do something like:
public ActionResult Bar(string returnUrl)
{
// do something
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
// redirect to default
}
The Url.IsLocalUrl check is to make sure that the return URL is a path on the current site, again, to prevent malicious attacks.

MVC - Excel download on button click Cannot redirect after HTTP headers have been sent

Firstly, I know there are multiple posts related to this error but nothing is helping so far.
I am getting an error "Cannot redirect after HTTP headers have been sent." in my MVC razor application when I make a call to SomeController.
How do I fix this?
[HttpPost]
public ActionResult SomeController(Object abc)
{
Helper.somemethod("","excel");
return View(abc);//I tried this
return RedirectToAction("SomeController"); //I tried this also
}
public static void somemethod(string settocken, string filenames, List<Sample> samples)
{
//Extra logic for excel that uses List<Sample> to generate excel.
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Cookies.Add(new HttpCookie("downloadToken", settocken));
HttpContext.Current.Response.ContentType = "Application/x-msexcel";
HttpContext.Current.Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}.xlsx", filenames));
using (MemoryStream ms = new MemoryStream())
{
try
{
book.Save(ms);
HttpContext.Current.Response.BinaryWrite(ms.ToArray());
}
catch
{
}
finally
{
}
HttpContext.Current.Response.End();
}
}
#CoolArchTek http communication loop will be ended after HttpContext.Current.Response.End() call, so you can't add anything after that, however as far as I know there is no possibility in http to do what you want, so I would recommend you render your view with javascript which will initiate file download by client's browser
I would suggest, have an iframe inside view where you want to redirect to and show the data. And set the excel file path(or the action which returns excel file) as source for that iframe.
With this, as soon as the page loads, download begins.
Hope it helps.

MVC Post Form, but optionally return download or content

So I have a form action, that uploads a document and process it...
[HttpPost]
public ActionResult Upload(FormCollection col)
{}
But I want to either return and download (NOT A LINK) but rather the download just starts, OR some html content to show the user on the page.
What should I return, and do I need to change the attribute ( HttpPost ) ?
This is the code that you can put in your Action-Method.
bool shouldDownload = true;
if (shouldDownload)
{
Response.AddHeader("Content-disposition", "attachment; filename=guitars_11.jpg");
return File(#"c:\Temp\guitars_11.jpg", "image/jpeg");
}
else
{
return View();
}
The [HttpPost] attribute can stay - it only has an affect on routing (if the request is a POST request, the action will be invoked). It has no influence on what is returned.
Ultimately whether you deliver an HTML page or file back to the browser it's all just HTTP.
You need only set the content-type http response header to the proper mime type for the file, and optionally set the content-disposition header to set the filename ( http download file name).

RedirectToAction is not redirecting at all

i'm using RedirectToAction to redirect after a post to another controller and it's working. so i tried to Redirect to another action in the same controller and it's NOT working too.
public ActionResult finalize(int id)
{
Meeting meeting = db.Meetings.Find(id);
meeting.meetingStatus = "finalized";
db.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Meeting meeting)
{
if (ModelState.IsValid)
{
db.Meetings.Add(meeting);
db.SaveChanges();
// return RedirectToAction("Invitation");
return (RedirectToAction("finalize", new { id = meeting.meetingID}));
}
return View(meeting);
}
you cant make 2 redirects in the same call , a redirect just return an http redirect code to another page , redirecting 2 times just wont work, don't treat action methods like normal methods they are different
for example when you request a page example.com/controller/action
action will be executed and for example it has a return value with RedirectToAction("NotFound")
what will happen in this scenario is
action body will be executed and the return value will send to the client an http header of 302 that says your new destination is /controller/NotFound
so RedirectToAction just return an http code to the client its not calling another method
Update
i was wrong i checked with fiddler2 , you can use redirect to action many times , what will happen the server will send multiple http redirect headers for each one
i jumped to conclusion this fast because i didnt think multiple redirect is the right way to do it, so after i tried it , i can say it works , just create a new project to see where is the problem exactly or use a tool like fiddler2

ASP.NET MVC How to output FileContent from within a controller action and continue

I am fairly new to MVC and want to know what the correct approach is - when a form is submitted the Edit ActionResult is executed, once the data is saved, I want to generate a file and send to the browser for download but also continue to another action.
The file is sent to the browser but no further processing occurs in the controller, because I use return RedirectToActions. Thanks in advance for any pointers.
public ActionResult Edit(int id, InvoiceFormData formData)
{
...
return base.RedirectToAction("ReturnPdf", new { id = 99 });
// More processing...ideally...then
return base.RedirectToAction("Action", "Controller");
}
public FileResult ReturnPdf(int? id)
{
...
return output; // writes file output and prompts user to download
}
You cannot use two return statements in the same action result and expect them to both run. When you "return" it means you're returning the output and then quiting out of the action result. Therefore, you could kind of chain your actions, so rather than doing the further processing inside the Edit action result, you could move that logic into the ReturnPdf AR(since that's what's I could see in your code), then finally return the final output in whatever action result you landed on. I hope that was clear enough...

Resources