如何使用WCF self host处理Ajax JQUERY POST请求

如何使用WCF self host处理Ajax JQUERY POST请求,wcf,jquery,http-post,wcf-data-services,Wcf,Jquery,Http Post,Wcf Data Services,创建RESTful WCF服务器有很多原因(这很容易),如果您可以避免ASP及其安全框(如果您所做的只是简单地请求返回信息),则更好。请参阅:关于如何做到这一点 我发现处理AJAX(JQUERY)GET请求很容易。但是在帖子中处理JSON是很棘手的 下面是一个简单的GET请求契约示例: [OperationContract] [WebGet(ResponseFormat = WebMessageFormat.Json)] String Version(); 实现在这里(

创建RESTful WCF服务器有很多原因(这很容易),如果您可以避免ASP及其安全框(如果您所做的只是简单地请求返回信息),则更好。请参阅:关于如何做到这一点

我发现处理AJAX(JQUERY)GET请求很容易。但是在帖子中处理JSON是很棘手的

下面是一个简单的GET请求契约示例:

    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    String Version();
实现在这里(返回一个JSON)

啊,但是如果你想发布一些JSON呢。你会发现很多关于堆栈溢出的文章告诉你你要做的就是:

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    BuildResponse BuildToby(BuildRequest request);
它将接收一条JSON消息,反序列化为一个普通的.NET对象(PONO),并让您使用它。事实上,当我在Fiddler中构建请求时,这种方法非常有效

POST /BuildToby HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: localhost:4326
Content-Length: 1999
但是,当您在JQUERY 1.8中使用以下AJAX时,您会发现一个惊喜:

通过指定“application/json”的内容类型,您会发现浏览器会触发一个“飞行前”检查,以查看是否允许您发布除www-url嵌入的POST消息之外的其他内容。(有)

下面是fiddler报告的内容:(注意这不是一条POST消息,而是一条选项消息)

发生的情况是,浏览器(在本例中为Firefox)必须通过选项HTTP消息向服务器进行额外调用,以查看是否允许发布(此内容类型)

所有关于修复此问题的文章都是关于如果您在ASP.NET中,哪些是好的,但是如果您正在进行自宿主WCF,则哪些是无用的


现在你看到了这个问题(很抱歉这么长篇大论,但我想把这篇文章写成一篇完整的文章,以便其他人能够了解结果)。

好吧,现在有一些真正的MSDN大师已经写出了解决方案,但我无法理解他们:

但我想出了一个简单的解决办法。至少在WCF 4.5中,您可以添加自己的OperationContract来处理选项请求:

    [OperationContract]
    [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
    void GetOptions();
请注意,方法签名是无效的,并且没有参数。这将首先调用,然后调用POST消息

GetOptions的实现是:

    public partial class CatalogService : ICatalogService
{
    public void GetOptions()
    {
        mon.IsActive = true;
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
    }
}
这就是你要做的一切

您可能还希望将此属性添加到服务类中,以便可以序列化大型JSON:

//This defines the base behavior of the CatalogService. All other files are partial classes that extend the service
[ServiceBehavior(MaxItemsInObjectGraph = 2147483647)]       // Allows serialization of very large json structures
public partial class CatalogService : ICatalogService
{
    PgSqlMonitor mon = new PgSqlMonitor();

    private void BypassCrossDomain()
    {
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    }
}
注意,我有一个名为BypassCrossDomain()的小助手方法,我在所有POST和GET方法上调用它,以便处理跨域调用


我在这里花了大量的研究时间(在MSDN论坛、堆栈溢出、博客中),我希望这能帮助其他人尝试做这类项目。

除了YSG博士列出的答案之外,我发现我收到了Firefox通知,说正在发生重定向,还有一个“405方法不允许”错误。添加

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");

GetOptions类似乎已经解决了这个问题。

除了Dr.YSG的答案之外,还有一个补充,如果您需要在向单个ID发送邮件的端点上支持OPTIONS方法,则必须实现多个GetOptions方法:

    [WebInvoke(Method = "OPTIONS", UriTemplate = "")]
    void GetOptions();
    [WebInvoke(Method = "OPTIONS", UriTemplate = "{id}")]
    void GetOptions(string id);

确实令人失望的是,WCF/Microsoft无法根据端点的签名自动生成正确的选项响应,但至少可以手动处理。

经过几天的搜索,阅读了许多帖子和建议的解决方案,我认为YSG博士的这个问题是理解和解决我的angular/wcf/post/CORS等问题的最佳资源

但真正对我起作用的是:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.End();
    }
}
我知道这不是一个完整的(也不是完美的)解决方案,因为我正在使用global.asax,并且有很多可能的场景,但我只想分享这个替代方案,因为它最终可能会帮助其他人


(除了添加标题)

谢谢,上面的BypassCrossDomain有助于解决我遇到的跨域问题。谢谢,这真的很有帮助。我用它从http上下文调用了一些https服务,效果非常好!似乎只是给我发了一个空白的回复!没有标题,什么都没有!谢谢,成功了。你从哪里得到这个神奇的选择?有记录吗?如果我能投票100次,我会的。这是一个使用WCF构建AJAX服务的优秀解决方案。其他(不那么优雅的)解决方案包括拦截请求和抛出包含200代码的HTTP异常。在Mono框架中,看起来无论我使用什么,选项请求都会无限期地挂起。这是您在实施时看到的吗?当然已经有一段时间了,是否有任何用户语音请求没有在WCF中正确实现?对于今年以后阅读并发现没有任何效果的人,我已经尝试了几个小时的各种选择。在我将第一行代码(allow origin)放入WCF方法主体之前,一切都不起作用。(不在某些GetOptions()方法中。)
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");
    [WebInvoke(Method = "OPTIONS", UriTemplate = "")]
    void GetOptions();
    [WebInvoke(Method = "OPTIONS", UriTemplate = "{id}")]
    void GetOptions(string id);
protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.End();
    }
}