Beispiel #1
0
 internal VerbExecutionContext(
     Method method,
     object target,
     Dictionary<string, string> input)
 {
     Method = method;
     Target = target;
     Input = input;
 }
Beispiel #2
0
        public DefaultVerbInvocation(string verb, Method verbMethod, List<object> parms, object target, IEnumerable<string> inputArgs, Dictionary<string, string> inputDictionary, Dictionary<string, string> unusedDictionary )
        {
            Debug.Assert(verb != null);
            Debug.Assert(verbMethod != null);
            Debug.Assert(inputArgs != null);
            Debug.Assert(inputDictionary != null);
            InputArgs = new ReadOnlyCollection<string>(inputArgs.ToList());
            InputDictionary = inputDictionary;
            UnusedDictionary = unusedDictionary ?? new Dictionary<string, string>();
            var verbParms = parms ?? new List<object>();

            Verb = verb;
            VerbMethod = verbMethod;
            VerbParameters = verbParms.AsReadOnly();
            TargetObject = target;
        }
Beispiel #3
0
        private PreVerbExecutionContext PreInterception(
            object target,
            Method method,
            ParameterAndValue[] parameters)
        {
            var preVerbExecutionContext = new PreVerbExecutionContext(method, target, parameters);

            // registered interceptors get top priority
            //
            if (m_registration.RegisteredPreVerbInterceptor != null)
            {
                m_registration.RegisteredPreVerbInterceptor(preVerbExecutionContext);
            }
            else
            {
                // try a defined verb interceptor
                //
                var preInterceptionMethods = Type.GetMethodsWith<PreVerbExecutionAttribute>();

                if (preInterceptionMethods.Any())
                {
                    Debug.Assert(preInterceptionMethods.Count() == 1);

                    var preInterceptionMethod = preInterceptionMethods.First();

                    MethodInvoker.Invoke(preInterceptionMethod, target, new[] { preVerbExecutionContext });
                }
                else
                {
                    // try a defined interceptor type
                    //
                    if (Type.HasAttribute<VerbInterception>())
                    {
                        var interception = Type.GetAttribute<VerbInterception>();

                        var interceptor = (IPreVerbInterceptor)Activator.CreateInstance(interception.InterceptorType);

                        interceptor.BeforeVerbExecution(preVerbExecutionContext);
                    }
                }
            }

            return preVerbExecutionContext;
        }
Beispiel #4
0
        private void PostInterception(
            object target,
            Method method,
            ParameterAndValue[] parameters,
            PreVerbExecutionContext preVerbExecutionContext,
            Exception verbException)
        {
            var postVerbExecutionContext = new PostVerbExecutionContext(
                method,
                target,
                parameters,
                preVerbExecutionContext.Cancel,
                verbException,
                preVerbExecutionContext.UserContext);

            // registered interceptors get top priority
            //
            if (m_registration.RegisteredPostVerbInterceptor != null)
            {
                m_registration.RegisteredPostVerbInterceptor(postVerbExecutionContext);
            }
            else
            {
                var postInterceptionMethods = Type.GetMethodsWith<PostVerbExecutionAttribute>();

                // try a defined interceptor type
                //
                if (postInterceptionMethods.Any())
                {
                    Debug.Assert(postInterceptionMethods.Count() == 1);

                    var postInterceptionMethod = postInterceptionMethods.First();

                    MethodInvoker.Invoke(postInterceptionMethod, target, new[] { postVerbExecutionContext });
                }
                else
                {
                    // try a defined interceptor type
                    //
                    if (Type.HasAttribute<VerbInterception>())
                    {
                        var interception = Type.GetAttribute<VerbInterception>();

                        var interceptor = (IPostVerbInterceptor)Activator.CreateInstance(interception.InterceptorType);

                        interceptor.AfterVerbExecution(postVerbExecutionContext);
                    }
                }
            }
        }
