rasbian

时间:2016-03-03 10:40:34

标签: c# mono cors raspbian

我在raspberry jessie上成功创建了一个自托管的WCF单一服务,它几乎可以工作。

版本

  • Mono JIT编译器版本4.2.1
  • Raspbian GNU / Linux 8 \ n \ l

问题是Chrome网络应用无法使用它,因为它不会响应任何OPTIONS请求。请求保持在'pending'状态,直到我终止该服务。

我真的尝试了很多与CORS相关的解决方案,但我认为问题可能会更深一些。我想是这样的,因为OPTIONS请求没有到达CorsDispatchMessageInspector(下面的第三个代码片段)。

我目前的设置。

的app.config

<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解决方案向任何OPTIONS请求添加所需的'alow'标头,但是那里的断点不会触发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时

服务合约界面。我定义了很多不同的操作合同来测试我到目前为止在互联网上找到的内容。没有人回应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,并且仅针对GET / POST命中了公共覆盖Message ReadMessage方法断点。我必须多深入OPTIONS请求断点?或者也许它只是单声道服务中的某个标志。

此外,当我停止服务时,所有挂起的选项请求都会返回网络错误。

当我启动请求然后发送任何请求(包括OPTIONS)时,应用程序输出中出现“Thread started:#16”消息,因此OPTIONS请求似乎达到“应用程序级别”。 / p>

下一步更深层次的是我自己的ServiceHost类和通道监听器,但这是大量的工作,可能是问题甚至都不在应用程序级别。

如果我错过了什么,请告诉我。我用这个问题作为我的最后手段。

1 个答案:

答案 0 :(得分:2)

好的,我已经厌倦了搜索单声道自定​​义请求方法了,我发现它是由mono-bug-tracker中记录的错误引起的。如果找到解决方法,我会更新此答案。

我正在寻找一种如何重新实施错误部分的方法。

编辑:我解决了我的问题。我无法使用其依赖项重新编译整个单声道,因此我只重新编译了System.ServiceModel.dll并将原始文件替换为单个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为其添加所需的标题。