【问题标题】:Can't expose REST XML, REST JSON and SOAP properly via configuration only for WCF无法通过仅针对 WCF 的配置正确公开 REST XML、REST JSON 和 SOAP
【发布时间】:2012-04-05 03:38:44
【问题描述】:

我希望能够构建一个 WCF 服务来实现以下目标:

  • RESTfully 公开 JSON
  • RESTful 公开 XML
  • 公开 SOAP
  • 必要时的其他绑定

这里的关键是,我想全部通过配置完成,并且每个所需方法只用代码编写一个函数,而不必在代码中单独指定ResponseFormat=ResponseFormat.Json或@ 987654324@ 以上为 RESTful 方法的单独函数。我已经做了大量的研究,但我找不到任何可靠的信息来证明这是否可以完全通过配置来实现。

奇怪的是,当我构建项目时,RESTful 方法在我通过 URL 访问它们时工作,但 WSDL 会引发错误 - 即,如果有人想通过 SOAP 引用/使用服务,它会在 WSDL 导入时失败一步。

服务的代码和配置如下,服务托管在本地http://localhost/WCF下进行测试。以下 2 个 RESTful 调用成功运行,并在浏览器中返回成功的 XML 和 JSON:

localhost/WCF/service1.svc/json/students

localhost/WCF/service1.svc/rest/students

但是,如果我打电话给http://localhost/WCF/service1.svc?wsdl,我会收到以下错误。如果我删除其中一个 webhttpBinding 端点配置,则 WSDL 可以正常工作和显示,因此可以被引用。

是不是不可能在配置中有多个 webHttpBindings(即必须通过单独的方法和属性,例如 ResponseFormat=ResponseFormat.Json)才能使 WSDL 生成有效?还是我在这里配置错误?

感谢任何帮助,通过配置指定序列化的额外功能会更直接。谢谢。

WSDL 生成错误

An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
    System.NullReferenceException: Object reference not set to an instance of an object.
       at System.ServiceModel.Description.WsdlExporter.CreateWsdlBindingAndPort(ServiceEndpoint endpoint, XmlQualifiedName wsdlServiceQName, Port& wsdlPort, Boolean& newBinding, Boolean& bindingNameWasUniquified)
       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.get_Metadata()
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.InitializationData.InitializeFrom(ServiceMetadataExtension extension)
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.GetInitData()
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.TryHandleMetadataRequest(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)

Web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="httpGetBehavior" name="WCF.Service1">
        <endpoint address="json" binding="webHttpBinding" name="jsonRest" contract="WCF.IService1" behaviorConfiguration="jsonBehavior"></endpoint>
        <endpoint address="rest" binding="webHttpBinding" name="xmlRest" contract="WCF.IService1" behaviorConfiguration="restBehaviour"></endpoint>
        <endpoint address="soap" binding="basicHttpBinding" name="soap" contract="WCF.IService1"></endpoint>
        <endpoint name="mex" address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost/WCF"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="httpGetBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp defaultOutgoingResponseFormat="Json"/>
        </behavior>
        <behavior name="restBehaviour">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
</configuration>

代码

public class Service1 : IService1
{       
    public IList<Student> GetStudents()
    {
        IList<Student> students = new List<Student>();
        students.Add(new Student() { FirstNme = "Bob", LastName = "Long", StudentId = 1, Subject = "Economics" });
        students.Add(new Student() { FirstNme = "Jack", LastName = "Short", StudentId = 2, Subject = "IT" });
        return students;
    }
}

[ServiceContract]
public interface IService1
{       
    [WebGet(UriTemplate = "/students")]
    [OperationContract]
    IList<Student> GetStudents();

}

[DataContract]
public class Student
{
    private int _studentId;
    private string _firstName;
    private string _lastName;
    private string _subject;

    [DataMember]
    public int StudentId
    {
        get { return _studentId; }
        set { _studentId = value; }
    }

    [DataMember]
    public string FirstNme
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    [DataMember]
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    [DataMember]
    public string Subject
    {
        get { return _subject; }
        set { _subject = value; }
    }
}

