2012-04-05 32 views
3

我希望能夠建立其實現以下WCF服務:不能暴露REST XML,JSON REST和SOAP通過適當的配置只對WCF

  • REST風格暴露出JSON
  • REST風格公開XML
  • 自曝SOAP
  • 其他綁定如有必要

這裏的關鍵是,我想要做的這一切通過配置,並且只有一個函數用代碼編寫,用於每個所需的方法,而不必在代碼ResponseFormat=ResponseFormat.JsonResponseFormat=ResponseFormat.Xml以上單獨指定RESTful方法的單獨函數。我已經做了大量的研究,並且我無法找到任何可靠的信息,純粹是否可以通過配置實現。

奇怪的是,當我構建項目時,RESTful方法在通過URL訪問它們時起作用,但WSDL引發錯誤 - 即如果有人想通過SOAP引用/使用服務,它將在WSDL上失敗導入步驟。

該服務的代碼如下,以及配置,該服務託管在本地進行測試http://localhost/WCF。以下2個RESTful的通話成功地工作,並在瀏覽器中成功返回XML和JSON:

本地主機/ WCF/service1.svc/JSON /學生

本地主機/ WCF/service1.svc/REST /學生

但是,如果我撥打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; } 
    } 
} 

回答

3

這是一個已知問題,哈哈ving json,單個服務的xml和soap端點引發異常。

我在MS Connect上提出了這個錯誤。

如果您將您的框架切換到3.5,那麼這將工作或提供解決方法。你可以得到從請求對象的內容頭,並確定在代碼中設置響應格式,並回送相應的響應。

而且在Web API中,框架自動確定此基礎上對內容類型,如果你WebGet/WebInvoke屬性沒有指定,並相應地返回響應。

注意:當我嘗試打開MS Connect上的鏈接時,MS Connect網站上出現一些系統錯誤。如果您希望解決方法讓我知道,我可以發送它。另外MS已經證實他們不打算修復它,因爲沒有多少客戶想要在單個服務上公開所有3種格式。

+0

感謝您的反饋,我實際上設法終於找到這個隱晦別的地方還有,但它似乎並不容易找到。請求內容類型的解決方法在這裏聽起來很不錯。 – Fitzroy79 2012-04-06 02:45:55

+0

的WebAPI不提供WSDL – PositiveGuy 2013-10-13 15:41:54

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; } 
} 
+0

你在.NET 3.5或.NET 4? – Rajesh 2012-07-25 08:52:48

+0

我在有針對性的.Net Framework 4中測試了這個項目 – Andreas 2012-07-25 09:23:06

1

請嘗試this

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