Beispiel #5
0
        private int Execute(
            object target,
            Method method,
            ParameterAndValue[] parameters)
        {
            // pre-interception
            //
            var preVerbExecutionContext = PreInterception(target, method, parameters);

            Exception verbException = null;

            try
            {
                // actual verb execution
                //
                if (!preVerbExecutionContext.Cancel)
                {
                    // invoke the method with the list of parameters
                    //
                    MethodInvoker.Invoke(method.MethodInfo, target, parameters.Select(p => p.Value).ToArray());
                }
            }
            catch (TargetInvocationException tex)
            {
                PreserveStackTrace(tex.InnerException);
                verbException = tex.InnerException;
            }
            catch (Exception ex)
            {
                verbException = ex;
            }
            finally
            {
                try
                {
                    PostInterception(target, method, parameters, preVerbExecutionContext, verbException);
                }
                finally
                {
                    if (verbException != null)
                    {
                        var rethrow = HandleError(verbException, target);

                        if (rethrow)
                        {
                            throw verbException;
                        }
                    }
                }
            }

            return verbException == null ? MultiParser.SuccessCode : MultiParser.ErrorCode;
        }
Beispiel #6
0
        private static void ValidateVerbInput(Method method, List<object> parameterValues)
        {
            var methodParameters = method.MethodInfo.GetParameters();

            // validate all parameters
            //
            var validators = method.MethodInfo.GetInterfaceAttributes<ICollectionValidation>().Select(a => a.GetValidator());

            if (validators.Any())
            {
                var parametersAndValues = new List<ValueInfo>();

                methodParameters.Each((p, i) =>
                {
                    parametersAndValues.Add(new ValueInfo(p.Name, p.ParameterType, parameterValues[i]));
                });

                // all validators must pass
                //
                foreach (var validator in validators)
                {
                    validator.Validate(parametersAndValues.ToArray());
                }
            }
        }
Beispiel #7
0
 public MissingRequiredArgumentException(Method method, string parameter)
     : base("Missing argument for required parameter '{0}'".FormatWith(parameter))
 {
     Method = method;
     ParameterName = parameter;
 }
