2012-04-07 6 views
1

У меня есть библиотека сервиса WCF, содержащая пользовательскую службу ServiceHostFactory, полученную из DefaultServiceHostFactory. Я не могу заставить тестового клиента использовать эту фабрику. Я просто получил ошибку «no parameterless constructor found».Могу ли я использовать WcfFacility с тестовым клиентом WCF?

Вот моя хостинг конфигурация окружающей среды:

<serviceHostingEnvironment> 
    <serviceActivations> 
    <add service="TestService.WcfLibrary.TestService" 
     relativeAddress="/TestService.svc" 
     factory="TestService.WcfLibrary.TestServiceHostFactory, TestService.WcfLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
    </serviceActivations> 
</serviceHostingEnvironment> 

Обратите внимание, что у меня нет SVC-файл на самом деле. Я пытаюсь использовать файловую активацию.

Вот мой заказ ServiceHostFactory:

public class TestServiceHostFactory : DefaultServiceHostFactory 
{ 
    public TestServiceHostFactory() : base(CreateKernel()) { } 

    private static IKernel CreateKernel() 
    { 
     WindsorContainer container = new WindsorContainer(); 

     container.AddFacility<WcfFacility>(); 

     container.Register(Component.For<TestService>()); 
     container.Register(Component.For<IServiceManager>().ImplementedBy<ServiceManager>()); 

     return container.Kernel; 
    } 
} 

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

+0

Как (или где) находится эта служба? –

+0

@PetarVucetin Это только служба WCF Service Library, я должен запустить ее на тестовом клиенте WCF при отладке. Я знаю, что могу установить фабрику в файл svc, если я размещаю ее на ISS или как службу Windows, но она все равно должна работать как библиотека. –

+1

Хорошо. Я просто не знаю, что делает WCF TC, когда он размещает эту услугу. –

ответ

3

ОК, это возможно, но это AINT довольно ...

Прежде всего нам нужен способ, чтобы зацепить в том, когда сборка загружается, так как в этом случае их не «основной» или «запуск приложения " или что-нибудь. Есть интересное событие на AppDomain, которое называется AssemblyLoaded, похоже, что он может сделать трюк, хм, но как подключиться к нему, так как я решил сделать это, чтобы определить пользовательский менеджер домена приложения, поэтому ...

Создать новую сборку и внутри него определить интерфейс, который может быть реализован с помощью какого-то клиента и AppDomainManager вроде так:

public interface IAssemblyLoaded 
{ 
    void AssemblyLoaded(); 
} 

public class CustomManager : AppDomainManager 
{ 
    public override void InitializeNewDomain(AppDomainSetup appDomainInfo) 
    { 
     base.InitializeNewDomain(appDomainInfo); 

     // Look for any classes that implement IAssemblyLoaded, 
     // constuct them (will only work if they have a default constructor) 
     // and call the AssemblyLoaded method 
     var loaded = typeof (IAssemblyLoaded); 
     AppDomain 
      .CurrentDomain 
      .AssemblyLoad += (s, a) => 
           { 
            var handlers = a 
             .LoadedAssembly 
             .GetTypes() 
             .Where(loaded.IsAssignableFrom); 

            foreach (var h in handlers) 
            { 
             ((IAssemblyLoaded) 
              Activator.CreateInstance(h)) 
              .AssemblyLoaded(); 
            } 
           }; 
    } 
} 

убедитесь, что сборка будет подписана, а затем добавить его в GAC. Скажем, я назвал сборочный AssemblyInitCustomDomainManager я могу добавить это как так (и я вернусь детали об этом сразу, потому что я буду нуждаться в них):

gacutil /i AssemblyInitCustomDomainManager.dll 
gacutil /l AssemblyInitCustomDomainManager 

Теперь отредактируйте WcfServiceHost.exe.config (как правило, расположенные по адресу: C: \ Program Files \ Microsoft Visual Studio 10.0 \ Common7 \ IDE или версии x86 на 64-разрядных системах) и добавьте следующие строки внутри выполнения элемента (см here информации об этом настройке):

<appDomainManagerType value="AssemblyInitCustomDomainManager.CustomManager" /> 
<appDomainManagerAssembly value="AssemblyInitCustomDomainManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c841b3549556e52a, processorArchitecture=MSIL" /> 

ПРИМЕЧАНИЕ. Вам нужно будет изменить хотя бы один из (и, возможно, всех в зависимости от того, что вы назвали выше): имя типа, пространство имен, имя сборки, открытый ключ, номер версии. Я думаю, вы должны быть в состоянии выяснить, что им нужно в вашем случае.

