简体   繁体   中英

WCF ignore duplex in webhttpbinding

Hi i have an service looks something like this.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public class Service : IService
{
    public string test(string value)
    {
        IServiceCallBack callback = OperationContext.Current.GetCallbackChannel<IServiceCallBack>();

        callback.callBackTest("callBack response");
        return value + ", normal response";
    }
}

[ServiceContract(CallbackContract = typeof(IServiceCallBack))]
public interface IService
{
    [OperationContract]
    [WebInvoke(
        ResponseFormat = WebMessageFormat.Json,
        RequestFormat = WebMessageFormat.Json,
        Method = "POST")]
    string test(string value);
}

public interface IServiceCallBack
{
    [OperationContract]
    void callBackTest(string value);
}

Now my needs are that two different bindings will use this same service (if possible) i know i can make two entire seperate services for this to work, but i rather not because the two bindings will use the same functions

My scenario is that we have some clients which is apple devices that will use an WebHttpBinding

And windows clients that will use NetTcpBinding

Now i want the windows clients to be able to use the callback, but with the apple devices i just want to ignore the callback.

if i try to host the service with the WebHttpBinding i get this error

base = {"Contract requires Duplex, 
but Binding 'WebHttpBinding' doesn't 
support it or isn't configured properly to support it."}

To me this means that it wont work but can possibly be configured to work? or do they mean that i have to configure and remove my callback for this to work?

So is it possible to ignore the callback for the WebHttpBinding and just receive the normal responses?

I solved this by editing the endpoint of the webhttpbinding by removing all info about the callback. so now i have two working endpoints one with callbacks and they can share the same service code.

the only downside is that i messed up my mex and i dont know how to solve that one but i made an workaround by not adding the webhttpbinding if you edit your settings that way.

Its not pretty but now i dont have to have two seperate services and duplicate code for all my wcf methods/operations.

public class WebServiceHost : IDisposable
{
    public WebServiceHost()
    {
        _tcpBaseAddress = "net.tcp://localhost:" + Globals.ClientTcpPort + "/V1";
        _httpBaseAddress = "http://localhost:" + Globals.ClientHttpPort + "/V1";

        List<Uri> addresses = new List<Uri>() { new Uri(_httpBaseAddress), new Uri(_tcpBaseAddress)};

        _host = new System.ServiceModel.Web.WebServiceHost(typeof(Service), addresses.ToArray());
        IsOpen = false;
    }

    readonly System.ServiceModel.Web.WebServiceHost _host;
    readonly string _httpBaseAddress;
    readonly string _tcpBaseAddress;

    public static bool IsOpen { get; set; }

    public void OpenHost()
    {
        try
        {
            //WebHttpBinding
            WebHttpBinding webBinding = new WebHttpBinding();
            webBinding.MaxBufferPoolSize = int.MaxValue;
            webBinding.MaxReceivedMessageSize = int.MaxValue;
            webBinding.Security.Mode = WebHttpSecurityMode.None;
            webBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;

            //NetTcpBinding
            NetTcpBinding tcpBinding = new NetTcpBinding();
            tcpBinding.MaxBufferPoolSize = int.MaxValue;
            tcpBinding.MaxReceivedMessageSize = int.MaxValue;
            tcpBinding.Security.Mode = SecurityMode.None;
            tcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;

            //ServiceBehavior
            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpsGetEnabled = false;
            smb.HttpGetEnabled = true;

            _host.Description.Behaviors.Add(smb);

            ServiceDebugBehavior sdb = _host.Description.Behaviors.Find<ServiceDebugBehavior>();
            sdb.HttpHelpPageEnabled = Globals.IsDebugMode;
            sdb.HttpsHelpPageEnabled = Globals.IsDebugMode;
            sdb.IncludeExceptionDetailInFaults = Globals.IsDebugMode;

            UseRequestHeadersForMetadataAddressBehavior urhfmab = new UseRequestHeadersForMetadataAddressBehavior();
            _host.Description.Behaviors.Add(urhfmab);

            //MEX endpoint
            _host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexTcpBinding(), "mex");

            if (Globals.UseClientTcpHost && Globals.UseClientHttpHost)
            {
                _host.AddServiceEndpoint(typeof(IService), tcpBinding, _tcpBaseAddress);
                _host.AddServiceEndpoint(typeof(IService), webBinding, _httpBaseAddress);
                _host.Description.Endpoints[2].Contract = CopyContract(_host.Description.Endpoints[1].Contract);
            } 
            else if (Globals.UseClientTcpHost)
            {
                _host.AddServiceEndpoint(typeof(IService), tcpBinding, _tcpBaseAddress);
            }
            else if (Globals.UseClientHttpHost)
            {
                _host.AddServiceEndpoint(typeof(IService), webBinding, _httpBaseAddress);
                _host.Description.Endpoints[1].Contract = CopyContract(_host.Description.Endpoints[1].Contract);
            }

            _host.Open();
            IsOpen = true;

}

Copy contract method

private ContractDescription CopyContract(ContractDescription contract)
    {
        //ContractDescription orgContract = _host.Description.Endpoints[1].Contract;
        ContractDescription value = new ContractDescription("IServiceWithCallBack");

        //copy the value from orgiginal to the new contract.
        foreach (var item in contract.Behaviors)
        {
            value.Behaviors.Add(item);
        }

        value.ConfigurationName = contract.ConfigurationName;
        value.ContractType = contract.ContractType;

        foreach (var item in contract.Operations)
        {
            OperationDescription operation = new OperationDescription(item.Name, value);
            operation.BeginMethod = item.BeginMethod;

            foreach (var behavior in item.Behaviors)
            {
                operation.Behaviors.Add(behavior);
            }

            operation.EndMethod = item.EndMethod;

            foreach (var fault in item.Faults)
            {
                operation.Faults.Add(fault);
            }

            operation.IsInitiating = item.IsInitiating;
            operation.IsTerminating = item.IsTerminating;

            foreach (var knownType in item.KnownTypes)
            {
                operation.KnownTypes.Add(knownType);
            }

            foreach (var message in item.Messages)
            {
                operation.Messages.Add(message);
            }

            operation.ProtectionLevel = item.ProtectionLevel;
            operation.SyncMethod = item.SyncMethod;

            value.Operations.Add(operation);
        }

        value.ProtectionLevel = contract.ProtectionLevel;
        value.SessionMode = contract.SessionMode;

        List<OperationDescription> removeList = new List<OperationDescription>();

        foreach (var item in value.Operations)
        {
            if (item.Name.ToLower().EndsWith("callback"))
                removeList.Add(item);
        }

        foreach (var item in removeList)
        {
            value.Operations.Remove(item);
        }

        return value;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM