Chris Marisic
Chris Marisic

Reputation: 33118

How to write a StructureMap Scanner for this case

I have these registrations in a registry and am trying to figure out the correct way to implement them with a scanner instead of manual registration.

For<ISomeView>.Use(HttpContext.Current.CurrentHandler)
For<IOtherView>.Use(HttpContext.Current.CurrentHandler)
For<IAnotherView>.Use(HttpContext.Current.CurrentHandler)

And so on. I have ever one of my interfaces inherent from IView to be used as a marker interface.

My original attempt came out looking like this

public void Process(Type type, Registry registry)
{
    Type _pluginType = typeof(IView);

    if (type.CanBeCastTo(_pluginType) && type.IsInterface)
    {
        string name = type.Name;
        registry.AddType(_pluginType, type, name);

        registry.For(_pluginType).Use(HttpContext.Current.CurrentHandler);
    }    
} 

This however caused my physical ASP.NET pages to be registered as itself instead. This is what I got from WhatDoIHave()

the_page_aspx (ASP.the_page_aspx) - 36d0cdb2-7118-4a1d-94a0-8de1b5ddc357 - 
Configured Instance of ASP.the_page_aspx, App_Web_4q8pukge, Version...

Edit: To respond to KevM's comment what I want to acheive is anytime StructureMap needs to inject any single of my IView's that it resolves it by by returning HttpContext.Current.CurrentHandler

So if I'd call ObjectFactory.Resolve<ISomeView>() I would get (ISomeView)HttpContext.Current.CurrentHandler

If I have a constructor that was SomePresenter(IListView listView, IEditView editView) that those would be resolved to (IListView)HttpContext.Current.CurrentHandler and (IEditView)HttpContext.Current.CurrentHandler.

I could do this with numerous For<>.Use() statements as in my example which means I should be able to achieve it with a scanner instead of needing to explicitly register each one manually. My interfaces will always be named I_____View if the naming convention would help for writing the scanner. I'm just not sure what I need to use in the if statement I have above for the Process() method.

Update: With the answer from @KevM it pointed me in the right direction to this

public class ViewScanner : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (type.IsA<IView>() && !type.IsConcrete())
        {
            registry.For(type).Use(c => HttpContext.Current.CurrentHandler);
        }
    }
}

(IsA<> is just an extension for IsAssignableFrom since to me the usage of it feels backwards)

Upvotes: 2

Views: 451

Answers (1)

KevM
KevM

Reputation: 2506

I hope this is close to what you are looking for.

public interface IView { }
public class View : IView { }
public class View2 : IView { }

public static class IckyStaticMonster
{
    public static IView Current { get; set;}
}

[TestFixture]
public class configuring_concrete_types
{
    [Test]
    public void TEST()
    {
        var container = new Container(cfg =>
        {
            cfg.Scan(scan =>
            {
                scan.TheCallingAssembly();
                scan.Convention<ViewScanner>();
            });
        });

        var current = new View2();
        IckyStaticMonster.Current = current;

        var view2 = container.GetInstance<View2>();

        view2.ShouldBeTheSameAs(current);
    }
}

public class ViewScanner : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        Type _pluginType = typeof (IView);

        if (_pluginType.IsAssignableFrom(type) && _pluginType.IsInterface)
        {
            registry.For(type).Use(c=>IckyStaticMonster.Current);
        }
    }
}

Upvotes: 1

Related Questions