如何通过HttpPostedFileBase和ViewModel发送上传的文件

本文关键字:文件 何通过 HttpPostedFileBase ViewModel | 更新日期: 2024-09-19 20:05:28

我有一个巨大的数据对象,其中应该通过控制器参数映射到视图模型。我还有一个文件(照片)的列表,我需要在前面提到的数据对象的数组中捕捉这些文件。

我的型号:

public class TestPerson
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Place { get; set; }
    public int Age { get; set; }
    public byte[] File { get; set; }
    //[FileSize(10240)]
    //[FileTypes("jpg,jpeg,png")]
    //public HttpPostedFileBase File { get; set; }
}

我的控制器方法:

    public void SavePersonData(HttpPostedFileBase personPhoto, TestPerson person)
    {
        var dataObject = Request.Form["person"];
        var serializer = new JavaScriptSerializer();
        TestPerson personReport = serializer.DeserializeObject(dataObject, typeOf(TestPerson));
        System.Console.WriteLine("dummy line");
    }

我的.cshtml页面:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
<div id="testKo">
    Name: <input type="text" data-bind="value: Name"/>
    Place: <input type="text" data-bind="value: Place" /><br />
    Age: <input type="text" data-bind="value: Age" /><br />
    <input type="button" id="submitForm" class="btn-lg" value="Submit" />
</div>
<form id="photoForm" method="post" enctype="multipart/form-data">
    <input type="hidden" id="personId" name="person" />
    <input type="file" id="personPhotoId" name="personPhoto" />
</form>
<script>
    $(document).ready(function () {
        $(document).ready(function () {
            var element = document.getElementById("testKo");
            ko.applyBindings(viewModel, element);
            $("#submitForm").on("click", function () {
                var vmData = ko.toJSON(viewModel);
                //$("#personId").val({ person: vmData });
                var formData = new FormData($("#photoForm")[0]);
                formData.append("person", vmData, "person");
                //var data = new FormData();
                //data.append("vmData", vmData);
                //data.append("photo", $("#personPhoto").get(0).files[0])
                $.ajax({
                    type: "POST",
                    url: '@Url.Action("SavePersonData", "Home")',
                    //cache: false,
                    //async: false,
                    contentType: false,
                    processData: false,
                    enctype: "multipart/form-data",
                    dataType: "json",
                    //data: {
                    //    testPerson: vmData
                    //},
                    //data: {
                    //    personPhoto: formData,
                    //    person: vmData
                    //},
                    data: formData,
                    success: function (data) {
                        alert("success!");
                    }
                });
            });
        });
        function generatedViewModel() {
            var self = this;
            self.Id = ko.observable("1");
            self.Name = ko.observable();
            self.Place = ko.observable();
            self.Age = ko.observable();
            self.File = ko.observable();
        }
        var viewModel = new generatedViewModel();
    });
</script>

有没有什么方法可以用这个代码接收控制器操作方法中的两个参数?或者我需要以任何方式调整它吗?我只需要将所有内容,包括文件/图像上传数据和非表单数据对象发送到我的控制器方法。

如何通过HttpPostedFileBase和ViewModel发送上传的文件

好吧,最好的解决方案是让两个同步的ajax调用一个在另一个中。发送";personPhoto";数据,然后将其转换为字节数组,并将其设置为会话变量。如果此ajax调用成功,则对处理Form/Model数据的主方法进行另一次ajax调用,并将缓存的会话对象用于";personPhoto";。

用以下代码替换ajax代码:

            var data = new FormData($("#photoForm").get(0));
            $.ajax({
                type: "POST",
                url: '@Url.Action("CacheUploads", "Home")',
                data: data,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function () {
                    var vmData = ko.toJS(viewModel);
                    $.ajax({
                        type: "POST",
                        url: '@Url.Action("SavePersonData", "Home")',
                        data: { person: vmData },
                        success: function (data) {
                        }
                    });
                }
            });

并用以下方法替换您的控制器方法:

    public void SavePersonData(TestPerson person)
    {
        // You no longer need to deserialize as you'll have data properly mapped to the TestPerson object.
        //var dataObject = Request.Form["person"];
        //var serializer = new JavaScriptSerializer();
        //object personReport = serializer.DeserializeObject(dataObject);
        person.File = (byte[])Session["UploadedPhoto"];
        System.Console.WriteLine("dummy line");
    }
    public JsonResult CacheUploads(HttpPostedFileBase personPhoto)
    {
        byte[] photoAsBytes = null;
        using (var binaryReader = new BinaryReader(personPhoto.InputStream))
        {
            photoAsBytes = binaryReader.ReadBytes(personPhoto.ContentLength);
        }
        Session.Add("UploadedPhoto", photoAsBytes);
        return Json(new { success = true }, JsonRequestBehavior.AllowGet);
    }

没有其他方法可以在单个ajax调用中同时处理FormData和Non-FormViewModel数据。这是我从解决方案的角度所能得到的最接近的结果。

使用这个。

@using (Html.BeginForm("Action", "Controller", System.Web.Mvc.FormMethod.Post, new { @id = "formid", enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
 <input type="hidden" id="personId" name="person" />
<input type="file" id="personPhotoId" name="personPhoto" />
 <input type="submit" id="submitForm" class="btn-lg" value="Submit" />
}