首页 \ 问答 \ Ninject Conventions and Interception(Ninject Conventions and Interception)

Ninject Conventions and Interception(Ninject Conventions and Interception)

我想用拦截属性来装饰我的服务,然后让基于约定的绑定为我设置拦截器。 我不希望我的属性从拦截属性继承...如果我可以避免它。

例如,我有以下课程:

[Log]
public class SomeClassToLog
{
    public void DoSomething() { ... }
}

我明白我可以绑定如下:

var kernel = new StandardKernel();
            kernel.Bind(x => x.FromAssembliesMatching("SomeProject.*")
                              .SelectAllClasses()
                              .WithAttribute(typeof(LogAttribute))
                              .BindToSelf().Configure(syntax => syntax.Intercept().With(LogInterceptor)));

如何使用不同的属性和拦截器组合来做到这一点? 例如:

如果我有Log和Authorize属性,我将不得不配置3组绑定? (1表示没有授权的日志,1表示没有日志的授权,1表示日志和授权的日志)。

更新:虽然我找不到基于原始问题参数的解决方案,但我偶然发现了一个类似的问题,这个问题引导我找到最终解决的问题。 这是源代码:

注意: Common.Interception.Interceptors命名空间位于一个程序集中 ,该程序集引用了Ninject.Extensions.Interception(及其所有必需的依赖项)。 我的属性在一个单独的程序集中定义,没有自己的依赖项。