Beispiel #8
0
        private (Method method, ParameterAndValue[] parameterValues) GetMethodAndParameterValues(string[] args, object obj)
        {
            //
            // *** empty args are handled by the multi-parser
            //
            //

            Debug.Assert(args.Length > 0 && args.All(a => !string.IsNullOrEmpty(a)));

            // the first arg should be the verb, unless there is no verb and a default is used
            //
            var firstArg = args[0];

            if (HandleHelp(firstArg, obj))
            {
                return(null, null);
            }

            // Configure services if supported
            var serviceProvider = CreateServiceProvider(obj);

            var verb = firstArg;

            // a flag, in case there is no verb
            //
            var noVerb = false;

            // find the method by the given verb
            //
            var typeVerbs = GetVerbs()
                            .ToDictionary(v => v, v => GetParameters(v.MethodInfo).ToList());

            // arguments
            var notVerbs = args
                           .Where(a => a.StartsWith(ArgumentPrefixes))
                           .ToList();

            var globals = GetDefinedGlobals()
                          .Where(g => notVerbs.Any(a => a.Substring(1).StartsWith(g.Name.ToLowerInvariant())))
                          .ToList();

            var notVerbsNotGlobals = notVerbs
                                     .Where(a => globals.All(g => !a.Substring(1).StartsWith(g.Name.ToLowerInvariant())))
                                     .ToList();

            // find the method by name, parameter count and parameter names
            var methods = (
                from v in typeVerbs
                where v.Key.Names.Contains(verb.ToLowerInvariant())
                where v.Value.Count == notVerbs.Count
                select v
                ).ToList();

            Method method = SelectMethod(methods, notVerbs);

            // if arguments do not match parameter names, exclude globals
            methods = (
                from v in typeVerbs
                where v.Key.Names.Contains(verb.ToLowerInvariant())
                where v.Value.Count == notVerbsNotGlobals.Count
                select v
                ).ToList();

            if (method == null)
            {
                method = SelectMethod(methods, notVerbsNotGlobals);
            }

            // if arguments do not match parameters names, exclude optional parameters
            if (method == null)
            {
                const bool avoidOptionalParameters = false;
                method = SelectMethod(methods, notVerbsNotGlobals, avoidOptionalParameters);
            }

            // if arguments do not match parameter names, use only argument count (without globals)
            if (method == null)
            {
                method = methods.FirstOrDefault().Key;
            }

            // if nothing matches...
            if (method == null)
            {
                method = typeVerbs.FirstOrDefault(v => v.Key.Names.Contains(verb.ToLowerInvariant())).Key;
            }

            // if no method is found - a default must exist
            if (method == null)
            {
                // if there is a verb input but no method was found
                // AND
                // the first arg is not an input argument (doesn't start with "-" etc)
                //
                if (verb != null && !verb.StartsWith(ArgumentPrefixes))
                {
                    throw new VerbNotFoundException(verb);
                }

                method = typeVerbs.FirstOrDefault(v => v.Key.IsDefault).Key;

                // no default - error
                //
                if (method == null)
                {
                    throw new MissingDefaultVerbException();
                }

                noVerb = true;
            }

            // if there is a verb - skip the first arg
            //
            var inputArgs = MapArguments(noVerb ? args : args.Skip(1));

            HandleGlobals(inputArgs, obj);

            // a list of the available parameters
            //
            var paremetersList = GetParameters(method.MethodInfo);

            // a list of values, used when invoking the method
            //
            var parameterValues = ValuesFactory.CreateParameterValues(method, obj, inputArgs, paremetersList, serviceProvider);

            ValidateVerbInput(method, parameterValues.Select(kvp => kvp.Value).ToList());

            // if some args weren't handled
            //
            if (inputArgs.Any())
            {
                throw new UnhandledParametersException(inputArgs);
            }

            return(method, parameterValues);
        }
        internal static ParameterAndValue[] CreateParameterValues(
            Method method,
            object target,
            Dictionary <string, string> inputArgs,
            IEnumerable <Parameter> list)
        {
            var parameters = new List <ParameterAndValue>();

            // inputArgs is getting emptied.
            // create a copy for the VerbExecutionContext
            //
            var inputArgsCopy = inputArgs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            foreach (var p in list)
            {
                var parameterInfo = p.ParameterInfo;

                var names = p.Names;

                // according to the parameter names, try to find a match from the input
                //
                var inputKey = names.FirstOrDefault(n => inputArgs.ContainsKey(n));

                // the input value
                //
                string stringValue = null;

                // the actual value, converted to the relevant parameter type
                //
                object value = null;

                // if no input was found that matches this parameter
                //
                if (inputKey == null)
                {
                    if (p.Required)
                    {
                        throw new MissingRequiredArgumentException(method, parameterInfo.Name);
                    }

                    if (p.DefaultProvider != null)
                    {
                        value = p.DefaultProvider.GetDefault(new VerbExecutionContext(method, target, inputArgsCopy));
                    }
                    else
                    {
                        // the default is the value
                        //
                        value = p.Default;
                    }

                    // convert the default value, if different from parameter's value (guid, for example)
                    //
                    if (value is string && !(parameterInfo.ParameterType == typeof(string)))
                    {
                        value = GetValueForParameter(parameterInfo, parameterInfo.ParameterType, "{DEFAULT}", (string)value);
                    }
                }
                else
                {
                    stringValue = inputArgs[inputKey];

                    // remove it so later we'll see which ones were not handled
                    //
                    inputArgs.Remove(inputKey);
                }

                if (value == null && inputKey != null)
                {
                    value = GetValueForParameter(parameterInfo, parameterInfo.ParameterType, inputKey, stringValue);
                }

                // validate each parameter
                //
                if (value != null && parameterInfo.HasAttribute <ValidationAttribute>())
                {
                    var validators = parameterInfo.GetAttributes <ValidationAttribute>().Select(a => a.GetValidator());

                    // all validators must pass
                    //
                    foreach (var validator in validators)
                    {
                        validator.Validate(new ValueInfo(parameterInfo.Name, parameterInfo.ParameterType, value));
                    }
                }

                // we have a valid value - add it to the list of parameters
                //
                parameters.Add(new ParameterAndValue(p, value));
            }

            return(parameters.ToArray());
        }