Asp.net WebApi 2.2 (REST) with Webforms and VB.net – Passing multiple simple POST Values (Part 2)

In the previous post I looked at how to add a very simple WebApi 2.2 REST service and demonstrated GET method using VS2013 and in particular VB.net (as the years go by VB.net examples are becoming rarer; it seems everyone is moving to C# and whilst I can program in C# I prefer VB.net).

In this post I wanted to know how to enable POST requests from a simple ASP.net webform but it appeared that whilst it was easy to consume simple datatypes with WebAPI 2.2 POST, it appears as though you can’t map POST form variables to simple parameters of a Web API method.  After some digging I found one way of doing it.. by encoding/decoding the POST data on the fly within the HttpPost method in the Web API method.  Whilst this is of course workable it looked to me that there must be a better solution at which point I came across Rick Strahl’s post “Passing multiple simple POST Values to ASP.NET Web API” which uses the clever method of extending WebApi by creating custom Parameter Binding.  This uses a simple class and a Global.asax hookup.

After reading through all of the comments I also noted that RoyiNamir had made some improvements to Rick Strahl’s code so I’ve converted his resultant C# class to VB.net and will explain how to add that to the WebAPI/Webforms project:

 

I’m going to add this to the basic “Cars” API that we already created in Part 1, so please refer to that first.

1. Add a New Class for the Custom Parameter Binding

  • I’ve put this in /App_Code/CC/Net/WebApi/SimplePostModelBinding.vb but feel free to put it elsewhere.

This is the code for the SimplePostModelBinding.vb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
' From: https://github.com/RoyiNamir/SimplePostVariableParameterBindingExtended
' And : http://weblog.west-wind.com/posts/2012/Sep/11/Passing-multiple-simple-POST-Values-to-ASPNET-Web-API
' Add this to Global.asax GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, SimplePostVariableParameterBinding.HookupParameterBinding)
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.Globalization
Imports System.Linq
Imports System.Net.Http
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Web.Helpers
Imports System.Web.Http.Controllers
Imports System.Web.Http.Metadata
Imports System.Web
Imports Newtonsoft.Json
 
Namespace CC.Net.WebApi
 
    Public Class SimplePostVariableParameterBinding
        Inherits HttpParameterBinding
        Public Const MultipleBodyParameters As String = "MultipleBodyParameters"
        Public Const MultipleBodyParametersRaw As String = "MultipleBodyParametersRaw"
        Public Const AllowJsonContentType As Boolean = True
 
 
        Public Sub New(descriptor As HttpParameterDescriptor)
            MyBase.New(descriptor)
        End Sub
 
        ''' 
        ''' Check for simple binding parameters in POST data. Bind POST
        ''' data as well as query string data
        ''' 
        '''
        '''
        '''
        ''' 
        Public Overrides Function ExecuteBindingAsync(metadataProvider As ModelMetadataProvider, actionContext As HttpActionContext, cancellationToken As CancellationToken) As Task
            Dim stringValue As String = Nothing
 
            Dim col As NameValueCollection = TryReadBody(actionContext.Request)
            If col IsNot Nothing Then
                stringValue = col(Descriptor.ParameterName)
            End If
 
            ' try reading query string if we have no POST/PUT match
            If stringValue Is Nothing Then
                Dim query = actionContext.Request.GetQueryNameValuePairs()
                If query IsNot Nothing Then
                    Dim matches = query.Where(Function(kv) kv.Key.ToLower() = Descriptor.ParameterName.ToLower())
                    Dim keyValuePairs = If(TryCast(matches, IList(Of KeyValuePair(Of String, String))), matches.ToList())
                    If keyValuePairs.Any() Then
                        stringValue = keyValuePairs.First().Value
                    End If
                End If
            End If
 
            Dim value As Object = StringToType(stringValue)
 
            ' Set the binding result here
            SetValue(actionContext, value)
 
            ' now, we can return a completed task with no result
            Dim tcs As New TaskCompletionSource(Of AsyncVoid)()
            tcs.SetResult(Nothing)
            Return tcs.Task
        End Function
 
 
        ''' 
        ''' Method that implements parameter binding hookup to the global configuration object's
        ''' ParameterBindingRules collection delegate.
        ''' 
        ''' This routine filters based on POST/PUT method status and simple parameter
        ''' types.
        ''' 
        '''
        ''' GlobalConfiguration.Configuration.
        '''       .ParameterBindingRules
        '''       .Insert(0,SimplePostVariableParameterBinding.HookupParameterBinding);
        '''    
        '''
        ''' 
        Public Shared Function HookupParameterBinding(descriptor As HttpParameterDescriptor) As HttpParameterBinding
            Dim supportedMethods = descriptor.ActionDescriptor.SupportedHttpMethods
 
            ' Only apply this binder on POST and PUT operations
            If supportedMethods.Contains(HttpMethod.Post) OrElse supportedMethods.Contains(HttpMethod.Put) Then
                Dim supportedTypes = New Type() {GetType(String), GetType(Integer), GetType(System.Nullable(Of Integer)), GetType(Decimal), GetType(System.Nullable(Of Decimal)), GetType(Double), _
                    GetType(System.Nullable(Of Double)), GetType(Long), GetType(System.Nullable(Of Long)), GetType(Boolean), GetType(System.Nullable(Of Boolean)), GetType(DateTime), _
                    GetType(System.Nullable(Of DateTime)), GetType(Byte())}
 
                If supportedTypes.Count(Function(typ) typ = descriptor.ParameterType) > 0 Then
                    Return New SimplePostVariableParameterBinding(descriptor)
                End If
            End If
 
            Return Nothing
        End Function
 
 
        Private Function StringToType(stringValue As String) As Object
            Dim value As Object = Nothing
 
            If stringValue Is Nothing Then
                value = Nothing
            ElseIf Descriptor.ParameterType = GetType(String) Then
                value = stringValue
            ElseIf Descriptor.ParameterType = GetType(Integer) Then
                value = Integer.Parse(stringValue, CultureInfo.CurrentCulture)
 
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Integer)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Integer)), Integer.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Long) Then
                value = Long.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Long)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Long)), Long.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Decimal) Then
                value = Decimal.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Decimal)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Decimal)), Decimal.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Double) Then
                value = Double.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Double)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Double)), Double.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(DateTime) Then
                value = DateTime.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of DateTime)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of DateTime)), DateTime.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Boolean) Then
                value = False
                If stringValue = "true" OrElse stringValue = "on" OrElse stringValue = "1" Then
                    value = True
                End If
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Boolean)) Then
                value = False
                If String.IsNullOrWhiteSpace(stringValue) Then
                    value = DirectCast(Nothing, System.Nullable(Of Boolean))
                ElseIf stringValue = "true" OrElse stringValue = "on" OrElse stringValue = "1" Then
                    value = True
                End If
            Else
                value = stringValue
            End If
 
            Return value
        End Function
 
        ''' 
        ''' Read and cache the request body
        ''' 
        '''
        ''' 
        Private Function TryReadBody(request As HttpRequestMessage) As NameValueCollection
            Dim result As Object
 
            ' try to read out of cache first
            If Not request.Properties.TryGetValue(MultipleBodyParameters, result) Then
                Dim contentType = request.Content.Headers.ContentType
 
 
 
                If contentType IsNot Nothing Then
 
                    Select Case contentType.MediaType
                        Case "application/json"
                            If True Then
                                If AllowJsonContentType Then
                                    result = request.Content.ReadAsStringAsync().Result
                                    request.Properties.Add(MultipleBodyParametersRaw, result)
                                    Dim values = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(result.ToString())
                                    result = values.Aggregate(New NameValueCollection(), Function(seed, current)
                                                                                             seed.Add(current.Key, current.Value)
                                                                                             Return seed
 
                                                                                         End Function)
 
 
 
                                    request.Properties.Add(MultipleBodyParameters, result)
                                End If
 
                            End If
                            Exit Select
                        Case "application/x-www-form-urlencoded"
                            result = request.Content.ReadAsFormDataAsync().Result
                            request.Properties.Add(MultipleBodyParameters, result)
                            Exit Select
                    End Select
                End If
            End If
 
 
            Return TryCast(result, NameValueCollection)
        End Function
 
        Private Structure AsyncVoid
        End Structure
    End Class
 
End Namespace
' From: https://github.com/RoyiNamir/SimplePostVariableParameterBindingExtended
' And : http://weblog.west-wind.com/posts/2012/Sep/11/Passing-multiple-simple-POST-Values-to-ASPNET-Web-API
' Add this to Global.asax GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, SimplePostVariableParameterBinding.HookupParameterBinding)
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.Globalization
Imports System.Linq
Imports System.Net.Http
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Web.Helpers
Imports System.Web.Http.Controllers
Imports System.Web.Http.Metadata
Imports System.Web
Imports Newtonsoft.Json

Namespace CC.Net.WebApi

    Public Class SimplePostVariableParameterBinding
        Inherits HttpParameterBinding
        Public Const MultipleBodyParameters As String = "MultipleBodyParameters"
        Public Const MultipleBodyParametersRaw As String = "MultipleBodyParametersRaw"
        Public Const AllowJsonContentType As Boolean = True


        Public Sub New(descriptor As HttpParameterDescriptor)
            MyBase.New(descriptor)
        End Sub

        ''' 
        ''' Check for simple binding parameters in POST data. Bind POST
        ''' data as well as query string data
        ''' 
        '''
        '''
        '''
        ''' 
        Public Overrides Function ExecuteBindingAsync(metadataProvider As ModelMetadataProvider, actionContext As HttpActionContext, cancellationToken As CancellationToken) As Task
            Dim stringValue As String = Nothing

            Dim col As NameValueCollection = TryReadBody(actionContext.Request)
            If col IsNot Nothing Then
                stringValue = col(Descriptor.ParameterName)
            End If

            ' try reading query string if we have no POST/PUT match
            If stringValue Is Nothing Then
                Dim query = actionContext.Request.GetQueryNameValuePairs()
                If query IsNot Nothing Then
                    Dim matches = query.Where(Function(kv) kv.Key.ToLower() = Descriptor.ParameterName.ToLower())
                    Dim keyValuePairs = If(TryCast(matches, IList(Of KeyValuePair(Of String, String))), matches.ToList())
                    If keyValuePairs.Any() Then
                        stringValue = keyValuePairs.First().Value
                    End If
                End If
            End If

            Dim value As Object = StringToType(stringValue)

            ' Set the binding result here
            SetValue(actionContext, value)

            ' now, we can return a completed task with no result
            Dim tcs As New TaskCompletionSource(Of AsyncVoid)()
            tcs.SetResult(Nothing)
            Return tcs.Task
        End Function


        ''' 
        ''' Method that implements parameter binding hookup to the global configuration object's
        ''' ParameterBindingRules collection delegate.
        ''' 
        ''' This routine filters based on POST/PUT method status and simple parameter
        ''' types.
        ''' 
        '''
        ''' GlobalConfiguration.Configuration.
        '''       .ParameterBindingRules
        '''       .Insert(0,SimplePostVariableParameterBinding.HookupParameterBinding);
        '''    
        '''
        ''' 
        Public Shared Function HookupParameterBinding(descriptor As HttpParameterDescriptor) As HttpParameterBinding
            Dim supportedMethods = descriptor.ActionDescriptor.SupportedHttpMethods

            ' Only apply this binder on POST and PUT operations
            If supportedMethods.Contains(HttpMethod.Post) OrElse supportedMethods.Contains(HttpMethod.Put) Then
                Dim supportedTypes = New Type() {GetType(String), GetType(Integer), GetType(System.Nullable(Of Integer)), GetType(Decimal), GetType(System.Nullable(Of Decimal)), GetType(Double), _
                    GetType(System.Nullable(Of Double)), GetType(Long), GetType(System.Nullable(Of Long)), GetType(Boolean), GetType(System.Nullable(Of Boolean)), GetType(DateTime), _
                    GetType(System.Nullable(Of DateTime)), GetType(Byte())}

                If supportedTypes.Count(Function(typ) typ = descriptor.ParameterType) > 0 Then
                    Return New SimplePostVariableParameterBinding(descriptor)
                End If
            End If

            Return Nothing
        End Function


        Private Function StringToType(stringValue As String) As Object
            Dim value As Object = Nothing

            If stringValue Is Nothing Then
                value = Nothing
            ElseIf Descriptor.ParameterType = GetType(String) Then
                value = stringValue
            ElseIf Descriptor.ParameterType = GetType(Integer) Then
                value = Integer.Parse(stringValue, CultureInfo.CurrentCulture)

            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Integer)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Integer)), Integer.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Long) Then
                value = Long.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Long)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Long)), Long.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Decimal) Then
                value = Decimal.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Decimal)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Decimal)), Decimal.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Double) Then
                value = Double.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Double)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of Double)), Double.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(DateTime) Then
                value = DateTime.Parse(stringValue, CultureInfo.CurrentCulture)
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of DateTime)) Then
                value = If(String.IsNullOrWhiteSpace(stringValue), DirectCast(Nothing, System.Nullable(Of DateTime)), DateTime.Parse(stringValue, CultureInfo.CurrentCulture))
            ElseIf Descriptor.ParameterType = GetType(Boolean) Then
                value = False
                If stringValue = "true" OrElse stringValue = "on" OrElse stringValue = "1" Then
                    value = True
                End If
            ElseIf Descriptor.ParameterType = GetType(System.Nullable(Of Boolean)) Then
                value = False
                If String.IsNullOrWhiteSpace(stringValue) Then
                    value = DirectCast(Nothing, System.Nullable(Of Boolean))
                ElseIf stringValue = "true" OrElse stringValue = "on" OrElse stringValue = "1" Then
                    value = True
                End If
            Else
                value = stringValue
            End If

            Return value
        End Function

        ''' 
        ''' Read and cache the request body
        ''' 
        '''
        ''' 
        Private Function TryReadBody(request As HttpRequestMessage) As NameValueCollection
            Dim result As Object

            ' try to read out of cache first
            If Not request.Properties.TryGetValue(MultipleBodyParameters, result) Then
                Dim contentType = request.Content.Headers.ContentType



                If contentType IsNot Nothing Then

                    Select Case contentType.MediaType
                        Case "application/json"
                            If True Then
                                If AllowJsonContentType Then
                                    result = request.Content.ReadAsStringAsync().Result
                                    request.Properties.Add(MultipleBodyParametersRaw, result)
                                    Dim values = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(result.ToString())
                                    result = values.Aggregate(New NameValueCollection(), Function(seed, current)
                                                                                             seed.Add(current.Key, current.Value)
                                                                                             Return seed

                                                                                         End Function)



                                    request.Properties.Add(MultipleBodyParameters, result)
                                End If

                            End If
                            Exit Select
                        Case "application/x-www-form-urlencoded"
                            result = request.Content.ReadAsFormDataAsync().Result
                            request.Properties.Add(MultipleBodyParameters, result)
                            Exit Select
                    End Select
                End If
            End If


            Return TryCast(result, NameValueCollection)
        End Function

        Private Structure AsyncVoid
        End Structure
    End Class

