Конструктор WCF с параметром / настраиваемым поведением, созданным в коде

Мне необходимо создать службу wcf с параметром.

Я слежу за этим http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8f18aed8-8e34-48ea-b8be-6c29ac3b4f41

Во-первых, я не знаю, как установить это настраиваемое поведение «MyServiceBehavior» в моем Web.config в приложении ASP.NET MVC, в котором оно будет размещено.

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

Во-вторых, в следующем примере они создали локальный хост (они используют

ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

для размещения в консольном приложении), но как добавить заголовки

OperationContext.Current.OutgoingMessageHeaders.Add ...

используется для инициализации конструктора, когда я использую ссылку на службу клиентского приложения WPF, и он уже создает экземпляр класса «клиент» веб-службы.

PBSDataCacheSyncContractClient client = new PBSDataCacheSyncContractClient();

не слишком ли поздно? Или, когда у меня есть собственное поведение, я могу сделать что-то вроде этого:

PBSDataCacheSyncContractClient client = new PBSDataCacheSyncContractClient(my var for service constructor) ?

С уважением, Даниэль Сковронски

РЕДАКТИРОВАТЬ: 31-05-2010

@manunt

Я улучшил свой второй вопрос.

Чтобы ответить на мой первый вопрос, мне удалось создать собственное расширение, но я не могу его зарегистрировать.

Мой сценарий:

  • У меня есть определения для моей веб-службы в библиотеке WCF (интерфейс, контракт, реализация IInstanceProvider, BehaviorExtensionElement)
  • затем я ссылаюсь на другое приложение ASP.NET проекта
  • внутри приложения ASP.NET у меня есть служебный файл WCF, и он указывает на мой класс из библиотеки WCF
  • вся моя конфигурация объявлена ​​в web.config

В моей библиотеке WCF есть:

namespace PBS.SyncService
{
using System;
using System.Data;
using System.Collections.ObjectModel;
using System.ServiceModel;
using Microsoft.Synchronization.Data;
using System.ServiceModel.Activation;
using Microsoft.Synchronization.Data.Server;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;

[XmlSerializerFormat()]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public partial class PBSDataCacheSyncService : object, IPBSDataCacheSyncContract
{

    private PBSDataCacheServerSyncProvider _serverSyncProvider;

    public PBSDataCacheSyncService()
    {
        this._serverSyncProvider = new PBSDataCacheServerSyncProvider();
    }

    public PBSDataCacheSyncService(long doctorId)
    {
        this._serverSyncProvider = new PBSDataCacheServerSyncProvider();
        this._serverSyncProvider.DoctorId = doctorId;
        this._serverSyncProvider.InitializeCustomSyncProvider();
    }

    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public virtual SyncContext ApplyChanges(Microsoft.Synchronization.Data.SyncGroupMetadata groupMetadata, DataSet dataSet, Microsoft.Synchronization.Data.SyncSession syncSession)
    {
        return this._serverSyncProvider.ApplyChanges(groupMetadata, dataSet, syncSession);
    }

    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public virtual SyncContext GetChanges(Microsoft.Synchronization.Data.SyncGroupMetadata groupMetadata, Microsoft.Synchronization.Data.SyncSession syncSession)
    {
        return this._serverSyncProvider.GetChanges(groupMetadata, syncSession);
    }

    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public virtual SyncSchema GetSchema(Collection<string> tableNames, Microsoft.Synchronization.Data.SyncSession syncSession)
    {
        return this._serverSyncProvider.GetSchema(tableNames, syncSession);
    }

    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public virtual SyncServerInfo GetServerInfo(Microsoft.Synchronization.Data.SyncSession syncSession)
    {
        return this._serverSyncProvider.GetServerInfo(syncSession);
    }

    public bool InitializeCustomSyncProvider(long doctorId)
    {
        this._serverSyncProvider.DoctorId = doctorId;
        return this._serverSyncProvider.InitializeCustomSyncProvider();
    }
}

[XmlSerializerFormat()]
[ServiceContractAttribute()]
public interface IPBSDataCacheSyncContract
{

