代码之家  ›  专栏  ›  技术社区  ›  Frinavale

ASP.NET MVC:绑定到多个模型

  •  0
  • Frinavale  · 技术社区  · 15 年前

    我在玩ASP.NET MVC应用程序,遇到了一些问题。我对ASP.NET MVC还很陌生,只是现在还不太了解让事情正常运行的基础知识。

    我有一个PersonModel、一个PersonController和一组视图,这些视图允许用户添加新的人员、编辑人员和搜索人员。

    我没有在后端使用数据库。我所做的一切都依赖于一个返回“person”结构(我将其转换为personmodel)的外部dll。

    为了搜索人员,我必须提供一个人员结构,作为外部dll中方法的搜索条件。方法返回与搜索条件匹配的人员结构集合。如果我想检索系统中的所有人员,我将为该方法提供一个空的人员结构。

    所以,我有“检索所有人”功能……但是我想提供一个高级搜索。

    我的搜索视图绑定到一个包含2个属性的类:

    Public Class PersonSearchModel
      Private _searchCriteria As PersonModel
      Private _searchResults As List(Of PersonModel)
      Public Property SearchCriteria As PersonModel
        Get
          return _searchCriteria
        End Get
        Set(ByVal value As PersonModel)
          _searchCriteria = value
        End Set
      End Property
      Public Property SearchResults As List(Of PersonModel)
        Get
          return _searchResults 
        End Get
        Set(ByVal value As List(Of PersonModel))
          _searchResults = value
        End Set
      End Property
    End Class
    

    现在,搜索视图绑定到这个PersonsearchModel,我有两个部分……一个部分,用户可以在其中提供搜索条件,另一个部分显示搜索结果。

    将personsearchModel.searchCriteria绑定到用于显示/收集人员搜索条件的控件时出现问题。

    我无法检索搜索条件。

    在我看来,搜索条件如下:

     <fieldset>
            <legend>Search Criteria</legend>
            <%
                With Model.SearchCriteria
             %>
            <div style="float:left">
            <p>
                <label for="FirstName">
                    FirstName:</label>
                <%=Html.TextBox("FirstName", Html.Encode(.FirstName))%>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">
                    LastName:</label>
                <%=Html.TextBox("LastName", Html.Encode(.LastName))%>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
             <!-- More controls -->
            </div>
            <%  End With%>
        </fieldset>
         <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%>
    <!-- The Search Results Section-->
    

    传入搜索方法的PersonModel是一个新的/空的PersonModel对象。 它不包含用户输入的数据。

    我在这里做错什么了?

    *** 编辑 *** 我尝试改变视图以不同方式绑定。我删除了vb“with”:

     <fieldset>
            <legend>Search Criteria</legend>
            <div style="float:left">
            <p>
                <label for="FirstName">
                    FirstName:</label>
                <%=Html.TextBox("FirstName", Html.Encode(.FirstName))%>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">
                    LastName:</label>
                <%=Html.TextBox("LastName", Html.Encode(.LastName))%>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
             <!-- More controls -->
            </div>
        </fieldset>
         <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%>
    <!-- The Search Results Section-->
    

    但这没有帮助。

    我也尝试过:

     <fieldset>
            <legend>Search Criteria</legend>
            <div style="float:left">
            <p>
                <label for="FirstName">
                    FirstName:</label>
                <%=Html.TextBox("Model.SearchCriteria.FirstName", Html.Encode(Model.SearchCriteria.FirstName))%>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">
                    LastName:</label>
                <%=Html.TextBox("Model.SearchCriteria.LastName", Html.Encode(Model.SearchCriteria.LastName))%>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
             <!-- More controls -->
            </div>
        </fieldset>
         <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%>
    <!-- The Search Results Section-->
    

    还有:

     <fieldset>
            <legend>Search Criteria</legend>
            <div style="float:left">
            <p>
                <label for="FirstName">
                    FirstName:</label>
                <%=Html.TextBox("SearchCriteria.FirstName")%>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">
                    LastName:</label>
                <%=Html.TextBox(".SearchCriteria.LastName")%>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
             <!-- More controls -->
            </div>
        </fieldset>
         <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%>
    <!-- The Search Results Section-->
    

    但是,我仍然得到一个空的/新的PersonModel传递到控制器中的搜索方法中。我还检查了personsearchModel.searchCriteria,查看它是否包含输入的值,但它也有一个新的/空的personmode。

    -弗林尼

    4 回复  |  直到 15 年前
        1
  •  0
  •   Matt J    15 年前

    使用反射几乎是MVC模型绑定器设置要做的,我猜您没有正确地命名字段,所以当它们返回到您的操作时,它们没有映射到您的参数。尝试做如下的事情:

    Function Search(ByVal personSearchModel As PersonSearchModel, ByVal collection As FormCollection) As ActionResult
    

    那么您的字段(HTML)的名称应该如下所示:

    <%= Html.TextBox("personSearchModel.SearchCriteria.FirstName", Html.Encode(Model.SearchCriteria.FirstName)) %>
    
        2
  •  0
  •   Eilon    15 年前

    我认为调用html.textbox和html.validationmessage时缺少必要的前缀。我推荐 使用vb的“with”关键字,因为它会隐藏成员的全名。HTML助手和模型绑定(用于将参数传递到操作方法)都需要属性或字段的全名才能检索值。

    试试这个:

    <%= Html.TextBox("SearchCriteria.FirstName", SearchCriteria.FirstName) %>
    <%= Html.ValidationMessage("SearchCriteria.FirstName", "*") %>
    

    另外,对于传递到文本框中的值,也不需要调用html.encode()——它无论如何都会自动编码。

        3
  •  0
  •   Frinavale    15 年前

    经过大量的测试和调试,我发现了一些有趣的东西:我可以从传递到搜索函数的FormCollection中检索用户输入的信息。最初我的搜索函数取了2个参数。第一个参数是应绑定到PersonSearchModel.SearchCriteria的PersonModel,第二个参数是视图的FormCollection。

    我可以根据传递到搜索函数的FormCollection创建用于PersonSearchModel.SearchCriteria的PersonModel。我删除了第一个参数(personmodel),因为它总是一个新的/空的对象。

    这是我当前的搜索方法:

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Search(ByVal collection As FormCollection) As ActionResult
            Dim searchModel As New SearchPersonsModel
    
            Dim personProperties() As PropertyInfo = GetType(PersonModel).GetProperties
            For Each pi As PropertyInfo In personProperties
                Dim piName As String = pi.Name
                Dim info As String = Array.Find(collection.AllKeys, Function(x) x.Compare(piName, x, true) = 0)
                If String.IsNullOrEmpty(info) = False Then
                    pi.SetValue(searchModel.SearchCriteria, collection.Item(info), Nothing)
                End If
            Next
    'The following code uses the searchModel.searchCriteria to search for People.
    End Function
    

    我的观点(如果你好奇的话)如下:

     <% Using Html.BeginForm()%>
     <%With Model.SearchCriteria%>
      <fieldset>
        <legend>Search Criteria</legend>
          <div style="float: left">
            <p>
              <label for="FirstName">FirstName:</label>
              <%=Html.TextBox("FirstName", Html.Encode(Model.SearchCriteria.FirstName))%>
               <%=Html.ValidationMessage("Model.SearchCriteria.FirstName", "*")%>
            </p>
            <p>
                <label for="LastName">LastName:</label>
                <%=Html.TextBox("LastName", Html.Encode(Model.SearchCriteria.LastName))%>
                <%=Html.ValidationMessage("Model.SearchCriteria.LastName", "*")%>
            </p>
          <!---..... more controls .... -->
        </div>
      </fieldset>
      <%End With%>
      <input type="submit" value="Search" />
    
    <!-- Search Results Controls -->
    
      <%End Using%>
    

    这个解决方案有效,但我真的不满意。 为什么我必须重新创建用作搜索条件的个人模型? 为什么不能将此对象作为参数传递到搜索方法中?

    -弗林尼

        4
  •  0
  •   Peder Skou    15 年前

    似乎updateModel()可能是您的朋友。MVC不会围绕Web窗体样式传递对象。

    即使模型由两个对象组成,也完全可以使用updateModel来检索其中一个对象的值。您只需将该对象指定为参数即可。例如。:

    Thing t = new Thing();
    UpdateModel(t);
    

    您可能需要查看参数名以允许MVC正确猜测。 此外,出于安全原因,您可能必须将属性列入白名单和/或避免过于热衷于模型验证。