예제 #1
0
 /// <summary>
 ///     Creates a new instance of this class
 /// </summary>
 /// <param name="jsVariableName">
 ///     The name of the variable to be used from the Javascript side to access the HybridMessaging
 ///     object
 /// </param>
 public HybridMessagingHandler(string jsVariableName = "HybridMessaging")
 {
     HybridMessagingProxy  = new ProxyClass(this);
     HybridMessagingBridge = new ClassBridge <ProxyClass>();
     HybridMessagingBridge.PushJavascript += OnPushJavascript;
     HybridMessagingBridge.AddInstance(HybridMessagingProxy, jsVariableName);
 }
예제 #2
0
        /// <summary>
        ///     Initialize the handler and generates the needed Javascript code
        /// </summary>
        /// <param name="bridge">The <see cref="BridgeController" /> object requesting initialization</param>
        public virtual void Initialize(BridgeController bridge)
        {
            var builder = new StringBuilder();

            builder.Append(ClassBridge.GenerateNameSpace(GenericType));
            builder.Append(ClassBridge.GenerateProxyClass(Identification, true));
            lock (Lock)
            {
                if (Methods != null)
                {
                    if (Fields != null)
                    {
                        foreach (var field in Fields)
                        {
                            builder.Append(ClassBridge.GenerateProxyField(Identification, field));
                        }
                    }
                    foreach (var method in Methods)
                    {
                        builder.Append(ClassBridge.GenerateProxyMethod(Identification, method.Key, method.Value));
                    }
                }
            }
            OnPushJavascript(new FireJavascriptEventArgs(builder.ToString(), bridge));
        }
예제 #3
0
        /// <summary>
        ///     Sends a message to the Javascript side and waits for the response
        /// </summary>
        /// <param name="messageString">Message identification, or string.Empty to send to all subscribers</param>
        /// <param name="argument">The argument to be send to the message subscriber</param>
        /// <typeparam name="TResult">The type of the expected result</typeparam>
        /// <typeparam name="TArgument">The type of the argument to send</typeparam>
        /// <returns>Returns the response of the last subscriber</returns>
        public virtual TResult Send <TResult, TArgument>(string messageString, TArgument argument)
        {
            var returnValue = HybridMessagingProxy.HandlerNewMessage(messageString, argument);

            try
            {
                return(ClassBridge.NormalizeVariable <TResult>(returnValue));
            }
            catch (Exception)
            {
                return(default(TResult));
            }
        }
예제 #4
0
        /// <summary>
        ///     The method to dispose this class
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (Disposed)
            {
                return;
            }
            Disposed = true;

            if (disposing)
            {
                if (HybridMessagingBridge != null)
                {
                    if (HybridMessagingProxy != null)
                    {
                        HybridMessagingBridge.RemoveInstance(HybridMessagingProxy);
                    }
                    HybridMessagingBridge.PushJavascript -= OnPushJavascript;
                }
                HybridMessagingProxy  = null;
                HybridMessagingBridge = null;
            }
        }
예제 #5
0
 /// <summary>
 ///     Removes the requested instances
 /// </summary>
 /// <param name="instances">The instances to be removed from the Javascript side</param>
 /// <returns>Returns <see langword="this" /> instance to be used for other operations</returns>
 public virtual ClassBridge <T> RemoveInstance(params T[] instances)
 {
     foreach (var instance in instances.Where(instance => Instances.ContainsKey(instance)))
     {
         foreach (var variable in Instances[instance].ToArray())
         {
             AddInstance(null, variable);
         }
         if (InstancesEventsDelegates.ContainsKey(instance))
         {
             foreach (var eventDelegate in InstancesEventsDelegates[instance])
             {
                 eventDelegate.Key.RemoveEventHandler(instance, eventDelegate.Value);
             }
             InstancesEventsDelegates.Remove(instance);
         }
         Instances.Remove(instance);
         OnPushJavascript(
             new FireJavascriptEventArgs(ClassBridge.GenerateInstanceChange(Identification,
                                                                            GlobalPool.GetInstanceId(instance), true)));
     }
     return(this);
 }
