NancyFx ConfigureRequestContainer

Я пытаюсь выяснить, как работает контейнер запросов NancyFx, поэтому я создал небольшой тестовый проект.

Я создал этот интерфейс

public interface INancyContextWrapper
{
    NancyContext Context { get; }
}

С этой реализацией

public class NancyContextWrapper : INancyContextWrapper
{
    public NancyContext Context { get; private set; }

    public NancyContextWrapper(NancyContext context)
    {
        Context = context;
    }
}

Затем в загрузчике я регистрирую это так

protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
    base.ConfigureRequestContainer(container, context);
    container.Register<INancyContextWrapper>(new NancyContextWrapper(context));
}

Я использую эту контекстную оболочку в классе, который ничего не делает, кроме как возвращает URL-адрес запроса в виде строки.

public interface IUrlString
{
    string Resolve();
}

public class UrlString : IUrlString
{
    private readonly INancyContextWrapper _context;

    public UrlString(INancyContextWrapper context)
    {
        _context = context;
    }

    public string Resolve()
    {
        return _context.Context.Request.Url.ToString();
    }
}

И, наконец, использовать это в модуле

public class RootModule : NancyModule
{
    public RootModule(IUrlString urlString)
    {
        Get["/"] = _ => urlString.Resolve();
    }
}

Когда я делаю это, запрос всегда нулевой. Теперь я могу более или менее понять, что с IUrlString не настроен в конфигурации контейнера запросов, TinyIoc разрешен INancyContextWrapper при запуске приложения до того, как был сделан какой-либо запрос, и TinyIoc не перерегистрирует зависимости, которые в графе зависимостей зависят от того, что сконфигурировано в конфигурации контейнера запроса.

Мой вопрос заключается в том, что лучше всего использовать ConfigureRequestContainer? Нужно ли регистрировать все, что каким-либо образом зависит от NancyContext явно в конфигурации контейнера запроса? Это может очень быстро стать раздутым и трудно поддерживать. Мне нравится, как TinyIoc выполняет сканирование ассемблера, поэтому необходимость сделать это немного неудача.

1 ответ

Решение

Предполагая, что приведенный выше пример является просто упрощением того, что вы на самом деле хотите - то есть что-то для переноса контекста Нэнси в течение времени жизни запроса для каких-то целей, вам может быть лучше вообще не использовать загрузчик, так как это зависит от использованный контейнер IoC.

Предложения:

Измените реализацию оболочки, чтобы не использовать ctor, а установщик свойств (вы всегда можете написать код, чтобы свойство можно было установить только один раз):

public interface INancyContextWrapper
{
    NancyContext Context { get; set; }
}

public class NancyContextWrapper : INancyContextWrapper
{
    private NancyContext _context;
    public NancyContext Context 
    { 
           get {return _context;} 
           set {_context = value;} //do something here if you want to prevent repeated sets
    }
}

Вместо непосредственного использования контейнера и загрузчика используйте реализацию IRegistration (они используются Нэнси и не зависят от контейнера)

public class NancyContextWrapperRegistrations : IRegistrations
{
    public IEnumerable<TypeRegistration> TypeRegistrations 
    {
        get 
        { 
            return new[]
            {
                new TypeRegistration(typeof(INancyContextWrapper), typeof(NancyContextWrapper), Lifetime.PerRequest),
                new TypeRegistration(typeof(IUrlString .... per request
            };
               // or you can use AssemblyTypeScanner, etc here to find
        }    

        //make the other 2 interface properties to return null
    }
}

Используйте задачу IRequestStartup (они также автоматически обнаруживаются Нэнси) для настройки контекста

public class PrepareNancyContextWrapper : IRequestStartup
{
    private readonly INancyContextWrapper _nancyContext;
    public PrepareNancyContextWrapper(INancyContextWrapper nancyContext)
    {
        _nancyContext = nancyContext;
    }

    public void Initialize(IPipelines piepeLinse, NancyContext context)
    {
         _nancyContext.Context = context;
    }
}

Хотя вышеприведенное выглядит излишним, это очень хороший способ организовать регистрацию типов независимым от IoC способом (т.е. если вы заменяете TinyIoC чем-то другим, вам не нужно трогать загрузчики и т. Д.)

Кроме того, это очень хороший способ контролировать, что происходит во время запуска запроса (или, если хотите, приложения), без переопределения чего-либо в загрузчике, и он будет работать с любым загрузчиком / контейнером, который вы решите использовать.

Другие вопросы по тегам