我有一个非常简单的自托管WCF应用程序,该应用程序是通过以下方式初始化的:
Host = new WebServiceHost(this, new Uri(serviceAddress));
var binding = new WebHttpBinding();
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.CrossDomainScriptAccessEnabled = true; // TODO: Remove this?
var endpoint = Host.AddServiceEndpoint(typeof(HttpService), binding, "");
Host.Open();
我的HttpService类具有此方法:
[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, PUT, DELETE");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");
return "";
}
else
{
try
{
return "12345";
}
catch (ProcessNotFoundException ex)
{
throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.NotFound);
}
catch (Exception ex)
{
throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
}
}
}
我在上面添加了CORS内容,以便任何人都可以从任何使用JavaScript的网站使用此API。而且我正在尝试使用fetch
运行一些POST请求,因为一旦它起作用,我将传递大量数据,因此GET方法将不起作用。通过JavaScript执行以下操作可以正常运行:
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '1232'});
这样做时,我的Evaluate
方法首先被OPTIONS调用,然后被POST调用,并且返回的XML字符串没有错误。以下内容也适用(请注意正文中的引号):
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '"hello world"'});
由于两个都是有效的JSON,尽管任何JSON字符串都可以使用,所以我做到了这一点,但出现了400错误的请求错误:
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '[10]'});
我想也许它想要一个可以转换为我的方法参数的JSON,但这也不起作用(给我400错误):
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: JSON.stringify({ query: "hey" })})
所以它可以带数字和字符串,但不能带别,我也不知道为什么。我尝试使用所有其他这些属性组合,并获得了完全相同的结果:
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped)]
我只想能够发送任何字符串,而无需检查它并确定它的好坏,同时还能够执行上面的CORS事情。有办法吗?
答案 0 :(得分:0)
我找到了一种解决方法,但是我仍然不确定为什么它让我传递数字和字符串而不是数组,因此,如果有人提出实际的解释,我很乐意接受。我的解决方案是在Evaluate
方法中采用Stream而不是字符串,然后读取流:
using (var memoryStream = new MemoryStream())
{
query.CopyTo(memoryStream);
var array = memoryStream.ToArray();
var lole = Encoding.UTF8.GetString(array);
}
我的想法是,由于我正在做CORS事情,并且浏览器在发送OPTIONS请求时发送了一个空的正文,因此WCF无法将其作为JSON处理,因此我必须自己处理一切并通过采取战争流来做到这一点。仍然不知道为什么它让我发送数字和字符串(以及BTW也为布尔值),但没有数组(或对象)。
答案 1 :(得分:0)
首先,以下定义仅支持使用request body
而不是URL参数来接受参数。
[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)
此外,默认情况下,参数的主体样式为裸露。
BodyStyle =WebMessageBodyStyle.Bare
这意味着服务器接受字符串而不包装参数名。
body:“ 1232”
正文:““ hello world”'
当我们手动将值切换为BodyStyle=WebMessageBodyStyle.Wrapped
时,服务器将接受以下格式。基本上,您的尝试是正确的。这里只是一个小问题。
{"value":"abcd"}
这是我的例子,希望对您有帮助。
服务器合同。
[OperationContract]
[WebInvoke(Method ="*",BodyStyle =WebMessageBodyStyle.Wrapped,ResponseFormat =WebMessageFormat.Json)]
string GetData(string value);
<script>
var para1 = { "value": "abcdefg" };
$.ajax({
type: "POST",
url: "http://localhost:8864/Service1.svc/getdata",
data: JSON.stringify(para1),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnSuccessCall,
error: OnErrorCall
});
function OnSuccessCall(response) {
console.log(response);
}
function OnErrorCall(response) {
console.log(response.status + " " + response.statusText);
}
</script>
关于处理CORS问题,我添加了一个额外的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("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With,Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
这是相关文件。
https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.web.webmessagebodystyle?view=netframework-4.8
请随时告诉我是否有什么我可以帮助的。