如何使用WCF自托管处理Ajax JQUERY POST请求

Dr.*_*YSG 14 wcf jquery http-post wcf-data-services

创建RESTful WCF服务器有很多原因(很容易),如果你可以避免ASP及其安全框(如果你所做的只是返回信息的简单请求),那就更好了.请参阅:http://msdn.microsoft.com/en-us/library/ms750530.aspx了解如何执行此操作.

我发现处理AJAX(JQUERY)GET请求很容易.但是在POST中处理JSON很棘手.

以下是一个简单的GET请求合同的示例:

    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    String Version();
Run Code Online (Sandbox Code Playgroud)

实现就在这里(返回一个JSON)

    public partial class CatalogService : ICatalogService
{
    public String Version()
    {
        mon.IsActive = true;
        this.BypassCrossDomain();
        ViewModel.myself.TransactionCount++;
        return ViewModel.myself.VersionString;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    BuildResponse BuildToby(BuildRequest request);
Run Code Online (Sandbox Code Playgroud)

它将接收JSON消息,反序列化为Plain .NET对象(PO​​NO)并让您使用它.事实上,当我在Fiddler中构建请求时,这工作正常.

POST /BuildToby HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: localhost:4326
Content-Length: 1999
Run Code Online (Sandbox Code Playgroud)

但是,当您在JQUERY 1.8中使用以下AJAX时,您会发现一个SURPRISE:

通过指定"application/json"的内容类型,您会发现有一个"预检"检查由浏览器触发,以查看您是否可以发布除了www-url-encloded post消息之外的其他内容.(堆栈中有关于此溢出的注释).

    var request = JSON.stringify({ FrameList: ExportData.buildList });
    var jqxhr = $.ajax({
    type: "POST",
    url: "http://localhost:4326/BuildToby",
    data: request,
    contentType: "application/json; charset=utf-8",
    dataType: "json"
});
Run Code Online (Sandbox Code Playgroud)

这是fiddler报告的内容:(注意它不是POST消息,而是OPTIONS消息).

OPTIONS http://localhost:4326/BuildToby HTTP/1.1
Host: localhost:4326
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://ysg4206
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Run Code Online (Sandbox Code Playgroud)

发生的事情是浏览器(在这种情况下是Firefox)必须使用OPTIONS HTTP消息对服务器进行额外调用,以查看是否允许POST(此内容类型).

所有关于修复它的文章都是关于编辑GLOBAL.ASAX,如果你在ASP.NET中这很好,但是如果你正在做一个自主WCF则没用.

所以现在你看到了这个问题(对不起这么长时间的啰嗦,但我想把它作为一篇完整的文章,以便其他人可以关注结果).

Dr.*_*YSG 26

好的,现在有一些真正的MSDN专家,他们有书面解决方案,但我无法弄清楚:http: //blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support -in-wcf.aspx

但我想出了一个简单的解决方案.至少在WCF 4.5中,您可以添加自己的OperationContract来处理OPTIONS请求:

    [OperationContract]
    [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
    void GetOptions();
Run Code Online (Sandbox Code Playgroud)

请注意,方法签名是void,并且没有参数.首先调用它,然后调用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");
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是你所要做的一切.

您可能还希望将此属性添加到服务类,以便可以序列化大型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", "*");
    }
}
Run Code Online (Sandbox Code Playgroud)

注意我有一个叫做BypassCrossDomain()的小辅助方法,我调用了所有的POST和GET方法,以便我可以处理跨域调用.

我在这里花了很多研究时间(在MSDN论坛,堆栈溢出,博客),我希望这将有助于其他人尝试做这些类型的项目.