0

I have the following AjaxActionLink code in my view:

@Ajax.ActionLink("Download", "DownloadDocument", "Document", new { Model.DocumentNumber, Model.DocumentName, TypeVisualization = TypeVisualization.Attachment }, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "modal-container", LoadingElementId = "ajaxLoading" }, new { @class = "modal-link" })

Then, in my DocumentController:

        [HttpPost]
        public async Task<ActionResult> DownloadDocument(DownloadFileRequest request)
        {
            DownloadFileCommand command = new DownloadFileCommand();
            Mapper.Map(UserModel, command);
            Mapper.Map(request, command);
            var result = await documentRepository.DownloadDocument(command);
            ContentDisposition cd = new ContentDisposition
            {
                FileName = Server.UrlPathEncode(result.DocumentName),
                Inline = request.TypeVisualization == TypeVisualization.Inline
            };
            return new FileContentResultWithContentDisposition(result.Content, result.MimeType, cd);
        }

The method is been hit, but after it return, no file is been sent to the browser and an exception is been thrown:

System.Web.HttpException (0x80004005): A public action method 'DownloadDocument' was not found on controller Document
   en System.Web.Mvc.Controller.HandleUnknownAction(String actionName)
   en System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   en System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
   en System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   en System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
   en System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
   en System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   en System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   en System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   en System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   en System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   en System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

What's going on here?

Oscar
  • 13,594
  • 8
  • 47
  • 75

1 Answers1

0

I would recommend you not using AJAX for downloading files. Even if the call succeeds there's not much you could do with the binary content in your success callback and you cannot save it to the client computer. For example in your AjaxLink you seem to have specified the UpdateTargetId = "modal-container" parameter but I wonder what exactly do you expect to happen inside this div if your controller action returns a binary stream.

Instead you could use an HTML form:

@using (Html.BeginForm("DownloadDocument", "Document", FormMethod.Post))
{
    @Html.HiddenFor(x => x.DocumentNumber)
    @Html.HiddenFor(x => x.DocumentName)
    @Html.Hidden("TypeVisualization", TypeVisualization.Attachment)
    <input type="submit" class="modal-link">Download</input>
}

Now as far as your error is concerned, I doubt that it is related to the fact that the action is async. This should work out of the box. Make sure that the action is properly placed inside a DocumentController:

public class DocumentController: Controller
{
    ...
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks for you time and advice. My DocumentController class have a public method called DownloadDocument and the method is been hit, I can see it running and returning if I place a breakpoint on it. The method used to work before in a synchronous version, I'm just trying to make it run async. I'm using ajax because I want it to be a link, not a submit button, just for aesthetics reasons. – Oscar Jan 13 '17 at 10:47
  • 1
    You could make a button look like a link without any problems: http://stackoverflow.com/questions/1367409/how-to-make-button-look-like-a-link – Darin Dimitrov Jan 13 '17 at 12:06
  • Also from what I can see you seem to be using asp.net mvc 4. I am not quite sure if it supports async actions out of the box. Can you try this with mvc 5? It should work. – Darin Dimitrov Jan 13 '17 at 12:07