Using NInject to bind a generic interface, with a default if a binding for the generic type is not set - ninject

Imagine I have the following classes and interfaces:
public interface IService<T> { }
public class DefaultService<T> : IService<T> { }
public class FooService : IService<Foo> { }
public class BarService : IService<Bar> { }
I would then like to be able to get instances from the Kernel like this:
Kernel.Get<IService<Foo>>(); // Should return FooService
Kernel.Get<IService<Bar>>(); // Should return BarService
Kernel.Get<IService<Dog>>(); // Should return DefaultService
Kernel.Get<IService<Cat>>(); // Should return DefaultService
Kernel.Get<IService<Giraffe>>(); // Should return DefaultService
Is it possible to setup bindings using NInject (possibly using the Conventions extension), so that I don't have to manually bind every single possible implementation of IService?

I've been working on something similar recently and came up with somewhat simpler solution of your problem (although a bit weaker).
What should suffice is to bind a generic implementation (DefaultService) to the generic interface, and concrete implementations (FooService, BarService) to the concrete interfaces. When you ask for a concrete instance of the interface, Ninject resolves whether you defined the concrete binding. If you did, it gives you the appropriate instance, otherwise it falls through to the generic binding. The following code should do the trick.
var kernel = new StandardKernel();
kernel.Bind(typeof(IService<>)).To(typeof(DefaultService<>));
kernel.Bind<IService<Foo>>().To<FooService>();
kernel.Bind<IService<Bar>>().To<BarService>();
EDIT:
The concept works throughout the whole Ninject, so you can use it along with Extensions.Conventions as well.
e.g. define the following:
public class Foo{}
public class Bar{}
public class Dog{}
public interface IService<T>{}
public class DefaultService<T> : IService<T>{}
public class FooService : IService<Foo>{}
public class BarService : IService<Bar>{}
use conventions to bind the services:
kernel.Bind(x => x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(typeof(IService<>))
.BindSingleInterface());
and create and check the appropriate services:
Assert.IsInstanceOf<BarService>(kernel.Get<IService<Bar>>());
Assert.IsInstanceOf<FooService>(kernel.Get<IService<Foo>>());
Assert.IsInstanceOf<DefaultService<Dog>>(kernel.Get<IService<Dog>>());

