我有一项服务,其中包含大量用于为我们的站点创建和管理 Assets 的方法。它还有两个需要从外部访问的方法,比如说“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 类。也许我只是以完全错误的方式处理问题?

最佳答案

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

这里的想法是将公共(public)和私有(private)功能拆分为两个独立的接口(interface):

[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 的公共(public)部分公开,而私有(private)版本在 http://host/service1.svc/admin 公开

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

关于.net - 在 WCF 服务中,如何公开只能访问某些方法的第二个端点?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8452126/

10-17 02:35