예제 #6
0
 /// <summary>
 ///     Creates a new instance of this class
 /// </summary>
 /// <exception cref="InvalidGenericTypeException">Indicates that the passed generic type is not a valid class</exception>
 public ClassBridge()
 {
     if (!GenericType.IsClass)
     {
         throw new InvalidGenericTypeException();
     }
     lock (Lock)
     {
         if (Methods == null)
         {
             Methods = GenericType.GetMethods()
                       .Where(
                 info =>
                 info.IsPublic && !info.IsGenericMethod)
                       .ToDictionary(info => info, info => info.GetParameters());
         }
         if (Constructors == null)
         {
             Constructors = GenericType.GetConstructors()
                            .Where(
                 info =>
                 info.IsPublic && !info.IsGenericMethod)
                            .ToDictionary(info => info, info => info.GetParameters());
         }
         if (Properties == null)
         {
             Properties =
                 GenericType.GetProperties()
                 .Where(
                     info =>
                     Methods.ContainsKey(info.GetGetMethod()) ||
                     Methods.ContainsKey(info.GetSetMethod()))
                 .ToList();
         }
         if (Fields == null)
         {
             Fields = GenericType.GetFields().Where(info => info.IsPublic).ToList();
         }
         if (Events == null)
         {
             Events =
                 GenericType.GetEvents()
                 .Where(
                     info =>
                     Methods.ContainsKey(info.GetAddMethod()) &&
                     Methods.ContainsKey(info.GetRemoveMethod()))
                 .ToList();
         }
         foreach (
             var info in
             Events.Where(info => info.GetAddMethod().IsStatic || info.GetRemoveMethod().IsStatic))
         {
             var eventInvokerReturn = info.EventHandlerType.GetMethod("Invoke").ReturnType;
             if ((eventInvokerReturn == typeof(void)) || (eventInvokerReturn == typeof(object)))
             {
                 var del = ClassBridge.CreateProxyDelegateForEvent(info, null, RaiseEvent);
                 StaticEventsDelegates.Add(info, del);
                 info.AddEventHandler(null, del);
             }
             else
             {
                 var del = ClassBridge.CreateProxyDelegateForEvent(info, null,
                                                                   (instance, eventName, isVoid, eventArgs) =>
                                                                   ClassBridge.NormalizeVariable(RaiseEvent(instance, eventName, isVoid, eventArgs),
                                                                                                 eventInvokerReturn, false));
                 StaticEventsDelegates.Add(info, del);
                 info.AddEventHandler(null, del);
             }
         }
         if (SubEnumerations == null)
         {
             SubEnumerations =
                 GenericType.GetNestedTypes(BindingFlags.Public)
                 .Where(type => type.IsEnum)
                 .Select(EnumBridge.FromType)
                 .ToList();
             foreach (var subEnum in SubEnumerations)
             {
                 subEnum.PushJavascript += (sender, args) => OnPushJavascript(args);
             }
         }
         if (SubClasses == null)
         {
             SubClasses =
                 GenericType.GetNestedTypes(BindingFlags.Public)
                 .Where(type => type.IsClass && !typeof(Delegate).IsAssignableFrom(type))
                 .Select(ClassBridge.FromType)
                 .ToList();
             foreach (var subClasses in SubClasses)
             {
                 subClasses.PushJavascript += (sender, args) => OnPushJavascript(args);
             }
         }
     }
 }
