1

I'm trying to trigger a jQuery AJAX post to my ASP.NET webservice. However, even though the subscribeToSearch method is executed, when I access the strSubscriber.email variable in that method it's empty. Why?

These are the varaible values I'm logging before they get posted:

email: [email protected]
objecttype: 15
provinceid: 7
city: "test"
distance: 0
minprice: 0
maxprice: 0
frequency: 0
rooms: 0
surface: 0

Here's the AJAX call:

   $.ajax({
        type: "POST",
        url: '/api/subscribetosearch',
        async: true,
        data: JSON.stringify({
            str: {
                'objecttype': objecttype,
                'email': email,
                'provinceid': provinceid,
                'city': city,
                'distance': distance,
                'minprice': minprice,
                'maxprice': maxprice,
                'frequency': frequency,
                'rooms': rooms,
                'surface': surface
            }
        }),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        error: function () {
        },
        success: function (msg) {


        }
    }); 

The webmethod signatures:

Ihouse.vb

    <OperationContract()>
    <Web.WebInvoke(Method:="POST", ResponseFormat:=Web.WebMessageFormat.Json, BodyStyle:=Web.WebMessageBodyStyle.WrappedRequest,
UriTemplate:="subscribetosearch")>
    Function subscribeToSearch(ByVal str As GlobalFunctions.SearchSubscriber) As Stream 

house.svc.vb

Public Function subscribeToSearch(ByVal strSubscriber As GlobalFunctions.SearchSubscriber) As Stream Implements Ihouse.subscribeToSearch
    LogError("subscribeToSearch hit")
    LogError("subscribeToSearch email: " + strSubscriber.email)
End Function

I checked out the headers in Google Chrome dev console and this is the request payload:

enter image description here

Here's the SearchSubscriber class.

Public Class GlobalFunctions

    <Runtime.Serialization.DataContract>
    Public Class SearchSubscriber
        <Runtime.Serialization.DataMember>
        Private _objecttype As Integer
        Public Property objecttype() As Integer
            Get
                Return _objecttype
            End Get
            Set(ByVal value As Integer)
                _objecttype = value
            End Set
        End Property

        Private _email As String
        Public Property email() As String
            Get
                Return _email
            End Get
            Set(ByVal value As String)
                _email = value
            End Set
        End Property

        Private _provinceid As Integer
        Public Property provinceid() As Integer
            Get
                Return _provinceid
            End Get
            Set(ByVal value As Integer)
                _provinceid = value
            End Set
        End Property

        Private _city As String
        Public Property city() As String
            Get
                Return _city
            End Get
            Set(ByVal value As String)
                _city = value
            End Set
        End Property

        Private _distance As Integer
        Public Property distance() As Integer
            Get
                Return _distance
            End Get
            Set(ByVal value As Integer)
                _distance = value
            End Set
        End Property

        Private _minprice As Integer
        Public Property minprice() As Integer
            Get
                Return _minprice
            End Get
            Set(ByVal value As Integer)
                _minprice = value
            End Set
        End Property

        Private _maxprice As Integer
        Public Property maxprice() As Integer
            Get
                Return _maxprice
            End Get
            Set(ByVal value As Integer)
                _maxprice = value
            End Set
        End Property

        Private _frequency As Integer
        Public Property frequency() As Integer
            Get
                Return _frequency
            End Get
            Set(ByVal value As Integer)
                _frequency = value
            End Set
        End Property

        Private _rooms As Integer
        Public Property rooms() As Integer
            Get
                Return _rooms
            End Get
            Set(ByVal value As Integer)
                _rooms = value
            End Set
        End Property

        Private _surface As Integer
        Public Property surface() As Integer
            Get
                Return _surface
            End Get
            Set(ByVal value As Integer)
                _surface = value
            End Set
        End Property

    End Class
End Class   

UPDATE 1

Followed suggestions by @Nkosi so now I have this:

//construct the object to be posted.
var searchSubscriber = {
    objecttype: objecttype,
    email: email,
    provinceid: provinceid,
    city: city,
    distance: distance,
    minprice: minprice,
    maxprice: maxprice,
    frequency: frequency,
    rooms: rooms,
    surface: surface
};

$.ajax({
    type: "POST",
    url: '/api/subscribetosearch',
    async: true,
    data: JSON.stringify(searchSubscriber),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    error: function () {
    },
    success: function (msg) {

    }
}); 

The request payload is now:

enter image description here

The following method on the server is hit, but the strSubscriber object is nothing...

Public Function subscribeToSearch(ByVal strSubscriber As GlobalFunctions.SearchSubscriber) As Stream Implements Ihouse.subscribeToSearch
    LogError("subscribeToSearch HIT")  <---- this line gets executed

    If strSubscriber Is Nothing Then
        LogError("subscribeToSearch strSubscriber IS NOTHING")  <---- this line gets executed
    Else
        LogError("subscribeToSearch strSubscriber IS SOMETHING")
    End If              

