0

I would like to get a file from my upload control and send it to a validator action though an ajax call without doing a post.

-User select several files

-Clicks 'validate', that runs some checks and returns the result of the validation.

-If the validation is success, the Upload button will be displayed and it could be posted.

JAVASCRIPT

function OnValidateSurveyFiles() {
    debugger;
    var SurveyId = $('#SurveyID').val();
    var file_1 = document.getElementById('surveyUploadcontrol_TextBox0_Input').files[0];
    var serializedFile = JSON.stringify(file_1, null, 2);
    var url = '/Survey/ValidateSurveyFiles';
    $.ajax({
        type: 'GET',
        url: url,
        data: { surveyFile: serializedFile },
        success: function (result) {
            //debugger;
            //
        },
        error: function (result) {
            // handle errors
            location.href = "/Home/"
        }
    });
}

CONTROLLER

public ActionResult ValidateSurveyFiles(object surveyFile)
{
    try
    {
       do something...
    }
    catch(Exception ex)
    {
        throw ex;
    }
    // I would like to return a json responde with html(partial view...) and a code with the validation's result.
    return View("_");
}

Actually, file_1 looks like the following:

file_1: File
lastModified: 1442499299116
lastModifiedDate: Thu Sep 17 2015 16:14:59 GMT+0200 (Mitteleuropäische Sommerzeit)
name: "File.csv"
size: 1176120
type: "application/vnd.ms-excel"
webkitRelativePath: ""
__proto__: File
constructor: File()
lastModified: (...)
get lastModified: ()
lastModifiedDate: (...)
get lastModifiedDate: ()
name: (...)
get name: ()
size: (...)
type: (...)
webkitRelativePath: (...)
get webkitRelativePath: ()
__proto__: Blob

But the serialized file is just {}

Any idea how could I achieve the desired behavior?

blfuentes
  • 2,731
  • 5
  • 44
  • 72
  • Unclear what your trying to do. What data are you trying to send to the controller and what are you expecting to validate? –  Sep 18 '15 at 12:05
  • My validator needs 4 files, some of them .txt, others .csv. I just need a way to run an Action without the user having to do a post in the form. Because once the post is runthe files are no longer in the form, and he should have to re-select the files again. I expect the user to select the files in one form. click validate, the validation runs in the server and returns a response and then the user can post the files. I don't want to change the state of the formular. – blfuentes Sep 18 '15 at 12:08
  • But what are you trying to send to the controller? Just the file name and its size? If you want to send the contents of the file to be validated you must POST it. You need to use `FormData` ([example here](http://stackoverflow.com/questions/29293637/how-to-append-whole-set-of-model-to-formdata-and-obtain-it-in-mvc/29293681#29293681)) and you need a POST method with a parameter `HttpPostedFileBase`. –  Sep 18 '15 at 12:12
  • Yes, I need the content of the files, so the ajax call should be a POST? Could you elaborate an answer to test it? There would be 4 files, as I said. – blfuentes Sep 18 '15 at 12:15
  • 1
    Have a look at the link I gave you. And the [documentation here](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects). –  Sep 18 '15 at 12:18

1 Answers1

0

Following @Stephen-Muecke links.

View

function OnValidateSurveyFiles() {
    debugger;
    var SurveyId = $('#SurveyID').val();
    var formData = new FormData();
    var fileSurvey = document.getElementById('surveyUploadcontrol_TextBox0_Input').files[0];
    formData.append("FileSurvey", fileSurvey);
    formData.append("SurveyID", SurveyId);

    var url = '/Survey/ValidateSurveyFiles';
    $.ajax({
        type: 'POST',
        url: url,
        data: formData,
        contentType: false,
        processData: false,
        success: function (result) {
            debugger;
            //
            if (result.error) {
                $('#containerErrorLog').show();
                $('#errorLogSurvey').html(result.message);
            }
            else
                $('#containerErrorLog').hide();
        },
        error: function (result) {
            // handle errors
            location.href = "/Home/"
        }
    });
}

Controller

[HttpPost]
public ActionResult ValidateSurveyFiles()
{
    try
    {
        int surveyId = -1;
        Int32.TryParse(Request.Params["SurveyId"], out surveyId);

        foreach (string file in Request.Files)
        {
            HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
            BinaryReader reader = new BinaryReader(hpf.InputStream);
            byte[] binData = reader.ReadBytes(hpf.ContentLength);
            string tmpFullContent = Encoding.UTF8.GetString(binData);

            if (hpf == null || hpf.ContentLength == 0)
                continue;
            // blablabla... validation and store list of errors into "Errors"
        }

        if (Errors.count > 0)
        {
            return Json(new
            {
                error = true,
                message = RenderHelper.RenderViewToString(this.ControllerContext, "_surveyErrorLog", resultSurvey)
            });
        }
    }           
    catch (Exception ex)
    {
        throw ex;
    }
}

RenderHelper class

public static class RenderHelper
{
    public static string RenderViewToString(ControllerContext context, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = context.RouteData.GetRequiredString("action");

        ViewDataDictionary viewData = new ViewDataDictionary(model);

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
            ViewContext viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }
}
blfuentes
  • 2,731
  • 5
  • 44
  • 72