End Namespace

Important Step: Make sure this class is set to auto compile….
Right Click is and Choose Properties then Set Build Action to Compile:

WebApi-Part2-1

2. Hook the Parameter Binding Rules on App_Start

  • Add a line to /Global.asax

This is the code for the root Global.asax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Imports System.Web.Http
Imports CC.Net
 
 
Public Class Global_asax
    Inherits HttpApplication
 
    Sub Application_Start(sender As Object, e As EventArgs)
        ' Fires when the application is started
 
        ' It is important this goes before the Routing line: GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
        GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, AddressOf CC.Net.WebApi.SimplePostVariableParameterBinding.HookupParameterBinding)
 
        GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
 
    End Sub
End Class
Imports System.Web.Http
Imports CC.Net


Public Class Global_asax
    Inherits HttpApplication

    Sub Application_Start(sender As Object, e As EventArgs)
        ' Fires when the application is started

        ' It is important this goes before the Routing line: GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
        GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, AddressOf CC.Net.WebApi.SimplePostVariableParameterBinding.HookupParameterBinding)

        GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)

    End Sub
End Class

We’ve added “GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, AddressOf CC.Net.WebApi.SimplePostVariableParameterBinding.HookupParameterBinding)”

3. Add a simple Html Form

  • Add a simple Html form /test/default.htm

