1. #51
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    Hey, guess what. I just tried my own DirectStore in my project attached to a combobox and I see your issue now. Or rather, I have the same issue as you - so ignore my last comment about encoding.

    Am going to play with it now, will let you know when I have a solution.

  2. #52
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    So basically, the way objects are being deserialized just doesn't work the way its set up. I've posed this question over on James' site (JSON.Net) to see if there is an out of the box solution, otherwise, the DirectRequest is going to need to have a custom deserializer.

    I'm working on it now, will let the group know if I get it working. Unless someone already has an answer to the question I posed over at JSON.Net.

  3. #53
    Sencha Premium Member
    Join Date
    Jun 2008
    Posts
    51
    Vote Rating
    1
    mbajema is on a distinguished road

      0  

    Default


    What would be really cool is if it would not deserialize the parameters when deserializing the DirectRequest object--just leave the parameters as a JSON string--and then attempt to deserialize each parameter in the DirectProvider.Execute() method based on the actual types (defaulting to a JObject if necessary). The SanitizeDates() method in the router 0.6 kind of does that for DateTime parameters.

    That way, our Direct methods could look like this:
    Code:
    [DirectMethod]
    public string MyDirectMethod(MyCustomConifgClass config)
    The way I described it might not make sense, but hopefully you get the picture.
    Last edited by mbajema; 29 Jul 2009 at 11:29 AM. Reason: added "in the DirectProvider.Execute() method"
    Mark Bajema
    Youth Mentoring Software from Innovative Mentoring

  4. #54
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    That didn't make sense to me.

    Attached is a new version of my branched copy that does the proper JSON Deserializing on embedded objects. (At least as far as I can tell in my tests.)

    So, if you pass in a DirectStore request it will look similar to this:

    Code:
    {"action":"Patient","method":"Search","data":[{"query":"test","start":0,"limit":5}],"type":"rpc","tid":8}
    This will be passed to your function as a Dictionary<string, object>. So, in the above case I have this catching method:

    Code:
    public string Search(Dictionary<string, object> Params){}
    If I want access to the properties in the dictionary, I just call them like so:

    Code:
    string query = Params["query"];
    I would STRONGLY suggest that something like this get added to the base Ext.Direct code. This is pretty important stuff. You might want to encapsulate the Dictionary into a custom Direct object, though I really don't think that's necessary unless you need it to support C# code that can't use generics.

    Note: this version of my code includes the EnableBuffer property on DirectMethod and DirectProvider, like I mention in the thread above. I've also added in the MaxRetries property to DirectProvider. (and really need to get in there and specify ALL of the properties that are listed in the RemoteProvider docs)

    Let me know if you find bugs or have questions.

    Dave

    (note: I'm not trying to subvert this thread to promote my own version - rather, I'd like to see these folded into the "official" version. Please steal whatever you need out of my code to bolster the official version, or just code-review my additions and make it version 0.7. Or ignore them entirely.)

    UPDATED: code updated to include mbajema's better Object Convertor described below.

    UPDATED: Code files removed. LATEST CODE IS IN THIS POST

  5. #55
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    Oh, and it will still be able to handle multiple parameters in the array. So this:

    Code:
    "data":["mystring", 4, {id:1,test2:"test"}]
    will be available in your method as:

    Code:
    public string MyMethod(string MyString, int ANumber, Dictionary<string, object> Params){}
    If you want to see what I did, take a look at the ComplexDataConverter class. This is assigned to the Data property with the JsonConverter Attribute in DirectRequest.

  6. #56
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    I would also suggest that you create these extension methods somewhere. These will aid you in easily getting the params out of the dictionary. With the below code, you can easily get a string, int, or bool out of the dictionary by calling the correct method.

    Code:
    bool myBool = Params.GetBool("ParamId");
    string myString = Params.GetString("ParamId");
    int myInt = Params.GetInt("ParamId");
    There is an optional "default" parameter too in case the item can't be converted:

    Code:
    int myInt = Params.GetInt("ParamId", -1);
    would set myInt = -1 if ParamId was missing, or wasn't an int.

    The extensions:

    Code:
            public static int GetInt(this Dictionary<string, object> Input, string Id)
            {
                try
                {
                    return Convert.ToInt32(Input[Id]);
                }
                catch
                {
                    return int.MinValue;
                }
            }
    
            public static int GetInt(this Dictionary<string, object> Input, string Id, int Default)
            {
                try
                {
                    return Convert.ToInt32(Input[Id]);
                }
                catch
                {
                    return Default;
                }
            }
    
            public static string GetString(this Dictionary<string, object> Input, string Id)
            {
                try
                {
                    return Input[Id].ToString();
                }
                catch
                {
                    return null;
                }
            }
    
            public static string GetString(this Dictionary<string, object> Input, string Id, string Default)
            {
                try
                {
                    return Input[Id].ToString();
                }
                catch
                {
                    return Default;
                }
            }
    
            public static bool GetBool(this Dictionary<string, object> Input, string Id)
            {
                try
                {
                    return Convert.ToBoolean(Input[Id]);
                }
                catch
                {
                    return false;
                }
            }
    
            public static bool GetBool(this Dictionary<string, object> Input, string Id, bool Default)
            {
                try
                {
                    return Convert.ToBoolean(Input[Id]);
                }
                catch
                {
                    return Default;
                }
            }

  7. #57
    Sencha Premium Member
    Join Date
    Jun 2008
    Posts
    51
    Vote Rating
    1
    mbajema is on a distinguished road

      0  

    Default


    The ComplexDataConverter class was not handling arrays within the object, so I updated it to be a more generic ComplexObjectConverter class (it doesn't need to start as an array). Here it is:

    Code:
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using Newtonsoft.Json;
    
    namespace Ext.Direct
    {
        internal class ComplexObjectConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                if (objectType == typeof(object[]) || objectType == typeof(object)) { return true; }
                return false;
            }
    
            public override object ReadJson(JsonReader reader, Type objectType)
            {
                if (reader.TokenType == JsonToken.StartArray)
                    return ReadArray(reader);
                else if (reader.TokenType == JsonToken.StartObject)
                    return ReadObject(reader);
                else
                    return null;
            }
    
            private object[] ReadArray(JsonReader reader)
            {
                ArrayList output = new ArrayList();
                while (reader.Read())
                {
                    if (reader.TokenType == JsonToken.EndArray)
                    {
                        return output.ToArray();
                    }
                    if (reader.TokenType == JsonToken.StartArray)
                    {
                        output.Add(ReadArray(reader));
                    }
                    if (reader.TokenType == JsonToken.StartObject)
                    {
                        output.Add(ReadObject(reader));
                    }
                    else
                    {
                        output.Add(reader.Value);
                    }
                }
    
                throw new JsonReaderException();
            }
    
            private object ReadObject(JsonReader reader)
            {
                Dictionary<string, object> subobject = new Dictionary<string, object>();
                string currentKey = null;
    
                while (reader.Read())
                {
                    if (reader.TokenType == JsonToken.EndObject)
                    {
                        return subobject;
                    }
                    else if (currentKey == null)
                    {
                        currentKey = reader.Value.ToString();
                    }
                    else
                    {
                        if (reader.TokenType == JsonToken.StartArray)
                        {
                            subobject.Add(currentKey, ReadArray(reader));
                        }
                        else if (reader.TokenType == JsonToken.StartObject)
                        {
                            subobject.Add(currentKey, ReadObject(reader));
                        }
                        else
                        {
                            subobject.Add(currentKey, reader.Value);
                        }
                        currentKey = null;
                    }
                }
                return null;
            }
    
            public override void WriteJson(JsonWriter writer, object value)
            {
                throw new NotImplementedException();
            }
        }
    }
    It could use some better exception handling, but it's a start.
    Mark Bajema
    Youth Mentoring Software from Innovative Mentoring

  8. #58
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    Excellent! I've incorporated this into my code instead of my version of the converter, and re-posted the code above.

    Thanks!
    Dave

  9. #59
    Ext User Dave.Sanders's Avatar
    Join Date
    Mar 2008
    Posts
    131
    Vote Rating
    0
    Dave.Sanders is on a distinguished road

      0  

    Default


    Yet another update. The JSON serialization was not serializing datetime fields into the format needed by Ext. I've updated the serializer to use the JavaScriptDateTimeConverter per this article from James.

    This latest version of the code is attached here. To not have any confusion, I'm going to go back to the old posts and point them here for the code. Hopefully we can just get this rolled into a .7 of the "official" code so there is less confusion.
    Attached Files

  10. #60
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    16,835
    Vote Rating
    609
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    FYI I am still monitoring this thread, however there's some other stuff that's a bit higher priority at the moment. Perhaps we could setup a google code project.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!