Search code examples
c#asp.net-mvcparametersdropzoneform-fields

ASP.Net MVC 5 with DropZone Can't Send Additional Parameters to Controller


Ok, I am sure this already has an answer somewhere, but I can honestly tell you that everything I have tried, has failed. Here is my current configuration:

Shared _Layout.cshtml (below the footer)

<script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    <script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
    @await RenderSectionAsync("Scripts", required: false)

Images View

@model NewProductVM
<form id="form2" method="post" enctype="multipart/form-data" data-parsley-validate class="form-horizontal form-label-left">    
    <div class="form-group">
        <label class="control-label col-md-2" for="first-name">
             <span class="required">*</span>
        </label>
        
        <input type="hidden" value="@Model.Id" />

        <div class="col-md-6" id="dropzone">
            <div action="UploadFiles" class="dropzone" id="uploader">
                Drop files here or click to upload.<br>
            </div>
        </div>
    </div>
</form>

Products Controller

[HttpPost]
public async Task<IActionResult> UploadFiles(string Id)
{
            bool bSuccess = true;            

            _ConnectionString = _Configuration.GetConnectionString("StorageConnectionString");
            _ContainerName = _Configuration.GetValue<string>("StorageContainerName");

            string uploads = Path.Combine(_hostingEnvironment.ContentRootPath, "Uploads");

            if (!Directory.Exists(uploads))
                Directory.CreateDirectory(uploads);

            foreach (var iFormFile in Request.Form.Files)
            {
                if (iFormFile.Length > 0)
                {
                    if (StorageHelper.IsImage(iFormFile))
                    {
                        var filePath = Path.Combine(uploads, iFormFile.FileName);
                        using (var stream = new FileStream(filePath, FileMode.Create))
                        {
                            await iFormFile.CopyToAsync(stream);
                        }

                        bSuccess = await StorageHelper.UploadFileToStorage(iFormFile, filePath, _ConnectionString, _ContainerName);
                        System.IO.File.Delete(filePath);

                        ProductImage productImage = new ProductImage
                        {
                            ProductId = int.Parse(Id),
                            ImageURL = $"{_Configuration.GetValue<string>("StorageContainerURL")}/{iFormFile.FileName}"                            
                        };

                        await _imageService.AddNewImageAsync(productImage);                        
                    }
                }
            }
            return RedirectToAction("Index");
}

I would really like to pass the entire NewProductVM model to the UploadFiles method, but there are not very many properties in the view model, so I could pass each property individually.

Right now I am taking someones suggestion to create a hidden form field and add a value I want to pass to the controller as a form field, but the parameter value in the UploadFiles method is null. I have also tried using asp-route-id="@Model.Id". When I did that, the value of id was 0 in the controller method.

Anyone have any suggestions?


Solution

  • Ok, I finally found the answer and I cannot believe how simple it was. I have been working on this for several hours. I found the answer here: https://social.msdn.microsoft.com/Forums/en-US/a87c6936-c0b5-4f47-b074-dbaf4c154cdd/id-parameter-returning-null-after-using-formdataappend-to-append-id-to-model-id-in-mvc-5?forum=aspmvc

    This is what I did:

    Images.cshtml

    <form id="form2" method="post" enctype="multipart/form-data" data-parsley-validate class="form-horizontal form-label-left">
        <div class="form-group">
                
            <label class="control-label col-md-2" for="first-name">
                <span class="required">*</span>
            </label>
    
            <div class="col-md-6" id="dropzone">
                <div action="[email protected]" class="dropzone" id="uploader">
                    Drop files here or click to upload.<br>
                </div>
    
            </div>
        </div>
    </form>   
    

    ProductsController.cs

    [HttpPost]        
    public async Task<IActionResult> UploadFiles(int Id)
    {
        bool bSuccess = true;            
    
        _ConnectionString = _Configuration.GetConnectionString("StorageConnectionString");
        _ContainerName = _Configuration.GetValue<string>("StorageContainerName");
    
        //int Id = int.Parse(fc["Id"]);
    
        string uploads = Path.Combine(_hostingEnvironment.ContentRootPath, "Uploads");
    
        if (!Directory.Exists(uploads))
            Directory.CreateDirectory(uploads);
    
        foreach (var iFormFile in Request.Form.Files)
        {
            if (iFormFile.Length > 0)
            {
                if (StorageHelper.IsImage(iFormFile))
                {
                    var filePath = Path.Combine(uploads, iFormFile.FileName);
                    using (var stream = new FileStream(filePath, FileMode.Create))
                    {
                        await iFormFile.CopyToAsync(stream);
                    }
    
                    bSuccess = await StorageHelper.UploadFileToStorage(iFormFile, filePath, _ConnectionString, _ContainerName);
                    System.IO.File.Delete(filePath);
    
                    //ProductImage productImage = new ProductImage
                    //{
                    //    ProductId = Id,
                    //    ImageURL = $"{_Configuration.GetValue<string>("StorageContainerURL")}/{iFormFile.FileName}"          
                    //};
    
                    //await _imageService.AddNewImageAsync(productImage);                        
                }
            }
        }
        return RedirectToAction("Index");
    }
    
    

    The part that really made it work was action="[email protected]".

    So basically, I am using the action to pass the values I want to my controller method.