Ошибка Autofac RegisterDecorator

У меня возникли проблемы с методом RegisterDecorator в Autofac.

В настоящее время у меня есть безымянная реализация IUserManager, зарегистрированная так:

builder.RegisterType<UserManager>().As<IUserManager>().InstancePerLifetimeScope();

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

builder.RegisterDecorator<IUserManager>(inner => new UserManager2(inner), null);

Однако я получаю следующую ошибку:

Служба IUserManager не может быть одновременно параметрами адаптера from и to — они должны различаться.

Почему они должны отличаться? Я думал, что весь смысл использования декораторов в том, что вы можете прозрачно добавлять декораторы от нуля ко многим. Конечно, реализация и декоратор должны иметь один и тот же интерфейс И ключи для достижения этого?


person Lawrence Wagerfield    schedule 20.07.2011    source источник
comment
Привет, Лоуренс, заказ декораторов обычно оказывается настолько важным, что прозрачные схемы требуют дополнения заказом. Autofac просто полностью пропускает бит прозрачности (и это необходимо для реализации ;)) Ура!   -  person Nicholas Blumhardt    schedule 21.07.2011
comment
@Nicholas - Конечно, порядок иногда важен. Но я не вижу, как это помогает моей проблеме. Вы говорите, что метод RegisterDecorator был плохой идеей, и мне не следует его использовать?   -  person Lawrence Wagerfield    schedule 21.07.2011
comment
Нет, как указывает Бен, существует множество способов реализации декораторов, и выбранный из них является наиболее широко применимым. Прозрачные декораторы, которые вы ищете, могут быть реализованы путем перехвата события Activating и замены e.Instance декоратором, как показано в code.google.com/p/autofac/source/browse/contrib/Source/.   -  person Nicholas Blumhardt    schedule 26.07.2011


Ответы (1)


RegisterDecorator Autofac нельзя использовать так, как вам хотелось бы. Это по дизайну. Как говорит Ник в комментарии к вашему вопросу.

Заказ декораторов обычно оказывается настолько важным, что прозрачные схемы требуют дополнения заказом. Autofac просто вообще пропускает бит прозрачности (и это необходимо для реализации).

Таким образом, вам нужно зарегистрировать тип, который будет оформлен как именованный сервис, используя Named вместо вашего As, и указать либо fromKey, либо toKey (конечно, вы также можете указать оба). Правильное использование RegisterDecorator объясняется в этой записи блога.

Следующий код будет работать.

var cb = new ContainerBuilder();
cb.RegisterType<UserManager>().Named<IUserManager>("inner").InstancePerLifetimeScope();
cb.RegisterDecorator<IUserManager>((c, inner) => new UserManager2(inner), fromKey : "inner");
cb.Build();

Вы также указали в комментариях ниже, что это не сработает, если у вас нет декораторов. Я бы посоветовал вам использовать условную регистрацию в этом случае или пройти через декоратор.

Обновление: еще одно обновление, основанное на комментарии Ника к вопросу. Если вам не нравится ни одно из этих предложений, альтернативой RegisterDecorator является использование события Activating. Как пишет Ник:

Искомые прозрачные декораторы можно реализовать, подключив событие Activating и заменив e.Instance декоратором, как показано в этот исходный код

