Вызов WCF, который ссылается на службу Windows

У меня есть долгосрочный сервис, который получает данные из одного источника, манипулирует ими, сохраняет их в базе данных и т. Д.

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

К сожалению, моя конечная точка, к которой я подключаюсь, никогда не является той, которую я выставляю через свою долгосрочную службу. Ниже приведен простой пример:

    [ServiceContract]
    public interface ITestWcfService
    {
        [OperationContract]
        CounterResult GetCurrentValue();
    }

public class TestWcfService : ITestWcfService
    {
        private ITestWindowsService _service;
        public TestWcfService() { /*NOTE: For discoverability*/ }
        public TestWcfService(ITestWindowsService service)
        {
            _service = service;
        }

        public CounterResult GetCurrentValue()
        {
            return _service.GetCurrentValue();
        }
    }

public interface ITestWindowsService
    {
        CounterResult GetCurrentValue();
    }

Затем у меня есть действительная служба Windows, которая самостоятельно размещает службу WCF через класс ServiceHost.

public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
    private static ServiceHost _wcfService;

    public TestWindowsService()
    {
        InitializeComponent();
    }

    public void OnStart(string[] args)
    {
        //Create instance of WCF, passing in reference to this service instance
        TestWcfService wcf = new TestWcfService(this);
        _wcfService = new ServiceHost(wcf);
    }

        public CounterResult GetCurrentValue()
    {
        //Note: Some logic here
    }
}

Теперь это более или менее работает, за исключением того, что каждый раз, когда я звоню TestWcfServiceClient()он использует конструктор по умолчанию и создает новый экземпляр службы Wcf и не использует экземпляр, созданный службой Windows. Это означает, что когда я звоню GetCurrentValue() Я получаю нулевую ссылку, потому что _service член не был установлен.

Я искал решения и нашел цитату ServiceHostFactory а также ServiceHost а также IInstanceProvider но каждый казался очень, очень сложным.

Любые мысли, которые вы могли бы предоставить, будут наиболее цениться.

РЕДАКТИРОВАТЬ: Вот моя информация ServiceModel

<system.serviceModel>
    <services>
      <service name="WcfService.TestWcfService">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> 
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

2 ответа

Вы пытаетесь положить квадратный колышек в круглое отверстие.

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

Если вы хотите чистый дизайн WCF, вам нужно будет создать слои абстракции и переместить свою бизнес-логику из существующего класса TestWindowsService. Затем служба Windows создает узел службы WCF, узел WCF создает службу WCF, а служба WCF не зависит от классов, в которых она размещена.

Сказав все это...

Чтобы на самом деле ответить на ваш вопрос:

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

  1. Когда вы передаете экземпляр службы в конструктор ServiceHost, он должен быть помечен как одиночный.

    [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single)]

  2. Убедитесь, что инициализация действительно работает так, как вы думаете:

    1. Установите предохранитель в свой конструктор TestService(ITestWindowsService), который выдает, если служба пуста.
    2. У вас есть комментарий к конструктору по умолчанию для TestWcfService(), который говорит "для обнаружения". Я бы удалил этот конструктор (по крайней мере, пока вы устраняете неполадки). Кусок кода может использовать этот конструктор для размещения экземпляра службы, который вам не нужен. Это может привести к тому, что ваше приложение начнет генерировать исключения или ошибки компиляции, которые указывают на вашу реальную проблему.

Если у вас по-прежнему возникают проблемы: как выглядит раздел "Модель сервиса" вашего app.config?

WCF ОЧЕНЬ расширяем, но для обеспечения такой расширяемости он также очень сложен. На мой взгляд, больше, чем должно быть, поэтому, если вы хотите использовать эту реализацию, это путь. Вам нужно создать поведение, которое изменяет фабрику сервисов, чтобы вы могли использовать собственный конструктор вместо пустого.

Тем не менее, я думаю, что может быть другая альтернатива. Поскольку и служба, и WCF совместно используют один и тот же домен приложения, они могут совместно использовать значения через статические объекты.

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

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