1. #141
    Sencha User
    Join Date
    Jan 2010
    Posts
    8
    Vote Rating
    0
    codeable is on a distinguished road

      0  

    Default


    Thought I'd post the code sample to demonstrate how I got it working. This is from my current sandbox, so the names are not the same as in previous examples, but you'll get the idea. [Edit: Viewers take note that this example is not fully implemented and is only a proof of concept. If EvanT doesn't implement it fully, I will later and post my changes]

    Code:
     
    // -<Temporary .NET Workarounds> ---------------------------
    // ID Fix for retrieval
    Saturn.Remote.UserHandler.id = "Saturn.Remote.UserHandler";
    // Mechanism to get param count
    Saturn.Remote.UserHandler.getMethodArgumentLength = function(action, method) {
    //TODO: convert to faster mechanism (dictionary-style instead of iteration)
    for (var mthd inthis.actions[action]) {
     if (this.actions[action][mthd].name == method) {
        returnthis.actions[action][mthd].len;
     }
    }
    }
    // -</Temporary .NET Workarounds> ---------------------------
    // -<Consumer Specifics> ---------------------------
    var dummy = 0;
    Saturn.Remote.UserHandler.acquireMetaData = function() {
    dummy++;
    return"Change #"+dummy;
    }
    // -</Consumer Specifics> ---------------------------
    // -<Standard Implementation> ---------------------------
    Ext.Direct.addProvider(Saturn.Remote.UserHandler);
    // -</Standard Implementation> ---------------------------
    // -<Client Side Upgrades> ---------------------------
    Ext.Direct.getProvider("Saturn.Remote.UserHandler").on("beforecall", preProcessCall);
    // -</Client Side Upgrades> ------------
    // -<Ext.Direct .NET Upgrades> ---------------------------
    function preProcessCall(provider, transaction) {
    //TODO: Currently only supports the first parameter as MetaDataParam
    if (Ext.isDefined(provider.acquireMetaData)) {
      var mLength = provider.getMethodArgumentLength(transaction.action,transaction.method);
      if (transaction.args.length == mLength + 1) { // its fully defined, replace values
         transaction.args[0] = provider.acquireMetaData();
         transaction.data[0] = transaction.args[0];
      } else { // its not full, we need to fix it.
         transaction.args.splice(0, 0, provider.acquireMetaData()); // Add the missing parameter
         transaction.data = transaction.args.slice(0, mLength); // fix the data
         var hs = transaction.args[mLength], scope = transaction.args[mLength + 1]; // fix the callback [duplicate code]
         transaction.cb = scope && Ext.isFunction(hs) ? hs.createDelegate(scope) : hs;
      }
    }
    return true;
    }
    // -</Ext.Direct .NET Upgrades> ---------------------------
    
    Last edited by codeable; 18 Mar 2010 at 11:54 AM. Reason: Adding Comment

  2. #142
    Sencha User
    Join Date
    Jan 2010
    Posts
    8
    Vote Rating
    0
    codeable is on a distinguished road

      0  

    Default Exceptions

    Exceptions


    The only other thing I found while ensuring the architecture fits my needs, was the exception handling in the request. I require a bit more info about exceptions so I can handle them on the client side. I have adjusted two basic bits:

    1) Added support for InnerException to DirectException.
    ------------------------------------------------------
    Providing the inner exception allows the ability to send the exception to the client. Where it can be processed with some intelligence.

    a) Add support for InnerException
    Code:
     
    public class DirectException : ApplicationException
    {
        ...
        public DirectException(string msg, Exception innerException)
           : base(msg, innerException)
        {
        }
        ...
    }
    b) Add support for sending the error type to the client
    Code:
     
    internal class DirectResponse
    {
        ...
        [JsonProperty(PropertyName = "implementationexceptiontype")]
        public string ImplementationExceptionType
        {
            get;
            set;
        }
        ...
    }
    c) Pass along the inner exception to the client
    Code:
     
    // DirectProcessor.ProcessRequest()
    private static DirectResponse ProcessRequest(DirectProvider provider, DirectRequest request)
    {
        DirectResponse r = new DirectResponse(request);
        try
        {
            r.Result = provider.Execute(request);
        }
        catch (DirectException ex)
        {
            r.ExceptionMessage = ex.Message;
            r.Type = DirectResponse.ResponseExceptionType;
            if(ex.InnerException != null)
           {
               r.ImplementationExceptionType = ex.InnerException.GetType().ToString(); //TODO: convert to JS object
           }
        }
        return r;
    }
    2) Skipping over any TargetInvocationExceptions thrown.
    -------------------------------
    Since all exceptions raised in client code will result in the target exception, I decided to simply ignore it and pass the actual exception raised.
    Code:
     
    // DirectProvider.Execute()
    internal object Execute(DirectRequest request)
    {
        ...
        try
        {
        ...
        }
        catch (TargetInvocationException tex)
        {
            throw new DirectException("Error occurred while calling Direct method: " + tex.InnerException.Message, tex.InnerException);
        }
    catch (Exception ex)
    {
        throw new DirectException("Error occurred while calling Direct method: " + ex.Message, ex);
    }

  3. #143
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    17,055
    Vote Rating
    659
    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


    I definitely think it would be a good idea to be able to attach certain metadata to calls (like a user id). However I'd prefer to wait until later, Direct will be having some work done on it for the 4.0 release, so I'll keep your suggestions in mind for then.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  4. #144
    Sencha User
    Join Date
    Jan 2010
    Posts
    8
    Vote Rating
    0
    codeable is on a distinguished road

      0  

    Default


    Sounds good to me. I'll just upgrade this version for now and await 4.0!

  5. #145
    Sencha User
    Join Date
    Jan 2010
    Posts
    8
    Vote Rating
    0
    codeable is on a distinguished road

      0  

    Default


    I've implemented my ideas! The only thing the client-side needs to do is provide an acquireMetaData method. Full client side would be:
    Code:
    // -<Consumer Specifics> ---------------------------
    function acquirePageIdentifier(action, method) {
      return pageIdentifier;
    }
    Saturn.Remote.UserHandler.acquireMetaData = acquirePageIdentifier;
    // -</Consumer Specifics> ---------------------------
     
    Ext.Direct.addProvider(Saturn.Remote.UserHandler);
    The Server side of things has two Attributes: DirectMetaParameter and DirectMetaParameterIgnore. With these two attributes you can define the metadata on the Action level or Method level as these examples will demonstrate.

    Implicit parameter called pageContextID
    Code:
    // C#
    [DirectMethod, DirectMetaParameter("pageContextID")]
    public string GetImplicitMetaParameter()
    {
     // simply returns the provided metaparameter
     object pageContextID = base.GetMetaParameter("GetImplicitMetaParameter", "pageContextID");
     return pageContextID.ToString();
    }
     
    // JS
    Saturn.User.GetImplicitMetaParameter(function(data, trans) {
      // handle results
    });
    
    Or the same implicit parameter at the Action level (will add to all DirectMethods)
    Code:
    [DirectAction("User"), DirectMetaParameter("pageContextID", false)]
    public classUserHandler : DirectHandler
    {
     [DirectMethod]
     public string GetImplicitMetaParameter()
     {
        // simply returns the provided metaparameter
        object pageID = base.GetMetaParameter("GetImplicitMetaParameter", "pageContextID");
        return pageID.ToString();
     }
    }
    You can use the ignore to skip a method when the class level attribute is used
    Code:
    [DirectAction("User"), DirectMetaParameter("pageContextID", false)]
    public classUserHandler : DirectHandler
    {
     [DirectMethod, DirectMetaParameterIgnore("pageContextID")]
     public string GetImplicitMetaParameter()
     {
        // there is no pageContextID Available here.
     }
    }
    You can also explicitly provide the metadata parameter like so:
    Code:
    [DirectMethod, DirectMetaParameter("pageContextID", true)]
    public string GetImplicitMetaParameter(object pageContextID)
    {
     // the provided value is overwritten based on the attribute "overwrite" option
     return pageContextID.ToString();
    }
    Anyhow, just thought I'd share my excitement.

  6. #146
    Sencha User Mjollnir26's Avatar
    Join Date
    Oct 2008
    Location
    Germany
    Posts
    152
    Vote Rating
    0
    Mjollnir26 is on a distinguished road

      0  

    Default


    Just a quick note: This implementation doesn't compile out of the Box
    with the latest RC of the JSON.NET Lib (3.5.6 RC 6 http://json.codeplex.com/releases/view/37810),
    but it's pretty easy to fix (just expanding the Parameter Lists of a few methods).

    Going to give it a try now and thanks for your work evant :-)

  7. #147
    Ext JS Premium Member Lloyd K's Avatar
    Join Date
    Oct 2007
    Location
    Brighton, United Kingdom
    Posts
    655
    Vote Rating
    1
    Lloyd K is on a distinguished road

      0  

    Default


    Ahh yeh I tried that but didn't yet fix it. Thanks for the heads up.
    - Lloyd K

    I blog about code from time to time: http://codeology.lloydkinsella.net/

  8. #148
    Sencha User Mjollnir26's Avatar
    Join Date
    Oct 2008
    Location
    Germany
    Posts
    152
    Vote Rating
    0
    Mjollnir26 is on a distinguished road

      0  

    Default


    No Problemo. BTW Fixing the Compile Errors ain't enough, the Newtonsoft Lib must have changed quite a bit compared to the one that's included in the Download. Not even the Echo sample works with the new Lib...
    Don't have too much time to investigate that tough and will stick with the provided binary for now. But it would be super sweet to have this fixed...

  9. #149
    Sencha User Mjollnir26's Avatar
    Join Date
    Oct 2008
    Location
    Germany
    Posts
    152
    Vote Rating
    0
    Mjollnir26 is on a distinguished road

      0  

    Default


    Or if there's no time to fix it (i think evant might be a really busy guy) he could tell us which one of the 6 "3.5" Beta-Versions from Codeplex he was using when creating the Router. The shipped assembly says only "3.5" as Version for the Router.

    Don't want to be bitchy, it's just that i like to compile everything from source if i can...

  10. #150
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    17,055
    Vote Rating
    659
    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


    I can easily update it, but it's only a couple of weeks old. I wonder what changed.

    I'll check it out tomorrow.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!