This is the code for the root default.htm

1
    API test
    API test

Cars

 



4. Add the POST method into the CarsController

  • Add the following to /Controllers/CarsController.vb

This is the code for the root CarsController.vb

1
2
3
4
     _
    Public Function PostMultipleSimpleValues(make As String, model As String) As String
        Return String.Format("Make: {0}, Model: {1}", make, model)
    End Function
     _
    Public Function PostMultipleSimpleValues(make As String, model As String) As String
        Return String.Format("Make: {0}, Model: {1}", make, model)
    End Function

The full /Controllers/CarsController.vb Class should now look like this…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Imports System.Net
Imports System.Web.Http
Imports System.Net.Http
 
Public Class CarsController
    Inherits ApiController
    Private cars As Car() = New Car() _
        {New Car() With { _
        .Id = 1, _
        .Make = "Aston Martin", _
        .Model = "V8 Vantage" _
    }, New Car() With { _
        .Id = 2, _
        .Make = "BMW", _
        .Model = "Z8" _
    }, New Car() With { _
        .Id = 3, _
        .Make = "Ferrari", _
        .Model = "California" _
    }, New Car() With { _
        .Id = 4, _
        .Make = "Pagani", _
        .Model = "Zonda" _
    }}
 
    Public Function GetCars() As IEnumerable(Of Car)
        Return cars
    End Function
 
    '' POST: api/Test
    'Public Sub PostValue(<FromBody()> ByVal value As String)
 
    'End Sub
 
    ' _
    'Public Function PostMultipleSimpleValues(name As String, value As Integer, entered As DateTime, Optional action As String = Nothing) As String
    '    Return String.Format("Name: {0}, Value: {1}, Date: {2}, Action: {3}", name, value, entered, action)
    'End Function
 
     _
    Public Function PostMultipleSimpleValues(make As String, model As String) As String
        Return String.Format("Make: {0}, Model: {1}", make, model)
    End Function
 
 