ОК, это было достаточно просто, теперь мы создадим новый проект «Библиотека WCF» в visual studio и создадим для нас приложение app.config и службу (это тип проекта, который вы хотите испытайте право, о, я надеюсь, что так!).

Прежде всего, удалите system.serviceModel часть из app.config, так как мы не хотим, чтобы приложение службы хоста, чтобы прочитать это в, а затем удалить Service1.cs и IService1.cs (как я иду сделать мой собственный немного позже). Убедитесь, что вы ссылаетесь на сборку менеджера домена приложения, которую вы создали ранее, так как вам нужно реализовать этот интерфейс.

Теперь создайте новый файл и вставить следующий код (мы просто с простой службой с зависимостью, организованной Касл WCF Facility):

using System; 
using System.ServiceModel; 

using AssemblyInitCustomDomainManager; 

using Castle.Facilities.WcfIntegration; 
using Castle.MicroKernel.Registration; 
using Castle.MicroKernel.SubSystems.Configuration; 
using Castle.Windsor; 
using Castle.Windsor.Installer; 

namespace TestWcfServiceLibrary 
{ 
    public class AssemblyInitializedHandler : IAssemblyLoaded 
    { 
     // This method is called when the assembly loads so we will create the 
     // windsor container and run all the installers we find 
     public void AssemblyLoaded() 
     {    
      new WindsorContainer().Install(FromAssembly.This());    
     }   
    } 

    // This installer will set up the services 
    public class ServicesInstaller : IWindsorInstaller 
    { 
     public void Install(IWindsorContainer container, 
          IConfigurationStore store) 
     { 
      container 
       .AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero) 
       .Register(Component 
           .For<ITestDependency>() 
           .ImplementedBy<TestDependency>(), 
          Component 
           .For<IService1>() 
           .ImplementedBy<Service1>() 
           .AsWcfService(new DefaultServiceModel(WcfEndpoint 
                     .BoundTo(new WSHttpBinding())) 
               .AddBaseAddresses("http://localhost:9777/TestWcfServiceLibrary/Service1") 
               .PublishMetadata(m => m.EnableHttpGet()))); 
     } 
    } 

    // This is the contract of something we want to make sure is loaded 
    // by Windsor 
    public interface ITestDependency 
    { 
     int DoSomething(int value); 
    } 

    public class TestDependency : ITestDependency 
    { 
     public int DoSomething(int value) 
     { 
      return value; 
     } 
    } 

    // Regular WCF service contract 
    [ServiceContract] 
    public interface IService1 
    { 
     [OperationContract] 
     string GetData(int value); 
    } 

    // Service implementation - notice it does not have a default 
    // constructor 
    public class Service1 : IService1 
    { 
     private readonly ITestDependency _td; 

     public Service1(ITestDependency td) 
     { 
      _td = td; 
     } 

     public string GetData(int value) 
     { 
      int v = _td.DoSomething(value); 
      return string.Format(
       "According to our dependency you entered: {0}", v); 
     } 
    } 
} 

Нажмите кнопку Выполнить, и вы получите сообщение об ошибке сообщение, которое гласит:

WCF Service Host не может найти какие-либо метаданные службы. Это может привести к неправильному запуску клиентского приложения . Проверьте, включены ли метаданные . Вы хотите выйти?

Не волнуйтесь, просто нажмите нет.

Клиент-клиент запускается, но, к сожалению, у него нет вашего обслуживания. Не беспокойтесь, просто щелкните правой кнопкой мыши добавить сервис ... и введите URL-адрес сервиса (он находится в установочном файле в коде - http://localhost:9777/TestWcfServiceLibrary/Service1).

И там вы идете - служба WCF размещена внутри тестового клиента WCF. Не верьте мне - протестируйте его, вызовите операцию GetData, и вы увидите результат.

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

+0

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

+2

+1 для кода ниндзя skilz :) –

1

Помню, я читал это где-то! link

«Самый большой недостаток WcfSvcHost заключается в том, что он подходит только для простых сценариев, когда вы не нуждаетесь в программном доступе к экземпляру хоста, прежде чем открывать его или программный доступ к своей модели событий после открытия. В отличие от хостинга с IIS или Windows Activation Service (WAS), не существует эквивалентной поддержки фабрики хостов, поэтому нет возможности динамически добавлять базовые адреса, настраивать конечные точки, дроссельные вызовы, настраивать пользовательские поведения на уровне хоста и т. Д. Мой опыт работы с WCF заключается в том, что во всех, кроме простейших случаях, в конечном итоге вам понадобится программный доступ к экземпляру хоста, поэтому я не рассматриваю WcfSvcHost как полноценный хостинг, достойный производства, так как я использую WAS или выделенный сам хост ».