Сначала пользовательский DataContactSerializerOperationBehavior
using System;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.Collections.Generic;
/// <summary>
/// Summary description for ReferencePreservingDataContractSerializerOperationBehavior
/// </summary>
public class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operation) : base(operation)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
public override XmlObjectSerializer CreateSerializer(Type type, System.Xml.XmlDictionaryString name, System.Xml.XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
}
Далее следует SelfDescribingServiceHost, который позволяет нам использовать ReferencePreservingDataContractSerializerOperationBehavior
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace NewWcfService
{
//This class is a custom derivative of ServiceHost
//that can automatically enabled metadata generation
//for any service it hosts.
class SelfDescribingServiceHost : ServiceHost
{
public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
//Overriding ApplyConfiguration() allows us to
//alter the ServiceDescription prior to opening
//the service host.
protected override void ApplyConfiguration()
{
//First, we call base.ApplyConfiguration()
//to read any configuration that was provided for
//the service we're hosting. After this call,
//this.ServiceDescription describes the service
//as it was configured.
base.ApplyConfiguration();
foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
SetDataContractSerializerBehavior(endpoint.Contract);
//Now that we've populated the ServiceDescription, we can reach into it
//and do interesting things (in this case, we'll add an instance of
//ServiceMetadataBehavior if it's not already there.
ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
mexBehavior = new ServiceMetadataBehavior();
this.Description.Behaviors.Add(mexBehavior);
}
else
{
//Metadata behavior has already been configured,
//so we don't have any work to do.
return;
}
//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
if (baseAddress.Scheme == Uri.UriSchemeHttp)
{
mexBehavior.HttpGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeHttps)
{
mexBehavior.HttpsGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexNamedPipeBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"mex");
}
}
}
private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
DataContractSerializerOperationBehavior dcsob = operation.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsob != null)
{
operation.Behaviors.Remove(dcsob);
}
operation.Behaviors.Add(new ReferencePreservingDataContractSerializerOperationBehavior(operation));
}
}
}
}
Тогда есть ServiceHostFactory:
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace NewWcfService
{
public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
//All the custom factory does is return a new instance
//of our custom host class. The bulk of the custom logic should
//live in the custom host (as opposed to the factory) for maximum
//reuse value.
return new SelfDescribingServiceHost(serviceType, baseAddresses);
}
}
}
И, конечно, Service.svc для использования нового HostFactory:
<%@ ServiceHost Language="C#" Debug="true" Service="NewWcfService.Service" Factory="ProTeriaWCF.SelfDescribingServiceHostFactory" CodeBehind="Service.svc.cs" %>