【问题标题】:WCF4 hosting in IIS, WSDL: bindingNamespace is never readWCF4 在 IIS、WSDL 中托管:从不读取 bindingNamespace
【发布时间】:2011-01-18 23:04:32
【问题描述】:

试图从 wsdl 文件中删除“tempuri”引用。我已经遵循了我能想到的所有现有建议。添加一个

[ServiceBehavior(Namespace="mynamespace")] 

实现类的属性,添加一个

[ServiceContract(Namespace="mynamespace")]

到合约接口并更改 web.config 中端点的“bindingNamespace”属性以匹配。然而,当加载(在 IIS 中)时,绑定命名空间永远不会改变......它总是 tempuri。

是否有人对解决此问题有任何其他想法?下面是来自网络配置的示例...绑定命名空间永远不会,无论我做什么,都不会更新为 mynamespace,它始终是 tempuri.org。如果在通过主机工厂加载端点后,我遍历主机描述中的绑定并更新它们,它们会发生变化,但这似乎是一种 hack。

对于位于“http://mydomain.com/MyService.svc”的服务,以下代表我的端点配置,这甚至被 IIS 使用吗?

<services>
  <service name="ServiceImplementationClassReference,MyAssembly" >
    <endpoint name=""
              address="MyService.svc"
              binding="basicHttpBinding"
              bindingNamespace="mynamespace"
              bindingConfiguration=""
              contract="IMyContract" />

    <endpoint name="mexHttpBinding" 
              address="mex"
              binding="mexHttpBinding"
              contract="IMetadataExchange" />        
  </service>
</services>

仍然引用 tempuri.org 的生成 WSDL 文件的相关片段

  <wsdl:import namespace="http://tempuri.org/" location="http://mydomain.org/MyService.svc?wsdl=wsdl0" />

........

  <wsdl:service name="Directory">
    <wsdl:port name="BasicHttpBinding_IDirectoryServices"
    binding="i0:BasicHttpBinding_IDirectoryServices">
      <soap:address location="http://mydomain.org/MyService.svc" />
    </wsdl:port>
  </wsdl:service>

在 wsdl:definition 节点中,xml 命名空间 i0(由上面列出的服务引用)也设置为 tempuri.org,因此需要 import 语句。如果我使用 BasicHttpBinding 或 wsHttpBinding,则 temprui 的使用没有变化。事实上,在 web.config 文件中设置绑定到 wsHttpBinding 仍然会导致上面的输出,引用 BasicHttpBinding_IdirectoryServices。

谢谢!

【问题讨论】:

  • Ladislav,是的,这是 .NET 4.0;我已经添加了 wsdl 文件的相关部分,希望这会有所帮助。整件事要乱七八糟才能正确发布。我非常乐意将完整的东西发送给任何可能觉得有用的人。谢谢!!感谢您的帮助。

标签: wcf iis wsdl


【解决方案1】:

似乎是一个已知问题:https://connect.microsoft.com/wcf/feedback/details/583163/endpoint-bindingnamespace?wa=wsignin1.0

这是我的 web.config 的一部分。请注意,我将我的使用限制为 HTTPS,所以 YMMV 与您可能需要做的事情:

    <behaviors>
        <endpointBehaviors>
            <behavior name="Secure" />
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="MetadataBehavior">
                <serviceMetadata httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
        <service name="Company.Services.Implementation.Service" behaviorConfiguration="MetadataBehavior">
            <endpoint address="" behaviorConfiguration="Secure"
                      binding="basicHttpBinding" bindingConfiguration="httpsBinding" bindingNamespace="http://services.company.com"
                      contract="Company.Services.Interfaces.IService" />
            <endpoint address="mex" behaviorConfiguration="Secure"
                      binding="mexHttpsBinding" bindingConfiguration="httpsBinding" bindingNamespace="http://services.company.com"
                      contract="IMetadataExchange" />
        </service>
    </services>
    <bindings>
        <basicHttpBinding>
            <binding name="httpsBinding">
                <security mode="Transport" />
            </binding>
        </basicHttpBinding>
        <mexHttpsBinding>
            <binding name="httpsBinding" />
        </mexHttpsBinding>
    </bindings>

