how register an interface that has no implentation with autofac?

2,171 views
Skip to first unread message

zhangb...@gmail.com

unread,
Jan 14, 2014, 4:54:31 AM1/14/14
to aut...@googlegroups.com

I want to register an interface that has no implentation,
like this:

builder.RegisterType(typeof(AInterface))
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(AInterceptor));

But it does not support in autofac,
so I use another way to finish it with "ProxyGen.CreateInterfaceProxyWithoutTarget":

assembly.GetTypes().Where(x => x.IsInterface && x.GetInterfaces().Any(t => t == (typeof(IDao))))
.ToList().ForEach(t =>
{
builder.Register(x =>
{
ProxyGenerator proxyGen = new ProxyGenerator();
return proxyGen.CreateInterfaceProxyWithoutTarget(t, new SqlMapperInterceptor());
}).As(t);
});

can autofac provide a way to finish this feature?

Travis Illig

unread,
Jan 14, 2014, 11:34:42 AM1/14/14
to aut...@googlegroups.com, zhangb...@gmail.com
It might help if you describe what you're trying to accomplish by having an interface registration that has, effectively, no backing code.

Every service (interface) has to have some sort of component (implementation) behind it or Autofac won't know how to activate (instantiate/provide an instance) of it. Plus, code that consumes your interface is going to expect that there is something backing that interface. (If you think about it, you can't go "new IMyInterface()" because interfaces don't have constructors, right?)

If all you want to do is register some sort of dynamic proxy, the solution you found is a good way to go - generate a dynamic proxy class as the implementation. Hypothetically, you could also...
  • Just create a dummy class that implements the interface but doesn't have any actual method implementations.
  • Use a mocking framework like Rhino or Moq and generate a mock object in the lambda rather than using a dynamic proxy.
  • Refactor the interceptor logic into a common class that can be used both by a simple real interface implementation and by the interceptor that it appears you want to apply to other classes/interfaces.
However, again, if you provide a more robust discussion of your use case, there may be other suggestions we can provide.

je...@sohlsmith.com

unread,
Mar 25, 2014, 6:14:37 PM3/25/14
to aut...@googlegroups.com, zhangb...@gmail.com
One valid use case for this usage might be for pulling configuration values from app.config using only the properties on an interface such as IConfigurationSource.

This is a great way to provide a configuration stub during tests but maintaining the real implementation to retrieve values from app.config using ConfigurationManager.AppSettings is a hassle due to the use of magic strings and then performing explicit type conversions from string to other value types.

An interceptor provides a clean way to provide all of the behavior necessary to retrieve values from app.config, providing the property name as the config key and then performing the appropriate type conversion. Of course, if the keys don't match the property names on the interface then you're in trouble but this is a risk regardless.

Maintaining a separate dummy class in this scenario seems like redundant overhead.

This type of usage is also being used by Autofac's Aggregate Services package.

Travis Illig

unread,
Mar 26, 2014, 12:47:40 PM3/26/14
to aut...@googlegroups.com, zhangb...@gmail.com
The aggregate service package is generating a dynamic proxy implementation, which is one of the options I mentioned (and the way the original poster solved the issue). I think the option between dynamic proxy, dummy/stub class, or whatever is sort of dependent on your use case. Sometimes it makes sense to maintain a stub implementation, sometimes it doesn't.

Back to the original poster's question, though, there's not really a way for Autofac right now to just automatically generate implementations for you outside of the original post's solution - generating a dynamic proxy as part of the registration. I'm not sure there's much call for a built-in Autofac feature to just generate empty dynamic proxies, either.

I don't know what the original poster was trying to accomplish by doing this, so it's hard to recommend a better solution (if there is one). Hence the request for clarification - what exactly is the original poster trying to accomplish so we can see if there is (or isn't) a better solution to that particular problem?

Jim Bolla

unread,
Mar 29, 2014, 9:14:22 AM3/29/14
to aut...@googlegroups.com, zhangb...@gmail.com
I think what OP is intending to do basically register a set of interceptors that "implement" the interface. I do something like this by creating a registration source that detects interfaces that it knows how to generate proxies of. Probably very similar to the AggregateService feature. I suppose it would be possible to implement a fluent syntax to set up an IRegistrationSource that delegates to a ProxyGenerator , but I'm not sure if that's all that useful. 

Jim Bolla

unread,
Mar 29, 2014, 10:51:14 AM3/29/14
to aut...@googlegroups.com, zhangb...@gmail.com
He's some code that should help OP solve his needs. Given this Autofac extension:

using System;
using System.Collections.Generic;
using System.Linq;

using Autofac.Builder;
using Autofac.Core;

namespace Autofac
{
    public static class Extensions
    {
        public static void RegisterSource(
            this ContainerBuilder builder,
            Func<Type, bool> forType,
            Func<IComponentContext, IEnumerable<Parameter>, Type, object> @delegate)
        {
            builder.RegisterSource(new DelegateRegistrationSource(forType, @delegate));
        }

        public static bool IsInterfaceImplementing<TInterface>(this Type t)
        {
            return t.IsInterface && t.GetInterfaces().Any(i => i == typeof(TInterface));
        }
    }

    public class DelegateRegistrationSource : IRegistrationSource
    {
        private readonly Func<IComponentContext, IEnumerable<Parameter>, Type, object> _delegate;
        private readonly Func<Type, bool> _forServiceType;

        public DelegateRegistrationSource(Func<Type, bool> forServiceType,
            Func<IComponentContext, IEnumerable<Parameter>, Type, object> @delegate)
        {
            _forServiceType = forServiceType;
            _delegate = @delegate;
        }

        public bool IsAdapterForIndividualComponents { get { return false; } }

        public IEnumerable<IComponentRegistration> RegistrationsFor(
            Service service,
            Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            var swt = service as IServiceWithType;
            
            if (swt == null || !_forServiceType(swt.ServiceType))
                return Enumerable.Empty<IComponentRegistration>();

            return new[]
            {
                RegistrationBuilder.ForDelegate(
                    (c, p) => _delegate(c, p, swt.ServiceType))
                    .As(service)
                    .CreateRegistration()
            };
        }
    }
}

Can be used to supply proxies like this:

            builder.RegisterType<ProxyGenerator>().SingleInstance();
            builder.RegisterType<SqlMapperInterceptor>();

            builder.RegisterSource(
                serviceType => serviceType.IsInterfaceImplementing<IDao>(),
                (context, parameters, serviceType) =>
                {
                    var proxyGenerator = context.Resolve<ProxyGenerator>();
                    var interceptor = context.Resolve<SqlMapperInterceptor>();
                    return proxyGenerator.CreateInterfaceProxyWithoutTarget(serviceType, interceptor);
                });

DISCLAIMER: I didn't test this code AT ALL.




Reply all
Reply to author
Forward
0 new messages