在代码中创建的参数/自定义行为的WCF构造函数

时间:2010-05-28 11:08:39

标签: wcf wcf-binding wcf-client

我必须使用参数创建wcf服务。

我正在关注此http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8f18aed8-8e34-48ea-b8be-6c29ac3b4f41

首先,我不知道如何在将托管它的ASP.NET MVC应用程序的Web.config中设置此自定义行为“MyServiceBehavior”。

据我所知,必须在wcf.config中的部分声明行为。 如何从服务程序集中将引用添加到我的行为类?

第二件事是,在下面的示例中,他们创建了本地主机(他们使用

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

在控制台应用程序中托管),但我如何添加标题

OperationContext.Current.OutgoingMessageHeaders.Add ...

用于在我的WPF客户端应用程序服务引用中使用时初始化构造函数,它已经创建了Web服务“client”类的实例

PBSDataCacheSyncContractClient client = new PBSDataCacheSyncContractClient();
是不是太迟了?或者当我有自己的自定义行为时,我可以这样做:

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

此致 DanielSkowroński

编辑:31-05-2010

@manunt

我改进了第二个问题。

为了回答我的第一个问题,我设法创建了自定义扩展,但我无法注册。

我的情景:

  • 我在WCF库中有我的Web服务的定义(接口,合同,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,在我的makrup中我有:

<%@ 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 / behavior创建配置节处理程序时发生错误:无法将扩展元素“PBSDataCacheSyncBehavior”添加到此元素。验证扩展是否已在system.serviceModel / extensions / behaviorExtensions的扩展集合中注册。   参数名称:element

编辑:01-06-2010

通过在一行中键入所有声明来解析解析器的问题。

当我有服务参考时,我仍然不知道如何添加标题。

在我的WPF应用程序中,我只有客户端实例,它实现了由服务引用自动生成的IPBSDataCacheSyncContract。

当我初始化它时,它只有构造函数:

public 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

此致 DanielSkowroński

2 个答案:

答案 0 :(得分:2)

我知道没有找到行为的问题是什么,以及为什么你需要没有名字的行为的黑客攻击。

如果你在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类不同。

我认为它应该是这样的:

而不是

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

这个

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

我认为这两个值不一定不确定,但在我的情况下,这两个值是不同的,我不得不做空白服务名称hack。但是通过设置两个值相同,它起作用了。它找到了行为而不需要空白行为,我能够访问我的wsdl。

答案 1 :(得分:0)

回答您可以找到的第一个问题here

关于你得到的错误 - 不要将扩展的定义分成两行,因为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);