【问题标题】:Access WCF hosted in Windows Service访问托管在 Windows 服务中的 WCF
【发布时间】:2016-02-11 16:57:05
【问题描述】:

当我尝试直接从 Web 应用程序访问托管在 Windows 服务中的 WCF 服务时遇到问题,我无法理解我做错了什么。

我尝试了所有我发现但没有任何帮助的建议。我使用 AngularJs,但这并不重要,我接受所有建议。

有我的项目:https://github.com/djromix/Portal.WorckFlow

Portal.Services 是 Windows 服务。

这是我的 Windows 服务配置:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>
</system.webServer>
<system.serviceModel>
    <behaviors>
          <serviceBehaviors>
            <behavior name="">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service name="Portal.Services.ServiceContract.PortalContract">
            <endpoint 
                address="" 
                binding="basicHttpBinding" 
                contract="Portal.Services.ServiceContract.IPortalContract">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint 
                address="mex" 
                binding="mexHttpBinding" 
                contract="IMetadataExchange" />
            <host>
                <baseAddresses>
                    <add baseAddress="http://localhost:8000/Portal" />
                </baseAddresses>
            </host>
        </service>
    </services>
</system.serviceModel>


服务代码:

 namespace Portal.Services.ServiceContract
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IPortalContract" in both code and config file together.
        [ServiceContract(Namespace = "")]
        public interface IPortalContract
        {
            [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
            double Ping();

            [OperationContract]
            object CashInResult(string key);
        }
    }

namespace Portal.Services.ServiceContract
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class PortalContract : IPortalContract
    {
        public double Ping()
        {
            return -1;
        }

        [WebGet]
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
        public object CashInResult(string key)
        {
            return new {Value = "Some Data"};
        }
    }
}

我只想简单地访问 url 并获取 json 结果
http://localhost:8000/Portal/CashInResult?key=secretkey

现在我收到错误[Failed to load resource: the server responded with a status of 400 (Bad Request)]

从网络应用程序我得到错误

 XMLHttpRequest cannot load /Portal/CashInResult?key=1. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '???' is therefore not allowed access. The response had HTTP status code 400.

【问题讨论】:

  • 您尝试了哪些方法,结果如何?你能看到服务吗?你有错误吗?
  • 从浏览器访问 url 时出现异常 [加载资源失败:服务器响应状态为 400 (Bad Request]

标签: c# wcf


【解决方案1】:

要让您的 GET 请求正常工作,您可以在浏览器中自己将标头 (Access-Control-Allow-Origin) 添加到请求中,但只有 GET 请求可以工作。

如果您在 Windows 服务中运行 WCF,则不会使用 system.webServer,因为没有 IIS。

此链接显示如何在 IIS 之外的 WCF 中实现完全 CORS。

https://code.msdn.microsoft.com/windowsdesktop/Implementing-CORS-support-c1f9cd4b

但在 SO 帖子中解释它有点长,但这就是为什么它目前不适合你....

CORS 世界中有两种类型的请求,“普通”请求和“预检”请求。

正常的或安全的(HTTP GET)请求涉及浏览器发送请求的 ORIGIN 标头,服务器根据该请求接受/拒绝。

预检或不安全(例如 POST、PUT 或 DELETE)请求涉及浏览器发送 HTTP OPTIONS 请求,请求允许将实际请求发送到服务器。

当您启用 system.webServer 部分中的设置时,IIS 会为您处理所有这些。将 WCF 作为 Windows 服务托管会使 IIS 脱颖而出,因此在 WCF 中您需要自己实现 CORS。

如果服务的目的是服务 HTTP 请求,我认为您应该重新考虑并使用 IIS。

【讨论】:

  • 我的任务听起来像这样,我有 Web 应用程序,通过这个 Web 应用程序我需要访问客户端上的本地设备而不访问服务器。我们将有一些门户网站供客户支付账单。我知道使用 Metro 应用程序或 Windows 应用程序更容易做到这一点。使用 windows 服务我找到了解决方案,但在这种情况下,服务器需要了解计算机,我只需获取客户端 ip,并更改端点地址,它就可以正常工作。但我们需要忽略通过服务器的调用。
【解决方案2】:

经过多次尝试,我找到了解决方案。


     namespace Portal.Services.ServiceContract
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IPortalContract" in both code and config file together.
    [ServiceContract(Namespace = "")]
    public interface IPortalContract
    {
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
        double Ping();

        [OperationContract]
        string CashInResult(string key);
    }
}


namespace Portal.Services.ServiceContract
        {
            [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
            public class PortalContract : IPortalContract
            {
                readonly Logger _nLog = LogManager.GetCurrentClassLogger();
                public double Ping()
                {
                    using (var tMeter = new TimeMeterLog(_nLog, "Ping"))
                    {
                        tMeter.Info("-1");
                        return -1;
                    }
                }

                [WebGet(UriTemplate = "/CashInResult/{key}", ResponseFormat = WebMessageFormat.Json)]
                public string CashInResult(string key)
                {
                    using (var tMeter = new TimeMeterLog(_nLog, "CashInResult"))
                    {
                        var result = JsonConvert.SerializeObject(new { Value = "Some Data" });
                        tMeter.Info(result);
                        return result;
                    }
                }
            }
        }


从浏览器调用服务:

http://localhost:8000/rest/Ping


结果:{"PingResult":-1}

有源代码。 https://github.com/djromix/Portal.WorckFlow

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    相关资源
    最近更新 更多