    [OperationContract()]
    SyncContext ApplyChanges(Microsoft.Synchronization.Data.SyncGroupMetadata groupMetadata, DataSet dataSet, Microsoft.Synchronization.Data.SyncSession syncSession);

    [OperationContract()]
    SyncContext GetChanges(Microsoft.Synchronization.Data.SyncGroupMetadata groupMetadata, Microsoft.Synchronization.Data.SyncSession syncSession);

    [OperationContract()]
    SyncSchema GetSchema(Collection<string> tableNames, Microsoft.Synchronization.Data.SyncSession syncSession);

    [OperationContract()]
    SyncServerInfo GetServerInfo(Microsoft.Synchronization.Data.SyncSession syncSession);

    [OperationContract()]
    bool InitializeCustomSyncProvider(long doctorId);

    [OperationContract()]
    string[] GetSyncAdapterInfo();
}

public class PBSDataCacheSyncProvider : IInstanceProvider
{
    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        string doctorId = message.Headers.GetHeader<string>("DoctorId", "http://***/SyncService.svc");
        if (doctorId != null)
        {
            return new PBSDataCacheSyncService(Convert.ToInt64(doctorId));
        }
        else
        {
            return new PBSDataCacheSyncService();
        }
    }
    public object GetInstance(InstanceContext instanceContext)
    {
        return new PBSDataCacheSyncService();
    }
    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
    }
}

public class PBSDataCacheSyncBehavior : BehaviorExtensionElement, IServiceBehavior
{
    PBSDataCacheSyncProvider pbsProvider = new PBSDataCacheSyncProvider();
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher ed in cd.Endpoints)
            {
                ed.DispatchRuntime.InstanceProvider = this.pbsProvider;
            }
        }
    }
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }

    public override Type BehaviorType
    {
        get { return typeof(PBSDataCacheSyncBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new PBSDataCacheSyncBehavior();
    }
}
}

Мой файл службы WCF имеет имя: SyncService.svc, а в моем макрупе есть:

<%@ ServiceHost Language="C#" Debug="true" Service="PBS.SyncService.PBSDataCacheSyncService" CodeBehind="PBS.SyncService.PBSDataCache.Server.SyncContract.cs" %>

Мой web.config:

<service name="PBS.Web.SyncService" behaviorConfiguration="behPBSDataCacheSyncBehavior">
    <host>
      <baseAddresses>
        <add baseAddress="http://***/SyncService.svc" />
      </baseAddresses>
    </host>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <endpoint address=""  binding="basicHttpBinding" contract="PBS.SyncService.IPBSDataCacheSyncContract" />
</service>

<serviceBehaviors>
    <behavior name="behPBSDataCacheSyncBehavior">
      <PBSDataCacheSyncBehavior /> <!-- this element is being ignored -->
    </behavior> 
</serviceBehaviors>

<extensions>
    <behaviorExtensions>
        <add name="PBSDataCacheSyncBehavior" type="PBS.SyncService.PBSDataCacheSyncBehavior, PBS.SyncService,
            Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
</extensions>

Можете ли вы сказать мне, что мне не хватает в этом месте? Почему парсер игнорирует мое объявление настраиваемого расширения?

У меня следующая ошибка:

Описание ошибки конфигурации: ошибка произошла во время обработки файла конфигурации, необходимого для обслуживания этого запроса. Просмотрите приведенные ниже сведения о конкретных ошибках и соответствующим образом измените файл конфигурации.

Сообщение об ошибке парсера: произошла ошибка при создании обработчика раздела конфигурации для system.serviceModel / поведения: элемент расширения «PBSDataCacheSyncBehavior» не может быть добавлен к этому элементу. Убедитесь, что расширение зарегистрировано в коллекции расширений в system.serviceModel / extensions / behaviorExtensions. Имя параметра: элемент

РЕДАКТИРОВАТЬ: 01-06-2010

Проблема с парсером решена путем ввода всего объявления в одну строку.

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

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

И когда я его инициализирую, у него есть только конструкторы:

общедоступный PBSDataCacheSyncContractClient () {}

    public PBSDataCacheSyncContractClient(string endpointConfigurationName) : 
            base(endpointConfigurationName) {
    }

    public PBSDataCacheSyncContractClient(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public PBSDataCacheSyncContractClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public PBSDataCacheSyncContractClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress) {
    }