MiscExtensions.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common.Interception.Interceptors
{
    // TODO: Remove the dependence on these eventually

    /// <summary>
    /// A bundle of extension methods which I needed to borrow from ninject source since they were internal:
    /// Ninject.Extensions.Interception.Infrastructure.Language
    /// ExtensionsForIEnumerable
    /// ExtensionsForMethodInfo
    /// ExtensionsForICustomAttributeProvider  
    /// </summary> 
    internal static class MiscExtensions
    {
        /// <summary>
        /// Converts all of the items in the specified series using the specified converter.
        /// </summary>
        /// <typeparam name="TInput">The type of items contained in the input list.</typeparam>
        /// <typeparam name="TOutput">The type of items to return.</typeparam>
        /// <param name="items">The series of items to convert.</param>
        /// <param name="converter">The converter to use to convert the items.</param>
        /// <returns>A list of the converted items.</returns>
        public static IEnumerable<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> items,
                                                                     Func<TInput, TOutput> converter)
        {
            return items.Select(converter);
        }

        /// <summary>
        /// Skips the last items where the count of skipped items is given by count.
        /// </summary>
        /// <typeparam name="T">The type of the enumerable.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="count">The count of skipped items.</param>
        /// <returns>An enumerable that skippes the last items from the source enumerable.</returns>
        public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
        {
            var enumerator = source.GetEnumerator();
            var items = new Queue<T>();

            while (enumerator.MoveNext())
            {
                if (count-- <= 0)
                {
                    yield return items.Dequeue();
                }

                items.Enqueue(enumerator.Current);
            }
        }

        private const BindingFlags DefaultBindingFlags =
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Instance;

        public static PropertyInfo GetPropertyFromMethod(this MethodInfo method, Type implementingType)
        {
            if (!method.IsSpecialName)
            {
                return null;
            }

            var isGetMethod = method.Name.Substring(0, 3) == "get";
            var returnType = isGetMethod ? method.ReturnType : method.GetParameterTypes().Last();
            var indexerTypes = isGetMethod ? method.GetParameterTypes() : method.GetParameterTypes().SkipLast(1);

            return implementingType.GetProperty(method.Name.Substring(4), DefaultBindingFlags, null, returnType, indexerTypes.ToArray(), null);
        }

        public static PropertyInfo GetPropertyFromMethod(this MethodInfo method)
        {
            if (!method.IsSpecialName)
            {
                return null;
            }
            return method.DeclaringType.GetProperty(method.Name.Substring(4), DefaultBindingFlags);
        }

        /// <summary>
        /// Gets the types of the parameters of the method.
        /// </summary>
        /// <param name="method">The method in question.</param>
        /// <returns>An array containing the types of the method's parameters.</returns>
        public static IEnumerable<Type> GetParameterTypes(this MethodBase method)
        {
            return method.GetParameters().Convert(p => p.ParameterType);
        }

        /// <summary>
        /// Gets the method handle of either the method or its generic type definition, if it is
        /// a generic method.
        /// </summary>
        /// <param name="method">The method in question.</param>
        /// <returns>The runtime method handle for the method or its generic type definition.</returns>
        public static RuntimeMethodHandle GetMethodHandle(this MethodBase method)
        {
            var mi = method as MethodInfo;

            if (mi != null &&
                 mi.IsGenericMethod)
            {
                return mi.GetGenericMethodDefinition().MethodHandle;
            }
            return method.MethodHandle;
        }

        /// <summary>
        /// Gets the first attribute of a specified type that decorates the member.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns>The first attribute matching the specified type.</returns>
        public static T GetOneAttribute<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            var attributes = member.GetCustomAttributes(typeof(T), true) as T[];

            return (attributes == null) ||
                   (attributes.Length == 0)
                       ? null
                       : attributes[0];
        }

        /// <summary>
        /// Gets the first attribute of a specified type that decorates the member.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns>The first attribute matching the specified type.</returns>
        public static object GetOneAttribute(this ICustomAttributeProvider member, Type type)
        {
            object[] attributes = member.GetCustomAttributes(type, true);

            return (attributes == null) ||
                   (attributes.Length == 0)
                       ? null
                       : attributes[0];
        }

        /// <summary>
        /// Gets an array of attributes matching the specified type that decorate the member.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns>An array of attributes matching the specified type.</returns>
        public static T[] GetAllAttributes<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            return member.GetCustomAttributes(typeof(T), true) as T[];
        }

        /// <summary>
        /// Gets an array of attributes matching the specified type that decorate the member.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns>An array of attributes matching the specified type.</returns>
        public static object[] GetAllAttributes(this ICustomAttributeProvider member, Type type)
        {
            return member.GetCustomAttributes(type, true);
        }

        /// <summary>
        /// Determines whether the member is decorated with one or more attributes of the specified type.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns><see langword="True"/> if the member is decorated with one or more attributes of the type, otherwise <see langword="false"/>.</returns>
        public static bool HasAttribute<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            return member.IsDefined(typeof(T), true);
        }

        /// <summary>
        /// Determines whether the member is decorated with one or more attributes of the specified type.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns><see langword="True"/> if the member is decorated with one or more attributes of the type, otherwise <see langword="false"/>.</returns>
        public static bool HasAttribute(this ICustomAttributeProvider member, Type type)
        {
            return member.IsDefined(type, true);
        }

        /// <summary>
        /// Determines whether the member is decorated with an attribute that matches the one provided.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <param name="attributeToMatch">The attribute to match against.</param>
        /// <returns><see langword="True"/> if the member is decorated with a matching attribute, otherwise <see langword="false"/>.</returns>
        public static bool HasMatchingAttribute<T>(this ICustomAttributeProvider member, T attributeToMatch)
            where T : Attribute
        {
            T[] attributes = member.GetAllAttributes<T>();

            if ((attributes == null) ||
                 (attributes.Length == 0))
            {
                return false;
            }

            return attributes.Any(attribute => attribute.Match(attributeToMatch));
        }
    }
}

AlternateInterceptorRegistrationStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Ninject;
using Ninject.Components;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Advice;
using Ninject.Extensions.Interception.Planning.Directives;
using Ninject.Extensions.Interception.Registry;
using Ninject.Planning;
using Ninject.Planning.Strategies;

namespace Common.Interception.Interceptors
{
    /// <summary>
    /// This is a derivation of InterceptorRegistrationStrategy from Ninject.Extensions.Interception.Planning.Strategies, merged with 
    /// http://stackoverflow.com/questions/6386461/ninject-intercept-any-method-with-certain-attribute
    /// </summary>
    public class AlternateInterceptorRegistrationStrategy<TAttribute, TInterceptor> : NinjectComponent, IPlanningStrategy
        where TAttribute : Attribute
        where TInterceptor : IInterceptor
    {
        protected const BindingFlags DefaultBindingFlags =
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Instance;

        public AlternateInterceptorRegistrationStrategy(IAdviceFactory adviceFactory, IAdviceRegistry adviceRegistry, IKernel kernel)
        {
            AdviceFactory = adviceFactory;
            AdviceRegistry = adviceRegistry;
            Kernel = kernel;
        }

        public IKernel Kernel { get; set; }
        public IAdviceFactory AdviceFactory { get; set; }
        public IAdviceRegistry AdviceRegistry { get; set; }

        public virtual void Execute(IPlan plan)
        {
            IEnumerable<MethodInfo> candidates = GetCandidateMethods(plan.Type);

            RegisterClassInterceptors(plan.Type, plan, candidates);

            foreach (MethodInfo method in candidates)
            {
                PropertyInfo property = method.GetPropertyFromMethod(plan.Type);
                ICustomAttributeProvider provider = (ICustomAttributeProvider)property ?? method;
                TAttribute[] attributes = provider.GetAllAttributes<TAttribute>();

                if (attributes.Length == 0)
                {
                    continue;
                }

                RegisterMethodInterceptor(plan.Type, method);

                // Indicate that instances of the type should be proxied.
                if (!plan.Has<ProxyDirective>())
                {
                    plan.Add(new ProxyDirective());
                }
            }
        }

        protected virtual void RegisterClassInterceptors(Type type, IPlan plan, IEnumerable<MethodInfo> candidates)
        {
            var attributes = type.GetAllAttributes<TAttribute>();

            if (attributes.Length == 0)
            {
                return;
            }

            foreach (MethodInfo method in candidates)
            {
                PropertyInfo property = method.GetPropertyFromMethod(type);
                ICustomAttributeProvider provider = (ICustomAttributeProvider) property ?? method;

                var config = Kernel.Get<IInterceptorConfig>();

                if (config.DoNotInterceptAttribute == null)
                {
                    // A "do not intercept" attribute wasn't defined in the config, so go ahead and register
                    RegisterMethodInterceptor(type, method);
                }
                else if (!provider.IsDefined(config.DoNotInterceptAttribute, true))
                {
                    // The method wasn't decorated with the "do not intercept" attribute, so go ahead and register
                    RegisterMethodInterceptor(type, method);
                }
            }

            if (!plan.Has<ProxyDirective>())
            {
                plan.Add(new ProxyDirective());
            }
        }

        protected virtual void RegisterMethodInterceptor(Type type, MethodInfo method)
        {
            IAdvice advice = AdviceFactory.Create(method);

            advice.Callback = request => request.Context.Kernel.Get<TInterceptor>();

            var config = Kernel.TryGet<IInterceptorConfig>();
            if (config != null)
            {
                advice.Order = config.GetOrder<TInterceptor>();
            }

            AdviceRegistry.Register(advice);
        }

        protected virtual IEnumerable<MethodInfo> GetCandidateMethods(Type type)
        {
            MethodInfo[] methods = type.GetMethods(DefaultBindingFlags);

            return methods.Where(ShouldIntercept);
        }

        protected virtual bool ShouldIntercept(MethodInfo methodInfo)
        {
            return methodInfo.DeclaringType != typeof(object) &&
                   !methodInfo.IsPrivate;// &&
            //!methodInfo.IsFinal;
        }
    }
}

IInterceptorConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public interface IInterceptorConfig
    {
        IInterceptorConfig SpecifyOrder<TInterceptor>(int order) where TInterceptor : IInterceptor;

        IInterceptorConfig SpecifyDoNotInterceptAttribute<TAttribute>() where TAttribute : Attribute;

        int GetOrder<TInterceptor>() where TInterceptor : IInterceptor;

        Type DoNotInterceptAttribute { get; }
    }
}

InterceptorConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public class InterceptorConfig : IInterceptorConfig
    {
        private readonly Dictionary<Type, int> _orderDictionary = new Dictionary<Type, int>();

        public IInterceptorConfig SpecifyOrder<TInterceptor>(int order) where TInterceptor : IInterceptor
        {
            _orderDictionary.Add(typeof(TInterceptor), order);
            return this;
        }

        public IInterceptorConfig SpecifyDoNotInterceptAttribute<TAttribute>() where TAttribute : Attribute
        {
            DoNotInterceptAttribute = typeof(TAttribute);
            return this;
        }

        public int GetOrder<TInterceptor>() where TInterceptor : IInterceptor
        {
            return _orderDictionary[typeof(TInterceptor)];
        }

        public Type DoNotInterceptAttribute { get; private set; }
    }
}

TraceInterceptor.cs - 只是一个示例拦截器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public class TraceInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("Enter Method");

            invocation.Proceed();

            Console.WriteLine("Exit Method");
        }
    }
}

