OperationHandler SelectHandler(IDictionary <string, object> environment, out AcceptVerbs verb, out string ext) { // out default verb = AcceptVerbs.Get; ext = ""; // verb check var method = environment["owin.RequestMethod"]; if (StringComparer.OrdinalIgnoreCase.Equals(method, "GET")) { verb = AcceptVerbs.Get; } else if (StringComparer.OrdinalIgnoreCase.Equals(method, "POST")) { verb = AcceptVerbs.Post; } else { environment.EmitMethodNotAllowed(); return(null); } // extract path var path = environment["owin.RequestPath"] as string; var keyBase = path.Trim('/').Split('/'); if (keyBase.Length != 2) { environment.EmitNotFound(); return(null); } // 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)) { return(handler); } else { environment.EmitNotFound(); return(null); } }
// cache all methods public IReadOnlyCollection <KeyValuePair <string, OperationInfo> > RegisterHandler(Assembly[] hostAssemblies) { if (Interlocked.Increment(ref alreadyRegistered) != 0) { return(new KeyValuePair <string, OperationInfo> [0]); } var contractTypes = hostAssemblies .SelectMany(x => { try { return(x.GetTypes()); } catch (ReflectionTypeLoadException ex) { return(ex.Types.Where(t => t != null)); } }) .Where(x => typeof(LightNodeContract).IsAssignableFrom(x)) .Where(x => !x.IsAbstract); Parallel.ForEach(contractTypes, classType => { var className = classType.Name; if (!classType.GetConstructors().Any(x => x.GetParameters().Length == 0)) { throw new InvalidOperationException(string.Format("Type needs parameterless constructor, class:{0}", classType.FullName)); } if (classType.GetCustomAttribute <IgnoreOperationAttribute>(true) != null) { return; // ignore } foreach (var methodInfo in classType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) { continue; // as property } if (methodInfo.GetCustomAttribute <IgnoreOperationAttribute>(true) != null) { continue; // ignore } var methodName = methodInfo.Name; // ignore default methods if (methodName == "Equals" || methodName == "GetHashCode" || methodName == "GetType" || methodName == "ToString") { continue; } var sw = Stopwatch.StartNew(); // create handler var handler = new OperationHandler(options, classType, methodInfo); lock (handlers) { // fail duplicate entry var path = new RequestPath(className, methodName); if (handlers.ContainsKey(path)) { throw new InvalidOperationException(string.Format("same class and method is not allowed, class:{0} method:{1}", className, methodName)); } handlers.Add(path, handler); } sw.Stop(); options.Logger.RegisiterOperation(handler.ClassName, handler.MethodName, sw.Elapsed.TotalMilliseconds); } }); // return readonly operation info return(handlers.Select(x => new KeyValuePair <string, OperationInfo>(x.Key.ToString(), new OperationInfo(x.Value))).ToList().AsReadOnly()); }
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); } }