public IMOwinServerMiddleware(Func<IDictionary<string, object>, Task> next, IIMOwinOptions options, Assembly[] hostAssemblies) { this._next = next; this._useOtherMiddleware = options.UseOtherMiddleware; this._engine = new IMOwinServer(options); this._engine.RegisterHandlers(options, hostAssemblies); }
public void RegisterHandlers(IIMOwinOptions options, Assembly[] hostAssemblies) { // memoized if (Interlocked.Increment(ref _alreadyRegistered) != 0) return; var contractTypes = hostAssemblies .SelectMany(x => { try { return x.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where(t => t != null); } }) .Where(x => typeof (IMOwinBehaviorContract).IsAssignableFrom(x)) .Where(x => !x.IsAbstract); Parallel.ForEach(contractTypes, classType => { var className = classType.Name; if (classType.GetConstructors().All(x => x.GetParameters().Length != 0)) { throw new InvalidOperationException(string.Format("Type needs parameterless constructor, class:{0}", classType.FullName)); } // ignore if (classType.GetCustomAttribute<IgnoreOperationAttribute>(true) != null) return; foreach (var methodInfo in classType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { // property if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) continue; // ignore if (methodInfo.GetCustomAttribute<IgnoreOperationAttribute>(true) != null) continue; var methodName = methodInfo.Name; // ignore default methods if (methodName == "Equals" || methodName == "GetHashCode" || methodName == "GetType" || methodName == "ToString") continue; // create handler var handler = new OperationHandler(classType, methodInfo); lock (_handlers) { var path = new RequestPath(className, methodName); // 簡単化のため duplicate entry ⇒ fail 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); } } }); }
internal void EmitCode(IIMOwinOptions options, IDictionary<string, object> environment) { environment[OwinConstants.ResponseStatusCode] = (int)StatusCode; if (ReasonPhrase != null) { environment[OwinConstants.ResponseReasonPhrase] = ReasonPhrase; } if (Content != null) { _contentFormatter = _contentFormatter ?? options.ContentFormatter; var encoding = _contentFormatter.Encoding; var responseHeader = environment.AsResponseHeaders(); responseHeader["Content-Type"] = new[] { _contentFormatter.MediaType + ((encoding == null) ? "" : "; charset=" + encoding.WebName) }; 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(CultureInfo.InvariantCulture) }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { buffer.CopyTo(responseStream); // not CopyToAsync } else { // can't await in catch clouse.. // return buffer.CopyToAsync(responseStream); buffer.CopyTo(responseStream); } } } } }
internal static object[] BindParameter(IDictionary<string, object> environment, IIMOwinOptions options, ValueProvider valueProvider, ParameterInfoSlim[] arguments) { var methodParameters = new object[arguments.Length]; for (var 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; } if (!item.ParameterTypeIsString && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } environment.EmitBadRequest(); return null; } if (!item.ParameterTypeIsArray) { var conv = TypeBinder.GetConverter(item.ParameterType); if (conv == null) throw new InvalidOperationException("critical:register code is broken"); object pValue; if (value != null && conv(value, out pValue)) { methodParameters[i] = pValue; continue; } if (item.IsOptional) { methodParameters[i] = item.DefaultValue; continue; } if (!item.ParameterTypeIsString && (item.ParameterTypeIsClass || item.ParameterTypeIsNullable)) { methodParameters[i] = null; continue; } environment.EmitBadRequest(); return null; } var arrayConv = TypeBinder.GetArrayConverter(item.ParameterType); if (arrayConv == null) throw new InvalidOperationException("critical:register code is broken"); methodParameters[i] = arrayConv(values ?? ((value != null) ? new[] { value } : (IList<string>)new string[0])); } return methodParameters; }
public IMOwinServer(IIMOwinOptions options) { this._options = options; }
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; } }
public static IAppBuilder UseIMOwin(this IAppBuilder app, IIMOwinOptions options, params Assembly[] hostAssemblies) { return app.Use(typeof(IMOwinServerMiddleware), options, hostAssemblies); }
public static IAppBuilder UseIMOwin(this IAppBuilder app, IIMOwinOptions options) { return app.Use(typeof(IMOwinServerMiddleware), options); }
public IMOwinServerMiddleware(Func<IDictionary<string, object>, Task> next, IIMOwinOptions options) : this(next, options, AppDomain.CurrentDomain.GetAssemblies()) { }
private async Task<object> ExecuteOperation(IIMOwinOptions options, OperationContext context) { // prepare var handler = this; var environment = context.Environment; var methodParameters = (object[])context.Parameters; var 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[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; if (responseHeader == null) return result; 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(CultureInfo.InvariantCulture) }; buffer.Position = 0; if (options.StreamWriteOption == StreamWriteOption.BufferAndWrite) { if (responseStream != null) buffer.CopyTo(responseStream); // not CopyToAsync } else { await buffer.CopyToAsync(responseStream).ConfigureAwait(false); } } } return result; } environment.EmitNoContent(); return null; }
private Task InvokeRecursive(int index, IOrderedEnumerable<IMOwinFilter> filters, IIMOwinOptions options, OperationContext context) { index += 1; return filters.Count() != index ? filters.Skip(index).First().Invoke(context, () => InvokeRecursive(index, filters, options, context)) : ExecuteOperation(options, context); }
public Task Execute(IIMOwinOptions options, OperationContext context) { var filters = options.Filters.OrderBy(f => f.Order); return InvokeRecursive(-1, filters, options, context); }