我在 raspberry jessie 上成功创建了一个自托管 WCF 单服务,并且它(几乎)可以工作。
版本
- Mono JIT 编译器版本 4.2.1
- Raspbian GNU/Linux 8\n\l
问题是 Chrome 网络应用无法使用它,因为它不响应任何 OPTIONS 请求。该请求将保持“待处理”状态,直到我终止该服务。
我确实尝试了很多与CORS相关的解决方案,但我认为问题可能更深一点。我是这样认为的,因为 OPTIONS 请求不会到达 CorsDispatchMessageInspector(下面的第三个代码片段)。
我目前的设置。
应用程序配置
<startup>
<supportedRuntime version="v4.5" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<services>
<service name="AspaDeviceControlCenter.Fp550Module.Fp550Module">
<endpoint address="http://localhost:8111/json/fp550/" binding="webHttpBinding" behaviorConfiguration="jsonEndpointBehaviour" contract="AspaDeviceControlCenter.Fp550Module.IFp550Module"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonEndpointBehaviour">
<webHttp/>
<corsEndpointBehaviorExtension/>
</behavior>
<behavior name="webscriptBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
<extensions>
<behaviorExtensions>
<add name="corsEndpointBehaviorExtension" type="AspaDeviceControlCenter.Service.Hosting.CorsEndpointBehaviorExtension, AspaDeviceControlCenter.Service"/>
</behaviorExtensions>
</extensions>
我使用了 enable-cors.org 中的 EndpoinBehaviorExtension 解决方案将所需的“允许” header 添加到任何 OPTIONS 请求,但不会为 OPTIONS 请求触发断点,仅针对 GET 和 POST
扩展实际部分
public class CorsEndpointBehaviorExtension : BehaviorExtensionElement, IEndpointBehavior
{
/*some empty methods*/
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
var requiredHeaders = new Dictionary<string, string>();
//requiredHeaders.Add("Access-Control-Allow-Origin", "*");
requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
requiredHeaders.Add("Access-Control-Allow-Headers", "Accept,Origin,Authorization,X-Requested-With,Content-Type,X-Tenant");
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CorsDispatchMessageInspector(requiredHeaders));
}
现在应该有帮助的部分,我认为问题是更深层次的,也许是操作系统配置问题,但我不是 Linux 专家。
public class CorsDispatchMessageInspector: IDispatchMessageInspector
{
Dictionary<string, string> requiredHeaders;
public CorsDispatchMessageInspector(Dictionary<string, string> headers)
{
requiredHeaders = headers ?? new Dictionary<string, string>();
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply,object correlationState)
{
var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
foreach (var item in requiredHeaders)
{
httpHeader.Headers.Add(item.Key, item.Value);
}
}
}
AfterReceiveRequest 和 BeforeSendReply 都有断点,当我发送 POST/GET 时它们会断点,但当请求方法为 OPTIONS 时则不会断点
服务合约接口(interface)。我定义了许多不同的运营契约(Contract)来测试我迄今为止在互联网上找到的内容。这些都没有响应 OPTIONS 请求。
[ServiceContract]
public interface IFp550Module : IControlCenterModule
{
[OperationContract]
bool Init();
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
string Open(/*int port, string settings*/);
[OperationContract]
[WebInvoke(Method = "*", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
string Version();
[OperationContract]
[WebInvoke(Method = "OPTIONS", UriTemplate="*", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
bool GetOptions();
}
运行时没有错误回调中断。
var host = new ServiceHost(module);
_serviceHosts.Add(host);
host.Faulted += OnFaulted;
host.UnknownMessageReceived += OnUnknownMessageReceived;
host.Opening += module.ServiceStarting;
host.Closing += module.ServiceClosing;
host.Open();
我还尝试了我自己的 CustomTextMessageEncoder :MessageEncoder,并且公共(public)覆盖 Message ReadMessage 方法断点仅在 GET/POST 时命中。我必须到达多深的 OPTIONS 请求断点?或者也许它只是单一服务中某处的某个标志。
此外,当我停止服务时,所有挂起的选项请求都会返回网络错误。
当我启动请求然后发送任何请求(包括选项)时,应用程序输出中都会有一条“线程已启动:#16”消息,因此看来 OPTIONS 请求达到了“应用程序级别”。
下一步更深入的是我自己的 ServiceHost 类和 channel 监听器,但这需要大量工作,而且问题可能根本不在于应用程序级别。
如果我错过了什么,请告诉我。我用这个问题作为我最后的手段。
最佳答案
好吧,我厌倦了搜索“单声道自定义请求方法”,我发现这是由于 mono-bug-tracker 中记录的错误造成的。如果找到解决方法,我会更新此答案。
我正在寻找一种方法来重新实现有缺陷的部分。
编辑:我解决了我的问题。我无法重新编译整个 mono 及其依赖项,因此我只重新编译了 System.ServiceModel.dll 并用 mono GAC 目录 System.ServiceModel 文件夹中的新文件替换了原始文件。新的 dll 已加载并接受更改。
更改位于 HttpReplyChannel.cs
if (ctxi.Request.HttpMethod == "POST" || ctxi.Request.HttpMethod == "PUT" )
msg = CreatePostMessage (ctxi);
else if (ctxi.Request.HttpMethod == "GET" || ctxi.Request.HttpMethod == "DELETE" || ctxi.Request.HttpMethod == "OPTIONS")
msg = Message.CreateMessage (MessageVersion.None, null);
我添加了额外的方法,更改之前只有 GET 和 POST。
现在我的服务能够接收选项请求并使用 MessageInspector 添加所需的 header 。
关于c# - raspbian 上的单一服务 WCF 选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35769843/