/// <summary>
        /// Invokes the service method.
        /// </summary>
        /// <param name="handler">The REST handler associated with the HTTP request.</param>
        /// <param name="service">The service instance.</param>
        /// <param name="method">The service method.</param>
        /// <returns>A task that invokes the service method.</returns>
        public virtual Task InvokeAsync(IRestServiceHandler handler, object service, MethodInfo method)
        {
            if (service == null || method == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound, Resources.Global.MismatchedServiceMethod);
            }

            if (handler == null)
            {
                throw new HttpResponseException(HttpStatusCode.InternalServerError, Resources.Global.MissingRouteHandler);
            }

            if (handler.Context == null)
            {
                throw new HttpResponseException(HttpStatusCode.InternalServerError, Resources.Global.MissingServiceContext);
            }

            List<IServiceBehavior> behaviors = GetServiceMethodBehaviors(handler, service, method);
            AddServiceBehaviors(method, behaviors);

            LogUtility.LogRequestData(handler.Context.GetHttpContext());

            object returnedObject = InvokeWithBehaviors(handler, service, method, behaviors);
            Task invocationTask = CreateResultTask(handler, returnedObject, method.ReturnType);

            LogUtility.LogResponseData(handler.Context.GetHttpContext());

            return invocationTask;
        }
        /// <summary>
        /// Creates a parameter value based on the routing and HTTP data.
        /// </summary>
        /// <param name="handler">The REST handler associated with the HTTP request.</param>
        /// <param name="parameter">The service method parameters.</param>
        /// <param name="isResource">
        /// true if the parameter represents a REST resource; otherwise, false. Only 1 resource per
        /// service method is allowed.
        /// </param>
        /// <returns>The created parameter value.</returns>
        public virtual object CreateValue(IRestServiceHandler handler, ParameterInfo parameter, out bool isResource)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }

            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            IServiceContext context = handler.Context;
            ITypeBinder typeBinder = GetParameterBinder(parameter);

            if (typeBinder is DoNotBindAttribute)
            {
                isResource = false;
                return null;
            }

            if (typeBinder != null)
            {
                isResource = IsResourceParameter(context, parameter);
                return GetTypeBindedValue(context, parameter, typeBinder);
            }

            object routeValue = TryGetRouteValue(parameter, context.Request.RouteValues);

            if (routeValue != null)
            {
                isResource = false;
                return routeValue;
            }

            if (IsResourceParameter(context, parameter))
            {
                isResource = true;
                return GetResourceValue(handler, parameter);
            }

            isResource = false;

            if (typeof(IRestContext).IsAssignableFrom(parameter.ParameterType))
            {
                return Rest.Configuration.ServiceLocator.GetService(parameter.ParameterType);
            }

            return null;
        }
        /// <summary>
        /// Locates the service method associated with the provided REST handler and returns the associated data.
        /// </summary>
        /// <param name="handler">A REST handler associated with HTTP request.</param>
        /// <returns>The service method data.</returns>
        public virtual ServiceMethodLocatorData Locate(IRestServiceHandler handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }

            var serviceContractType = GetServiceContractType(handler.ServiceContractTypeName);
            object service = InitializeService(serviceContractType, m_serviceContext.Request);

            HttpMethod httpMethod = m_serviceContext.Request.Method;

            if (httpMethod == HttpMethod.Head)
            {
                m_serviceContext.GetHttpContext().Response.SuppressContent = true;
            }

            MethodInfo method = GetServiceMethod(handler.ServiceUrl, serviceContractType, handler.UrlTemplate, httpMethod);

            return new ServiceMethodLocatorData(service, method);
        }
 public RestServiceRouteInitializer(IRestServiceHandler handler)
 {
     m_handler = handler;
 }
        private static List<IServiceBehavior> GetServiceMethodBehaviors(IRestServiceHandler handler, object service, MethodInfo method)
        {
            List<IServiceBehavior> behaviors = ServiceBehaviorRegistry.GetBehaviors(handler)
                                                                      .Where(behavior => behavior.AppliesTo(handler.Context, new MethodAppliesContext(service, method)))
                                                                      .ToList();

            return behaviors;
        }
        private async Task CreateResultTask(IRestServiceHandler handler, object returnedObject, Type methodReturnType)
        {
            var returnedTask = returnedObject as Task;

            if (returnedTask != null)
            {
                await returnedTask;

                var taskInfo = GetTaskInfo(returnedTask);
                returnedObject = taskInfo.Item1;
                methodReturnType = taskInfo.Item2;
            }

            if (returnedObject is IAsyncResult)
            {
                throw new InvalidOperationException(Resources.Global.InvalidIAsyncResultReturned);
            }

            var resultExecutor = new ResultExecutor();

            if (methodReturnType == typeof(void))
            {
                resultExecutor.ExecuteNoContent(handler.Context);
                return;
            }

            IResult result = m_resultWrapper.Wrap(handler, returnedObject, methodReturnType);

            await resultExecutor.Execute(result, handler.Context);
        }
        private object[] GenerateMethodArguments(IRestServiceHandler handler, MethodInfo method, out object resource)
        {
            var methodArguments = new List<object>();
            resource = null;

            foreach (ParameterInfo parameter in method.GetParameters())
            {
                bool isResource;
                object argumentValue = m_parameterValueProvider.CreateValue(handler, parameter, out isResource);

                if (isResource)
                {
                    resource = argumentValue;
                }

                methodArguments.Add(argumentValue);
            }

            return methodArguments.ToArray();
        }
        private object InvokeWithBehaviors(IRestServiceHandler handler, object service, MethodInfo method, List<IServiceBehavior> behaviors)
        {
            m_behaviorInvoker.InvokeOnAuthorizingBehaviors(behaviors.OfType<ISecureServiceBehavior>().ToList(), service, method);

            object resource;
            object[] methodArguments = GenerateMethodArguments(handler, method, out resource);

            if (!ReferenceEquals(null, resource))
            {
                handler.Context.Request.ResourceBag.Resource = resource;
            }

            if (m_behaviorInvoker.InvokeOnExecutingBehaviors(behaviors, service, method, resource) == BehaviorMethodAction.Stop)
            {
                return null;
            }

            object result = method.Invoke(service, methodArguments);
            m_behaviorInvoker.InvokeOnExecutedBehaviors(behaviors, service, method, result);

            return result;
        }
 public static void SetExceptionHandler(IRestServiceHandler handler, IServiceExceptionHandler exceptionHandler)
 {
     handlerExceptionHandlers.AddOrUpdate(handler, handlerToAdd => exceptionHandler, (handlerToUpdate, exceptionHandlerToUpdate) => exceptionHandler);
 }
        public static IServiceExceptionHandler GetExceptionHandler(IRestServiceHandler handler)
        {
            IServiceExceptionHandler exceptionHandler;

            return handlerExceptionHandlers.TryGetValue(handler, out exceptionHandler) ? exceptionHandler : globalExceptionHandler;
        }
 public static void Add(IRestServiceHandler handler)
 {
     unvalidatedHandlers.Add(handler);
 }
 public static bool IsUnvalidated(IRestServiceHandler handler)
 {
     return unvalidatedHandlers.Contains(handler);
 }
        /// <summary>
        /// Gets the resource value for the service method parameter.
        /// </summary>
        /// <param name="handler">The REST handler.</param>
        /// <param name="parameter">The service method parameter.</param>
        /// <returns>The resource value.</returns>
        protected virtual object GetResourceValue(IRestServiceHandler handler, ParameterInfo parameter)
        {
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }

            string contentType = handler.Context.Request.Headers.ContentType;

            if (String.IsNullOrEmpty(contentType))
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType, Resources.Global.MissingOrInvalidContentType);
            }

            IMediaTypeFormatter formatter = MediaTypeFormatterRegistry.GetHandlerFormatter(handler, contentType) ??
                                            MediaTypeFormatterRegistry.GetFormatter(contentType);

            if (formatter == null || !formatter.CanFormatRequest)
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType, Resources.Global.MissingOrInvalidContentType);
            }

            object argumentValue;

            try
            {
                argumentValue = formatter.FormatRequest(handler.Context, parameter.ParameterType);

                if (argumentValue != null)
                {
                    LogRequest(handler.Context);
                }
            }
            catch (Exception ex)
            {
                if (ExceptionUnwrapper.IsDirectResponseException(ex))
                {
                    throw;
                }

                var httpException = ex as HttpException;

                if (httpException != null)
                {
                    throw new HttpResponseException((HttpStatusCode) httpException.GetHttpCode(), httpException.Message);
                }

                throw new HttpResponseException(HttpStatusCode.BadRequest, Resources.Global.InvalidResourceBody);
            }

            return argumentValue;
        }
        private static void ProcessRequest(IRestServiceHandler handler)
        {
            var handlerTask = Task.Factory.FromAsync(handler.BeginProcessRequest, handler.EndProcessRequest, (HttpContext) null, null);

            try
            {
                handlerTask.Wait();
            }
            catch (AggregateException ex)
            {               
                throw ex.InnerException;
            }
        }