【问题讨论】:

    标签: xml json wcf rest configuration


    【解决方案1】:

    这是一个已知问题,单个服务的 json、xml 和 soap 端点会引发异常。

    我已在MS Connect 上将其作为错误提出。

    如果您将框架切换到 3.5,那么这将起作用,或者也提供了一种解决方法。您可以从请求对象中获取内容标头,并在您的代码中确定它以设置响应格式并相应地发回响应。

    同样在 Web API 中,如果您的 WebGet/WebInvoke 属性中没有指定任何内容,框架会根据内容类型自动确定这一点,并相应地返回响应。

    注意:当我尝试打开 MS Connect 上的链接时,我在 MS Connect 站点上遇到了一些系统错误。如果您想要解决方法,请告诉我,我可以将其发送出去。此外,MS 已确认他们不会修复它,因为没有多少客户希望在单个服务上公开所有 3 种格式。

    【讨论】:

    • 感谢您的反馈,实际上我终于设法在其他地方隐晦地找到了这个,但似乎并不容易找到。请求内容类型的解决方法在这里听起来像是一个不错的选择。
    • WebAPI 不提供 wsdl
    【解决方案2】:

    嗯,我创建了一个非常简单的服务,可以使用 SOAP、JSON 和 XML 端点。它的工作原理仅仅是因为它的简单性吗?

    我发现我必须为 json 和 xml 声明单独的绑定配置(尽管是空的)。这是配置(已更新,因为之前只有 system.serviceModel 部分可见):

    <?xml version="1.0"?>
    <configuration>
    
      <system.web>
        <compilation debug="true" targetFramework="4.0"/>
      </system.web>
    
      <system.serviceModel>
    
        <bindings>
          <webHttpBinding>
            <!-- separate bindings are necessary -->
            <binding name="jsonBinding"/>
            <binding name="xmlBinding"/>
          </webHttpBinding>
        </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
    
          <endpointBehaviors>
            <behavior name="xmlEndpoint">
              <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Xml"/>
            </behavior>
            <behavior name="jsonEndpoint">
              <!-- do not specify enableWebScript or UriTemplate will not work -->
              <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json"/>
            </behavior>
          </endpointBehaviors>
        </behaviors>
    
        <services>
          <service name="Services.Addressbook.AddressbookService">
            <endpoint address="" binding="basicHttpBinding" name="soap" contract="Services.Addressbook.IAddressbookService" />
            <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange" />
            <endpoint address="json" behaviorConfiguration="jsonEndpoint" binding="webHttpBinding" bindingConfiguration="jsonBinding" name="restJson" contract="Services.Addressbook.IAddressbookService" />
            <endpoint address="xml" behaviorConfiguration="xmlEndpoint" binding="webHttpBinding" bindingConfiguration="xmlBinding" name="restXml" contract="Services.Addressbook.IAddressbookService" />
          </service>
        </services>
    
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    
      </system.serviceModel>
    
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    
    </configuration>
    

    这是服务合同:

    [ServiceContract]
    public interface IAddressbookService {
      [OperationContract]
      [WebGet(UriTemplate = "Version")]
      string GetVersion();
    
      [OperationContract]
      [WebGet(UriTemplate = "Entries/Count")]
      int GetEntriesCount();
    
      [OperationContract]
      [WebGet(UriTemplate = "Entries")]
      Address[] GetEntries();
    
      [OperationContract]
      [WebGet(UriTemplate = "Entries/{name}")]
      Address[] SearchEntriesByName(string name);
    
      [OperationContract]
      [WebInvoke(Method = "POST", UriTemplate = "Entries/Add")]
      bool AddEntry(Address entry);
    
      [OperationContract]
      [WebInvoke(Method = "DELETE", UriTemplate = "Entries/Remove")]
      bool RemoveEntry(Address entry);
    }
    

    这是数据合约:

    [DataContract]
    public class Address {
      [DataMember]
      public string FirstName { get; set; }
      [DataMember]
      public string LastName { get; set; }
      [DataMember]
      public string Street { get; set; }
      [DataMember]
      public string City { get; set; }
      [DataMember]
      public int ZipCode { get; set; }
      [DataMember]
      public string Country { get; set; }
      [DataMember]
      public string Phone { get; set; }
      [DataMember]
      public string Email { get; set; }
    }
    

    【讨论】:

    • 您使用的是 .NET 3.5 还是 .NET 4?
    【解决方案3】:

    请尝试this

    <bindings>
      <webHttpBinding>
        <binding name="webBindingXML"></binding>
        <binding name="webBindingSOAP"></binding>
      </webHttpBinding>
    </bindings>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 2012-02-26
      • 2012-08-21
      相关资源
      最近更新 更多