/// <summary>
        /// Dispatch the HttpRequest message to the appropriate service
        /// </summary>
        internal bool Dispatch(ServiceDispatcher serviceDispatcher, RestRequestMessage requestMessage, RestResponseMessage responseMessage)
        {
            // Allow message inspectors to inspect the message before next stage
            try
            {
                this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Begin endpoint dispatch of {0} {1} > {2}", requestMessage.Method, requestMessage.Url, this.m_serviceEndpoint.Description.Contract);

                foreach (var mfi in this.m_messageInspector)
                {
                    mfi.AfterReceiveRequest(requestMessage);
                }

                var ops = this.m_serviceEndpoint.Operations.Where(o => o.Dispatcher.CanDispatch(requestMessage));
                if (ops.Count() == 0)
                {
                    throw new FaultException(404, $"Resource not Found - {requestMessage.Url.AbsolutePath}");
                }
                var op = ops.FirstOrDefault(o => requestMessage.Method.ToLowerInvariant() == o.Description.Method.ToLowerInvariant());
                if (op == null)
                {
                    throw new FaultException(405, "Method not permitted");
                }

                RestOperationContext.Current.EndpointOperation = op;
                op.Dispatcher.Dispatch(serviceDispatcher, requestMessage, responseMessage);

                // Allow message inspectors to inspect before sending response
                foreach (var mfi in this.m_messageInspector)
                {
                    mfi.BeforeSendResponse(responseMessage);
                }

                return(true);
            }
            catch (Exception e)
            {
                this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString());
                return(serviceDispatcher.HandleFault(e, responseMessage));
            }
        }
Exemple #2
0
        /// <summary>
        /// Dispatch the message
        /// </summary>
        internal bool Dispatch(ServiceDispatcher serviceDispatcher, RestRequestMessage requestMessage, RestResponseMessage responseMessage)
        {
            try
            {
                this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Begin operation dispatch of {0} {1} to {2}", requestMessage.Method, requestMessage.Url, this.m_endpointOperation.Description.InvokeMethod);

                foreach (var pol in this.m_operationPolicies)
                {
                    pol.Apply(this.m_endpointOperation, requestMessage);
                }

                var invoke     = this.m_endpointOperation.Description.InvokeMethod;
                var parameters = new object[invoke.GetParameters().Length];

                // By default parameters are passed by name
                var parmMatch = this.m_dispatchRegex.Match(requestMessage.OperationPath);
                for (int i = 0; i < this.m_regexGroupNames.Length; i++)
                {
                    var    pindex = Array.FindIndex(invoke.GetParameters(), o => $"{{{o.Name}}}" == this.m_regexGroupNames[i]);
                    var    sparm  = invoke.GetParameters()[pindex];
                    object sval   = parmMatch.Groups[i + 1].Value;
                    if (sparm.ParameterType == typeof(int))
                    {
                        sval = Int32.Parse(sval.ToString());
                    }
                    else if (sparm.ParameterType == typeof(Guid))
                    {
                        sval = Guid.Parse(sval.ToString());
                    }

                    parameters[pindex] = sval;
                }

                this.DispatchFormatter.DeserializeRequest(this.m_endpointOperation, requestMessage, parameters);

                this.m_traceSource.TraceData(TraceEventType.Verbose, 0, parameters);

                // Validate parameters
                if (!Enumerable.Range(0, invoke.GetParameters().Length).All(o => parameters[o] == null || invoke.GetParameters()[o].ParameterType.IsAssignableFrom(parameters[o]?.GetType())))
                {
                    throw new FaultException(400, "Bad Request");
                }

                // Gather instance
                object instance = serviceDispatcher.Service.Instance;
                if (serviceDispatcher.Service.InstanceMode == Attributes.ServiceInstanceMode.PerCall)
                {
                    instance = Activator.CreateInstance(serviceDispatcher.Service.BehaviorType);
                }

                object result = invoke.Invoke(instance, parameters);

                // Does the invoke override content-type?
                var format = invoke.ReturnParameter.GetCustomAttribute <MessageFormatAttribute>()?.MessageFormat;
                if (format.HasValue)
                {
                    responseMessage.Format = format.Value;
                }

                if (result == null && responseMessage.StatusCode == 0)
                {
                    responseMessage.StatusCode = 204;
                }
                else
                {
                    this.DispatchFormatter.SerializeResponse(responseMessage, parameters, result);
                }

                parameters = null;

                return(true);
            }
            catch (TargetInvocationException e)
            {
                this.m_traceSource.TraceEvent(TraceEventType.Error, 0, e.ToString());
                return(serviceDispatcher.HandleFault(e.InnerException, responseMessage));
            }
            catch (Exception e)
            {
                this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString());
                return(serviceDispatcher.HandleFault(e, responseMessage));
            }
        }