End Function
4
  • @downvoter: please tell me how I can improve this post. I believe I've added all code needed including what I tried debugging wise. Commented Aug 20, 2017 at 0:29
  • I don't think /api/subscribetosearch is a valid URL for subscribeToSearch method. Am I missing something? Commented Aug 21, 2017 at 22:00
  • @Win: yes it is, see my updated post, where you can see that the method is actually hit, however, the data in the request payload does not seem to arrive/arrive correctly. FYI: I'm using Routing, so no .svc extension is visible in the URL. Commented Aug 23, 2017 at 13:03
  • 1
    @Flo also just noticed that you are missing <Runtime.Serialization.DataMember> attribute on all the properties that you want to access on the server. Commented Aug 23, 2017 at 14:27

2 Answers 2

2
+50

UPDATE

However, even though the subscribeToSearch method is executed, when I access the strSubscriber.email variable in that method it's empty. Why?

Noticed that you are missing <Runtime.Serialization.DataMember> attribute on all the properties that you want to access on the server. When using DataContract you need to properly tag all the properties that are to be used when serializing/deserializing the model. So because the member was not tagged it was not populated when data was deserialized.

Public Class GlobalFunctions
    <Runtime.Serialization.DataContract>
    Public Class SearchSubscriber
        <Runtime.Serialization.DataMember>
        Public Property objecttype As Integer

        <Runtime.Serialization.DataMember>
        Public Property email As String

        <Runtime.Serialization.DataMember>
        Public Property provinceid As Integer

        <Runtime.Serialization.DataMember>
        Public Property city As String

        <Runtime.Serialization.DataMember>
        Public Property distance As Integer

        <Runtime.Serialization.DataMember>
        Public Property minprice As Integer

        <Runtime.Serialization.DataMember>
        Public Property maxprice As Integer

        <Runtime.Serialization.DataMember>
        Public Property frequency As Integer

        <Runtime.Serialization.DataMember>
        Public Property rooms As Integer

        <Runtime.Serialization.DataMember>
        Public Property surface As Integer

    End Class
End Class 

ORIGINAL

Payload is not being constructed properly based on what is expected by the service.

The function is expecting a GlobalFunctions.SearchSubscriber, not an object that has a str property that is a GlobalFunctions.SearchSubscriber which is what the code in the original question was sending.

simplify it to make it easier to troubleshoot.

//construct the object to be posted.
var searchSubscriber = {
    objecttype: objecttype,
    email: email,
    provinceid: provinceid,
    city: city,
    distance: distance,
    minprice: minprice,
    maxprice: maxprice,
    frequency: frequency,
    rooms: rooms,
    surface: surface
};

$.ajax({
    type: "POST",
    url: '/api/subscribetosearch',
    async: true,
    data: JSON.stringify(searchSubscriber),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    error: function () {
    },
    success: function (msg) {

    }
}); 

The web method signatures would also need to be updated:

Ihouse.vb

<OperationContract()>
<Web.WebInvoke(Method:="POST", ResponseFormat:=Web.WebMessageFormat.Json, BodyStyle:=Web.WebMessageBodyStyle.Bare, UriTemplate:="subscribetosearch")>
Function subscribeToSearch(ByVal model As GlobalFunctions.SearchSubscriber) As Stream   
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Thr <Runtime.Serialization.DataMember> and BodyStyle:=Web.WebMessageBodyStyle.Bare did the trick. One last question: why does my page refresh once I post this request?
It should not given that you are posting it via ajax. Are you using a standard submit button with a form? chances are that it is causing the page to refresh when clicked.
0

You don't need to specify a dataType or contentType. You are misusing these options.

I don't know vb but I know c# and asp.net. When you use JSON.stringify() this results in a string. The fact that it is a JSON string does not matter. When you receive the string on the server you will need to deserialize the string to your strongly typed object. With asp.net web api if you just pass the JavaScript object (not a string) it will bind automatically.

 $.ajax({
    type: "POST",
    url: '/api/subscribetosearch',
    async: true,
    data: {
        obj: {
            'objecttype': objecttype,
            'email': email,
            'provinceid': provinceid,
            'city': city,
            'distance': distance,
            'minprice': minprice,
            'maxprice': maxprice,
            'frequency': frequency,
            'rooms': rooms,
            'surface': surface
        }
    },
    error: function () {
    },
    success: function (msg) {
    }
}); 

[HttpPost]
public void Foo(SearchSubscriber obj)
{
    // obj will be bound automatically 
}

alternatively passing a string:

$.ajax({
    type: "POST",
    url: '/api/subscribetosearch',
    async: true,
    data: JSON.stringify({
            'objecttype': objecttype,
            'email': email,
            'provinceid': provinceid,
            'city': city,
            'distance': distance,
            'minprice': minprice,
            'maxprice': maxprice,
            'frequency': frequency,
            'rooms': rooms,
            'surface': surface
    }),
    error: function () {
    },
    success: function (msg) {
    }
}); 

[HttpPost]
public void Foo(string obj)
{
    // obj will be string needing to be deserialized to a strongly typed object
}

async is also depreciated and should not be used, but that won't have any affect on the issue you're having.

2 Comments

Question: does it matter whether I wrap the variable names in the JSON string in parentheses? E.g. per your example 'objecttype': objecttype or if I would do this: objecttype: objecttype?
In the example we are creating a JavaScript object not a JSON string. We use the the JSON.stringify() method to turn a JavaScript object into a JSON string (just a regular string that a JSON parser can understand). The quote marks around the objects property names are optional and not normally used. The quotes (single or double) allow you to use a complex property name in an object like var x = {'foo bar': 5} which can later be accessed like x['foo bar']

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.