예제 #7
0
 /// <summary>
 ///     Registers an instance of the generic type and adds it to the list of registered instances
 /// </summary>
 /// <param name="instance">The instance of the generic type to ad</param>
 /// <param name="variableName">The name of the variable that is accessible from the Javascript side</param>
 /// <returns>Returns <see langword="this" /> instance to be used for other operations</returns>
 public virtual ClassBridge <T> AddInstance(T instance, string variableName)
 {
     if (instance != null)
     {
         if (!Instances.ContainsKey(instance))
         {
             Instances.Add(instance, new List <string>());
             if (!InstancesEventsDelegates.ContainsKey(instance))
             {
                 InstancesEventsDelegates.Add(instance, new Dictionary <EventInfo, Delegate>());
             }
             foreach (
                 var info in
                 Events.Where(info => !info.GetAddMethod().IsStatic&& !info.GetRemoveMethod().IsStatic))
             {
                 var eventDelegate =
                     InstancesEventsDelegates[instance].FirstOrDefault(pair => pair.Key == info).Value;
                 if (eventDelegate == null)
                 {
                     var eventInvokerReturn = info.EventHandlerType.GetMethod("Invoke").ReturnType;
                     if ((eventInvokerReturn == typeof(void)) || (eventInvokerReturn == typeof(object)))
                     {
                         eventDelegate = ClassBridge.CreateProxyDelegateForEvent(info, instance, RaiseEvent);
                     }
                     else
                     {
                         eventDelegate = ClassBridge.CreateProxyDelegateForEvent(info, instance,
                                                                                 (o, s, arg3, arg4) =>
                                                                                 ClassBridge.NormalizeVariable(RaiseEvent(o, s, arg3, arg4), eventInvokerReturn,
                                                                                                               false));
                     }
                     InstancesEventsDelegates[instance].Add(info, eventDelegate);
                 }
                 info.AddEventHandler(instance, eventDelegate);
             }
             OnPushJavascript(
                 new FireJavascriptEventArgs(ClassBridge.GenerateInstanceChange(Identification,
                                                                                GlobalPool.GetInstanceId(instance), false)));
         }
     }
     if (!string.IsNullOrWhiteSpace(variableName))
     {
         foreach (
             var key in
             Instances.Keys.Where(key => key != instance)
             .Where(key => Instances[key].Contains(variableName))
             .ToArray())
         {
             RemoveInstance(variableName, key as T);
         }
         if (instance != null)
         {
             if (!Instances[instance].Contains(variableName))
             {
                 Instances[instance].Add(variableName);
                 OnPushJavascript(
                     new FireJavascriptEventArgs(ClassBridge.GenerateInstanceVariable(Identification,
                                                                                      GlobalPool.GetInstanceId(instance), variableName)));
             }
         }
         else
         {
             OnPushJavascript(
                 new FireJavascriptEventArgs(ClassBridge.GenerateInstanceVariable(Identification, null,
                                                                                  variableName)));
         }
     }
     return(this);
 }
예제 #8
0
        /// <summary>
        ///     Initialize the handler and generates the needed Javascript code
        /// </summary>
        /// <param name="bridge">The <see cref="BridgeController" /> object requesting initialization</param>
        public virtual void Initialize(BridgeController bridge)
        {
            var builder = new StringBuilder();

            builder.Append(ClassBridge.GenerateNameSpace(GenericType));
            builder.Append(ClassBridge.GenerateProxyClass(Identification, false));
            lock (Lock)
            {
                if (Fields != null)
                {
                    foreach (var field in Fields)
                    {
                        builder.Append(ClassBridge.GenerateProxyField(Identification, field));
                    }
                }
                if (Methods != null)
                {
                    if (Properties != null)
                    {
                        foreach (var property in Properties)
                        {
                            var get = property.GetGetMethod();
                            if ((get != null) && !Methods.ContainsKey(get))
                            {
                                get = null;
                            }
                            var set = property.GetSetMethod();
                            if ((set != null) && !Methods.ContainsKey(set))
                            {
                                set = null;
                            }
                            builder.Append(ClassBridge.GenerateProxyProperty(Identification, property, get, set));
                        }
                    }
                    foreach (
                        var method in
                        Methods.Where(
                            pair =>
                            (Events == null) ||
                            !Events.Any(
                                info => (pair.Key == info.GetAddMethod()) || (pair.Key == info.GetRemoveMethod()))))
                    {
                        builder.Append(ClassBridge.GenerateProxyMethod(Identification, method.Key, method.Value));
                    }
                }
                if (Events != null)
                {
                    foreach (var info in Events)
                    {
                        var isStatic = info.GetAddMethod().IsStatic || info.GetRemoveMethod().IsStatic;
                        builder.Append(ClassBridge.GenerateProxyField(Identification, info.Name, isStatic, true,
                                                                      new object[0]));
                        builder.Append(ClassBridge.GenerateProxyEventMethods(Identification, info, isStatic));
                    }
                }
            }
            foreach (var instance in Instances.Where(pair => pair.Key != null).ToArray())
            {
                var instanceId = GlobalPool.GetInstanceId(instance.Key);
                if (instanceId != null)
                {
                    builder.AppendLine(ClassBridge.GenerateInstanceChange(Identification, instanceId, false));
                    foreach (var variableName in instance.Value.Where(s => !string.IsNullOrWhiteSpace(s)))
                    {
                        builder.AppendLine(ClassBridge.GenerateInstanceVariable(Identification, instanceId, variableName));
                    }
                }
            }
            OnPushJavascript(new FireJavascriptEventArgs(builder.ToString(), bridge));
            lock (Lock)
            {
                if (SubEnumerations != null)
                {
                    foreach (var subEnum in SubEnumerations)
                    {
                        subEnum.Initialize(bridge);
                    }
                }
                if (SubClasses != null)
                {
                    foreach (var subClass in SubClasses)
                    {
                        subClass.Initialize(bridge);
                    }
                }
            }
        }