注意:这是一个简单的控制台应用程序,显示如何连接属性/拦截器。 这依赖于Ninject.Extensions.Interception.DynamicProxy和Ninject.Extensions.Conventions(及其所有必需的依赖项)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Common.Interception.Attributes;
using Common.Interception.Interceptors;
using Ninject;
using Ninject.Extensions.Conventions;
using Ninject.Planning.Strategies;
using SomeProject.Infrastructure;

namespace SomeProject.ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            kernel.Components.Add<IPlanningStrategy, AlternateInterceptorRegistrationStrategy<TraceAttribute, TraceInterceptor>>();
            kernel.Components.Add<IPlanningStrategy, AlternateInterceptorRegistrationStrategy<AuthorizeAttribute, AuthorizeInterceptor>>();

            // I needed a way to specify execution order and "DoNotIntercept" without deriving from attributes that would force ninject references all over my domain
            // not 100% confident this is the best way - but it works
            kernel.Bind<IInterceptorConfig>().ToConstant(new InterceptorConfig()
                                                             .SpecifyOrder<TraceInterceptor>(1)
                                                             .SpecifyOrder<AuthorizeInterceptor>(0)
                                                             .SpecifyDoNotInterceptAttribute<DoNotInterceptAttribute>());

            // SomeProject.Infrastructure contains my service classes decorated with my custom attributes
            kernel.Bind(x => x.FromAssembliesMatching("SomeProject.Infrastructure")
                              .SelectAllClasses()
                              .BindToSelf());

            var a = kernel.Get<SomeServiceA>();
            var b = kernel.Get<SomeServiceB>();

            Console.WriteLine("Calling a.DoSomeStuff()...");
            a.DoSomeStuff();

            Console.WriteLine("Calling b.DoMyThing()...");
            b.DoMyThing();

            Console.WriteLine("Calling b.NowTraceThis()...");
            b.NowTraceThis();

            Console.ReadLine();
        }
    }
}

I want to decorate my services with attributes for interception, and then have conventions based binding set the interceptors up for me. I don't want my attributes to inherit from the interception attributes... if I can avoid it.

For example, I have the following class:

[Log]
public class SomeClassToLog
{
    public void DoSomething() { ... }
}

I understand I can bind this as follows:

var kernel = new StandardKernel();
            kernel.Bind(x => x.FromAssembliesMatching("SomeProject.*")
                              .SelectAllClasses()
                              .WithAttribute(typeof(LogAttribute))
                              .BindToSelf().Configure(syntax => syntax.Intercept().With(LogInterceptor)));

How can I do this with different combinations of attributes and interceptors? For example:

If I have Log and Authorize attributes I would have to configure 3 sets of bindings? (1 for log without authorize, 1 for authorize without log and one for both log and authorize).

Updated: While I couldn't find a solution based on my original question parameters, I did stumble upon a similar question which lead me to the solution I ended up going with. Here is the source code:

Notes: Common.Interception.Interceptors namespace is in an assembly which has a reference to Ninject.Extensions.Interception (and all of its required dependencies). My attributes are defined in a separate assembly with no dependencies of their own.

