pers
pers

Reputation: 195

How to avoid implicit collection resolving in Autofac?

I'm implementing MVP pattern in ASP.NET and I have defined a view like below:

public interface IMyView
    {
         IList<User> Users { get; set; }
    }

    public partial class MyPage : Page, IMyView
    {
        public IList<User> Users
        {
            set
            {
                this.grid.DataSource = value;
                this.grid.DataBound();
            }
        }

My sample page inherits from the view but whenever I visit the page Autofac assigns a default empty value to Users property and DataBound throws an exception because my page is not built completely yet. How can I configure Autofac to not to resolve it automatically? The only thing I can do now is to change IList to List.

Upvotes: 1

Views: 416

Answers (2)

Cyril Durand
Cyril Durand

Reputation: 16192

The easiest solution would be to modify your registration and not to use property injection for this type, this is the solution I recommend.

By the way, if you can't change the registration mode, I can see 3 solutions.

  1. Change the way the property works by using a state.

    public MyPage: Page, IMyView
    {
    
      private Boolean _isInitialized; 
    
    
      public void Page_Init(Object sender, EventArgs e)
      {
        this._isInitialized = true; 
      }
    
    
      public IList<User> Users
      {
        get { ... }
        set
        {
          if (this._isInitialized) 
          {
            this.grid.DataSource = value;
            this.grid.DataBound();
          }
        }
      }
    }
    

    Dirty but simple to implement.

  2. Implement your own PropertiesAutoWiring. You can do so by using the OnActivating event.

    ContainerBuilder builder = new ContainerBuilder();
    
    builder.RegisterType<MyPage>().OnActivating(e =>
    {
        foreach (PropertyInfo pi in e.Instance.GetType()
                                                .GetProperties()
                                                .Where(pi => pi.CanWrite))
        {
            if (!pi.PropertyType.IsClosedTypeOf(typeof(IList<>)))
            {
                Object propertyValue = e.Context.ResolveOptional(pi.PropertyType);
                if (propertyValue != null)
                {
                    pi.SetValue(e.Instance, propertyValue);
                }
            }
        }
    });
    

    Don't use this code, it is just to get you the iead. Look at AutowiringPropertyInjector.cs for a good implementation of this code.

  3. Remove the collection support in Autofac. Collection support is managed by the CollectionRegistrationSource. Unfortunately There is no way to tell Autofac to remove only the collection support, you can only remove all default adapters.

    IContainer container = builder.Build(ContainerBuildOptions.ExcludeDefaultModules);
    

    This will remove all default modules, ie :

    private void RegisterDefaultAdapters(IComponentRegistry componentRegistry)
    {
      this.RegisterGeneric(typeof(KeyedServiceIndex<, >)).As(new Type[]
      {
        typeof(IIndex<, >)
      }).InstancePerLifetimeScope();
      componentRegistry.AddRegistrationSource(new CollectionRegistrationSource());
      componentRegistry.AddRegistrationSource(new OwnedInstanceRegistrationSource());
      componentRegistry.AddRegistrationSource(new MetaRegistrationSource());
      componentRegistry.AddRegistrationSource(new LazyRegistrationSource());
      componentRegistry.AddRegistrationSource(new LazyWithMetadataRegistrationSource());
      componentRegistry.AddRegistrationSource(new StronglyTypedMetaRegistrationSource());
      componentRegistry.AddRegistrationSource(new GeneratedFactoryRegistrationSource());
    }
    

Unfortunately, when PropertiesAutoWired() is used, there is no way to tell Autofac not to inject a specific property.

Upvotes: 1

pers
pers

Reputation: 195

I found the problem. Thanks to your answer it helped me to find the cause. After upgrading to version Autofac version 3 I have following module in web config:

<add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web" preCondition="managedHandler" />

So I need to remove it and replace it with following:

 <add
        name="AttributedInjection"
        type="Autofac.Integration.Web.Forms.AttributedInjectionModule, Autofac.Integration.Web"
        preCondition="managedHandler" />

Upvotes: 0

Related Questions