开发者

WCF Constructor with parameter / Custom Behavior Created In Code

I've a must to create wcf service with parameter.

I'm following this http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8f18aed8-8e34-48ea-b8be-6c29ac3b4f41

First this is that I don't know how can I set this custom behavior "MyServiceBehavior" in my Web.config in ASP.NET MVC app that will host it.

As far as I know behaviors must be declared in section in wcf.config. How can I add reference there to my behavior class from service assembly?

An second thing is that in the following example they have created local host (they use

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

to host in console application), but how I can add headers

OperationContext.Current.OutgoingMessageHeaders.Add ...

used to initialize constructor when I use in my WPF client application service reference and it will already create instance of web service "client" class

PBSDataCacheSyncContractClient client = new PBSDataCacheSyncContractClient();

is't it too late? Or when I have my own custom behavior can I do something like this:

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

Regards, Daniel Skowroński

EDIT: 31-05-2010

@manunt

I've improved my second question.

For answer to my first question, I've managed to create custom extenstion but I can't register it.

My scenario:

  • I have definitions for my web service in WCF library (interface, contract, implementation of IInstanceProvider, BehaviorExtensionElement)
  • then I reference it to another project ASP.NET application
  • inside ASP.NET application I have WCF service file and it is pointed to my class from WCF library
  • all my configuration is declared in web.config

In my WCF library I have:

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();
    }
}
}

开发者_开发问答My WCF Service file has name: SyncService.svc and in my makrup I have:

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

My 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>

Can you tell me what I'm missing in this point? Why parser ignores my custom extension declaration?

I have following error:

Configuration Error Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: An error occurred creating the configuration section handler for system.serviceModel/behaviors: Extension element 'PBSDataCacheSyncBehavior' cannot be added to this element. Verify that the extension is registered in the extension collection at system.serviceModel/extensions/behaviorExtensions. Parameter name: element

EDIT: 01-06-2010

Problem with parser resolved by typing all the declaration in one single line.

I still don't know how to add header when I have service reference.

In my WPF application I have only client instance witch implements my IPBSDataCacheSyncContract autogenerated by Service Reference.

And when I initialize it it only has constructors:

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) {
    }

Where I can add headers?

"As for the second question - you should define message contract with needed headers in it and provide header values for each message separately." Could you be more specific?

EDIT: 02-06-2010

I've encountered other issue.

When I have now my configuration httpGetEnabled is ignored... :

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

How can I fix it?

EDIT: 02-06-2010

OK I've figured workaround. Still it is weird but it works!

My problem was with web.config. And none name behavior entry entry is recognized by my service and not any other... So I simply added no name behavior to collection.

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

And I add header in my code this way:

int doctorId = 2;

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

I've changed topic to be more useful.

HTH

Regards, Daniel Skowroński


I know what the problem is with the behavior not being found and why you need the hack with the behavior with no name.

If you look at this line in your svc markup file:

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

and this line in your web.Config:

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

You will notice that the name specified in the service tag is different from the Service class specified in the Service attribute in the markup file.

I think it should be something like this:

instead of

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

this

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

These two values I think have to the same not sure but in my case the two values were different and I had to do the blank service name hack. But by setting both values the same, it worked. It found the behavior without needing the blank one and I was able to access my wsdl.


Answer for the first question you can find here.

Regarding error you are getting - do not split definition of your extension into two lines, because xml parser cannot handle that.

A sample how to define custom headers without specifying message contract:

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);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