Хост службы MEF + WCF?

Я только начинаю работать с MEF и столкнулся с проблемой, которую не могу решить. У меня есть служба Windows, которая читает мои библиотеки DLL (через MEF), и каждая библиотека DLL является узлом службы WCF. Когда я запускаю свою службу Windows и читаю библиотеки DLL, все работает нормально, за исключением того, что всякий раз, когда одна из библиотек WCF получает какую-либо «активность», они повторно создают экземпляры, а затем обрабатывают поступающие данные. Мне нужно, чтобы они просто создавали экземпляр один раз в начале. Это возможно?


person Travyguy9    schedule 15.12.2009    source источник


Ответы (2)


Службы WCF по умолчанию используют режим экземпляра на вызов. Это означает, что новый экземпляр службы WCF создается для каждого входящего вызова метода. Похоже, что вам нужен режим экземпляра singleton, но вы действительно хотите избежать этого, если масштабируемость является проблемой.

Способ, которым я обошел это, заключается в использовании режима экземпляра per call, но за кулисами у меня есть хранилище статических данных, к которому я синхронизирую доступ. По крайней мере, это позволяет клиентам подключаться, даже если им приходится на мгновение блокироваться, пока хранилище данных используется после установления соединения.

См. справку MSDN в System.ServiceModel.InstanceContextMode для более подробной информации.

person Matt Davis    schedule 15.12.2009

Вы можете справиться с этим, внедрив IServiceBehavior и IInstanceProvider, зарегистрировав мою реализацию IServiceBehavior в OnStart и IInstanceProvider управляя временем жизни объекта для вас. В частности, вы можете использовать инверсию контейнера управления, который обслуживает один и тот же экземпляр вашего типа службы при каждом запросе (т. е. одноэлементное поведение, но не одноэлементное).

public partial class MyServiceHost : ServiceBase {
    // details elided

    protected override void OnStart(string[] args) {
            this.Host = new ServiceHost(typeof(MySerivce));
            this.Host.Description.Behaviors.Add(new MyServiceBehavior());
            this.Host.Open();
    }
}

public class MyServiceBehavior : IServiceBehavior {
    public void AddBindingParameters(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase,
        Collection<ServiceEndpoint> endpoints,
        BindingParameterCollection bindingParameters
    ) { }

    public void ApplyDispatchBehavior(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase) {
            IIoCContainer container = new IocContainer();
            foreach (var cdBase in serviceHostBase.ChannelDispatchers) {
                ChannelDispatcher cd = cdBase as ChannelDispatcher;
                if (cd != null) {
                    foreach (EndpointDispatcher ed in cd.Endpoints) {
                        ed.DispatchRuntime.InstanceProvider = new MyInstanceProvider(
                            container,
                            serviceDescription.ServiceType
                        );
                    }
                }
            }
        }

    public void Validate(
        ServiceDescription serviceDescription, 
        ServiceHostBase serviceHostBase
    ) { }
}

public class MyInstanceProvider : IInstanceProvider {
    readonly IIocContainer _container;
    readonly Type _serviceType;

    public InstanceProvider(IIoCContainer container, Type serviceType) {
        _container = container;
        _serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext, Message message) {
        return _container.Resolve(_serviceType);
    }

    public object GetInstance(InstanceContext instanceContext) {
        return GetInstance(instanceContext, null);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance) { }       
}
person jason    schedule 15.12.2009
comment
Я думаю, не могли бы вы дать мне небольшой образец или, может быть, рассказать более подробно. Я ни в коем случае не являюсь экспортером в MEF или WCF. - person Travyguy9; 15.12.2009
comment
Я добавил базовую реализацию того, о чем я говорю. Ключом является инверсия контейнера управления, который управляет временем жизни объекта. - person jason; 15.12.2009
comment
В какой сборке находится IIocContainer? - person Travyguy9; 15.12.2009
comment
Это вам решать. IIoCContainer создан, но вы можете использовать любую инверсию контейнера управления (например, Castle Windsor, StructureMap или Unity). - person jason; 15.12.2009
comment
Я немного осмотрелся и заметил, что моя служба WCF, которая считывается моей службой Windows, имеет идентификатор AppDomain 1, а затем служба WCF, которая получает уведомление о поступающих данных, имеет идентификатор AppDomain 2. Решение, которое вы дал мне (думаю, на WindowService) гарантию, что я всегда буду использовать тот, у которого AppDomain равен 1? - person Travyguy9; 15.12.2009