예제 #9
0
        /// <summary>
        ///     Handles the passed request and returns the result
        /// </summary>
        /// <param name="method">The method name to handle</param>
        /// <param name="parameters">The method parameters</param>
        /// <param name="hasResult">A boolean value indicting if the handling process resulted in a value</param>
        /// <returns>Returns the value that created from the handling of the request</returns>
        public virtual object InterceptRequest(string method, Dictionary <string, object> parameters, out bool hasResult)
        {
            hasResult = false;
            MethodInfo      methodInfo       = null;
            ConstructorInfo constructorInfo  = null;
            var             methodParameters = new object[0];
            FieldInfo       fieldInfo        = null;
            object          fieldValue       = null;
            object          classInstance    = null;
            var             methodParts      = method.Split('/');

            if (methodParts.Length > 1)
            {
                method        = string.Join("/", methodParts, 1, methodParts.Length - 1);
                classInstance =
                    Instances.FirstOrDefault(
                        instance => GlobalPool.GetInstanceId(instance.Key) == methodParts[0]).Key;
            }
            lock (Lock)
            {
                if (string.IsNullOrWhiteSpace(method))
                {
                    if ((Constructors != null) && parameters.ContainsKey("arguments"))
                    {
                        var constructorParameters = parameters["arguments"] as JArray;
                        foreach (var pair in Constructors)
                        {
                            var matchedArguments = 0;
                            try
                            {
                                var param = new List <object>();
                                for (var i = 0; i < pair.Value.Length; i++)
                                {
                                    if ((constructorParameters != null) && (i < constructorParameters.Count))
                                    {
                                        param.Add(ClassBridge.NormalizeVariable(constructorParameters.ToArray()[i],
                                                                                pair.Value[i].ParameterType, true));
                                        matchedArguments++;
                                    }
                                    else
                                    {
                                        if (pair.Value[i].IsOptional)
                                        {
                                            param.Add(pair.Value[i].DefaultValue);
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                }
                                if ((param.Count != pair.Value.Length) ||
                                    (matchedArguments != (constructorParameters?.Count ?? 0)))
                                {
                                    continue;
                                }
                                methodParameters = param.ToArray();
                            }
                            catch (InvalidCastException)
                            {
                                // ignore
                            }
                            constructorInfo = pair.Key;
                        }
                    }
                }
                else
                {
                    if (Methods != null)
                    {
                        foreach (var pair in Methods.Where(pair => pair.Key.Name.Equals(method)))
                        {
                            var matchedArguments = 0;
                            try
                            {
                                var param = new List <object>();
                                for (var i = 0; i < pair.Value.Length; i++)
                                {
                                    if (i < parameters.Count)
                                    {
                                        if (pair.Value[i].Name == parameters.Keys.ToArray()[i])
                                        {
                                            param.Add(ClassBridge.NormalizeVariable(parameters.Values.ToArray()[i],
                                                                                    pair.Value[i].ParameterType, true));
                                            matchedArguments++;
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        if (pair.Value[i].IsOptional)
                                        {
                                            param.Add(pair.Value[i].DefaultValue);
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                }
                                if ((param.Count != pair.Value.Length) || (matchedArguments != parameters.Count))
                                {
                                    continue;
                                }
                                methodParameters = param.ToArray();
                            }
                            catch (InvalidCastException)
                            {
                                // ignore
                            }
                            methodInfo = pair.Key;
                        }
                    }
                    if ((methodInfo == null) && (Fields != null))
                    {
                        foreach (
                            var field in
                            Fields.Where(info => info.Name.Equals(method, StringComparison.OrdinalIgnoreCase)))
                        {
                            if (parameters.Keys.Contains("value"))
                            {
                                try
                                {
                                    fieldValue = ClassBridge.NormalizeVariable(parameters["value"], field.FieldType,
                                                                               true);
                                }
                                catch (InvalidCastException)
                                {
                                    // ignore
                                }
                            }
                            fieldInfo = field;
                        }
                    }
                }
            }
            if (constructorInfo != null)
            {
                var newObject = constructorInfo.Invoke(methodParameters) as T;
                if (newObject != null)
                {
                    AddInstance(newObject);
                    var instanceId = GlobalPool.GetInstanceId(newObject);
                    if (!string.IsNullOrWhiteSpace(instanceId))
                    {
                        hasResult = true;
                        return(instanceId);
                    }
                }
                return(null);
            }
            if (methodInfo != null)
            {
                if (methodInfo.ReturnType != typeof(void))
                {
                    hasResult = true;
                    return(methodInfo.Invoke(classInstance, methodParameters.ToArray()));
                }
                // Let's not block the UI/Javascript thread if there is no result for the requested method
                Task.Factory.StartNew(() => methodInfo.Invoke(classInstance, methodParameters.ToArray()));
                return(null);
            }
            if (fieldInfo != null)
            {
                if (fieldValue != null)
                {
                    fieldInfo.SetValue(classInstance, fieldValue);
                    return(null);
                }
                hasResult = true;
                return(fieldInfo.GetValue(classInstance));
            }
            return(null);
        }
예제 #10
0
        /// <summary>
        ///     Initialize the handler and generates the needed Javascript code
        /// </summary>
        /// <param name="bridge">The <see cref="BridgeController" /> object requesting initialization</param>
        public virtual void Initialize(BridgeController bridge)
        {
            var identification = typeof(ProxyClass).FullName.Replace('+', '.');
            var builder        = new StringBuilder();

            HybridMessagingBridge.Initialize(bridge);
            builder.Append(ClassBridge.GenerateProxyField(identification, "__subscriptions", false, true,
                                                          new Dictionary <string, object>()));
            builder.Append(ClassBridge.GenerateProxyMethod(identification, "Subscribe",
                                                           new[]
            {
                new ClassBridge.InternalParameterInfo("messageString"),
                new ClassBridge.InternalParameterInfo("callback")
            }, @"
    var_messageString = var_messageString.toLowerCase().trim();
    if (this.__subscriptions[var_messageString] === undefined) {
        this.__subscriptions[var_messageString] = [];
    }
    var index = this.__subscriptions[var_messageString].indexOf(var_callback);
    if (index < 0) {
        this.__subscriptions[var_messageString].push(var_callback);
        return true;
    }
    return false;", false));
            builder.Append(ClassBridge.GenerateProxyMethod(identification, "UnSubscribe",
                                                           new[]
            {
                new ClassBridge.InternalParameterInfo("messageString"),
                new ClassBridge.InternalParameterInfo("callback")
            }, @"
    var_messageString = var_messageString.toLowerCase().trim();
    if (this.__subscriptions[var_messageString] === undefined) {
        return false;
    }
    var index = this.__subscriptions[var_messageString].indexOf(var_callback);
    if (index < 0) {
        return false;
    }
    this.__subscriptions[var_messageString].splice(index, 1);
    if (this.__subscriptions[var_messageString].length < 1) {
        this.__subscriptions[var_messageString] = undefined;
    }
    return true;", false));
            builder.Append(ClassBridge.GenerateProxyMethod(identification, "__raise",
                                                           new[]
            {
                new ClassBridge.InternalParameterInfo("messageString"),
                new ClassBridge.InternalParameterInfo("arguments", true, null)
            }, @"
    var result = undefined;
    var_messageString = var_messageString.toLowerCase().trim();
    for (var messageString in this.__subscriptions) {
        if (!messageString || !var_messageString || messageString == var_messageString) {
            for (index = 0; index < this.__subscriptions[messageString].length; ++index) {
                result = this.__subscriptions[messageString][index].apply(this, [ var_arguments ]);
            }
        }
    }
    return result;", false));
            var instanceId = GlobalPool.GetInstanceId(HybridMessagingProxy);

            if (!string.IsNullOrEmpty(instanceId))
            {
                builder.AppendFormat("\r\n{0}.__instances[\"{1}\"].add_NewMessage({0}.__instances[\"{1}\"].__raise);",
                                     identification, instanceId);
            }
            OnPushJavascript(this, new FireJavascriptEventArgs(builder.ToString()));
        }
예제 #11
0
        /// <summary>
        ///     The method to be called when a new message received from the Javascript side
        /// </summary>
        /// <param name="messageString">The message identification string, or string.Empty to match all</param>
        /// <param name="arguments">The message arguments, or null</param>
        /// <returns>Returns the response of the last subscriber</returns>
        protected virtual object OnNewMessage(string messageString, object arguments)
        {
            messageString = messageString.ToLower().Trim();
            object result = null;

            Delegate[] delegates;
            lock (Lock)
            {
                delegates =
                    Subscriptions.Where(
                        pair =>
                        string.IsNullOrEmpty(messageString) || string.IsNullOrEmpty(pair.Key) ||
                        messageString.Equals(pair.Key, StringComparison.CurrentCulture))
                    .SelectMany(pair => pair.Value)
                    .ToArray();
            }
            foreach (var subscription in delegates)
            {
                var methodInfo       = subscription.Method;
                var methodArguments  = new List <object>();
                var methodResultType = methodInfo.ReturnType;
                try
                {
                    var methodParameters = methodInfo.GetParameters();
                    var failed           = false;
                    if (methodParameters.Length > 0)
                    {
                        foreach (var methodParameter in methodParameters)
                        {
                            if (methodArguments.Count == 0 && !(methodParameter.IsOptional && arguments == null))
                            {
                                methodArguments.Add(arguments == null
                                    ? null
                                    : ClassBridge.NormalizeVariable(arguments, methodParameter.ParameterType, true));
                            }
                            else if (methodParameter.IsOptional)
                            {
                                methodArguments.Add(methodParameter.DefaultValue);
                            }
                            else
                            {
                                failed = true;
                                break;
                            }
                        }
                        if (failed)
                        {
                            continue;
                        }
                    }
                }
                catch (Exception)
                {
                    continue;
                }
                if (methodInfo == null)
                {
                    continue;
                }
                if (methodResultType == typeof(void))
                {
                    // If we don't need the result of this method, we better run it in a new thread, so the UI thread don't get blocked
                    Task.Factory.StartNew(() => methodInfo.Invoke(subscription.Target, methodArguments.ToArray()));
                }
                else
                {
                    var methodResult = methodInfo.Invoke(subscription.Target, methodArguments.ToArray());
                    result = methodResult == null
                        ? null
                        : ClassBridge.NormalizeVariable(methodResult, methodResultType, true);
                }
            }
            return(result);
        }