在WCF服务中,如何公开第二个端点只能访问某些方法?

时间:2011-12-09 21:48:23

标签: .net wcf iis

我有一项服务,其中包含一系列用于为我们的网站创建和管理资产的方法。它还有两个需要外部访问的方法,比如说“GetConfiguration”和“GetElement”。我想使用不同的ServiceContracts在不同的端点公开相同的服务。但我希望这两种方法在两个端点都可用。

以下是我App.Config的相关部分:

  <service name="Manager.Manager" behaviorConfiguration="Manager.ManagerBehavior">
    <endpoint address="" binding="customBinding" bindingConfiguration="NetHttpBinding" contract="Manager.IManager" />
    <endpoint address="Runtime" binding="customBinding" bindingConfiguration="NetHttpBinding" contract="Manager.IPublicManager" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>

当我将这个东西加载到IIS并尝试访问它时,我收到以下错误:

 An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
 System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension: System.ServiceModel.Description.DataContractSerializerOperationBehavior
 contract: http://tempuri.org/:IPublicManager ----> System.InvalidOperationException: The Manager.IPublicManager.GetConfiguration operation references a message element [http://tempuri.org/:GetConfiguration] that has already been exported from the Manager.IManager.GetConfiguration operation. You can change the name of one of the operations by changing the method name or using the Name property of OperationContractAttribute. Alternatively, you can control the element name in greater detail using the MessageContract programming model.
 at System.ServiceModel.Description.MessageContractExporter.AddElementToSchema(XmlSchemaElement element, String elementNs, XmlSchemaSet schemaSet)
 at System.ServiceModel.Description.MessageContractExporter.ExportWrappedPart(Message message, String elementName, String elementNs, XmlSchemaSet schemaSet, Boolean skipSchemaExport)
 at System.ServiceModel.Description.DataContractSerializerMessageContractExporter.ExportBody(Int32 messageIndex, Object state)
 at System.ServiceModel.Description.MessageContractExporter.ExportMessage(Int32 messageIndex, Object state)
 at System.ServiceModel.Description.MessageContractExporter.ExportMessageContract()
 at System.ServiceModel.Description.WsdlExporter.CallExtension(WsdlContractConversionContext contractContext, IWsdlExportExtension extension)
 --- End of inner ExceptionDetail stack trace ---
 at System.ServiceModel.Description.WsdlExporter.CallExtension(WsdlContractConversionContext contractContext, IWsdlExportExtension extension)
 at System.ServiceModel.Description.WsdlExporter.CallExportContract(WsdlContractConversionContext contractContext)
 at System.ServiceModel.Description.WsdlExporter.ExportContract(ContractDescription contract)
 at System.ServiceModel.Description.WsdlExporter.ExportEndpoint(ServiceEndpoint endpoint, XmlQualifiedName wsdlServiceQName)
 at System.ServiceModel.Description.WsdlExporter.ExportEndpoints(IEnumerable`1 endpoints, XmlQualifiedName wsdlServiceQName)
 at System.ServiceModel.Description.ServiceMetadataBehavior.MetadataExtensionInitializer.GenerateMetadata()
 at System.ServiceModel.Description.ServiceMetadataExtension.EnsureInitialized()
 at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.InitializationData.InitializeFrom(ServiceMetadataExtension extension)
 at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.GetInitData()
 at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.TryHandleDocumentationRequest(Message httpGetRequest, String[] queries, Message& replyMessage)
 at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.ProcessHttpRequest(Message httpGetRequest)
 at SyncInvokeGet(Object , Object[] , Object[] )
 at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
 at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
 at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
 at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
 at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

所以它不喜欢操作具有相同的名称。有任何想法吗?它们都使用相同的Service类。也许我只是以完全错误的方式解决问题?

2 个答案:

答案 0 :(得分:1)

虽然这并不能完全解决您的问题,但我希望它可以提供一些帮助。我使用webHttpBinding,因为我最熟悉它。

这里的想法是将公共和私有功能分成两个独立的接口:

[ServiceContract]
public interface IPrivate  : IPublic
{
    [WebGet(UriTemplate = "/admin")]
    [OperationContract]
    int PrivateStuff();
}

[ServiceContract]
public interface IPublic
{
    [WebGet(UriTemplate = "/common")]
    [OperationContract]
    int PublicStuff();
}

正如您所见,IPrivate的实现者也必须实现IPublic为什么服务实现IPrivate可以作为两者公开。

现在可以将服务实现公开为IPublicIPrivate,并且可以在服务(“service1.svc”)下公开端点:

    <system.serviceModel>
      <behaviors>
        <serviceBehaviors>
          <behavior>
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="false"/>
          </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
          <behavior name="rest">
            <webHttp/>
          </behavior>
        </endpointBehaviors>
      </behaviors>
      <services>
        <service name="ManagerService.Service">
          <endpoint address="private" behaviorConfiguration="rest" contract="ManagerService.IPrivate" binding="webHttpBinding"/>
          <endpoint address="public" behaviorConfiguration="rest" contract="ManagerService.IPublic" binding="webHttpBinding" />
          <endpoint address="/private/mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          <endpoint address="/public/mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
      </services>

该服务现已公开在http://host/service1.svc/common的公共部分,而私人版本则公开于http://host/service1.svc/admin

元数据交换似乎无法正常工作,但这可能是由于绑定类型造成的。

答案 1 :(得分:0)

1)创建具有服务合同属性的两个接口/合同。 2)实施两种服务合同。 3)尽管服务相同,但创建端点并提及不同的合同名称(接口)。

有关详细信息,请参阅思考链接

https://www.safaribooksonline.com/library/view/learning-wcf/9780596101626/ch01s07.html