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



我已经创建了两个独立的子模型,我希望能够创建一个父模型,允许我在一个视图中使用两个子模型。

我遇到的问题是,我的视图中不断出现错误,通知我父模型没有访问变量。"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>

家庭控制器:

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

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
}
}

首先,为什么有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>

那么,一切都应该很好。

最新更新