End Class
Imports System.Net
Imports System.Web.Http
Imports System.Net.Http

Public Class CarsController
    Inherits ApiController
    Private cars As Car() = New Car() _
        {New Car() With { _
        .Id = 1, _
        .Make = "Aston Martin", _
        .Model = "V8 Vantage" _
    }, New Car() With { _
        .Id = 2, _
        .Make = "BMW", _
        .Model = "Z8" _
    }, New Car() With { _
        .Id = 3, _
        .Make = "Ferrari", _
        .Model = "California" _
    }, New Car() With { _
        .Id = 4, _
        .Make = "Pagani", _
        .Model = "Zonda" _
    }}

    Public Function GetCars() As IEnumerable(Of Car)
        Return cars
    End Function

    '' POST: api/Test
    'Public Sub PostValue(<FromBody()> ByVal value As String)

    'End Sub

    ' _
    'Public Function PostMultipleSimpleValues(name As String, value As Integer, entered As DateTime, Optional action As String = Nothing) As String
    '    Return String.Format("Name: {0}, Value: {1}, Date: {2}, Action: {3}", name, value, entered, action)
    'End Function

     _
    Public Function PostMultipleSimpleValues(make As String, model As String) As String
        Return String.Format("Make: {0}, Model: {1}", make, model)
    End Function


End Class

5. Testing

  • Run the application and navigate to /test/

Enter some values into the webform and submit it:
WebApi-Part2-2

You should see some output like this:

WebApi-Part2-3

6. Results

So what we see happening here is form values posted to WebAPI and automatically being mapped to Parameters of Post method within the API. Clever.