访问 Windows Service 中托管的 WCF
本文关键字:WCF Windows Service 访问 | 更新日期: 2023-09-27 18:34:23
当我尝试直接从 Web 应用程序访问 Windows 服务中托管的 WCF 服务时,我遇到了问题,但我无法理解我做错了什么。
我尝试了我发现的所有建议,但没有帮助任何东西。我使用AngularJs,但这并不重要,我接受所有建议。
有我的项目:https://github.com/djromix/Portal.WorckFlow
Portal.Services
是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"};
}
}
}
我只想简单访问网址并获得 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.
要使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 选项请求,请求将实际请求发送到服务器的权限。
当您启用 system.webServer 部分中的设置时,IIS 会为您处理所有这些。将 WCF 作为 Windows 服务承载会使 IIS 脱颖而出,因此在 WCF 中,您需要自己实现 CORS 内容。
我认为您应该重新考虑并使用IIS,如果该服务的目的是为HTTP请求提供服务。
经过多次尝试,我找到了解决方案。
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