I took the liberty of refactoring the answer from #cbp, so that it works for the new IBindingGenerator signature in Ninject v3 conventions. It's pretty much replacing the Process() method signature with the CreateBindings() method signature, but I didn't test this, so there's a chance you'll have to tweak it a bit if you use it.
/// <summary>
/// Creates bindings on open generic types.
/// This is similar to the out-of-the-box
/// <see cref="GenericBindingGenerator" />,
/// but allows a default class to be
/// specified if no other bindings can be found.
/// See the test case for usages.
/// </summary>
public class GenericBindingGeneratorWithDefault : IBindingGenerator
{
private static readonly Type TypeOfObject = typeof(object);
private readonly Type _contractType;
private readonly Dictionary<Type, Type> _cachedBindings;
private readonly Type _defaultType;
public GenericBindingGeneratorWithDefault(Type contractType, Type defaultType)
{
if (!(contractType.IsGenericType || contractType.ContainsGenericParameters))
throw new ArgumentException("The contract must be an open generic type.",
"contractType");
_cachedBindings = new Dictionary<Type, Type>();
_contractType = contractType;
_defaultType = defaultType;
}
/// <summary>
/// Creates the bindings for a type.
/// </summary>
/// <param name="type">The type for which the bindings are created.</param>
/// <param name="bindingRoot">The binding root that is used to create the bindings.</param>
/// <returns>
/// The syntaxes for the created bindings to configure more options.
/// </returns>
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type == null) throw new ArgumentNullException("type");
if (bindingRoot == null) throw new ArgumentNullException("bindingRoot");
if (type.IsInterface || type.IsAbstract) yield break;
if (type == _defaultType)
{
yield return bindingRoot.Bind(_contractType).ToMethod(
ctx =>
{
Type requestedType = ctx.Request.Service;
Type resolution = _cachedBindings.ContainsKey(requestedType)
? _cachedBindings[requestedType]
: _defaultType.MakeGenericType(ctx.GenericArguments);
return ctx.Kernel.Get(resolution);
});
}
else
{
Type interfaceType = ResolveClosingInterface(type);
if (interfaceType != null)
{
yield return bindingRoot.Bind(type).To(_cachedBindings[interfaceType]);
}
}
}
/// <summary>
/// Resolves the closing interface.
/// </summary>
/// <param name="targetType">Type of the target.</param>
/// <returns></returns>
private Type ResolveClosingInterface(Type targetType)
{
if (targetType.IsInterface || targetType.IsAbstract) return null;
do
{
Type[] interfaces = targetType.GetInterfaces();
foreach (Type #interface in interfaces)
{
if (!#interface.IsGenericType) continue;
if (#interface.GetGenericTypeDefinition() == _contractType)
{
return #interface;
}
}
targetType = targetType.BaseType;
} while (targetType != TypeOfObject);
return null;
}
}

I figured out how to do this after a couple of hours messing around with NInject Convention's GenericBindingGenerator.
If anyone is interested I can post it.
Update:
/// <summary>
/// Creates bindings on open generic types.
/// This is similar to the out-of-the-box <see cref="GenericBindingGenerator" />, but allows a default class to be
/// specified if no other bindings can be found. See the test case for usages.
/// </summary>
public class GenericBindingGeneratorWithDefault : IBindingGenerator
{
private static readonly Type TYPE_OF_OBJECT = typeof (object);
private readonly Type _contractType;
private Dictionary<Type, Type> _cachedBindings = new Dictionary<Type, Type>();
private readonly Type _defaultType;
public GenericBindingGeneratorWithDefault(Type contractType, Type defaultType)
{
if ( !( contractType.IsGenericType || contractType.ContainsGenericParameters ) )
{
throw new ArgumentException( "The contract must be an open generic type.", "contractType" );
}
_contractType = contractType;
_defaultType = defaultType;
}
/// <summary>
/// Processes the specified type creating kernel bindings.
/// </summary>
/// <param name="type">The type to process.</param>
/// <param name="scopeCallback">the scope callback.</param>
/// <param name="kernel">The kernel to configure.</param>
public void Process( Type type, Func<IContext, object> scopeCallback, IKernel kernel )
{
if (type == _defaultType)
{
kernel.Bind(_contractType).ToMethod(
ctx =>
{
var requestedType = ctx.Request.Service;
var resolution = _cachedBindings.ContainsKey(requestedType)
? _cachedBindings[requestedType]
: _defaultType.MakeGenericType(ctx.GenericArguments);
return ctx.Kernel.Get(resolution);
});
}
else
{
Type interfaceType = ResolveClosingInterface(type);
if (interfaceType != null)
{
_cachedBindings[interfaceType] = type;
}
}
}
/// <summary>
/// Resolves the closing interface.
/// </summary>
/// <param name="targetType">Type of the target.</param>
/// <returns></returns>
public Type ResolveClosingInterface( Type targetType )
{
if ( targetType.IsInterface || targetType.IsAbstract )
{
return null;
}
do
{
Type[] interfaces = targetType.GetInterfaces();
foreach ( Type #interface in interfaces )
{
if ( !#interface.IsGenericType )
{
continue;
}
if ( #interface.GetGenericTypeDefinition() == _contractType )
{
return #interface;
}
}
targetType = targetType.BaseType;
} while ( targetType != TYPE_OF_OBJECT );
return null;
}
}

Related

MVC Custom ClientSide Validation

I have the following custom required attribute code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class AddressRequiredAttribute : RequiredAttribute, IClientValidatable
{
/// <summary>
/// The _property name
/// </summary>
private string _propertyName;
/// <summary>
/// Initializes a new instance of the <see cref="AddressRequiredAttribute"/> class.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
public AddressRequiredAttribute(string propertyName)
: base()
{
_propertyName = propertyName;
}
/// <summary>
/// Checks that the value of the required data field is not empty.
/// </summary>
/// <param name="value">The data field value to validate.</param>
/// <returns>
/// true if validation is successful; otherwise, false.
/// </returns>
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (context.ObjectType.BaseType == typeof(AddressModel))
{
PropertyInfo property = context.ObjectType.GetProperty(_propertyName);
if (property != null && (bool)property.GetValue(context.ObjectInstance))
{
return base.IsValid(value, context);
}
}
return ValidationResult.Success;
}
/// <summary>
/// When implemented in a class, returns client validation rules for that class.
/// </summary>
/// <param name="metadata">The model metadata.</param>
/// <param name="context">The controller context.</param>
/// <returns>
/// The client validation rules for this validator.
/// </returns>
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
string errorMessage = this.ErrorMessage;
// Get the specific error message if set, otherwise the default
if (string.IsNullOrEmpty(errorMessage) && metadata != null)
{
errorMessage = FormatErrorMessage(metadata.GetDisplayName());
}
var clientValidationRule = new ModelClientValidationRule()
{
ErrorMessage = errorMessage,
ValidationType = "requiredaddress"
};
return new[] { clientValidationRule };
}
and the following jquery for the client side validation which is run on window.load:
$.validator.addMethod('requiredaddress', function (value, element, params) {
return value != '';
}, '');
$.validator.unobtrusive.adapters.add('requiredaddress', {}, function (options) {
options.rules['requiredaddress'] = true;
options.messages['requiredaddress'] = options.message;
});
However, the clientside doesn't kick in so I get the normal clientside validation working, then the form will submit but come back with the custom errors after postback. All the examples that I have looked at say that my code should be correct so I'm not sure what is wrong here.
Can anyone see anything obvious I'm doing wrong here, thanks
I did something similar to this and found that if I put the code in the document.ready on window.load it wouldn't work. In the end I went with using the following code placed after the jquery validate scripts:
(function ($) {
$.validator.addMethod('requiredaddress', function (value, element, params) {
return value != '';
}, 'Clientside Should Not Postback');
// i think you should be able to use this as your adapter
$.validator.unobtrusive.adapters.addBool('requiredaddress');
})(jQuery);

Ninject Conventions and Interception

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();
}
}
}
After scouring and scouring, I found that a similar question had been asked and answered here: Ninject Intercept any method with certain attribute?
I used this in conjunction with the source code of the InterceptorRegistrationStrategy class within Ninject.Extensions.Interception.Planning.Strategies to create a derivation which I am now using.
crickets

SignalR dependency injection via Spring.Net

I'm trying to inject dependencies via Spring.NET.
First I created a custom DependencyResolver:
public class SignalRSpringNetDependencyResolver : DefaultDependencyResolver
{
private IApplicationContext _context;
public SignalRSpringNetDependencyResolver(IApplicationContext context)
{
_context = context;
}
/// <summary>
/// Gets the application context.
/// </summary>
/// <value>The application context.</value>
public IApplicationContext ApplicationContext
{
get
{
if (_context == null || _context.Name != ApplicationContextName)
{
if (string.IsNullOrEmpty(ApplicationContextName))
{
_context = ContextRegistry.GetContext();
}
else
{
_context = ContextRegistry.GetContext(ApplicationContextName);
}
}
return _context;
}
}
/// <summary>
/// Gets or sets the name of the application context.
/// </summary>
/// <remarks>
/// Defaults to using the root (default) Application Context.
/// </remarks>
/// <value>The name of the application context.</value>
public static string ApplicationContextName { get; set; }
/// <summary>
/// Resolves singly registered services that support arbitrary object creation.
/// </summary>
/// <param name="serviceType">The type of the requested service or object.</param>
/// <returns>The requested service or object.</returns>
public override object GetService(Type serviceType)
{
System.Diagnostics.Debug.WriteLine(serviceType.FullName);
if (serviceType != null && !serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
{
var services = ApplicationContext.GetObjectsOfType(serviceType).GetEnumerator();
services.MoveNext();
try
{
return services.Value;
}
catch (InvalidOperationException)
{
return null;
}
}
else
{
return base.GetService(serviceType);
}
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <param name="serviceType">The type of the requested services.</param>
/// <returns>The requested services.</returns>
public override IEnumerable<object> GetServices(Type serviceType)
{
var services = ApplicationContext.GetObjectsOfType(serviceType).Cast<object>();
services.Concat(base.GetServices(serviceType));
return services;
}
Note that i escape interfaces and abstract classes so that I will get the default implementations of SignalR from the base DefaultDependencyResolver
and here I assigned the resolver using WebActivator:
public static void PostStart()
{
// Inject Dependencies to SignalR, should be always come before ASP.NET MVC configuration
var dependecyResolver = new SignalRSpringNetDependencyResolver(ContextRegistry.GetContext());
GlobalHost.DependencyResolver = dependecyResolver;
RouteTable.Routes.MapHubs();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
However, SignalR is always trying to resolve it's own dependencies using the Resolver i assigned and i get the following error:
'myhub' hub could not be resolved.
I only need the resolver to be aware of other dependencies(my Repository for example) and keep the default implementation of SignalR services.
I think it's hard to get Spring.Net working with SignalR
for the current version (Spring.Net 1.3.2) it's difficult to support asynchronous programming. Spring.Net session management doesn't play well with Task<T> types.
I ended up injecting my dependencies in 2 steps:
1- registering the required type on WebActivator PostStart:
GlobalHost.DependencyResolver.Register(
typeof(IUserService),
() => (UserService)ctx.GetObject("UserService"))
2- picking them up in my Hub constructor:
public MyHub()
{
_userService =
DependencyResolver.Current.GetService<IUserService>();
}

Workflow services scalability issue

I'm currently experiencing some issues with workflow services.
They work fine if I start 4, 5 in short sequence, but if I increase this value (starting from ~10) then I get the following exception:
This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server.
I think that the problem is in the way I create proxies. I use the following code to provide proxies, attempting to reuse existing ones:
public abstract class ProxyProvider<TService>
where TService : class
{
/// <summary>
/// Static reference to the current time provider.
/// </summary>
private static ProxyProvider<TService> current = DefaultProxyProvider.Instance;
private TService service;
/// <summary>
/// Gets or sets the current time provider.
/// </summary>
/// <value>
/// The current time provider.
/// </value>
public static ProxyProvider<TService> Current
{
get
{
return ProxyProvider<TService>.current;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
ProxyProvider<TService>.current = value;
}
}
/// <summary>
/// Resets to default.
/// </summary>
public static void ResetToDefault()
{
ProxyProvider<TService>.current = DefaultProxyProvider.Instance;
}
/// <summary>
/// Loads the proxy.
/// </summary>
/// <param name="forceNew">if set to <c>true</c> [force new].</param>
/// <returns>The instance of the proxy.</returns>
public virtual TService Provide(bool forceNew = false)
{
if (forceNew || !this.IsInstanceValid())
{
this.service = this.CreateInstance();
return this.service;
}
return this.service;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected abstract TService CreateInstance();
private bool IsInstanceValid()
{
var instance = this.service as ICommunicationObject;
if (instance == null)
{
return false;
}
return instance.State != CommunicationState.Faulted && instance.State != CommunicationState.Closed && instance.State != CommunicationState.Closing;
}
/// <summary>
/// Defines the default <see cref="ProxyProvider<TService>"/> which uses the System DateTime.UtcNow value.
/// </summary>
private sealed class DefaultProxyProvider : ProxyProvider<TService>
{
/// <summary>
/// Reference to the instance of the <see cref="ProxyProvider<TService>"/>.
/// </summary>
private static ProxyProvider<TService> instance;
/// <summary>
/// Gets the instance.
/// </summary>
public static ProxyProvider<TService> Instance
{
get
{
if (DefaultProxyProvider.instance == null)
{
DefaultProxyProvider.instance = new DefaultProxyProvider();
}
return DefaultProxyProvider.instance;
}
}
/// <summary>
/// Loads the specified force new.
/// </summary>
/// <returns>A non-disposed instance of the given service.</returns>
protected override TService CreateInstance()
{
var loadedService = Activator.CreateInstance<TService>();
return loadedService;
}
}
With an additional "lazy" provider:
public class CustomConstructorProxyProvider<TService> : ProxyProvider<TService>
where TService : class
{
private readonly Func<TService> constructor;
/// <summary>
/// Initializes a new instance of the <see cref="CustomConstructorProxyProvider<TService>"/> class.
/// </summary>
/// <param name="constructor">The constructor.</param>
public CustomConstructorProxyProvider(Func<TService> constructor)
{
this.constructor = constructor;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected override TService CreateInstance()
{
var service = this.constructor();
return service;
}
}
Used this way:
var proxy = ProxyProvider<IWorkflowService>.Current.Provide();
proxy.DoSomething();
Initialized like this:
ProxyProvider<IWorkflowService>.Current = new CustomConstructorProxyProvider<IWorkflowService>(() => new WorkflowServiceProxy("endpoint"));
Workflow services are hosted by IIS and I added the following throttling settings:
<serviceThrottling
maxConcurrentCalls="512"
maxConcurrentInstances="2147483647"
maxConcurrentSessions="1024"/>
which should be enough for my needs.
I hope that someone can help me configuring client and server to have achieve the desired scalability (a few hundreds started in sequence and running in parallel, using the WorkflowInstance sql store).
UPDATE:
I'm using NetTcpBinding for all services.
UPDATE 2:
All services are hosted and consumed by now locally.
Thanks
Francesco

Problem with DataContract and hierarchy on WCF

i have a problem with an object in my wcf project.
I have lets say this object:
[DataContract(Name="ClassA")]
public class Person{
//---attributes---
}
[DataContract(Name="ClassB")]
public class Men : Person{
//---attributes---
}
Where ClassB is child of ClassA on the other side.
Then i have a method that is post:
[OperationContract]
[WebInvoke(UriTemplate= "Person", ResponseFormat = WebMessageFormat.Json, Method= "POST")]
public string PostPerson(Person person) {
if(person is Men){
//code...
}
}
The thing is that i receive the person (in the other side, they sendme as a ClassB) but the person is Men returns false.. why?
You need to add the [ServiceKnownType(typeof(Men))] attribute to the PostPerson method.
As Ryan Gross mentions, you need Men to be a known type. Here's a similar question/answer here on SO. One option not mentioned in the linked article is the KnownType attribute. Here's an example of code I've used in the past. The prerequisite is that this class is the base class for all of your data contracts and all of your data contracts are in the same assembly:
/// <summary>
/// Base class for all data contracts.
/// </summary>
[DataContract(Name = "Base", Namespace = "your namespace")]
[KnownType("GetKnownTypes")]
public class BaseDC : IExtensibleDataObject
{
#region Constants and Fields
/// <summary>
/// Instance used to control access to the known types list.
/// </summary>
private static readonly object _knownTypesLock = new object();
/// <summary>
/// Classes derived from this class. Needed to ensure proper functioning of the WCF data
/// constract serializer.
/// </summary>
private static List<Type> _knownTypes;
#endregion
#region Properties
/// <summary>
/// Gets or sets an <c>ExtensionDataObject</c> that contains data that is not recognized as belonging to the
/// data contract.
/// </summary>
public ExtensionDataObject ExtensionData { get; set; }
#endregion
#region Public Methods
/// <summary>
/// Enumerates the types in the assembly containing <c>BaseDC</c> that derive from <c>BaseDC</c>.
/// </summary>
/// <returns>List of <c>BaseDC</c>-derived types.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
Justification = "Not appropriate for a property.")]
public static IEnumerable<Type> GetKnownTypes()
{
lock (_knownTypesLock)
{
if (_knownTypes == null)
{
_knownTypes = new List<Type>();
Assembly contractsAssembly = Assembly.GetAssembly(typeof(BaseDC));
Type[] assemblyTypes = contractsAssembly.GetTypes();
foreach (Type assemblyType in assemblyTypes)
{
if (assemblyType.IsClass && !assemblyType.IsGenericType)
{
if (assemblyType.IsSubclassOf(typeof(BaseDC)))
{
_knownTypes.Add(assemblyType);
}
}
}
_knownTypes.Add(typeof(BaseDC));
}
return _knownTypes;
}
}
#endregion
}