2015-03-31 34 views
0

我已經使用WCF實現了一個RESTful服務。其中一個要求是,該服務駐留在將要消耗它的網站的不同服務器(或至少端口)上。WCF - 返回HTTP 204拋出異常導致正文被髮送

爲此,我實現了自定義消息檢查器 - 並非真的是我的工作,但我設法從幾個不同的來源放置了一些東西。一個是here另一個我現在找不到。

基本上這是這樣,我可以說,發件人的來源是允許的。另外,當瀏覽器發送OPTIONS請求時,它不會嘗試執行該方法。

一切運作良好,只是當一個204返回提琴手抱怨有響應的身體。經檢查,我發現有被拋出的異常 -

The server encountered an error processing the request. The exception message is 'The communication object, System.ServiceModel.InstanceContext, cannot be used for communication because it has been Aborted.'. 

堆棧跟蹤:

at System.ServiceModel.Channels.CommunicationObject.ThrowIfClosedOrNotOpen() 
at System.ServiceModel.InstanceContext.GetServiceInstance(Message message) 
at System.ServiceModel.Dispatcher.InstanceBehavior.EnsureServiceInstance(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) 

的代碼 -

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext) 
    { 
     HttpRequestMessageProperty httpRequestHeader = request.Properties["httpRequest"] as HttpRequestMessageProperty; 

     if (httpRequestHeader.Method.ToUpper() == "OPTIONS" || httpRequestHeader.Headers[HttpRequestHeader.Authorization] == null) 
     { 
      instanceContext.Abort(); 
     } 

     return httpRequestHeader; 
    } 

    public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState) 
    { 
     HttpRequestMessageProperty httpRequestHeader = correlationState as HttpRequestMessageProperty; 
     HttpResponseMessageProperty httpResponseHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty; 

     httpResponseHeader.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,pulse-symphonycrm-userloginid,pulse-symphonycrm-domainandusername"); 
     httpResponseHeader.Headers.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS"); 
     httpResponseHeader.Headers.Add("Access-Control-Allow-Credentials", "true"); 
     string origin = httpRequestHeader.Headers["origin"]; 
     if (origin != null) 
     { 
      httpResponseHeader.Headers.Add("Access-Control-Allow-Origin", origin); 
     } 

     if (httpRequestHeader.Method.ToUpper() == "OPTIONS") 
     { 
      httpResponseHeader.StatusCode = HttpStatusCode.NoContent; 
     } 
     else if (httpRequestHeader.Headers[HttpRequestHeader.Authorization] == null) 
     { 
      httpResponseHeader.StatusDescription = "Unauthorized"; 
      httpResponseHeader.StatusCode = HttpStatusCode.Unauthorized; 
     } 
    } 

我覺得一定有什麼東西在instanceContext.Abort()後一種操作然後導致拋出異常並生成一個主體,但無法追蹤這是從哪裏來的。

任何人都可以闡明這一點,以及如何停止它,同時保持頭髮送。

+0

您的意圖是?中止實例上下文不是一個好主意。您可以設置可由OperationInvoker檢查的消息屬性,並且只要未設置屬性就不調用該操作。 – 2015-03-31 15:30:01

+0

@PetarVučetin我相信沒有這個方法試圖在OPTIONS請求被瀏覽器發送時執行。由於參數不存在,導致錯誤。你提到的關於不調用操作的想法聽起來像我想要做的。你能詳細解釋一下嗎?謝謝 – Zak 2015-03-31 19:23:00

回答

0

正如我懷疑和Petar提到的instanceContext.Abort()肯定是在錯誤的根源,因爲一旦我刪除了這個問題就消失了。

我到底是當瀏覽器發送此類請求簡單地提供等效的選項方法被調用,將返回沒事就去方法 -

// Note the void return type 
[WebInvoke(Method = "OPTIONS", UriTemplate = "/login")] 
void OptionsLogin(); 

[WebInvoke(Method = "POST", UriTemplate = "/login", ResponseFormat = WebMessageFormat.Json)] 
LogInResult LogIn(LogInInformation loginInformation); 

這種方法除一個實際上做了並返回一些東西。

但是我相信最好的方法,如果你有很多方法最終會以這種方式被調用,那就是實現Petar提到的OperationInvoker,如here所示,它不會調用底層方法。