static bool IsRethrowOrEmitException(IOperationCoordinator coordinator, ILightNodeOptions options, IDictionary <string, object> environment, Exception ex) { var exString = ex.ToString(); coordinator.OnProcessInterrupt(options, environment, InterruptReason.ExecuteFailed, exString); switch (options.ErrorHandlingPolicy) { case ErrorHandlingPolicy.ReturnInternalServerError: environment.EmitInternalServerError(); environment.EmitStringMessage("500 InternalServerError"); return(false); case ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails: environment.EmitInternalServerError(); environment.EmitStringMessage(exString); return(false); case ErrorHandlingPolicy.ThrowException: default: environment.EmitInternalServerError(); return(true); } }
internal static object[] BindParameter(IDictionary<string, object> environment, ILightNodeOptions options, IOperationCoordinator coordinator, ValueProvider valueProvider, ParameterInfoSlim[] arguments) { var methodParameters = new object[arguments.Length]; for (int i = 0; i < arguments.Length; i++) { var item = arguments[i]; var _values = valueProvider.GetValue(item.Name); var value = _values as string; var values = _values as List<string>; var isEmpty = _values == null; var byteArray = _values as byte[]; // TODO:Experimental support if (byteArray != null && item.ParameterTypeIsArray && item.ParameterType == typeof(byte[])) { methodParameters[i] = byteArray; continue; } if (isEmpty && !item.ParameterTypeIsArray) { if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { coordinator.OnProcessInterrupt(options, environment, InterruptReason.ParameterBindMissing, "Lack of Parameter:" + item.Name); options.Logger.ParameterBindMissing(OperationMissingKind.LackOfParameter, item.Name); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new ParameterMissingException(OperationMissingKind.LackOfParameter, item.Name); } else { environment.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("Lack of Parameter:" + item.Name); } return null; } } } else if (!item.ParameterTypeIsArray) { var conv = TypeBinder.GetConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (conv == null) throw new InvalidOperationException("critical:register code is broken"); object pValue; if (conv(value ?? values[0], out pValue)) { methodParameters[i] = pValue; continue; } else if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { coordinator.OnProcessInterrupt(options, environment, InterruptReason.ParameterBindMissing, "Mismatch ParameterType:" + item.Name); options.Logger.ParameterBindMissing(OperationMissingKind.MissmatchParameterType, item.Name); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new ParameterMissingException(OperationMissingKind.MissmatchParameterType, item.Name); } else { environment.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("Mismatch ParameterType:" + item.Name); } return null; } } } var arrayConv = TypeBinder.GetArrayConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (arrayConv == null) throw new InvalidOperationException("critical:register code is broken"); methodParameters[i] = arrayConv((values != null) ? values : (value != null) ? new[] { value } : (IList<string>)new string[0]); continue; } return methodParameters; }
// Accept, Accept-Encoding flow internal IContentFormatter NegotiateFormat(IDictionary <string, object> environment, string ext, ILightNodeOptions options, IOperationCoordinator coorinator) { var requestHeader = environment["owin.RequestHeaders"] as IDictionary <string, string[]>; string[] accepts; if (ForceUseFormatter != null) { return(ForceUseFormatter); } if (!string.IsNullOrWhiteSpace(ext)) { // Ext match -> ContentEncoding match var selectedFormatters = formatterByExt[ext] as ICollection <IContentFormatter> ?? formatterByExt[ext].ToArray(); if (!selectedFormatters.Any()) { coorinator.OnProcessInterrupt(options, environment, InterruptReason.NegotiateFormatFailed, "Ext:" + ext); options.Logger.NegotiateFormatFailed(OperationMissingKind.NegotiateFormatFailed, ext); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new NegotiateFormatFailedException(OperationMissingKind.NegotiateFormatFailed, ext); } else { environment.EmitNotAcceptable(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("NegotiateFormat failed, ext:" + ext); } } return(null); } return(SelectAcceptEncodingFormatter(requestHeader, selectedFormatters)); } else if (requestHeader.TryGetValue("Accept", out accepts)) { if (optionFormatters.Length == 1) { return(options.DefaultFormatter); // optimize path, defaultFormatter only } // MediaType match -> ContentEncoding match var acceptsValues = GetDescendingQualityHeaderValues(accepts); var formatters = acceptsValues.SelectMany(x => formatterByMediaType[x.Item3]).ToArray(); if (formatters.Length == 0) { // only accept-encoding goto CONTENT_ENCODING_MATCH; } return(SelectAcceptEncodingFormatter(requestHeader, formatters)); } // ContentEncoding match CONTENT_ENCODING_MATCH: { if (optionFormatters.Length == 1) { return(options.DefaultFormatter); // optimize path, defaultFormatter only } // ContentEncoding match string[] rawAcceptEncoding; if (!requestHeader.TryGetValue("Accept-Encoding", out rawAcceptEncoding)) { return(options.DefaultFormatter); } var acceptEncodings = GetDescendingQualityHeaderValues(rawAcceptEncoding); var formatter = acceptEncodings .Select(kvp => formatterByContentEncoding[kvp.Item3].FirstOrDefault()) .FirstOrDefault(x => x != null); if (formatter == null) { return(options.DefaultFormatter); } return(formatter); } }
public static void EmitNotAcceptable(this IDictionary <string, object> environment) { environment["owin.ResponseStatusCode"] = (int)System.Net.HttpStatusCode.NotAcceptable; // 406 environment.EmitStringMessage("406 NotAcceptable"); }
OperationHandler SelectHandler(IDictionary <string, object> environment, IOperationCoordinator coorinator, out AcceptVerbs verb, out string ext) { // out default verb = AcceptVerbs.Get; ext = ""; var path = environment["owin.RequestPath"] as string; var method = environment["owin.RequestMethod"] as string; // extract path var keyBase = path.Trim('/').Split('/'); if (keyBase.Length != 2) { goto NOT_FOUND; } // extract "extension" for media type var extStart = keyBase[1].LastIndexOf("."); if (extStart != -1) { ext = keyBase[1].Substring(extStart + 1); keyBase[1] = keyBase[1].Substring(0, keyBase[1].Length - ext.Length - 1); } // {ClassName, MethodName} var key = new RequestPath(keyBase[0], keyBase[1]); OperationHandler handler; if (handlers.TryGetValue(key, out handler)) { // verb check if (StringComparer.OrdinalIgnoreCase.Equals(method, "GET")) { verb = AcceptVerbs.Get; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "POST")) { verb = AcceptVerbs.Post; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "PUT")) { verb = AcceptVerbs.Put; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "DELETE")) { verb = AcceptVerbs.Delete; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "PATCH")) { verb = AcceptVerbs.Patch; } else { goto VERB_MISSING; } if (!handler.AcceptVerb.HasFlag(verb)) { goto VERB_MISSING; } return(handler); // OK } else { goto NOT_FOUND; } VERB_MISSING: coorinator.OnProcessInterrupt(options, environment, InterruptReason.MethodNotAllowed, "MethodName:" + method); options.Logger.MethodNotAllowed(OperationMissingKind.MethodNotAllowed, path, method); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new MethodNotAllowedException(OperationMissingKind.MethodNotAllowed, path, method); } else { environment.EmitMethodNotAllowed(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("MethodNotAllowed:" + method); } return(null); } NOT_FOUND: coorinator.OnProcessInterrupt(options, environment, InterruptReason.OperationNotFound, "SearchedPath:" + path); options.Logger.OperationNotFound(OperationMissingKind.OperationNotFound, path); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new OperationNotFoundException(OperationMissingKind.MethodNotAllowed, path); } else { environment.EmitNotFound(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("OperationNotFound:" + path); } return(null); } }
public static void EmitNotFound(this IDictionary <string, object> environment) { environment["owin.ResponseStatusCode"] = (int)System.Net.HttpStatusCode.NotFound; // 404 environment.EmitStringMessage("404 NotFound"); }
public static void EmitMethodNotAllowed(this IDictionary <string, object> environment) { environment["owin.ResponseStatusCode"] = (int)System.Net.HttpStatusCode.MethodNotAllowed; // 405 environment.EmitStringMessage("405 MethodNotAllowed"); }
// Accept, Accept-Encoding flow internal IContentFormatter NegotiateFormat(IDictionary<string, object> environment, string ext, ILightNodeOptions options, IOperationCoordinator coorinator) { var requestHeader = environment["owin.RequestHeaders"] as IDictionary<string, string[]>; string[] accepts; if (ForceUseFormatter != null) return ForceUseFormatter; if (!string.IsNullOrWhiteSpace(ext)) { // Ext match -> ContentEncoding match var selectedFormatters = formatterByExt[ext] as ICollection<IContentFormatter> ?? formatterByExt[ext].ToArray(); if (!selectedFormatters.Any()) { coorinator.OnProcessInterrupt(options, environment, InterruptReason.NegotiateFormatFailed, "Ext:" + ext); options.Logger.NegotiateFormatFailed(OperationMissingKind.NegotiateFormatFailed, ext); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new NegotiateFormatFailedException(OperationMissingKind.NegotiateFormatFailed, ext); } else { environment.EmitNotAcceptable(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("NegotiateFormat failed, ext:" + ext); } } return null; } return SelectAcceptEncodingFormatter(requestHeader, selectedFormatters); } else if (requestHeader.TryGetValue("Accept", out accepts)) { if (optionFormatters.Length == 1) return options.DefaultFormatter; // optimize path, defaultFormatter only // MediaType match -> ContentEncoding match var acceptsValues = GetDescendingQualityHeaderValues(accepts); var formatters = acceptsValues.SelectMany(x => formatterByMediaType[x.Item3]).ToArray(); if (formatters.Length == 0) { // only accept-encoding goto CONTENT_ENCODING_MATCH; } return SelectAcceptEncodingFormatter(requestHeader, formatters); } // ContentEncoding match CONTENT_ENCODING_MATCH: { if (optionFormatters.Length == 1) return options.DefaultFormatter; // optimize path, defaultFormatter only // ContentEncoding match string[] rawAcceptEncoding; if (!requestHeader.TryGetValue("Accept-Encoding", out rawAcceptEncoding)) { return options.DefaultFormatter; } var acceptEncodings = GetDescendingQualityHeaderValues(rawAcceptEncoding); var formatter = acceptEncodings .Select(kvp => formatterByContentEncoding[kvp.Item3].FirstOrDefault()) .FirstOrDefault(x => x != null); if (formatter == null) return options.DefaultFormatter; return formatter; } }
internal static object[] BindParameter(IDictionary <string, object> environment, ILightNodeOptions options, IOperationCoordinator coordinator, ValueProvider valueProvider, ParameterInfoSlim[] arguments) { var methodParameters = new object[arguments.Length]; for (int i = 0; i < arguments.Length; i++) { var item = arguments[i]; var _values = valueProvider.GetValue(item.Name); var value = _values as string; var values = _values as List <string>; var isEmpty = _values == null; if (isEmpty && !item.ParameterTypeIsArray) { if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { coordinator.OnProcessInterrupt(options, environment, InterruptReason.ParameterBindMissing, "Lack of Parameter:" + item.Name); options.Logger.ParameterBindMissing(OperationMissingKind.LackOfParameter, item.Name); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new ParameterMissingException(OperationMissingKind.LackOfParameter, item.Name); } else { environment.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("Lack of Parameter:" + item.Name); } return(null); } } } else if (!item.ParameterTypeIsArray) { var conv = TypeBinder.GetConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (conv == null) { throw new InvalidOperationException("critical:register code is broken"); } object pValue; if (conv(value ?? values[0], out pValue)) { methodParameters[i] = pValue; continue; } else if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { coordinator.OnProcessInterrupt(options, environment, InterruptReason.ParameterBindMissing, "Mismatch ParameterType:" + item.Name); options.Logger.ParameterBindMissing(OperationMissingKind.MissmatchParameterType, item.Name); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new ParameterMissingException(OperationMissingKind.MissmatchParameterType, item.Name); } else { environment.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("Mismatch ParameterType:" + item.Name); } return(null); } } } var arrayConv = TypeBinder.GetArrayConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (arrayConv == null) { throw new InvalidOperationException("critical:register code is broken"); } methodParameters[i] = arrayConv((values != null) ? values : (value != null) ? new[] { value } : (IList <string>) new string[0]); continue; } return(methodParameters); }
OperationHandler SelectHandler(IDictionary<string, object> environment, IOperationCoordinator coorinator, out AcceptVerbs verb, out string ext) { // out default verb = AcceptVerbs.Get; ext = ""; var path = environment["owin.RequestPath"] as string; var method = environment["owin.RequestMethod"] as string; // extract path var keyBase = path.Trim('/').Split('/'); if (keyBase.Length != 2) { goto NOT_FOUND; } // extract "extension" for media type var extStart = keyBase[1].LastIndexOf("."); if (extStart != -1) { ext = keyBase[1].Substring(extStart + 1); keyBase[1] = keyBase[1].Substring(0, keyBase[1].Length - ext.Length - 1); } // {ClassName, MethodName} var key = new RequestPath(keyBase[0], keyBase[1]); OperationHandler handler; if (handlers.TryGetValue(key, out handler)) { // verb check if (StringComparer.OrdinalIgnoreCase.Equals(method, "GET")) { verb = AcceptVerbs.Get; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "POST")) { verb = AcceptVerbs.Post; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "PUT")) { verb = AcceptVerbs.Put; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "DELETE")) { verb = AcceptVerbs.Delete; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "PATCH")) { verb = AcceptVerbs.Patch; } else { goto VERB_MISSING; } if (!handler.AcceptVerb.HasFlag(verb)) { goto VERB_MISSING; } return handler; // OK } else { goto NOT_FOUND; } VERB_MISSING: coorinator.OnProcessInterrupt(options, environment, InterruptReason.MethodNotAllowed, "MethodName:" + method); options.Logger.MethodNotAllowed(OperationMissingKind.MethodNotAllowed, path, method); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new MethodNotAllowedException(OperationMissingKind.MethodNotAllowed, path, method); } else { environment.EmitMethodNotAllowed(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("MethodNotAllowed:" + method); } return null; } NOT_FOUND: coorinator.OnProcessInterrupt(options, environment, InterruptReason.OperationNotFound, "SearchedPath:" + path); options.Logger.OperationNotFound(OperationMissingKind.OperationNotFound, path); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ThrowException) { throw new OperationNotFoundException(OperationMissingKind.MethodNotAllowed, path); } else { environment.EmitNotFound(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { environment.EmitStringMessage("OperationNotFound:" + path); } return null; } }
private static bool IsRethrowOrEmitException(IIMOwinOptions options, IDictionary<string, object> environment, Exception ex) { var exString = ex.ToString(); switch (options.ErrorHandlingPolicy) { case ErrorHandlingPolicy.ParseReturnStatusCodeException: environment.ParseReturnStatusCodeException(ex); return false; case ErrorHandlingPolicy.ReturnInternalServerError: environment.EmitInternalServerError(); environment.EmitStringMessage("500 InternalServerError"); return false; case ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails: environment.EmitInternalServerError(); environment.EmitStringMessage(exString); return false; default: environment.EmitInternalServerError(); return true; } }
static bool IsRethrowOrEmitException(IOperationCoordinator coordinator, ILightNodeOptions options, IDictionary<string, object> environment, Exception ex) { var exString = ex.ToString(); coordinator.OnProcessInterrupt(options, environment, InterruptReason.ExecuteFailed, exString); switch (options.ErrorHandlingPolicy) { case ErrorHandlingPolicy.ReturnInternalServerError: environment.EmitInternalServerError(); environment.EmitStringMessage("500 InternalServerError"); return false; case ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails: environment.EmitInternalServerError(); environment.EmitStringMessage(exString); return false; case ErrorHandlingPolicy.ThrowException: default: environment.EmitInternalServerError(); return true; } }
// Routing -> ParameterBinding -> Execute public async Task ProcessRequest(IDictionary<string, object> environment) { try { AcceptVerbs verb; string ext; var handler = SelectHandler(environment, out verb, out ext); if (handler == null) return; // verb check | TODO:check operation verb attribute if (!options.DefaultAcceptVerb.HasFlag(verb)) { environment.EmitMethodNotAllowed(); return; } // Parameter binding var valueProvider = new ValueProvider(environment, verb); var methodParameters = ParameterBinder.BindParameter(environment, options, valueProvider, handler.Arguments); if (methodParameters == null) return; // select formatter var formatter = NegotiateFormat(environment, ext); if (formatter == null) return; // Operation execute var context = new OperationContext(environment, handler.ClassName, handler.MethodName, verb) { Parameters = methodParameters, ContentFormatter = formatter, Attributes = handler.AttributeLookup }; await handler.Execute(options, context).ConfigureAwait(false); return; } catch (ReturnStatusCodeException statusException) { statusException.EmitCode(environment); return; } catch (Exception ex) { switch (options.ErrorHandlingPolicy) { case ErrorHandlingPolicy.ReturnInternalServerError: environment.EmitInternalServerError(); return; case ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails: environment.EmitInternalServerError(); environment.EmitStringMessage(ex.ToString()); return; case ErrorHandlingPolicy.ThrowException: default: throw; } } }
internal static object[] BindParameter(IDictionary<string, object> environment, LightNodeOptions options, ValueProvider valueProvider, ParameterInfoSlim[] arguments) { var methodParameters = new object[arguments.Length]; for (int i = 0; i < arguments.Length; i++) { var item = arguments[i]; var _values = valueProvider.GetValue(item.Name); var value = _values as string; var values = _values as List<string>; var isEmpty = _values == null; if (isEmpty && !item.ParameterTypeIsArray) { if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { environment.EmitBadRequest(); environment.EmitStringMessage("Lack of Parameter:" + item.Name); return null; } } else if (!item.ParameterTypeIsArray) { var conv = TypeBinder.GetConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (conv == null) throw new InvalidOperationException("critical:register code is broken"); object pValue; if (conv(value ?? values[0], out pValue)) { methodParameters[i] = pValue; continue; } else if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { environment.EmitBadRequest(); environment.EmitStringMessage("Mismatch Parameter Type:" + item.Name); return null; } } var arrayConv = TypeBinder.GetArrayConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (arrayConv == null) throw new InvalidOperationException("critical:register code is broken"); methodParameters[i] = arrayConv((values != null) ? values : (value != null) ? new[] { value } : Enumerable.Empty<string>()); continue; } return methodParameters; }
internal static object[] BindParameter(IDictionary <string, object> environment, LightNodeOptions options, ValueProvider valueProvider, ParameterInfoSlim[] arguments) { var methodParameters = new object[arguments.Length]; for (int i = 0; i < arguments.Length; i++) { var item = arguments[i]; var _values = valueProvider.GetValue(item.Name); var value = _values as string; var values = _values as List <string>; var isEmpty = _values == null; if (isEmpty && !item.ParameterTypeIsArray) { if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { environment.EmitBadRequest(); environment.EmitStringMessage("Lack of Parameter:" + item.Name); return(null); } } else if (!item.ParameterTypeIsArray) { var conv = TypeBinder.GetConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (conv == null) { throw new InvalidOperationException("critical:register code is broken"); } object pValue; if (conv(value ?? values[0], out pValue)) { methodParameters[i] = pValue; continue; } else if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } else if ((!item.ParameterTypeIsString || options.ParameterStringImplicitNullAsDefault) && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } else { environment.EmitBadRequest(); environment.EmitStringMessage("Mismatch Parameter Type:" + item.Name); return(null); } } var arrayConv = TypeBinder.GetArrayConverter(item.ParameterType, !options.ParameterEnumAllowsFieldNameParse); if (arrayConv == null) { throw new InvalidOperationException("critical:register code is broken"); } methodParameters[i] = arrayConv((values != null) ? values : (value != null) ? new[] { value } : Enumerable.Empty <string>()); continue; } return(methodParameters); }
// Routing -> ParameterBinding -> Execute public async Task ProcessRequest(IDictionary <string, object> environment) { try { AcceptVerbs verb; string ext; var handler = SelectHandler(environment, out verb, out ext); if (handler == null) { return; } // verb check | TODO:check operation verb attribute if (!options.DefaultAcceptVerb.HasFlag(verb)) { environment.EmitMethodNotAllowed(); return; } // Parameter binding var valueProvider = new ValueProvider(environment, verb); var methodParameters = ParameterBinder.BindParameter(environment, options, valueProvider, handler.Arguments); if (methodParameters == null) { return; } // select formatter var formatter = NegotiateFormat(environment, ext); if (formatter == null) { return; } // Operation execute var context = new OperationContext(environment, handler.ClassName, handler.MethodName, verb) { Parameters = methodParameters, ContentFormatter = formatter, Attributes = handler.AttributeLookup }; await handler.Execute(options, context).ConfigureAwait(false); return; } catch (ReturnStatusCodeException statusException) { statusException.EmitCode(environment); return; } catch (Exception ex) { switch (options.ErrorHandlingPolicy) { case ErrorHandlingPolicy.ReturnInternalServerError: environment.EmitInternalServerError(); return; case ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails: environment.EmitInternalServerError(); environment.EmitStringMessage(ex.ToString()); return; case ErrorHandlingPolicy.ThrowException: default: throw; } } }