如何在asp.net核心中的视图组件带有输入文件的表单和控制器之间进行交互?

问题描述

我是使用 asp.net core 进行网页设计的初学者。我写了一个视图组件,它有一个表单,其中包含一些与视图模型相关的输入。这些输入之一是文件输入(IFormFile 数据类型)。

我想将此视图模型提交给控制器的操作(POST 模式),检查模型的有效性,如果模型状态有效,则返回另一个视图组件,如果模型状态有效,则使用此视图模型留在此视图组件上无效。

这是我的 viewmodel:Pricingviewmodel.cs

    public class Pricingviewmodel
    {
        [display(Name = "Select a file")]
        public IFormFile formFile { get; set; }

        [display(Name = "ColumnCode")]
        [required(ErrorMessage = "Enter {0} value,please")]
        public string colCode { get; set; }

        [display(Name = "ColumnName")]
        [required(ErrorMessage = "Enter {0} value,please")]         
        public string colName { get; set; }
    }

我的 ViewComponent(控制器):PricingComponent.cs

   public class PricingComponent : ViewComponent
   {
       public async Task<IViewComponentResult> InvokeAsync(Pricingviewmodel pricing)
       {               
          return await Task.Fromresult((IViewComponentResult)View("PricingView",pricing));
       }
   }

我的 ViewComponent(视图):PricingView.cshtml

<form class="text-left" method="post" enctype="multipart/form-data">

   <input name="IsValidPricing" type="hidden" value="@ViewBag.isValid" />

   <div class="form-group text-left">
     <label asp-for="colCode" class="control-label"></label>
     <input asp-for="colCode" class="form-control" id="colCodeId"/>
     <span asp-validation-for="colCode" class="text-danger"></span>
   </div>

   <div class="form-group text-left">
     <label asp-for="colName" class="control-label"></label>
     <input asp-for="colName" class="form-control" id="colNameId"/>
     <span asp-validation-for="colName" class="text-danger"></span>
   </div>

   <div class="form-group text-left">
     <label asp-for="formFile " class="control-label"></label>
     <input type="file" accept=".xlsx,.csv" asp-for="formFile" id="MyInputFile"/>
   </div>

   <div class="form-group mt-4">
     <input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
   </div>
</form>

我的家庭控制器:HomeController.cs

    [HttpPost]
    public IActionResult ShowPricing(Pricingviewmodel pricing)
    {
        if (ModelState.IsValid)
        {
            int temp;
            if (!int.TryParse(pricing.colCode,out temp))
            {
                ViewBag.isValid = 0;
                ModelState.AddModelError("colCode","Invalid Data");
                return ViewComponent("PricingComponent",new { pricing = pricing }); // 1
            }
            else if (!int.TryParse(pricing.colName,out temp))
            {
                ViewBag.isValid = 0;
                ModelState.AddModelError("colName",new { pricing = pricing }); //2
            }
            else
            {
                ViewBag.isValid = 1;   
                
                // do something ...

                return ViewComponent("ShowPricingExcelComponent"); //Call another view component
            }
        }
        else
        {
           ViewBag.isValid = 0;
           return ViewComponent("PricingComponent",new { pricing = pricing }); //3
        }
    }

问题:

计划A:如果我使用上面的提交输入标签(asp-action,asp-controller)选项,视图模型发送正确,但我不知道如何处理模型的有效性并留在这个视图组件上。在上面的代码中,当“ShowPricing”操作运行时,如果模型状态有效,代码正常工作,但当模型无效(1,2,3)时,“PricingView”不显示验证汇总,只加载当前视图模型.

计划 B:我使用 ajax 将 viewmodel 发送到操作,而不是显示验证摘要,我使用 ajax 向用户发送警报。我将 PricingView 更改如下:

我的 ViewComponent(视图):PricingView.cshtml

