[CLOSED] [#636] Difference between DirectMethod request params and Ajax request params

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1

    [CLOSED] [#636] Difference between DirectMethod request params and Ajax request params

    Hi,

    I think Arrays are not being submitted in the same way for DirectMethod requests as they are for Ajax requests:

    Consider this (the URL that direct method or ajax request is going to doesn't matter - it can fail, it is the HTTP post that is significant)

    var params = {
      a: 1,
      b: [1, 2, 3]
    };
    Now, if I submit via direct method:

    Ext.net.DirectMethod.request({
      url: '/does/not/matter',
      cleanRequest: true,
      params: params
    })
    Look at the HTTP request, and you will see params are sent like this:

    application/x-www-form-urlencoded
    Parameters
    a 1
    b [1,2,3]
    Raw
    a=1&b=%5B1%2C2%2C3%5D


    Now if you run the same with Ajax:

    Ext.Ajax.request({
        url: '/does/not/matter',
        method:'post',
        params:params,
    });
    You get this:

    application/x-www-form-urlencoded
    Parameters
    a 1
    b 1
    b 2
    b 3
    Raw
    a=1&b=1&b=2&b=3

    This is quite significant for me in a certain scenario.

    Is there any way Direct Method can be configured to send params in the way that Ext.Ajax.request is doing when using params when some of the params (complex objects) contains arrays?

    Reason this is important for me is that it makes it consistent, especially for those coming in from a pure Ext JS background and also works better with ASP.NET MVC Controllers that use plain old C# objects as controller argument. In other words the type of the argument is a class that has many properties including things like List<int> in the type definition. ASP.NET MVC automatically binds such variables to these if they are sent, as seen by the Ext.Ajax.request approach. When I am using a DirectMethod like above it becomes null because MVC cannot deserialize.

    To clarify, if I have a C# object like this:

    public class MyClass
    {
        int a { get; set; }
        List<int> b { get; set; }
    }
    Then my Controller signature can take an argument of type MyClass as the parameter, but b will be null...
    Last edited by Daniil; Jan 17, 2015 at 10:43 AM. Reason: [CLOSED]
  2. #2
    Hi Anup,

    I will be investigating it tomorrow with a fresh head:)
  3. #3
    I was rushed last night when I wrote that post so didn't have a chance to create an example, but here is one to help reproduce:

    Test ASPX:
    <%@ Page Language="C#" %>
    
    <!DOCTYPE html>
    
    <html>
    <head runat="server">
        <title>DirectMethod with Arrays</title>
    </head>
    <body>
        <ext:ResourceManager runat="server" />
            
        <ext:Button ID="Button1" runat="server" Text="Call direct method">
            <Listeners>
                <Click Handler="
                    var params = {
                        a: 1,
                        b: [1, 2, 3]
                    };
    
                    Ext.net.DirectMethod.request({
                        url: '/ArraysInDirectMethod',
                        cleanRequest: true,
                        params: params,
                        success: function(result) {
                            Ext.Msg.alert('Result', 'This is what we got: ' + result);
                        }
                    });
                " />
            </Listeners>
        </ext:Button>
    </body>
    </html>
    Test controller:

        public class MyClass
        {
            [JsonProperty(PropertyName="a")]
            int A { get; set; }
    
            [JsonProperty(PropertyName = "b")]
            List<int> B { get; set; }
        }
    
        public class ArraysInDirectMethodController : Controller
        {
            public ActionResult Index(MyClass myClassExample)
            {
                return this.Direct(JSON.Serialize(myClassExample));
            }
        }

    When you click the button, the arguments will be passed through as shown in the first post in this thread. When the direct method finishes, it will returned a serialized version of what it thinks it received, which will be alerted to the user. It will show that the "b" property is null, rather than the array that it was given. The alert message will be something like:

    This is what we got: {"a":0,"b":null}



    Notes,
    • The result will be the same whether I use [DirectMethod] attribute on the controller or not
    • This is only observed with DirectMethods (and I am guessing DirectEvents)
    • When I use Ext.Ajax.request, or Store AJAX proxies etc, then this is not a problem.
      • This means if I have another controller (or maybe the same one) called that also takes the same object as one of its arguments, the values are correctly present.

    • Because of this inconsistency, this is perhaps quite a significant issue (at least for me).
      • For example, I reuse the same complex class for both AJAX Proxy load requests and and manually calling other DirectMethods to perform other operations on a bunch of data, but this inconsistency may mean I cannot reuse that code.

    • Last night I was looking at why Ext.Ajax.request worked, and it is something to do with using Ext.Object.toQueryString I think so that it creates the form post parameters in the correct way. Perhaps something similar needs to apply for DirectMethod/Event requests?


    I can understand that a potential fix may have compatibility issues for anyone relying on the current behaviour, so if there is a way to fix it with a flag (maybe at ResourceManager level or global level) to say what kind of serialization behaviour DirectMethod will have, perhaps that is a way out?

    Hope that helps?
    Attached Thumbnails Click image for larger version. 

Name:	alert-null-array.png 
Views:	54 
Size:	4.3 KB 
ID:	18891  
  4. #4
    Thank you, Anup!

    A quick question for now - was is introduced in v3 or it is similar in v1 and v2?
  5. #5
    Hi,

    I think the problem exists in all versions - definitely 2.x as well as I copy pasted the code into a 2.x test project.

    I have a test 1.x project but it doesn't have MVC support (very old project!) and while I need to run a few manual steps to get the controller routes to work etc I can see the HTTP post contains the same type of array post as show in the original post, so I suspect the problem is there too.

    If your question was implying whether to fix in those versions too, I am not sure. Given it seems others have not been affected (perhaps) then maybe only fixing in 3.x is okay - of course, I am biased :)

    The reason I have not had this problem in 1.x even though I am using the same objects as I migrate my massive project from 1.x to 3.x is that in 1.x I used ASHX handlers and manually deserialized my post variables as needed. In 3.x I am moving wholesale to MVC/Web API controllers so this is why I have only noticed it now.

    Hope that helps.
  6. #6
    Ok, thanks.

    This is what we got: {"a":0,"b":null}
    Could you, please, clarify why "1" from params does not go to the "a" property? There is 0 which is a default for the int type. I guess MVC cannot handle this case automatically? I mean automatic serialization a params to a MyClass instance. Can we avoid using an IModelBinder in such a case with the MyClass? Here is some information about the IModelBinder interface.
    http://forums.ext.net/showthread.php...l=1#post105622

    Also I cannot reproduce the different between the Ext.Ajax.request and Ext.net.DirectMethod.request. Is my test case valid? I see the same behavior for both.

    - An array is being sent as an array [1,2,3] for both the requests
    - A MyClass instance doesn't get both a and b from the sent params.

    Am I missing something?

    View
    @{
        var X = Html.X();    
    }
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Ext.Net.MVC v3 Example</title>
    
        <script>
            var params = {
                a: 1,
                b: [1, 2, 3]
            };
    
            var callDirectMethod = function () {
                Ext.net.DirectMethod.request({
                    url: '/Razor/TestAction',
                    cleanRequest: true,
                    params: params,
                    success: function (result) {
                        Ext.Msg.alert('DirectMethod', 'This is what we got: ' + result);
                    }
                });
            };
    
            var callExtJsAjax = function () {
                Ext.Ajax.request({
                    url: '/Razor/TestAction',
                    method: 'post',
                    params: params,
                    success: function (r) {
                        Ext.Msg.alert('ExtJS result', 'This is what we got: ' + r.responseText);
                    }
                });
            };
        </script>
    </head>
    <body>
        @X.ResourceManager()
    
        @(X.Button()
            .Text("DirectMethod")
            .Handler("callDirectMethod")
        )
    
        @(X.Button()
            .Text("ExtJS AJAX")
            .Handler("callExtJsAjax")
        )
    </body>
    </html>
    Controller
    public class MyClass
    {
        [JsonProperty(PropertyName = "a")]
        int A { get; set; }
    
        [JsonProperty(PropertyName = "b")]
        List<int> B { get; set; }
    }
    
    public ActionResult Index()
    {
        return this.View();
    }
    
    public ActionResult TestAction(MyClass myClassExample)
    {
        return this.Direct(JSON.Serialize(myClassExample));
    }
  7. #7
    Hi,

    Regarding not seeing any difference between DirectMethod and Ext JS Ajax, for a moment I could not either. Then I realized the order of the two examples seems to matter.

    For example if you run this in Firebug console:

    var params = {
      a: 1,
      b: [1, 2, 3]
    };
    
    Ext.Ajax.request({
        url: '/does/not/matter',
        method:'post',
        params:params,
    });
    
    
    Ext.net.DirectMethod.request({
      url: '/does/not/matter',
      cleanRequest: true,
      params: params
    });
    You will see a difference.

    Now, if you
    a) Clear the console
    b) Swap the two requests around

    You will see both send in the way DirectMethod sends.

    It may be that reusing params in this contrived example is not good. I used two different test objects and it seems to be consistently different now:

    var params1 = {
      a: 1,
      b: [1, 2, 3]
    };
    
    var params2 = {
      a: 1,
      b: [1, 2, 3]
    };
    
    Ext.net.DirectMethod.request({
      url: '/does/not/matter',
      cleanRequest: true,
      params: params1
    });
    
    Ext.Ajax.request({
        url: '/does/not/matter',
        method:'post',
        params:params2,
    });
    In the above, Ext.Ajax.request consistently sends separate b parameters for each array item, where Ext.net.DirectMethod does not.

    As for other part - why is the response in my example showing a as 0 instead of 1 - good spot! I didn't notice that... And I am not sure why. In my real example with a much more complex object, I get the other simpler properties populated, just these arrays are not. I will double check that and get back to you.

Similar Threads

  1. Replies: 2
    Last Post: Oct 10, 2014, 8:50 AM
  2. Replies: 13
    Last Post: May 16, 2011, 1:26 PM
  3. [CLOSED] Adding params as jsonData for jsin Ajax requests
    By r_honey in forum 1.x Legacy Premium Help
    Replies: 7
    Last Post: May 06, 2010, 7:31 AM
  4. Ext.net.DirectMethod.request PARAMS
    By sipo in forum 1.x Help
    Replies: 0
    Last Post: Apr 15, 2010, 5:06 AM
  5. Page_ Ajax Load Complete BUG on Ajax Request
    By jeybonnet in forum 1.x Help
    Replies: 8
    Last Post: Jun 22, 2009, 11:19 AM

Posting Permissions