Использование Autofac для DI в службе WCF, размещенной в приложении ASP.NET

У меня возникают проблемы с вложением служб зависимостей в мою службу WCF с использованием Autofac 1.4.5. Я прочитал и просмотрел страницу Autofac wiki на WcfIntegration, но моя отладка показывает мне, что моя служба WCF создается методом System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance(), а не по AutofacWebServiceHostFactory. Что я делаю неправильно?

Я установил свой файл ajax.svc, чтобы он выглядел так, как в примере для WebHttpBinding:

<%@ ServiceHost Language="C#" Debug="true"
    Service="Generic.Frontend.Web.Ajax, Generic.Frontend.Web"
    Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory,
             Autofac.Integration.Wcf" %>

Мой класс сервиса WCF Ajax определяется следующим образом:

namespace Generic.Frontend.Web
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Ajax
    {
        public MapWebService MapWebService { get; set;}

        public Ajax() {
            // this constructor is being called
        }

        public Ajax(MapWebService mapWebService)
        {
            // this constructor should be called
            MapWebService = mapWebService;
        }

        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        [OperationContract(Name = "mapchange")]
        public MapChangeResult ProcessMapChange(string args)
        {
            // use the injected service here
            var result = MapWebService.ProcessMapChange(args);
            return result;
        }
    }
}

Теперь я использовал проводку в Global.asax.cs, как показано в вики, упомянутом выше:

var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModuleWebservice());
var container = builder.Build();
AutofacServiceHostFactory.Container = container;

с

class AutofacModuleWebservice : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register<Ajax>();
        builder.Register<MapWebService>().ContainerScoped();
    }
}

В моем web.config у меня есть

<services>
    <service name="Generic.Frontend.Web.Ajax">
        <endpoint address="http://mysite.com/ajax.svc/" binding="webHttpBinding"
                  contract="Generic.Frontend.Web.Ajax" />
    </service>
</services>

.

Сервис уже работает нормально, но я не могу получить биты Autofac (read: creation/injection) для работы. Любые идеи?

Edit: К сожалению, удаление конструктора по умолчанию приводит к следующему исключению:

System.InvalidOperationException:
The service type provided could not be loaded as a service because it does not
have a default (parameter-less) constructor. To fix the problem, add a default
constructor to the type, or pass an instance of the type to the host.

Приветствия, Оливер

Ответы

Ответ 1

Установлена ​​ли ваша служба с помощью InstanceContextMode.Single? Если это тогда, wcf создаст вашу службу, используя конструктор по умолчанию. Чтобы обойти это, измените свой контекстный режим экземпляра и дайте autofac управлять сроком службы вашей службы.

Ответ 2

Попробуйте удалить конструктор Ajax по умолчанию и модифицировать его. Если он запускается с mapWebService == null, что указывает на проблему с разрешением.

    public Ajax(MapWebService mapWebService = null)
    {
        // this constructor should be called
        MapWebService = mapWebService;
    }

Ответ 3

Я просто получил такое же System.InvalidOperationException и решил его, изменив ServiceBehavior InstanceContextMode реализации с InstanceContextMode.PerCall на InstanceContextMode.PerSession, возможно, ваша продолжительность жизни AutoFac не синхронизирована с вашей реализацией веб-службы?

Для тестирования создания сервиса AutoFac я рекомендую создать unit test и напрямую разрешать их, так как это выявит все проблемы и даст более значимые сообщения об исключениях. Для служб с областью охвата запроса создайте тестовую страницу aspx и снова разрешите их напрямую.

Ответ 4

У меня была такая же проблема и наткнулся на этот вопрос, ища ответ.

В моем случае использование слияния свойств обработано, а код в вопросе уже имеет свойство, которое можно использовать:

namespace Generic.Frontend.Web
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Ajax
    {
        // inject the dependency here
        public MapWebService MapWebService { get; set;}

        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        [OperationContract(Name = "mapchange")]
        public MapChangeResult ProcessMapChange(string args)
        {
            // use the injected service here
            var result = MapWebService.ProcessMapChange(args);
            return result;
        }
    }
}

и зарегистрируйтесь для использования инъекции свойств (пример кода из вики и синтаксис изменился, так как теперь используется версия 2.5.2.830):

builder.RegisterType<Ajax>().PropertiesAutowired();

Ответ 5

Следуя инструкциям, я решил:

code.google.com/p/autofac/wiki/... Я просто делаю: builder.RegisterType();

и я следил за их попытками изменить файл .svc.

Когда вы смотрите на свой .svc файл, вы не получаете никаких намеков о том, что что-то не так там?

Вы размещаете его в iis и не используете WAS, я не вижу, чтобы ваш код переопределял global.asax.cs

Добавьте глобальный файл к вашему решению и там вы реализуете:

  protected void Application_Start(object sender, EventArgs e)
        {
            // build and set container in application start
            IContainer container = AutofacContainerBuilder.BuildContainer();
            AutofacHostFactory.Container = container;


        }

AutofacContainerBuilder - это мой контейнер-конструктор.