Return either a file OR an ajax alert in MVC
Let's say I have a form with multiple options on the home page. One of these is a partial view that takes a customerID. If the customerID is valid and has products, I return a CSV file like so:
public ActionResult CustomerProductsExport(string CustomerId)
{
var export = "\"ProductID\"\n";
IEnumerable<int> products = CustomerFactory.GetProducts(CustomerId);
export += string.Join("\n", products);
var aFileContent = Encoding.ASCII.GetBytes(export);
var aMemoryStream = new MemoryStream(aFileContent);
return File(aMemoryStream, "text/plain",
string.Format("{0}.csv", CustomerId));
}
There are, however, a couple cases where this will fail: either the customer ID doesn't exist, or they have no products. I would like to just return a javascript alert to indicate either of these cases. I've tried both FormMethod.Get and .Post with this:
return Javascript("alert('foo');");
But that always results in a literal string instead of running my javascript. How can I get my desired behavior or either delivering the file or giving a javascript alert wit开发者_Python百科hout the post? I've also tried both a submit button vs an ActionLink... same results.
In this kind of situation, I would return JSON that indicates the result; if successful, you then make a second request to get the actual file resource.
You would do something like this:
public ActionResult SomeMethod()
{
if(EverythingIsOk)
return Json(new { IsError = false, Url = "http://someUrl/" });
return Json(new { IsError = true, Error = "You're doing it wrong" });
}
Your client receives the Json, and then checks to see if there is an error. If not, then it takes the Url and requests that resource (thus, downloading the file).
It should work if you set the content-type to application/javascript
public ActionResult CustomerProductsExport(string CustomerId)
{
var export = "\"ProductID\"\n";
var products = CustomerFactory.GetProducts(CustomerId);
if (products == null)
{
return new ContentResult {
Content = "alert('Invalid customer id');",
ContentType = "application/javascript"
};
}
export += string.Join("\n", products);
var fileContent = Encoding.ASCII.GetBytes(export);
var stream = new MemoryStream(fileContent);
return File(stream, "text/plain",
string.Format("{0}.csv", CustomerId));
}
Edit
The JavascriptResult
uses the obsolete application/x-javascript
header which might be the cause of it not working as expected. That's why the code above should work.
See these questions:
- Difference between application/x-javascript and text/javascript content types
- When serving JavaScript files, is it better to use the application/javascript or application/x-javascript
精彩评论