ProjectInstaller 安装的 WCF Windows 服务无法处理 POST 请求
WCF Windows Service installed by ProjectInstaller not working on POST request
我有一个 WCF C# Rest API 应用程序,主要希望通过 HTTP 访问以通过设备执行扫描文档。我已经配置了 CORS 并使用 ProjectInstaller 生成了应该用于安装为 windows 服务的包。当我 运行 这个应用程序在没有 ProjectInstaller 功能的开发模式下时,一切正常。当我尝试执行扫描操作时,问题就出现了——然后 CORS 选项请求失败。这很好奇,特别是因为用于检查扫描仪可用性的 GET 方法在执行时没有任何 CORS 问题。我尝试了多种变体来解决这个问题,从 Google 搜索结果中应用了 CORS 实现并且它有效,但仅限于开发模式。最后我使用了 WebHttpBehaviorExtensions,但问题仍然存在。
明确 - ProjectInstaller 嵌入到与 WCF 应用程序链接的 ConsoleApplication 中。
我的 app.config 是 here。
我的合同看起来像:
[ServiceContract]
public interface IScanService
{
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json, UriTemplate = "ScanDocument")]
Task ScanDocument(int userId, Guid caseId, string fileName);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json, UriTemplate = "IsAlive")]
bool IsAlive();
}
我应该怎么做才能在启用 CORS 的情况下允许发送 POST 请求?
提前感谢您的回复。
在你的配置文件中,我看到你使用crossDomainScriptAccessEnabled来解决cross-domain。如果用它来解决cross-domain,WCF服务只支持Jsonp访问,全部只支持GET请求
如果你的服务托管在IIS中,可以在项目中添加Global.asax,在Global.asax中添加如下代码:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
HttpContext.Current.Response.End();
}
}
当 WCF 托管在 IIS 中时,IIS 会将其视为 Web 服务,因此 Global.asax 中的配置将生效。
如果您使用 self-hosting,您可以实现 IDispatchMessageInspector 以在服务响应之前添加响应 headers。
public class ServerMessageLogger : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
}
}
将 ServerMessageLogger 添加到服务行为:
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)]
public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
{
public Type TargetContract => throw new NotImplementedException();
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.MessageInspectors.Add(new ServerMessageLogger());
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
return;
}
}
最后,我们需要将此行为应用于服务以支持 cross-domain:
我有一个 WCF C# Rest API 应用程序,主要希望通过 HTTP 访问以通过设备执行扫描文档。我已经配置了 CORS 并使用 ProjectInstaller 生成了应该用于安装为 windows 服务的包。当我 运行 这个应用程序在没有 ProjectInstaller 功能的开发模式下时,一切正常。当我尝试执行扫描操作时,问题就出现了——然后 CORS 选项请求失败。这很好奇,特别是因为用于检查扫描仪可用性的 GET 方法在执行时没有任何 CORS 问题。我尝试了多种变体来解决这个问题,从 Google 搜索结果中应用了 CORS 实现并且它有效,但仅限于开发模式。最后我使用了 WebHttpBehaviorExtensions,但问题仍然存在。
明确 - ProjectInstaller 嵌入到与 WCF 应用程序链接的 ConsoleApplication 中。
我的 app.config 是 here。
我的合同看起来像:
[ServiceContract]
public interface IScanService
{
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json, UriTemplate = "ScanDocument")]
Task ScanDocument(int userId, Guid caseId, string fileName);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json, UriTemplate = "IsAlive")]
bool IsAlive();
}
我应该怎么做才能在启用 CORS 的情况下允许发送 POST 请求?
提前感谢您的回复。
在你的配置文件中,我看到你使用crossDomainScriptAccessEnabled来解决cross-domain。如果用它来解决cross-domain,WCF服务只支持Jsonp访问,全部只支持GET请求
如果你的服务托管在IIS中,可以在项目中添加Global.asax,在Global.asax中添加如下代码:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
HttpContext.Current.Response.End();
}
}
当 WCF 托管在 IIS 中时,IIS 会将其视为 Web 服务,因此 Global.asax 中的配置将生效。
如果您使用 self-hosting,您可以实现 IDispatchMessageInspector 以在服务响应之前添加响应 headers。
public class ServerMessageLogger : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
}
}
将 ServerMessageLogger 添加到服务行为:
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)]
public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
{
public Type TargetContract => throw new NotImplementedException();
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.MessageInspectors.Add(new ServerMessageLogger());
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
return;
}
}
最后,我们需要将此行为应用于服务以支持 cross-domain: