包含两个模型的父视图模型

时间:2017-11-17 07:46:39

标签: c# asp.net-core

我创建了两个独立的子模型,我希望能够创建一个父模型,这样我就可以在一个视图中使用这两个子模型。

我遇到的问题是我不断从我的View中收到错误,这告诉我Parent Model没有访问变量。 “MainPageModel不包含定义......”

我的最终目标是能够拥有一个使用输入的表单,并且能够在一个模型中上传所有图像。这将创建一个带图像的简单配置文件。提交后,您将被带到另一个视图,其中包含您的个人资料。

模型1:

namespace Profile.Models
{
    public class Profiler
    {
        public string FName { get; set; }
        public string Address { get; set; }
        public string BirthDate { get; set; }
        public string PhoneNumber { get; set; }
        public string Comments { get; set; }
    }
}

模型2:

namespace Profile.Models
{
    public interface IFormFile
    {
        string ContentType { get; }
        string ContentDisposition { get; }
        IHeaderDictionary Headers { get; }
        long Length { get; }
        string Name { get; }
        string FileName { get; }
        Stream OpenReadStream();
        void CopyTo(Stream target);
        Task CopyToAsync(Stream target, CancellationToken cancellationToken);
    }
}

父模型:

namespace Profile.Models
{
    public class MainPageModel
    {
        public Profiler Profiler { get; set; }
        public IFormFile IFormFile { get; set; }

        public MainPageModel(Profiler Profiler)
        {
            Profiler = Profiler;
        }
    }
}

查看:

@model Profile.Models.MainPageModel
@{
    ViewData["Title"] = "Profiler";
}
<h2>Create your Profile using the form below</h2>
<h3>On Submission, your profile will be created for you to see.</h3>

<form asp-action="Profiler" >
    <label asp-for="FName"></label>
    <input asp-for="FName" /> <br /><br />
    <label asp-for="Address"></label>
    <input asp-for="Address" /> <br /><br />
    <label asp-for="BirthDate"></label>
    <input asp-for="BirthDate" /> <br /><br />
    <label asp-for="PhoneNumber"></label>
    <input asp-for="PhoneNumber" /> <br /><br />
    <label asp-for="Comments"></label>
    <input asp-for="Comments" /> <br /><br />
    <input type="submit" value="Submit" />
</form>

<form method="post" enctype="multipart/form-data">
    <input type="file" name="files" multiple />
    <input type="submit" value="Upload" />
</form>

HomeController中:

public IActionResult Profiler([Bind("FName,Address,BirthDate,PhoneNumber,Comments")] Profiler Profiles)
    {
        return View(new MainPageModel (Profiles));
    }

2 个答案:

答案 0 :(得分:1)

将参数构造函数添加到MainPageModel

namespace Profile.Models
{
    public class MainPageModel
    {
        public MainPageModel () {}

        public MainPageModel(Profiler profiler)
        {
            Profiler = profiler;
        }

        public Profiler Profiler { get; set; }

        public IFormFile Image{ get; set; }

    }
}

然后将Profile前缀添加到配置文件表单中的输入名称,并将文件输入名称更改为Image

@model Profile.Models.MainPageModel
@{
    ViewData["Title"] = "Profiler";
}
<h2>Create your Profile using the form below</h2>
<h3>On Submission, your profile will be created for you to see.</h3>

<form asp-action="Profiler" method="post">
    <label asp-for="Profile.FName"></label>
    <input asp-for="Profile.FName" /> <br /><br />
    <label asp-for="Profile.Address"></label>
    <input asp-for="Profile.Address" /> <br /><br />
    <label asp-for="Profile.BirthDate"></label>
    <input asp-for="Profile.BirthDate" /> <br /><br />
    <label asp-for="Profile.PhoneNumber"></label>
    <input asp-for="Profile.PhoneNumber" /> <br /><br />
    <label asp-for="Profile.Comments"></label>
    <input asp-for="Profile.Comments" /> <br /><br />
    <input type="submit" value="Submit" />
</form>

<form asp-action="Profiler" method="post" enctype="multipart/form-data">
    <input type="file" name="Image" />
    <input type="submit" value="Upload" />
</form>

和控制器

[HttpGet]
public IActionResult Profiler()
{
    return View(new MainPageModel(profile));
}

[HttpPost]
public IActionResult Profiler(MainPageModel viewModel)
{
    if(viewModel.Profile != null )
    {
        // Save profile
    }
    else if(viewModel.Image != null)
    {
        // Save image
    }
}

答案 1 :(得分:1)

首先,为什么你有IFormFile的界面? 已经内置于ASP.NET Core的这样一个接口。至少,它是多余的和不必要的,并且最多你最终会导致冲突。摆脱它,并使用内置的IFormFile

然后,您的操作仅接受Profiler个实例。您的操作需要接受您传递给视图的相同视图模型,否则您将遇到各种问题。换句话说,如果你想要这样的组合视图模型,那么你也需要发布它。

但是,如果您实际上首先正确设置它,则根本不需要它。首先,您应该永远直接绑定到实体。实体类是并且应该是一个简单的DTO类,并且应该只关注数据库的需求来设计,因为这是它的目的。视图有不同的关注点和需求,完全不适合您的实体类处理。这是视图模型的目的,因此您应该使用ProfilerViewModel之类的模型。您的Profiler实体应该有一些方法来保存文件上传,无论是byte[]属性还是仅指向可以找到上载文件的URL或文件路径的简单字符串属性。同时,您的视图模型将具有您的IFormFile属性。从视图模型映射到实体时,您将保存上传的文件并在实体上填充相应的属性。

这也可以让你摆脱上帝遗弃的Bind属性,这个属性应该永远不会被使用。说真的,它在每个方面都很可怕。它只是为了解决直接使用实体造成的明显安全漏洞,而不是实际上鼓励开发人员首先正确设计应用程序。

如果您的操作接受正确的视图模型,则可以解决在页面上有两个单独的表单的问题,这会严重影响您的用户,因为提交第一个表单不会发布任何上传的文件并提交第二个表单不会发布他们所做的任何个人资料更改。基本上,无论哪种方式,您都在丢弃用户输入。将文件输入移动到第一个表单并删除第二个表单。当然,还要带上enctype属性。

最后,您允许上传多个文件,但您拥有的只是一个接受单个IFormFile的属性。您需要List<IFormFile>

长短:

public class ProfilerViewModel
{
    public string FName { get; set; }
    public string Address { get; set; }
    public string BirthDate { get; set; }
    public string PhoneNumber { get; set; }
    public string Comments { get; set; }

    public List<IFormFile> Files { get; set; }
}

然后:

public async Task<IActionResult> Profiler(ProfilerViewModel model)
{
    if (ModelState.IsValid)
    {
        var profile = new Profiler
        {
            FName = model.FName,
            Address = model.Address,
            BirthDate = model.BirthDate,
            PhoneNumber = model.PhoneNumber
            Comments = model.Comments
        };

        foreach (var file in model.Files)
        {
            // handle your file uploads
        }

        db.Profiles.Add(profile);
        await db.SaveChangesAsync();

        return RedirectToAction("Somewhere");
    }

    return View(model);
}

在你看来:

@model Profile.Models.ProfilerViewModel
@{
    ViewData["Title"] = "Profiler";
}
<h2>Create your Profile using the form below</h2>
<h3>On Submission, your profile will be created for you to see.</h3>

<form asp-action="Profiler" method="post" enctype="multipart/form-data">
    <label asp-for="FName"></label>
    <input asp-for="FName" /> <br /><br />
    <label asp-for="Address"></label>
    <input asp-for="Address" /> <br /><br />
    <label asp-for="BirthDate"></label>
    <input asp-for="BirthDate" /> <br /><br />
    <label asp-for="PhoneNumber"></label>
    <input asp-for="PhoneNumber" /> <br /><br />
    <label asp-for="Comments"></label>
    <input asp-for="Comments" /> <br /><br />
    <input asp-for="Files" />
    <input type="submit" value="Submit" />
</form>

然后,一切都应该正常工作。