<form class="text-left" method="post" enctype="multipart/form-data">

   <input name="IsValidPricing" type="hidden" value="@ViewBag.isValid" />

   <div class="form-group text-left">
     <label asp-for="colCode" class="control-label"></label>
     <input asp-for="colCode" class="form-control" id="colCodeId"/>
     <span asp-validation-for="colCode" class="text-danger"></span>
   </div>

   <div class="form-group text-left">
     <label asp-for="colName" class="control-label"></label>
     <input asp-for="colName" class="form-control" id="colNameId"/>
     <span asp-validation-for="colName" class="text-danger"></span>
   </div>

   <div class="form-group text-left">
     <label asp-for="fromFile " class="control-label"></label>
     <input type="file" accept=".xlsx,.csv" asp-for="formFile" id="MyInputFile"/>
   </div>

    <script>
      $(document).ready(function () {
        $('#ShowPricingBtn').click(function () {
                var _url = '@Url.Action("ShowPricing","Home")';
                var input = $("#MyInputFile").get(0).files[0]; 

                $.ajax({
                    type: "POST",url: _url,data: {
                       formFile: input,colCode: $("#colCode").val(),colName: $("#colName").val(),},success: function (result) 
                    {
                       var IsValid = $('body').find('[name="IsValidPricing"]').val();
                       if (IsValid) 
                       {
                          $("#ShowExcelTable").html(result);
                       }
                       else {
                          alert("Invalid Data");
                       }
                    },});
           });
       });
    </script>
   <div class="form-group mt-4">
     <input type="submit" value="Show" id="ShowPricingBtn" />
   </div>
</form>

问题:

在此代码中: 1. 如果模型状态无效,警报会正确发送。但如果模型状态有效: 2. formFile 输入未正确发送到操作,并且在视图模型中为空。

我不知道我应该在 Plan A 或 Plan B 中做什么来解决他们的问题。你知道我哪里错了吗?

解决方法

我无法重现您的错误。如上所示,您的代码按预期工作。显示验证消息。

为了使它成为一个工作示例,我首先添加了一个 GET 方法。

[HttpGet]
public IActionResult ShowPricing() => ViewComponent("PricingComponent",new { pricing = new PricingViewModel() });

打开 URL Home/ShowPricing

填写表格。

enter image description here

发送表格。并显示验证消息。

enter image description here

,

不知道你如何调用视图组件,这里是工作演示:

对于计划A

1.创建 ViewComponents/PricingComponent.csViewComponents/ShowPricingExcelComponent.cs

public class PricingComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
    {
        return await Task.FromResult((IViewComponentResult)View("PricingView",pricing));
    }
}    
public class ShowPricingExcelComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
    {
        return await Task.FromResult((IViewComponentResult)View("ShowPricingExcel",pricing));
    }
}

2.创建Views/Shared/Components/PricingComponent/PricingView.cshtml

@model PricingViewModel 
<form class="text-left" method="post" enctype="multipart/form-data">

    <input name="IsValidPricing" type="hidden" value="@ViewBag.isValid" />

    <div class="form-group text-left">
        <label asp-for="colCode" class="control-label"></label>
        <input asp-for="colCode" class="form-control" id="colCodeId" />
        <span asp-validation-for="colCode" class="text-danger"></span>
    </div>

    <div class="form-group text-left">
        <label asp-for="colName" class="control-label"></label>
        <input asp-for="colName" class="form-control" id="colNameId" />
        <span asp-validation-for="colName" class="text-danger"></span>
    </div>

    <div class="form-group text-left">
        <label asp-for="formFile " class="control-label"></label>
        <input type="file" accept=".xlsx,.csv" asp-for="formFile" id="MyInputFile" />
    </div>

    <div class="form-group mt-4">
        <input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
    </div>
</form>

3.创建Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml

<h1>Excel....</h1>

项目结构:

enter image description here

4.Views/Home/Index.cshtml

@await Component.InvokeAsync("PricingComponent")

5.HomeController:

