Suche mit ASP.NET Model Binding

Es gibt eine 8 Jahre alte Webforms Anwendung, die renoviert werden muss. Die Frage ist, wie setzt man Model Binding (ab ASP.NET 4) dafür ein. Die meisten Beispiele nehmen eine Dropdown Liste als Filter. In diesem Beispiel kommt eine Textbox (HTML Input) und ein Button zum Einsatz.

Beim Modelbinding werden für die vier CRUD Methoden in das Code Behind der ASPX Seite entsprechende Methoden gelegt. Natürlich kann das auch eine separate VB.NET Klasse sein.

Da eine Textbox als Datenquelle für die LINQ Query dient, wird mit dem ControlAttribut aus Microsoft.AspNet.FriendlyUrls.ModelBinding der Parameter übergeben.

   1:  Public Function GridView1_GetData(<Control("TextBox1")> ss As String) As IQueryable(Of ADRESSEN)
   2:          Dim pp As New ppCompanyEntities
   3:          Dim query = From k In pp.ADRESSEN
   4:                      Where k.Name1.Contains(search)
   5:                      Select k
   6:          Return query
   7:  End Function

Wer Visual Studio verwendet, kann den VB.NET Methoden Rumpf automatisch aus dem HTML erzeugen lassen, wenn man das SelectMethod Attribut tippt.

   1:  <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
   2:  <asp:Button ID="Button1" runat="server"  Text="Button" />
   3:      
   4:  <asp:GridView ID="GridView1" runat="server" SelectMethod="GridView1_GetData" 
AutoGenerateColumns="true">
   5:  </asp:GridView>

Das wars auch schon. Damit funktioniert die Suche.

Allerdings wenn man die Sache zu Ende denkt, ist diese Lösung leicht unbefriedigend. Der Weg hängt am HTML Form Submit und damit auch am POST. Es ist dabei egal ob man MVC wählt oder den Webforms Postback. Das Problem liegt im HTML. Zwar lässt sich der Submit auf GET umstellen und man erhält damit die Form Fields in der URL, aber Friendly im Sinne von REST ist das nicht.

   1:  <form method="get" >
   2:          <input name="Text1" type="text" />
   3:          <input id="Button1" type="submit" value="button" />
   4:  </form>

image

Der Vorteil dieser Methode ist, das nun der Link direkt angesprungen werden kann. Egal ob als Favorit oder per eMail weitergeleitet, ist dieses Deep Linking in jedem Fall vorzuziehen.

Das kann man mit Webforms  auch mal probieren. Allerdings gibts da denn Viewstate der dann im Querystring übertragen wird. Ensprechend in der Page und in den Controls abschalten.

   1:   <form id="form1" runat="server" method="get"  >
   2:          <asp:TextBox ID="TextBox1" runat="server" EnableViewState="false"></asp:TextBox>
   3:          <asp:Button ID="Button1" runat="server"  Text="Button" EnableViewState="false"  />
   4:          <asp:GridView EnableViewState="false"
   5:  ...

Die URL samt Querystring sieht dann so aus

   1:  http://localhost:58913/adressen/company?
   2:  __VIEWSTATE=Vp3EqfpyfbxLUQBC0LjmNDmi
   3:  TMlRbMzz2b5V%2Btswt0ecVgUT23do5UT9M
   4:  %2BozdAPHiJTYWSULnGH0hmrV2sgPOP7Oh%2FE1nsYq9rhjZpI5kYO5pAVtFTI3Vne9FcQ
   5:  Oql8p&TextBox1=wacker&Button1=Button

Um die Get Methode mit dem passenden Parameter zu füllen kommt das QueryStringAttribut mit dem Webforms Control Namen zum Einsatz.

   1:   Public Function GridView1_GetData(<QueryString("TextBox1")> search As String)
      As IQueryable(Of ADRESSEN)

Klappt auch, schon besser,  ist aber nicht im Format wie das URL Routing in MVC oder FriendlyUrls definiert.

Um auf eine andere Seite umzulenken, bzw. einen Request auszulösen, ist ein Hyperlink besser als ein Button.

   1:    <a href="/adressen/company/search/xxx" id="link" >search</a>
   2:      

Leider ist der Link nicht dynamisch und muss erst per JavaScript das DOM Element geparst und verändert werden. Unter Zuhilfenahme von JQuery wird so der Inhalt des HTML Input Elements (gerendert aus dem Webforms Textbox Control) an stelle des xxx gesetzt.

   1:   <script>
   2:           $(function () {
   3:               $('#link').click(function () {
   4:                   var v = $("#TextBox1").val();
   5:                   var url = this.href.replace("xxx", v);
   6:                   this.href = url;
   7:               });
   8:           });
   9:  </script>

Die Url sieht dann schon sehr freundlich aus

image

Nun muss nur noch das Attribut  in der Get Methode verändert werden. Da “Search” das erste Segment ist, mit dem Index 1.

   1:     Public Function GridView1_GetData(<FriendlyUrlSegments(1)> search As String) 
As IQueryable(Of ADRESSEN)

In vielen Blog Einträgen (u.a auch von Scott Hanselman) findet man eine Syntax die direkt den Segmentnamen als String übergibt. Dies funktioniert bei mir in der aktuellen Version mit ASP.NET 4.51 nicht.

Kommentare sind geschlossen