public void OnProcessInterrupt(ILightNodeOptions options, IDictionary <string, object> environment, InterruptReason reason, string detail) { MessageBroker.Publish(new InterruptMessage() { Reason = reason, Detail = detail }); }
#pragma warning restore 618 public bool OnStartProcessRequest(ILightNodeOptions options, IDictionary <string, object> environment) { MessageBroker.Publish(new ProcessStartMessage() { Options = options, Environment = environment }); return(true); }
public async Task <object> ExecuteOperation(ILightNodeOptions options, OperationContext context, Func <ILightNodeOptions, OperationContext, Task <object> > originalOperation) { if (MessageBroker == null || Timer == null) { return(await originalOperation(options, context)); } var timer = Timer; object result; var start = timer.Start(); try { result = await originalOperation(options, context); var stop = timer.Stop(start); var message = new LightNodeExecuteResultMessage() { ContractName = context.ContractName, OperationName = context.OperationName, Result = result, Environment = context.Environment, UsedContentFormatter = context.ContentFormatter, Options = options, FromRequestStart = timer.Point().Offset, Phase = OperationPhase.Operation } .AsTimelineMessage(context.ToString(), OperationCategory) .AsTimedMessage(stop); MessageBroker.Publish(message); return(result); } catch (Exception ex) { var stop = timer.Stop(start); var message = new LightNodeExecuteResultMessage() { ContractName = context.ContractName, OperationName = context.OperationName, Result = ex.ToString(), Environment = context.Environment, UsedContentFormatter = context.ContentFormatter, Options = options, FromRequestStart = timer.Point().Offset, Phase = (ex is ReturnStatusCodeException) ? OperationPhase.ReturnStatusCode : OperationPhase.Exception } .AsTimelineMessage(context.ToString(), OperationCategory) .AsTimedMessage(stop); MessageBroker.Publish(message); throw; } }
public IReadOnlyList<LightNodeFilterAttribute> GetFilters(ILightNodeOptions options, OperationContext context, IReadOnlyList<LightNodeFilterAttribute> originalFilters) { if (MessageBroker == null || Timer == null) return originalFilters; MessageBroker.Publish(context); if (originalFilters.Count == 0) return originalFilters; var array = new LightNodeFilterAttribute[originalFilters.Count]; for (int i = 0; i < originalFilters.Count; i++) { array[i] = new FilterWrapper(MessageBroker, Timer, originalFilters[i]); } return array; }
public LightNodeServerMiddleware(AppFunc next, ILightNodeOptions options, Assembly[] hostAssemblies) { this.next = next; this.engine = new LightNodeServer(options); var sw = Stopwatch.StartNew(); var registeredHandler = this.engine.RegisterHandler(hostAssemblies); options.Logger.InitializeComplete(sw.Elapsed.TotalMilliseconds); lock (runningHandlerLock) { runningHandlers = runningHandlers.SelectMany(g => g, (g, xs) => new { g.Key, xs }) .Concat(new[] { new { Key = options.ServerEngineId, xs = new RegisteredHandlersInfo(options.ServerEngineId, options, registeredHandler) }}) .ToLookup(x => x.Key, x => x.xs); } }
public LightNodeServerMiddleware(AppFunc next, ILightNodeOptions options, Assembly[] hostAssemblies) { this.next = next; this.engine = new LightNodeServer(options); var sw = Stopwatch.StartNew(); var registeredHandler = this.engine.RegisterHandler(hostAssemblies); options.Logger.InitializeComplete(sw.Elapsed.TotalMilliseconds); lock (runningHandlerLock) { runningHandlers = runningHandlers.SelectMany(g => g, (g, xs) => new { g.Key, xs }) .Concat(new[] { new { Key = options.ServerEngineId, xs = new RegisteredHandlersInfo(options.ServerEngineId, options, registeredHandler) } }) .ToLookup(x => x.Key, x => x.xs); } }
internal void EmitCode(ILightNodeOptions options, IDictionary <string, object> environment) { environment[OwinConstants.ResponseStatusCode] = (int)StatusCode; if (ReasonPhrase != null) { environment[OwinConstants.ResponseReasonPhrase] = ReasonPhrase; } if (content != null) { contentFormatter = contentFormatter ?? options.DefaultFormatter; var encoding = contentFormatter.Encoding; var responseHeader = environment.AsResponseHeaders(); responseHeader["Content-Type"] = new[] { contentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; if (environmentEmitter != null) { environmentEmitter(environment); } var responseStream = environment.AsResponseBody(); if (options.StreamWriteOption == StreamWriteOption.DirectWrite) { contentFormatter.Serialize(new UnclosableStream(responseStream), content); } else { using (var buffer = new MemoryStream()) { contentFormatter.Serialize(new UnclosableStream(buffer), content); responseHeader["Content-Length"] = new[] { buffer.Position.ToString() }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { // EmitCode is void:) buffer.CopyTo(responseStream); } } } } }
internal void EmitCode(ILightNodeOptions options, IDictionary<string, object> environment) { environment[OwinConstants.ResponseStatusCode] = (int)StatusCode; if (ReasonPhrase != null) { environment[OwinConstants.ResponseReasonPhrase] = ReasonPhrase; } if (content != null) { contentFormatter = contentFormatter ?? options.DefaultFormatter; var encoding = contentFormatter.Encoding; var responseHeader = environment.AsResponseHeaders(); responseHeader["Content-Type"] = new[] { contentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; if (environmentEmitter != null) { environmentEmitter(environment); } var responseStream = environment.AsResponseBody(); if (options.StreamWriteOption == StreamWriteOption.DirectWrite) { contentFormatter.Serialize(new UnclosableStream(responseStream), content); } else { using (var buffer = new MemoryStream()) { contentFormatter.Serialize(new UnclosableStream(buffer), content); responseHeader["Content-Length"] = new[] { buffer.Position.ToString() }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { // EmitCode is void:) buffer.CopyTo(responseStream); } } } } }
public IReadOnlyList <LightNodeFilterAttribute> GetFilters(ILightNodeOptions options, OperationContext context, IReadOnlyList <LightNodeFilterAttribute> originalFilters) { if (MessageBroker == null || Timer == null) { return(originalFilters); } MessageBroker.Publish(context); if (originalFilters.Count == 0) { return(originalFilters); } var array = new LightNodeFilterAttribute[originalFilters.Count]; for (int i = 0; i < originalFilters.Count; i++) { array[i] = new FilterWrapper(MessageBroker, Timer, originalFilters[i]); } return(array); }
internal void EmitCode(ILightNodeOptions options, HttpContext httpContext) { httpContext.Response.StatusCode = (int)StatusCode; if (content != null) { contentFormatter = contentFormatter ?? options.DefaultFormatter; var encoding = contentFormatter.Encoding; var responseHeader = httpContext.Response.Headers; responseHeader["Content-Type"] = new[] { contentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; contextEmitter?.Invoke(httpContext); var responseStream = httpContext.Response.Body; if (options.StreamWriteOption == StreamWriteOption.DirectWrite) { contentFormatter.Serialize(new UnclosableStream(responseStream), content); } else { using (var buffer = new MemoryStream()) { contentFormatter.Serialize(new UnclosableStream(buffer), content); responseHeader["Content-Length"] = new[] { buffer.Position.ToString() }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { // EmitCode is void:) buffer.CopyTo(responseStream); } } } } }
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); } }
public OperationHandler(ILightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes <LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes <LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); var operationOption = methodInfo.GetCustomAttributes <OperationOptionAttribute>(true).FirstOrDefault() ?? classType.GetCustomAttributes <OperationOptionAttribute>(true).FirstOrDefault(); this.AcceptVerb = (operationOption != null && operationOption.AcceptVerbs != null) ? operationOption.AcceptVerbs.Value : options.DefaultAcceptVerb; var verbSpecifiedAttr = methodInfo.GetCustomAttributes <HttpVerbAttribtue>(true); if (verbSpecifiedAttr.Any()) { this.AcceptVerb = verbSpecifiedAttr.Aggregate((AcceptVerbs)0, (x, y) => x | y.AcceptVerbs); } this.ForceUseFormatter = (operationOption != null && operationOption.ContentFormatter != null) ? operationOption.ContentFormatter : null; var formatterChoiceBase = new[] { options.DefaultFormatter }.Concat(options.SpecifiedFormatters).Where(x => x != null).ToArray(); this.optionFormatters = formatterChoiceBase; this.formatterByExt = formatterChoiceBase.SelectMany(x => (x.Ext ?? "").Split('|'), (fmt, ext) => new { fmt, ext }).ToLookup(x => x.ext, x => x.fmt, StringComparer.OrdinalIgnoreCase); this.formatterByMediaType = formatterChoiceBase.ToLookup(x => x.MediaType, StringComparer.OrdinalIgnoreCase); this.formatterByContentEncoding = formatterChoiceBase.ToLookup(x => x.ContentEncoding, StringComparer.OrdinalIgnoreCase); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary <string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], Task> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda <Func <object, object> >( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda <Action <IDictionary <string, object>, object[]> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], object> >( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
Task InvokeRecursive(int index, IReadOnlyList <LightNodeFilterAttribute> filters, ILightNodeOptions options, OperationContext context, IOperationCoordinator coordinator) { index += 1; if (filters.Count != index) { // chain next filter return(filters[index].Invoke(context, () => InvokeRecursive(index, filters, options, context, coordinator))); } else { // execute operation return(coordinator.ExecuteOperation(options, context, ExecuteOperation)); } }
// 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 void OnProcessInterrupt(ILightNodeOptions options, IDictionary<string, object> environment, InterruptReason reason, string detail) { MessageBroker.Publish(new InterruptMessage() { Reason = reason, Detail = detail }); }
public virtual bool OnStartProcessRequest(ILightNodeOptions options, HttpContext httpContext) { return true; }
public virtual IReadOnlyList<LightNodeFilterAttribute> GetFilters(ILightNodeOptions options, OperationContext context, IReadOnlyList<LightNodeFilterAttribute> originalFilters) { return originalFilters; }
public virtual bool OnStartProcessRequest(ILightNodeOptions options, IDictionary <string, object> environment) { return(true); }
public virtual bool OnStartProcessRequest(ILightNodeOptions options, HttpContext httpContext) { 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; } }
public LightNodeServer(ILightNodeOptions options) { this.options = options; }
public async Task<object> ExecuteOperation(ILightNodeOptions options, OperationContext context, Func<ILightNodeOptions, OperationContext, Task<object>> originalOperation) { if (MessageBroker == null || Timer == null) return await originalOperation(options, context); var timer = Timer; object result; var start = timer.Start(); try { result = await originalOperation(options, context); var stop = timer.Stop(start); var message = new LightNodeExecuteResultMessage() { ContractName = context.ContractName, OperationName = context.OperationName, Result = result, Environment = context.Environment, UsedContentFormatter = context.ContentFormatter, Options = options, FromRequestStart = timer.Point().Offset, Phase = OperationPhase.Operation } .AsTimelineMessage(context.ToString(), OperationCategory) .AsTimedMessage(stop); MessageBroker.Publish(message); return result; } catch (Exception ex) { var stop = timer.Stop(start); var message = new LightNodeExecuteResultMessage() { ContractName = context.ContractName, OperationName = context.OperationName, Result = ex.ToString(), Environment = context.Environment, UsedContentFormatter = context.ContentFormatter, Options = options, FromRequestStart = timer.Point().Offset, Phase = (ex is ReturnStatusCodeException) ? OperationPhase.ReturnStatusCode : OperationPhase.Exception } .AsTimelineMessage(context.ToString(), OperationCategory) .AsTimedMessage(stop); MessageBroker.Publish(message); throw; } }
public virtual void OnProcessInterrupt(ILightNodeOptions options, HttpContext httpContext, InterruptReason reason, string detail) { }
public virtual void OnProcessInterrupt(ILightNodeOptions options, IDictionary<string, object> environment, InterruptReason reason, string detail) { }
public virtual IReadOnlyList <LightNodeFilterAttribute> GetFilters(ILightNodeOptions options, OperationContext context, IReadOnlyList <LightNodeFilterAttribute> originalFilters) { return(originalFilters); }
public RegisteredHandlersInfo(string engineId, ILightNodeOptions options, IReadOnlyCollection <KeyValuePair <string, OperationInfo> > registeredHandlers) { this.EngineId = engineId; this.Options = options; this.RegisteredHandlers = registeredHandlers; }
public virtual Task<object> ExecuteOperation(ILightNodeOptions options, OperationContext context, Func<ILightNodeOptions, OperationContext, Task<object>> originalOperation) { return originalOperation(options, context); }
public static IAppBuilder UseLightNode(this IAppBuilder app, ILightNodeOptions options) { return(app.Use(typeof(LightNodeServerMiddleware), options)); }
public virtual void OnProcessInterrupt(ILightNodeOptions options, IDictionary <string, object> environment, InterruptReason reason, string detail) { }
public LightNodeServerMiddleware(AppFunc next, ILightNodeOptions options) : this(next, options, AppDomain.CurrentDomain.GetAssemblies()) { }
public virtual Task <object> ExecuteOperation(ILightNodeOptions options, OperationContext context, Func <ILightNodeOptions, OperationContext, Task <object> > originalOperation) { return(originalOperation(options, context)); }
public static IAppBuilder UseLightNode(this IAppBuilder app, ILightNodeOptions options, params Assembly[] hostAssemblies) { return app.Use(typeof(LightNodeServerMiddleware), options, hostAssemblies); }
public static IAppBuilder UseLightNode(this IAppBuilder app, ILightNodeOptions options, params Assembly[] hostAssemblies) { return(app.Use(typeof(LightNodeServerMiddleware), options, hostAssemblies)); }
#pragma warning restore 618 public bool OnStartProcessRequest(ILightNodeOptions options, IDictionary<string, object> environment) { MessageBroker.Publish(new ProcessStartMessage() { Options = options, Environment = environment }); return true; }
public static IApplicationBuilder UseLightNode(this IApplicationBuilder app, ILightNodeOptions options, params Assembly[] hostAssemblies) { return(app.UseMiddleware <LightNodeServerMiddleware>(options, hostAssemblies)); }
public RegisteredHandlersInfo(string engineId, ILightNodeOptions options, IReadOnlyCollection<KeyValuePair<string, OperationInfo>> registeredHandlers) { this.EngineId = engineId; this.Options = options; this.RegisteredHandlers = registeredHandlers; }
public static IApplicationBuilder UseLightNode(this IApplicationBuilder app, ILightNodeOptions options, Assembly[] hostAssemblies) { return app.UseMiddleware<LightNodeServerMiddleware>(options, hostAssemblies); }
public static IAppBuilder UseLightNode(this IAppBuilder app, ILightNodeOptions options) { return app.Use(typeof(LightNodeServerMiddleware), options); }
// 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 Task Execute(ILightNodeOptions options, OperationContext context, IOperationCoordinator coordinator) { var targetFilters = coordinator.GetFilters(options, context, filters); return InvokeRecursive(-1, targetFilters, options, context, coordinator); }
internal static object[] BindParameter(HttpContext httpContext, 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, httpContext, 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 { httpContext.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { httpContext.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, httpContext, 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 { httpContext.EmitBadRequest(); if (options.OperationMissingHandlingPolicy == OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails) { httpContext.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); }
Task InvokeRecursive(int index, IReadOnlyList<LightNodeFilterAttribute> filters, ILightNodeOptions options, OperationContext context, IOperationCoordinator coordinator) { index += 1; if (filters.Count != index) { // chain next filter return filters[index].Invoke(context, () => InvokeRecursive(index, filters, options, context, coordinator)); } else { // execute operation return coordinator.ExecuteOperation(options, context, ExecuteOperation); } }
public Task Execute(ILightNodeOptions options, OperationContext context, IOperationCoordinator coordinator) { var targetFilters = coordinator.GetFilters(options, context, filters); return(InvokeRecursive(-1, targetFilters, options, context, coordinator)); }
async Task<object> ExecuteOperation(ILightNodeOptions options, OperationContext context) { // prepare var handler = this; var environment = context.Environment; var methodParameters = (object[])context.Parameters; bool isVoid = true; object result = null; switch (handler.handlerBodyType) { case HandlerBodyType.Action: handler.methodActionBody(environment, methodParameters); break; case HandlerBodyType.Func: isVoid = false; result = handler.methodFuncBody(environment, methodParameters); break; case HandlerBodyType.AsyncAction: var actionTask = handler.methodAsyncActionBody(environment, methodParameters); await actionTask.ConfigureAwait(false); break; case HandlerBodyType.AsyncFunc: isVoid = false; var funcTask = handler.methodAsyncFuncBody(environment, methodParameters); await funcTask.ConfigureAwait(false); var extractor = taskResultExtractors[FindTaskType(funcTask.GetType())]; result = extractor(funcTask); break; default: throw new InvalidOperationException("critical:register code is broken"); } if (!isVoid) { // append header var responseHeader = environment["owin.ResponseHeaders"] as IDictionary<string, string[]>; var encoding = context.ContentFormatter.Encoding; responseHeader["Content-Type"] = new[] { context.ContentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; if (!string.IsNullOrWhiteSpace(context.ContentFormatter.ContentEncoding)) { responseHeader["Content-Encoding"] = new[] { context.ContentFormatter.ContentEncoding }; } environment.EmitOK(); var responseStream = environment["owin.ResponseBody"] as Stream; if (options.StreamWriteOption == StreamWriteOption.DirectWrite) { context.ContentFormatter.Serialize(new UnclosableStream(responseStream), result); } else { using (var buffer = new MemoryStream()) { context.ContentFormatter.Serialize(new UnclosableStream(buffer), result); responseHeader["Content-Length"] = new[] { buffer.Position.ToString() }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { await buffer.CopyToAsync(responseStream).ConfigureAwait(false); } } } return result; } else { environment.EmitNoContent(); return null; } }
async Task <object> ExecuteOperation(ILightNodeOptions options, OperationContext context) { // prepare var handler = this; var environment = context.Environment; var methodParameters = (object[])context.Parameters; bool isVoid = true; object result = null; switch (handler.handlerBodyType) { case HandlerBodyType.Action: handler.methodActionBody(environment, methodParameters); break; case HandlerBodyType.Func: isVoid = false; result = handler.methodFuncBody(environment, methodParameters); break; case HandlerBodyType.AsyncAction: var actionTask = handler.methodAsyncActionBody(environment, methodParameters); await actionTask.ConfigureAwait(false); break; case HandlerBodyType.AsyncFunc: isVoid = false; var funcTask = handler.methodAsyncFuncBody(environment, methodParameters); await funcTask.ConfigureAwait(false); var extractor = taskResultExtractors[FindTaskType(funcTask.GetType())]; result = extractor(funcTask); break; default: throw new InvalidOperationException("critical:register code is broken"); } if (!isVoid) { // append header var responseHeader = environment["owin.ResponseHeaders"] as IDictionary <string, string[]>; var encoding = context.ContentFormatter.Encoding; responseHeader["Content-Type"] = new[] { context.ContentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; if (!string.IsNullOrWhiteSpace(context.ContentFormatter.ContentEncoding)) { responseHeader["Content-Encoding"] = new[] { context.ContentFormatter.ContentEncoding }; } environment.EmitOK(); var responseStream = environment["owin.ResponseBody"] as Stream; if (options.StreamWriteOption == StreamWriteOption.DirectWrite) { context.ContentFormatter.Serialize(new UnclosableStream(responseStream), result); } else { using (var buffer = new MemoryStream()) { context.ContentFormatter.Serialize(new UnclosableStream(buffer), result); responseHeader["Content-Length"] = new[] { buffer.Position.ToString() }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { await buffer.CopyToAsync(responseStream).ConfigureAwait(false); } } } return(result); } else { environment.EmitNoContent(); return(null); } }
public OperationHandler(ILightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes<LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes<LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); var operationOption = methodInfo.GetCustomAttributes<OperationOptionAttribute>(true).FirstOrDefault() ?? classType.GetCustomAttributes<OperationOptionAttribute>(true).FirstOrDefault(); this.AcceptVerb = (operationOption != null && operationOption.AcceptVerbs != null) ? operationOption.AcceptVerbs.Value : options.DefaultAcceptVerb; var verbSpecifiedAttr = methodInfo.GetCustomAttributes<HttpVerbAttribtue>(true); if (verbSpecifiedAttr.Any()) { this.AcceptVerb = verbSpecifiedAttr.Aggregate((AcceptVerbs)0, (x, y) => x | y.AcceptVerbs); } this.ForceUseFormatter = (operationOption != null && operationOption.ContentFormatter != null) ? operationOption.ContentFormatter : null; var formatterChoiceBase = new[] { options.DefaultFormatter }.Concat(options.SpecifiedFormatters).Where(x => x != null).ToArray(); this.optionFormatters = formatterChoiceBase; this.formatterByExt = formatterChoiceBase.SelectMany(x => (x.Ext ?? "").Split('|'), (fmt, ext) => new { fmt, ext }).ToLookup(x => x.ext, x => x.fmt, StringComparer.OrdinalIgnoreCase); this.formatterByMediaType = formatterChoiceBase.ToLookup(x => x.MediaType, StringComparer.OrdinalIgnoreCase); this.formatterByContentEncoding = formatterChoiceBase.ToLookup(x => x.ContentEncoding, StringComparer.OrdinalIgnoreCase); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast<Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary<string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], Task>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda<Action<IDictionary<string, object>, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], object>>( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
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; }
public virtual bool OnStartProcessRequest(ILightNodeOptions options, IDictionary<string, object> environment) { return true; }