public class HomeController : Controller
{       
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult ShowPricing(PricingViewModel pricing)
    {
        if (ModelState.IsValid)
        {
            int temp;
            if (!int.TryParse(pricing.colCode,out temp))
            {
                ViewBag.isValid = 0;
                ModelState.AddModelError("colCode","Invalid Data");
                return View("Index",pricing);
            }
            if (!int.TryParse(pricing.colName,out temp))
            {
                ViewBag.isValid = 0;
                ModelState.AddModelError("colName",pricing);
            }
            else 
            {
                ViewBag.isValid = 1;

                // do something ...

                return ViewComponent("ShowPricingExcelComponent"); //Call another view component
            }              
        }
        else
        {
            ViewBag.isValid = 0;
            return View("Index",pricing); //3
        }
    }
}

结果:

enter image description here

对于 PlanB

1.创建 ViewComponents/PricingComponent.csViewComponents/ShowPricingExcelComponent.cs

2.创建Views/Shared/Components/PricingComponent/PricingView.cshtml

首先应该是type="button",否则会向后端调用两次。其次,你在ajax中所做的不正确,更详细的解释你可以参考this answer。最后,你无法通过获取成功函数中的 IsValidPricing 值来判断模型状态。因为您获取的值始终是您首次渲染页面的数据,因此在 ajax 回发时无法获取更改后的 ViewBag 值。

@model PricingViewModel
<form class="text-left" method="post" enctype="multipart/form-data">

    <input name="IsValidPricing" type="hidden" value="@ViewBag.isValid" />

    <div class="form-group text-left">
        <label asp-for="colCode" class="control-label"></label>
        <input asp-for="colCode" class="form-control" id="colCodeId" />
        <span asp-validation-for="colCode" class="text-danger"></span>
    </div>

    <div class="form-group text-left">
        <label asp-for="colName" class="control-label"></label>
        <input asp-for="colName" class="form-control" id="colNameId" />
        <span asp-validation-for="colName" class="text-danger"></span>
    </div>

    <div class="form-group text-left">
        <label asp-for="formFile " class="control-label"></label>
        <input type="file" accept=".xlsx,.csv" asp-for="formFile" id="MyInputFile" />
    </div>

    <div class="form-group mt-4">
        @*it should be type="button"*@
        <input type="button" value="Show" id="ShowPricingBtn" />
    </div>
</form>

<script src="~/lib/jquery/dist/jquery.min.js"></script>

<script>
      $(document).ready(function () {
        $('#ShowPricingBtn').click(function () {
            var _url = '@Url.Action("ShowPricing","Home")';
            var input = $("#MyInputFile").get(0).files[0];

            var fdata = new FormData();
            fdata.append("formFile",input);
            $("form input[type='text']").each(function (x,y) {
                fdata.append($(y).attr("name"),$(y).val());
            });
            $.ajax({
                type: "POST",url: _url,data: fdata,contentType: false,processData: false,success: function (result)
                {
                    console.log(result);
                    if (result==false)
                    {
                        alert("Invalid Data");
                    }
                    else {
                        $("#ShowExcelTable").html(result);

                    }
                },});
        });
  });
</script>

3.创建Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml

<h1>Excel....</h1>

4.Views/Home/Index.cshtml

@await Component.InvokeAsync("PricingComponent")
<div id="ShowExcelTable"></div>

5.HomeController:

public class HomeController : Controller
{       
    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public IActionResult ShowPricing(PricingViewModel pricing)
    {
        if (ModelState.IsValid)
        {
            int temp;
            if (!int.TryParse(pricing.colCode,out temp)|| !int.TryParse(pricing.colName,out temp))
            {
                ViewBag.isValid = 0;
                return Json(false);
            }
            else
            {
                ViewBag.isValid = 1;

                // do something ...
                return ViewComponent("ShowPricingExcelComponent"); //Call another view component
            }
        }
        else
        {
            ViewBag.isValid = 0;
            return Json(false);
        }
    }
}

结果: enter image description here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...