Exemple #1
0
        /// <summary>
        /// Builds object mapper from OWIN environment for given .NET type.
        /// </summary>
        /// <param name="type">The type of object to map.</param>
        public static Func <IOwinContext, object> Build(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
            var ctor  = ctors.FirstOrDefault(c => c.GetParameters().Any(p => p.HasAttribute <BindingAttribute>()));

            if (ctor != null)
            {
                var args = ParameterMapper.Build(ctor);
                // TODO build expression tree to create instance
                return(ctx => ctor.Invoke(args(ctx)));
            }

            var props = type
                        .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                        .Where(p => p.CanWrite && p.GetIndexParameters().Length == 0 && p.HasAttribute <BindingAttribute>())
                        .ToArray();

            var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                         .Where(f => !f.IsLiteral && !f.IsInitOnly && f.HasAttribute <BindingAttribute>())
                         .ToArray();

            var setters = props
                          .Select(p => Setter(p))
                          .Concat(fields.Select(f => Setter(f)))
                          .ToArray();

            return(ctx =>
            {
                var instance = Activator.CreateInstance(type);

                foreach (var setter in setters)
                {
                    setter(ctx, instance);
                }

                return instance;
            });
        }
        /// <summary>
        /// Registers methods annotated with <see cref="RouteAttribute"/> into routing pipeline.
        /// </summary>
        /// <typeparam name="T">Type to reflect.</typeparam>
        /// <param name="mapRouteBuilder">The fluent API to register http method handlers.</param>
        /// <param name="getInstance">Function to get instance of T.</param>
        /// <returns></returns>
        public static MapRouteBuilder UseApi <T>(this MapRouteBuilder mapRouteBuilder, Func <IOwinContext, T> getInstance)
        {
            if (getInstance == null)
            {
                throw new ArgumentNullException("getInstance");
            }

            var type       = typeof(T);
            var prefixAttr = type.GetAttribute <RoutePrefixAttribute>();
            var prefix     = prefixAttr != null ? prefixAttr.Prefix : string.Empty;

            var serializerSettings = type.GetProperties(BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public)
                                     .Where(p => p.HasAttribute <ResponseSerializerSettingsAttribute>() && p.PropertyType == typeof(JsonSerializerSettings))
                                     .Select(p => p.GetValue(null) as JsonSerializerSettings)
                                     .FirstOrDefault();

            var errorHandler = type.GetMethods(BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public)
                               .Where(m => m.HasAttribute <ErrorHandlerAttribute>())
                               .Select(m => DynamicMethods.CompileMethod(type, m))
                               .FirstOrDefault();

            const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;

            var actions = (from m in type.GetMethods(bindingFlags)
                           let route = m.GetAttribute <RouteAttribute>()
                                       where route != null
                                       select new { Method = m, Route = route }).ToList();

            actions.ForEach(a =>
            {
                var invoke     = DynamicMethods.CompileMethod(type, a.Method);
                var mapper     = ParameterMapper.Build(a.Method);
                var returnType = a.Method.ReturnType;

                var verb    = GetHttpMethod(a.Method);
                var pattern = AddPrefix(prefix, a.Route.Template);

                mapRouteBuilder.Register(pattern, verb, async ctx =>
                {
                    Exception error;
                    var args = MapParameters(ctx, mapper, out error);
                    if (error != null)
                    {
                        if (null != errorHandler)
                        {
                            var errorResponse = errorHandler(null, new object[] { ctx, error });
                            if (null != errorResponse)
                            {
                                await ctx.WriteJson(errorResponse);
                            }
                        }
                        else
                        {
                            ctx.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                            await ctx.WriteJson(new { error = error.Message });
                        }
                        return;
                    }

                    var instance = a.Method.IsStatic ? (object)null : getInstance(ctx);
                    var result   = invoke(instance, args);

                    var task = result as Task;
                    if (null != task)
                    {
                        result = await HandleAsyncResult(task, returnType);
                    }

                    if (result != null)
                    {
                        await ctx.WriteJson(result, serializerSettings);
                    }
                });
            });

            return(mapRouteBuilder);
        }