MiscExtensions.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common.Interception.Interceptors
{
    // TODO: Remove the dependence on these eventually

    /// <summary>
    /// A bundle of extension methods which I needed to borrow from ninject source since they were internal:
    /// Ninject.Extensions.Interception.Infrastructure.Language
    /// ExtensionsForIEnumerable
    /// ExtensionsForMethodInfo
    /// ExtensionsForICustomAttributeProvider  
    /// </summary> 
    internal static class MiscExtensions
    {
        /// <summary>
        /// Converts all of the items in the specified series using the specified converter.
        /// </summary>
        /// <typeparam name="TInput">The type of items contained in the input list.</typeparam>
        /// <typeparam name="TOutput">The type of items to return.</typeparam>
        /// <param name="items">The series of items to convert.</param>
        /// <param name="converter">The converter to use to convert the items.</param>
        /// <returns>A list of the converted items.</returns>
        public static IEnumerable<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> items,
                                                                     Func<TInput, TOutput> converter)
        {
            return items.Select(converter);
        }

        /// <summary>
        /// Skips the last items where the count of skipped items is given by count.
        /// </summary>
        /// <typeparam name="T">The type of the enumerable.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="count">The count of skipped items.</param>
        /// <returns>An enumerable that skippes the last items from the source enumerable.</returns>
        public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
        {
            var enumerator = source.GetEnumerator();
            var items = new Queue<T>();

            while (enumerator.MoveNext())
            {
                if (count-- <= 0)
                {
                    yield return items.Dequeue();
                }

                items.Enqueue(enumerator.Current);
            }
        }

        private const BindingFlags DefaultBindingFlags =
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Instance;

        public static PropertyInfo GetPropertyFromMethod(this MethodInfo method, Type implementingType)
        {
            if (!method.IsSpecialName)
            {
                return null;
            }

            var isGetMethod = method.Name.Substring(0, 3) == "get";
            var returnType = isGetMethod ? method.ReturnType : method.GetParameterTypes().Last();
            var indexerTypes = isGetMethod ? method.GetParameterTypes() : method.GetParameterTypes().SkipLast(1);

            return implementingType.GetProperty(method.Name.Substring(4), DefaultBindingFlags, null, returnType, indexerTypes.ToArray(), null);
        }

        public static PropertyInfo GetPropertyFromMethod(this MethodInfo method)
        {
            if (!method.IsSpecialName)
            {
                return null;
            }
            return method.DeclaringType.GetProperty(method.Name.Substring(4), DefaultBindingFlags);
        }

        /// <summary>
        /// Gets the types of the parameters of the method.
        /// </summary>
        /// <param name="method">The method in question.</param>
        /// <returns>An array containing the types of the method's parameters.</returns>
        public static IEnumerable<Type> GetParameterTypes(this MethodBase method)
        {
            return method.GetParameters().Convert(p => p.ParameterType);
        }

        /// <summary>
        /// Gets the method handle of either the method or its generic type definition, if it is
        /// a generic method.
        /// </summary>
        /// <param name="method">The method in question.</param>
        /// <returns>The runtime method handle for the method or its generic type definition.</returns>
        public static RuntimeMethodHandle GetMethodHandle(this MethodBase method)
        {
            var mi = method as MethodInfo;

            if (mi != null &&
                 mi.IsGenericMethod)
            {
                return mi.GetGenericMethodDefinition().MethodHandle;
            }
            return method.MethodHandle;
        }

        /// <summary>
        /// Gets the first attribute of a specified type that decorates the member.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns>The first attribute matching the specified type.</returns>
        public static T GetOneAttribute<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            var attributes = member.GetCustomAttributes(typeof(T), true) as T[];

            return (attributes == null) ||
                   (attributes.Length == 0)
                       ? null
                       : attributes[0];
        }

        /// <summary>
        /// Gets the first attribute of a specified type that decorates the member.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns>The first attribute matching the specified type.</returns>
        public static object GetOneAttribute(this ICustomAttributeProvider member, Type type)
        {
            object[] attributes = member.GetCustomAttributes(type, true);

            return (attributes == null) ||
                   (attributes.Length == 0)
                       ? null
                       : attributes[0];
        }

        /// <summary>
        /// Gets an array of attributes matching the specified type that decorate the member.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns>An array of attributes matching the specified type.</returns>
        public static T[] GetAllAttributes<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            return member.GetCustomAttributes(typeof(T), true) as T[];
        }

        /// <summary>
        /// Gets an array of attributes matching the specified type that decorate the member.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns>An array of attributes matching the specified type.</returns>
        public static object[] GetAllAttributes(this ICustomAttributeProvider member, Type type)
        {
            return member.GetCustomAttributes(type, true);
        }

        /// <summary>
        /// Determines whether the member is decorated with one or more attributes of the specified type.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <returns><see langword="True"/> if the member is decorated with one or more attributes of the type, otherwise <see langword="false"/>.</returns>
        public static bool HasAttribute<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            return member.IsDefined(typeof(T), true);
        }

        /// <summary>
        /// Determines whether the member is decorated with one or more attributes of the specified type.
        /// </summary>
        /// <param name="member">The member to examine.</param>
        /// <param name="type">The type of attribute to search for.</param>
        /// <returns><see langword="True"/> if the member is decorated with one or more attributes of the type, otherwise <see langword="false"/>.</returns>
        public static bool HasAttribute(this ICustomAttributeProvider member, Type type)
        {
            return member.IsDefined(type, true);
        }

        /// <summary>
        /// Determines whether the member is decorated with an attribute that matches the one provided.
        /// </summary>
        /// <typeparam name="T">The type of attribute to search for.</typeparam>
        /// <param name="member">The member to examine.</param>
        /// <param name="attributeToMatch">The attribute to match against.</param>
        /// <returns><see langword="True"/> if the member is decorated with a matching attribute, otherwise <see langword="false"/>.</returns>
        public static bool HasMatchingAttribute<T>(this ICustomAttributeProvider member, T attributeToMatch)
            where T : Attribute
        {
            T[] attributes = member.GetAllAttributes<T>();

            if ((attributes == null) ||
                 (attributes.Length == 0))
            {
                return false;
            }

            return attributes.Any(attribute => attribute.Match(attributeToMatch));
        }
    }
}

AlternateInterceptorRegistrationStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Ninject;
using Ninject.Components;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Advice;
using Ninject.Extensions.Interception.Planning.Directives;
using Ninject.Extensions.Interception.Registry;
using Ninject.Planning;
using Ninject.Planning.Strategies;

namespace Common.Interception.Interceptors
{
    /// <summary>
    /// This is a derivation of InterceptorRegistrationStrategy from Ninject.Extensions.Interception.Planning.Strategies, merged with 
    /// http://stackoverflow.com/questions/6386461/ninject-intercept-any-method-with-certain-attribute
    /// </summary>
    public class AlternateInterceptorRegistrationStrategy<TAttribute, TInterceptor> : NinjectComponent, IPlanningStrategy
        where TAttribute : Attribute
        where TInterceptor : IInterceptor
    {
        protected const BindingFlags DefaultBindingFlags =
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Instance;

        public AlternateInterceptorRegistrationStrategy(IAdviceFactory adviceFactory, IAdviceRegistry adviceRegistry, IKernel kernel)
        {
            AdviceFactory = adviceFactory;
            AdviceRegistry = adviceRegistry;
            Kernel = kernel;
        }

        public IKernel Kernel { get; set; }
        public IAdviceFactory AdviceFactory { get; set; }
        public IAdviceRegistry AdviceRegistry { get; set; }

        public virtual void Execute(IPlan plan)
        {
            IEnumerable<MethodInfo> candidates = GetCandidateMethods(plan.Type);

            RegisterClassInterceptors(plan.Type, plan, candidates);

            foreach (MethodInfo method in candidates)
            {
                PropertyInfo property = method.GetPropertyFromMethod(plan.Type);
                ICustomAttributeProvider provider = (ICustomAttributeProvider)property ?? method;
                TAttribute[] attributes = provider.GetAllAttributes<TAttribute>();

                if (attributes.Length == 0)
                {
                    continue;
                }

                RegisterMethodInterceptor(plan.Type, method);

                // Indicate that instances of the type should be proxied.
                if (!plan.Has<ProxyDirective>())
                {
                    plan.Add(new ProxyDirective());
                }
            }
        }

        protected virtual void RegisterClassInterceptors(Type type, IPlan plan, IEnumerable<MethodInfo> candidates)
        {
            var attributes = type.GetAllAttributes<TAttribute>();

            if (attributes.Length == 0)
            {
                return;
            }

            foreach (MethodInfo method in candidates)
            {
                PropertyInfo property = method.GetPropertyFromMethod(type);
                ICustomAttributeProvider provider = (ICustomAttributeProvider) property ?? method;

                var config = Kernel.Get<IInterceptorConfig>();

                if (config.DoNotInterceptAttribute == null)
                {
                    // A "do not intercept" attribute wasn't defined in the config, so go ahead and register
                    RegisterMethodInterceptor(type, method);
                }
                else if (!provider.IsDefined(config.DoNotInterceptAttribute, true))
                {
                    // The method wasn't decorated with the "do not intercept" attribute, so go ahead and register
                    RegisterMethodInterceptor(type, method);
                }
            }

            if (!plan.Has<ProxyDirective>())
            {
                plan.Add(new ProxyDirective());
            }
        }

        protected virtual void RegisterMethodInterceptor(Type type, MethodInfo method)
        {
            IAdvice advice = AdviceFactory.Create(method);

            advice.Callback = request => request.Context.Kernel.Get<TInterceptor>();

            var config = Kernel.TryGet<IInterceptorConfig>();
            if (config != null)
            {
                advice.Order = config.GetOrder<TInterceptor>();
            }

            AdviceRegistry.Register(advice);
        }

        protected virtual IEnumerable<MethodInfo> GetCandidateMethods(Type type)
        {
            MethodInfo[] methods = type.GetMethods(DefaultBindingFlags);

            return methods.Where(ShouldIntercept);
        }

        protected virtual bool ShouldIntercept(MethodInfo methodInfo)
        {
            return methodInfo.DeclaringType != typeof(object) &&
                   !methodInfo.IsPrivate;// &&
            //!methodInfo.IsFinal;
        }
    }
}

IInterceptorConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public interface IInterceptorConfig
    {
        IInterceptorConfig SpecifyOrder<TInterceptor>(int order) where TInterceptor : IInterceptor;

        IInterceptorConfig SpecifyDoNotInterceptAttribute<TAttribute>() where TAttribute : Attribute;

        int GetOrder<TInterceptor>() where TInterceptor : IInterceptor;

        Type DoNotInterceptAttribute { get; }
    }
}

InterceptorConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public class InterceptorConfig : IInterceptorConfig
    {
        private readonly Dictionary<Type, int> _orderDictionary = new Dictionary<Type, int>();

        public IInterceptorConfig SpecifyOrder<TInterceptor>(int order) where TInterceptor : IInterceptor
        {
            _orderDictionary.Add(typeof(TInterceptor), order);
            return this;
        }

        public IInterceptorConfig SpecifyDoNotInterceptAttribute<TAttribute>() where TAttribute : Attribute
        {
            DoNotInterceptAttribute = typeof(TAttribute);
            return this;
        }

        public int GetOrder<TInterceptor>() where TInterceptor : IInterceptor
        {
            return _orderDictionary[typeof(TInterceptor)];
        }

        public Type DoNotInterceptAttribute { get; private set; }
    }
}

TraceInterceptor.cs - just a sample interceptor

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject.Extensions.Interception;

namespace Common.Interception.Interceptors
{
    public class TraceInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("Enter Method");

            invocation.Proceed();

            Console.WriteLine("Exit Method");
        }
    }
}

Notes: Here is a simple console app that shows how to wire up the attributes/interceptors. This has dependencies on both Ninject.Extensions.Interception.DynamicProxy and Ninject.Extensions.Conventions (and all their required dependencies)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Common.Interception.Attributes;
using Common.Interception.Interceptors;
using Ninject;
using Ninject.Extensions.Conventions;
using Ninject.Planning.Strategies;
using SomeProject.Infrastructure;

namespace SomeProject.ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            kernel.Components.Add<IPlanningStrategy, AlternateInterceptorRegistrationStrategy<TraceAttribute, TraceInterceptor>>();
            kernel.Components.Add<IPlanningStrategy, AlternateInterceptorRegistrationStrategy<AuthorizeAttribute, AuthorizeInterceptor>>();

            // I needed a way to specify execution order and "DoNotIntercept" without deriving from attributes that would force ninject references all over my domain
            // not 100% confident this is the best way - but it works
            kernel.Bind<IInterceptorConfig>().ToConstant(new InterceptorConfig()
                                                             .SpecifyOrder<TraceInterceptor>(1)
                                                             .SpecifyOrder<AuthorizeInterceptor>(0)
                                                             .SpecifyDoNotInterceptAttribute<DoNotInterceptAttribute>());

            // SomeProject.Infrastructure contains my service classes decorated with my custom attributes
            kernel.Bind(x => x.FromAssembliesMatching("SomeProject.Infrastructure")
                              .SelectAllClasses()
                              .BindToSelf());

            var a = kernel.Get<SomeServiceA>();
            var b = kernel.Get<SomeServiceB>();

            Console.WriteLine("Calling a.DoSomeStuff()...");
            a.DoSomeStuff();

            Console.WriteLine("Calling b.DoMyThing()...");
            b.DoMyThing();

            Console.WriteLine("Calling b.NowTraceThis()...");
            b.NowTraceThis();

            Console.ReadLine();
        }
    }
}

原文:https://stackoverflow.com/questions/15098757
更新时间:2021-12-23 14:12

最满意答案

我不建议在这个环境中运行内置的rails服务器,因为它只适用于你的本地开发环境。

由于您使用的是Windows Azure,因此我建议您从Azure人员那里查看本教程。 它展示了如何设置nginx web服务器以及独角兽来托管Rails应用程序。

http://www.windowsazure.com/en-us/develop/ruby/tutorials/web-app-with-capistrano/


I would not recommend running the built-in rails server in this environment, as it is only meant for your local development environment.

Since you're on Windows Azure I would recommend you take a look at this tutorial from the Azure folks. It shows how to setup a nginx web server along with unicorn to host a Rails application.

http://www.windowsazure.com/en-us/develop/ruby/tutorials/web-app-with-capistrano/

相关问答

更多

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)