Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional Guidance for Custom Metadata Usage #144

Open
hawkerm opened this issue Sep 25, 2021 · 2 comments
Open

Additional Guidance for Custom Metadata Usage #144

hawkerm opened this issue Sep 25, 2021 · 2 comments

Comments

@hawkerm
Copy link

hawkerm commented Sep 25, 2021

Problem Statement

It's unclear from the metadata docs on how to use an attribute that's created outside the filtering scenario and instead to lookup values on the metadata either during or before resolution.

For instance modifying the WeakTypedAttributeScenarioTestFixture to demonstrate what I was trying:

            // arrange
            var builder = new ContainerBuilder();
            builder.RegisterModule<AttributedMetadataModule>();
            builder.RegisterType<CombinationalWeakTypedScenario>().As<ICombinationalWeakTypedScenario>();

            // act
            var items = builder.Build().Resolve<IEnumerable<Lazy<ICombinationalWeakTypedScenario, CombinationalWeakAgeMetadataAttribute>>>();

            // assert
            Assert.Single(items);
            Assert.Single(items.Where(p => p.Metadata.Age == 42));

But this leads to a Autofac.Core.DependencyResolutionException : The type 'CombinationalWeakAgeMetadataAttribute' cannot be used as a metadata view. A metadata view must be a concrete class with a parameterless or dictionary constructor. error.

If I add a parameterless constructor to the type, then it appears to work in the test project (though I'm having trouble making this work in my own project with an enum instead of an int/string).

Anyway, it'd be great to see more examples for different setups in the documentation for using these types of more strongly-typed custom attributes.

Desired Solution

More guidance on using strongly-typed custom metadata within autofac. Especially around metadata lookup before resolution, if possible?

@tillig
Copy link
Member

tillig commented Sep 27, 2021

I think we could definitely improve on the examples in the docs. Looks like it's pretty light in there.

For your immediate issue, you'll notice in the CombinationalWeakTypedAttributeScenarioTestFixture that the thing being resolved is an interface, not a class/attribute:

[Fact]
public void Validate_wireup_of_generic_attributes_to_strongly_typed_metadata_on_resolve()
{
    // arrange
    var builder = new ContainerBuilder();
    builder.RegisterMetadataRegistrationSources();

    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As<ICombinationalWeakTypedScenario>()
        .WithAttributedMetadata();

    // act
    var items = builder.Build().Resolve<IEnumerable<Lazy<ICombinationalWeakTypedScenario, ICombinationalWeakTypedScenarioMetadata>>>();

    // assert
    Assert.Single(items);
    Assert.Single(items.Where(p => p.Metadata.Name == "Hello"));
    Assert.Single(items.Where(p => p.Metadata.Age == 42));
}

...and that interface looks like...

public interface ICombinationalWeakTypedScenarioMetadata
{
    int Age { get; }

    string Name { get; }
}

The interface is pretty important because it means Autofac can use the magic of MEF to get a strongly typed view over the metadata.

If you use a class rather than an interface, the metadata registration sources won't handle it and it falls back to the default Autofac view provider which is where you're getting that exception. The default provider basically calls new on the type and tries to set properties, which is why adding the parameterless constructor fixes things up.

But, I agree, we could probably clean up the metadata docs a bit to bring it together better. There's nothing in there about metadata views and I think in general the doc could probably just be tightened up a bit to tie the concepts all together. Trying to pick up various bits from each section and put them all together is a challenge.

@hawkerm
Copy link
Author

hawkerm commented Sep 29, 2021

Thanks for the info @tillig, that's helpful to know. The error messages from autofac or elsewhere in the stack are sometimes a bit obtuse on the underlying issue or solution, so seeing it laid out in your example is helpful.

I was definitely trying to avoid having to create an interface for the metadata class in my scenario if possible, so that's probably leading me to some of the troubles. The parameterless constructor helped in my test scenario, but didn't seem to work in my practical example using a similar setup for some reason. Still wasn't able to figure that out, depending on tweaks I did it seemed to either look for the dictionary based constructor or throw some other exception outside of autofac I believe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants