WCF - 返回HTTP 204抛出异常导致发送正文

时间:2015-03-31 14:43:19

标签: wcf http

我已经使用WCF实现了RESTful服务。其中一个要求是服务驻留在将要使用它的网站的不同服务器(或至少端口)上。

为此,我实现了自定义消息检查器 - 不是我的工作,但我设法从几个不同的来源放置了一些东西。一个是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()之后运行,然后引发异常并生成一个正文,但无法追踪它的来源。

任何人都可以对此有所了解,以及如何在保持标题发送的同时停止它。

1 个答案:

答案 0 :(得分:0)

正如我所怀疑的那样,Petar提到instanceContext.Abort()肯定是错误的根源,因为一旦我删除了这个问题就会消失。

我最后使用的方法是简单地提供一个OPTIONS等效方法,当浏览器发送这种类型的请求时,该方法不会返回任何内容 -

// 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,它不会调用底层方法。