Где я могу добавить заголовки?

«Что касается второго вопроса - вы должны определить контракт сообщения с необходимыми заголовками в нем и указать значения заголовков для каждого сообщения отдельно». Не могли бы вы быть более конкретным?

РЕДАКТИРОВАТЬ: 02-06-2010

Я столкнулся с другой проблемой.

Когда у меня есть моя конфигурация, httpGetEnabled игнорируется ...:

<serviceBehaviors>
    <behavior name="behPBSDataCacheSyncBehavior">
      <PBSDataCacheSyncBehavior />
      <serviceMetadata httpGetEnabled="true" /><!-- ignored -->
      <serviceDebug includeExceptionDetailInFaults="true" /><!-- ignored -->
    </behavior> 
</serviceBehaviors>

Как я могу это исправить?

РЕДАКТИРОВАТЬ: 02-06-2010

Хорошо, я нашел обходной путь. Как ни странно, но работает!

Моя проблема была в web.config. И ни одна запись поведения имени не распознается моей службой, а не какой-либо другой ... Поэтому я просто не добавил поведение имени в коллекцию.

<serviceBehaviors>
    <behavior name="">
        <PBSDataCacheSyncBehavior />
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior> 
    <behavior name="behPBSDataCacheSyncBehavior">
        <PBSDataCacheSyncBehavior />
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior> 
</serviceBehaviors>

И я добавляю заголовок в свой код следующим образом:

int doctorId = 2;

Sync.PBSDataCacheSyncContractClient client = new Sync.PBSDataCacheSyncContractClient();
new OperationContextScope (client.InnerChannel);
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader("DoctorId", "http://***/SyncService.svc", doctorId));

Я изменил тему, чтобы она была более полезной.

HTH

С уважением, Даниэль Сковронски


person Daniel Skowroński    schedule 28.05.2010    source источник


Ответы (2)


Ответ на первый вопрос вы можете найти здесь.

Что касается получаемой вами ошибки - не разделяйте определение вашего расширения на две строки, потому что синтаксический анализатор xml не может с этим справиться.

Пример определения настраиваемых заголовков без указания контракта сообщения:

var client = new Service1Client();
new OperationContextScope(client.InnerChannel);
MessageHeader<string> typedHeader = new MessageHeader<string>("headercontent");
MessageHeader header = typedHeader.GetUntypedHeader("myheader", "myns");            
OperationContext.Current.OutgoingMessageHeaders.Add(header);
person Community    schedule 28.05.2010
comment
Пожалуйста, ответьте на мои последние изменения. Спасибо, Даниэль - person Daniel Skowroński; 31.05.2010
comment
И снова буду признателен, если вы ответите. Спасибо, Даниэль - person Daniel Skowroński; 01.06.2010

Я знаю, в чем проблема с поведением, которое не найдено, и почему вам нужен взлом с поведением без имени.

Если вы посмотрите на эту строку в своем файле разметки svc:

<%@ ServiceHost Language="C#" Debug="true" Service="PBS.SyncService.PBSDataCacheSyncService" CodeBehind="PBS.SyncService.PBSDataCache.Server.SyncContract.cs" %>

и эта строка в вашем web.Config:

<service name="PBS.Web.SyncService" behaviorConfiguration="behPBSDataCacheSyncBehavior">

Вы заметите, что имя, указанное в теге службы, отличается от класса службы, указанного в атрибуте Service в файле разметки.

Думаю должно быть примерно так:

вместо

<service name="PBS.Web.SyncService" behaviorConfiguration="behPBSDataCacheSyncBehavior">

это

<service name="PBS.SyncService.PBSDataCacheSyncService"   behaviorConfiguration="behPBSDataCacheSyncBehavior">

Эти два значения, я думаю, должны быть одинаковыми, но в моем случае эти два значения были разными, и мне пришлось взломать пустое имя службы. Но установив оба значения одинаковыми, это сработало. Он обнаружил поведение без необходимости в пустом, и я смог получить доступ к своему wsdl.

person tbiz    schedule 27.02.2011