c# - raspbian 上的单一服务 WCF 选项

标签 c# mono cors raspbian

我在 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/

相关文章:

c# - DateTime.ToString 格式化并将结果字符串反转回日期时间

C# - 每页上的 itextSharp 小计

c# - Linux 上的 TCP 代理错误

Monotouch 绑定(bind)类别(使用类别属性)

cors - 缓存选项 - 预检请求

asp.net-core - CORS 策略会阻止来自非浏览器请求的资源访问吗?

c# - 使用 RegEx 读取 CSV 文件

c# - 剪贴板 SetText 失败而 SetDataObject 没有

c# - 使用单声道时出现 Serial.IO.Ports 问题,适用于 dotnet core 3.1/arm/raspberry pi 4

xml - 如何使 Azure API 管理(API 网关)CORS 策略动态化?