person bentayloruk    schedule 20.07.2011
comment
Но почему? А если декораторов нет? Другое имя реализации означает, что она не будет внедрена в другие службы в отсутствие декоратора. Моя система не должна полагаться на наличие хотя бы одного декоратора. Моя система разработана на многоуровневой архитектуре, при этом базовый уровень предоставляет рабочий сервис, который может быть дополнен уровнями более высокого уровня. Извините, но -1. - person Lawrence Wagerfield; 21.07.2011
comment
Разве вы не можете просто поставить условие в регистрации? Если нет декораторов, не регистрироваться как Named и не вызывать RegisterDecorator? - person bentayloruk; 21.07.2011
comment
Другой вариант - всегда регистрировать проход через декоратор (который ничего не делает, кроме вызова внутренней реализации). Это некрасиво, но это вариант. По какой причине мой ответ -1? Вы не упоминаете декораторов в своем вопросе. Я не думаю, что мой ответ соответствует критериям здесь stackoverflow.com/привилегии/голоса-вниз Комментария было бы достаточно. - person bentayloruk; 21.07.2011
comment
Извиняюсь, если голосование против показалось резким, но вы просто указали мне на стандартную (и единственную) документацию для метода, которую, я надеялся, вы предполагали, что я прочитал. Я специально сказал, что мне не нужна именованная служба реализации. Два решения, которые вы предоставили, будут работать. Тем не менее, они кажутся неприятными хаками для чего-то, что должно предоставляться из коробки. - person Lawrence Wagerfield; 21.07.2011
comment
Я ничего не предполагаю. Если этого нет в вопросе, его нет в вопросе (во всяком случае, тот факт, что вы неправильно использовали API, означает, что вы не читали его). Условная регистрация — это не неприятный хак. Это одна из основных причин, по которой вы можете использовать контейнер. Ник и другие участники Autofac должны предоставлять все, что им хочется. Возможно, вы могли бы предложить лучшее решение. - person bentayloruk; 21.07.2011
comment
Только что вспомнил: Николай на самом деле демонстрирует мой пример в своих комментариях на той странице. Он использует безымянный сервис реализации и даже утверждает, что параметр name в RegisterDecorator может стать необязательным в будущем. Эта функция явно должна была поддерживаться. - person Lawrence Wagerfield; 23.07.2011
comment
Вы имеете в виду комментарий, в котором он говорит, что API мог бы быть лучше, если бы он также был необязательным аргументом? - person bentayloruk; 23.07.2011
comment
Верный. Кто-то спрашивает (как и я) «Должна ли украшаемая служба быть зарегистрирована с использованием именованного ключа?», и Николас отвечает: «Нет, вы можете передать null fromKey. API мог бы быть лучше, если бы он также был необязательным аргументом». Тем не менее, я получаю сообщение об ошибке, когда пытаюсь это сделать. - person Lawrence Wagerfield; 23.07.2011
comment
Конечно, но сказать, что API может быть лучше, вряд ли то же самое, что сказать, что функциональность должна поддерживаться. - person bentayloruk; 23.07.2011
comment
Четко. Тем не менее, он заявляет, что «вы можете передать null fromKey»… попробуйте сделать это, и он сломается. - person Lawrence Wagerfield; 23.07.2011
comment
Нет — при передаче нулевого значения fromKey вам необходимо передать действительное значение toKey: требование, чтобы они отличались, является преднамеренной частью API и не будет затронуто. Наблюдение состоит только в том, что C# делает неудобным иметь параметры одного и того же типа. Лоуренс, я знаю, что это непреднамеренно, но твой тон в этой ветке действительно кажется спорным. Бен давно работает с Autofac и явно хочет помочь. Чтобы получить информацию, которую вы ищете в SO, вам нужно написать очень четкий вопрос и потратить время на руководство респондентами. Процесс требует усилий с обеих сторон. - person Nicholas Blumhardt; 26.07.2011
comment
+1 за комментарий Ника. Я по-прежнему разочарован отрицательным голосованием и тоном в этих комментариях. Это, конечно, не побудит меня отвечать на ваши вопросы в будущем. Несмотря на это, я обновил ответ, чтобы отразить дополнительное предложение Ника, и разъяснил использование fromKey и toKey. Я надеюсь, что это поможет другим пользователям Autofac. - person bentayloruk; 26.07.2011
comment
Нет проблем, ребята, действительные баллы. Я ценю, что вы обслуживаете «широко применимое» использование, но решение явно не обслуживать использование без декоратора все еще кажется мне странным; особенно когда ваши интерфейсы поддерживают это. Вместо этого я начну использовать OnActivating. - person Lawrence Wagerfield; 27.07.2011
comment
И спасибо за помощь тоже :) Я проголосовал, так как ответ теперь отвечает на мой вопрос, хотя и не на то решение, на которое я надеялся. - person Lawrence Wagerfield; 27.07.2011