/// <summary> /// Start this service /// </summary> public void Start() { if (this.IsRunning) { throw new InvalidOperationException("Already running"); } else if (this.m_endpoints.Count == 0) { throw new InvalidOperationException($"Service {this.Name} has 0 endpoints"); } this.IsRunning = true; try { this.m_traceSource.TraceInformation("Starting RestService {0}", this.Name); var dispatcher = new ServiceDispatcher(this); foreach (var bhvr in this.m_serviceBehaviors) { bhvr.ApplyServiceBehavior(this, dispatcher); } // Apply behaviors foreach (var ep in this.Endpoints) { foreach (var bhvr in ep.Behaviors) { bhvr.ApplyEndpointBehavior(ep, ep.Dispatcher); } foreach (var op in ep.Operations) { foreach (var bhvr in op.Description.Behaviors) { bhvr.ApplyOperationBehavior(op, op.Dispatcher); } } ep.Binding.AttachEndpoint(dispatcher, ep); } } catch { this.IsRunning = false; throw; } }
/// <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)); } }
/// <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)); } }