我已经使用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()
之后运行,然后引发异常并生成一个正文,但无法追踪它的来源。
任何人都可以对此有所了解,以及如何在保持标题发送的同时停止它。
答案 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,它不会调用底层方法。