【问题标题】:Razor Pages : Inheritance of a model to add fields during creationRazor Pages:继承模型以在创建期间添加字段
【发布时间】:2019-11-15 00:49:08
【问题描述】:

这些实体是我想要完成的虚构等价物(实际上更复杂)。

只有在创建文章时,我才需要额外的字段(SendToSubscribers 字段),这些字段不是实体本身的一部分。

public class Article {
    public string Title { get; set }
}

public class ArticleCreateForm : Article {
    public bool SendToSubscribers { get; set; }
}

在创建/更新的cshtml中有:

@model Article
...
@if (string.IsNullOrEmpty(Model.Id))
{
    <admin-input asp-for="SendToSubscribers" />

不幸的是,这是我得到的错误:

“Article”不包含“SendToSubscribers”的定义,并且找不到接受“Article”类型的第一个参数的可访问扩展方法“SendToSubscribers”(您是否缺少 using 指令或程序集引用?)

对不起,如果方法一点都不好,我来自 PHP 背景。

我想这不是一个好的解决方案,所以我怎样才能使它正确?谢谢。

【问题讨论】:

  • 不需要创建另一个模型只是为了隐藏title字段,当razor页面渲染成html表单时,只会渲染razor页面中定义的字段。
  • 在这种情况下它不起作用,因为该字段是 SendToSubscribers
  • c# 不适合这个。
  • @dctremblay 请检查 formcollection 对象以传递类中的动态实体

标签: c# asp.net-mvc asp.net-core razor


【解决方案1】:

也许您不喜欢它,但通常,最简洁的方法是为不同的视图创建不同的模型,并使这些模型与您的持久性模型不同。

在这种方法中,您应该ArticleCreateModel 仅具有创建文章所需的那些属性,包括SendToSubscribers。但它不应该具有Id 属性,因为视图中不需要Id。所以这应该是模型:

public class Article
{
    public string Id { get; set; }
    public string Title { get; set; }
}
public class ArticleCreateModel
{
    public string Title { get; set; }
    public bool SendToSubscribers { get; set; }
}

然后在ArticleContollerCreate动作中,接收ArticleCreateModel然后持久化数据,你可以创建一个Article并持久化到存储中,根据SendToSubscribers的值你将决定也将文章发送给订阅者:

public ActionResult Create(ArticleCreateModel model)
{
    if(ModelState.IsValid())
    {
        ArticleBustinessLogic.Create(ArticleCreateModel model);
        return RedirectToAction("Index");

        // Or simply
        // var article = new Article();
        // article.Id = Guid.NewGuid().ToString();
        // article.Title = model.Title();
        // ArticleRepository.Create(article);
        // ArticleSubcription.NotifySubscribers(article);
        // return RedirectToAction("Index");
    }
    return View();
}

在这种方法中,View 的模型应该是ArticleCreateModel,你不需要任何if 语句:

@model ArticleCreateModel

...    

<input asp-for="Title" />
<admin-input asp-for="SendToSubscribers" />

...

注意

正如我之前提到的,它不是唯一的解决方案,但它是最干净的解决方案之一。乍一看,你可能会说因为视图和模型不同而增加了开发开销,但从长远来看,值得使用这种方法,因为它使视图代码、控制器代码和业务逻辑代码更清晰,无需 if 语句并使应用程序更易于测试和维护。您可能还想使用对象到对象的映射器,例如 AutoMapper,以便更轻松地将视图模型映射到持久性模型。

【讨论】:

    【解决方案2】:

    您的解决方案有一种与设计模式相关的方法。

    创建一个容器类,它将占用两个模型:

    public class MainArticleModel{
        public Article article {get; set;}
        public ArticleCreateForm articleCreateForm {get; set;}
    }
    

    那么你就可以使用它了:

    @model MainArticleModel
    ...
    @if (string.IsNullOrEmpty(Model.Id))
    {
        <admin-input asp-for="SendToSubscribers" />
    

    这样,两个模型都将包含在一个视图中。

    【讨论】:

      【解决方案3】:

      您可以使用Form Collection在视图中添加额外的参数,这在模型中是不可用的

      查看

      @model Article
          ViewBag.Title = "Home Page";
      }
      
      @using (Html.BeginForm("submit", "Home", new { id = "form1" }, FormMethod.Post))
      {
      
       <p>Use this area to provide additional information.</p>
       <input type="text" name="Title" value="est" />
       <input type="checkbox" name="SendToSubscribers" value="true" />
       <div class="col-md-offset-2 col-md-10">
           <input type="button" id="btnLogOn" value="Save" class="btn btn-default" />
       </div>
      }
      

      C#

          public class HomeController : Controller
          {
              public ActionResult Index()
              {
                  return View();
              }
      
              public void submit(Article a, FormCollection formCollection)
              {
                  var data = a as ArticleCreateForm;
                  bool SendToSubscribers = Convert.ToBoolean(formCollection["SendToSubscribers"]);
      
              }
          }
      

      代码

      你也可以将formcollection转换为类对象

      how to convert formcollection to model in mvc

      【讨论】:

        【解决方案4】:
        @{var m = (ArticleCreateForm)Model;
        if (string.IsNullOrEmpty(m.Id))
        {
            <admin-input asp-for="m.SendToSubscribers" /> }}
        

        【讨论】:

          【解决方案5】:

          您可以使用数据传输对象

          型号:

              public class Article
          {
              public int Id { get; set; }
              [Required]
              public string Title { get; set; }
          }
          

          .

              public class ArticleDto
          {
              public int Id { get; set; }
              [Required]
              public string Title { get; set; }
              public bool SendToSubscribers { get; set; }
          }
          

          控制器:我使用AutoMapper

          public async Task<IActionResult> Create([Bind("Title,SendToSubscribers")] ArticleDto articleDto)
          {
              if (ModelState.IsValid)
              {
                  var article =_mapper.Map<Article>(articleDto); // AutoMapper here
                  //Here you can use articleDto.SendToSubscribers as you want
                  await _articleRepository.AddAsync(article);//Example
                  return RedirectToAction(nameof(Index));
              }
              return View(article);
          }
          

          查看:

          @model WebApplication1.Models.ArticleDto
          
          @{
              ViewData["Title"] = "Create";
          }
          
          <h1>Create</h1>
          
          <h4>ArticleDto</h4>
          <hr />
          <div class="row">
              <div class="col-md-4">
                  <form asp-action="Create">
                      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                      <div class="form-group">
                          <label asp-for="Title" class="control-label"></label>
                          <input asp-for="Title" class="form-control" />
                          <span asp-validation-for="Title" class="text-danger"></span>
                      </div>
                      <div class="form-group form-check">
                          <label class="form-check-label">
                              <input class="form-check-input" asp-for="SendToSubscribers" /> @Html.DisplayNameFor(model => model.SendToSubscribers)
                          </label>
                      </div>
                      <div class="form-group">
                          <input type="submit" value="Create" class="btn btn-primary" />
                      </div>
                  </form>
              </div>
          </div>
          
          <div>
              <a asp-action="Index">Back to List</a>
          </div>
          
          @section Scripts {
              @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
          }
          

          【讨论】:

            猜你喜欢
            • 2020-11-04
            • 1970-01-01
            • 2015-08-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-08-12
            • 1970-01-01
            • 2015-03-16
            相关资源
            最近更新 更多