这是来自Raffaele Rialdi 的代码解决方案(我稍作修改):

/// <summary>
/// Attribute which will add a binding namespace to every endpoint it's used in.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class BindingNamespaceBehaviorAttribute : Attribute, IServiceBehavior
{
    /// <summary>
    /// The binding namespace;
    /// </summary>
    private readonly string bindingNamespace;

    /// <summary>
    /// Initializes a new instance of the <see cref="BindingNamespaceBehaviorAttribute"/> class.
    /// </summary>
    /// <param name="bindingNamespace">The binding namespace.</param>
    public BindingNamespaceBehaviorAttribute(string bindingNamespace)
    {
        this.bindingNamespace = bindingNamespace;
    }

    /// <summary>
    /// Gets the binding namespace.
    /// </summary>
    /// <value>The binding namespace.</value>
    public string BindingNamespace
    {
        get
        {
            return this.bindingNamespace;
        }
    }

    /// <summary>
    /// Provides the ability to pass custom data to binding elements to support the contract implementation.
    /// </summary>
    /// <param name="serviceDescription">The service description of the service.</param>
    /// <param name="serviceHostBase">The host of the service.</param>
    /// <param name="endpoints">The service endpoints.</param>
    /// <param name="bindingParameters">Custom objects to which binding elements have access.</param>
    public void AddBindingParameters(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase,
        Collection<ServiceEndpoint> endpoints,
        BindingParameterCollection bindingParameters)
    {
    }

    /// <summary>
    /// Provides the ability to change run-time property values or insert custom extension objects such as error
    /// handlers, message or parameter interceptors, security extensions, and other custom extension objects.
    /// </summary>
    /// <param name="serviceDescription">The service description.</param>
    /// <param name="serviceHostBase">The host that is currently being built.</param>
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    /// <summary>
    /// Provides the ability to inspect the service host and the service description to confirm that the service
    /// can run successfully.
    /// </summary>
    /// <param name="serviceDescription">The service description.</param>
    /// <param name="serviceHostBase">The service host that is currently being constructed.</param>
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        if (serviceHostBase == null)
        {
            throw new ArgumentNullException("serviceHostBase");
        }

        foreach (var endpoint in serviceHostBase.Description.Endpoints)
        {
            endpoint.Binding.Namespace = this.bindingNamespace;
        }
    }
}

像这样使用:

[ServiceBehavior(Namespace = "http://schemas.vevy.com/Printing")]
[BindingNamespaceBehavior("http://schemas.vevy.com/Printing")]
public class LabelsService : ILabelsService
{
    // ...
}

【讨论】:

  • 厉害,至少是有原因的!谢谢 Jesse,我没想到会去看那里,我没想到它会成为架构中的错误。
  • 虽然我很好奇为什么 节点似乎根本没有被读取。例如,我可以删除对 mex 端点的引用,并且该服务仍然可以毫无问题地提供 wsdl 数据,只要我有一个使用空名称定义的服务行为。删除空名称以使其成为命名实例会禁用元数据,但将此命名实例应用为 的 behaviorConfigruation 不会执行任何操作。好像 WCF 4 的简化配置没有被 web.config 中的项目覆盖 =/
  • 进一步的研究表明这是默认情况下:msdn.microsoft.com/en-us/library/ee358768.aspx 如何覆盖它以强制 IIS 使用 web.config 配置的端点,这是在外部实现自定义主机的唯一方法IIS?
  • 我刚刚在我提供的一项服务上尝试了这一点,但没有遇到 tempuri.org 问题。我所拥有的是一个非常完整的 web.config。请参阅我对答案的更新,看看这是否对您有帮助。
  • 劝告。请注意,我正在使用 WCF4,我怀疑我正在与内置的新“简化配置”默认值作斗争。我可以非常类似于您的方式配置我的端点,我什至可以在行为和绑定配置命名方面犯错误并产生错误(“不存在这样的行为”)。这告诉我正在读取和解析配置文件。它只是从未使用过。 IIS 似乎锁定了使用所有默认设置:读取 *.svc 文件并使用 name="" 锁定 serviceBehavior。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2014-07-30
  • 2017-07-10
  • 1970-01-01
相关资源
最近更新 更多