zoukankan      html  css  js  c++  java
  • CrossDomain AJAX Enabled WCF Service

    Background

    For the basic of how to create an AJAX enabled WCF service, please refer to MSDN: http://msdn.microsoft.com/en-us/library/bb924552.aspx.

    For the basic of JSONP, please refer to: http://en.wikipedia.org/wiki/JSON#JSONP.

    This article introduce how to make AJAX enabled WCF service support cross-domain request.

    In the WCF & WF samples provided by Microsoft, there is already a “custom binding extension” implementation for JSONP support. But there is some limitation, the biggest limitation is it could not support both JSON & JSONP protocol for one AJAX enabled WCF service URL, and it requires each endpoint you want to support JSONP protocol be configured with the specific custom JSONP binding extension which increased configuration complexity & cost.

    Here I introduce a more general “custom Http Module” implementation for cross-domain calling AJAX enabled WCF services.

    At the beginning, firstly, please realize WCF does not support custom Http Modules by default, which means, by default, a WCF service request, even a webHttpBinding AJAX enabled WCF service request, doesn’t go through any custom Http Modules. To enable it, you need to set the aspNetCompatibilityEnabled property of serviceHostingEnvironment element to true like below:

     <system.serviceModel>
       
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
       ...
    </system.serviceModel>

    And to enable a WCF service support custom Http Module, you also need to mark the AspNetCompatibilityRequirementsAttribute on the service contract like below:

    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode
    =AspNetCompatibilityRequirementsMode.Allowed)]
    public class TestAjaxClientService
    {
           ...
    }

    JSONPModule

    Since with the aspNetCompatibilityEnabled property set to true, an Http WCF service request goes through custom Http Modules, it is possible to write a custom Http Module to automatically convert any JSON response to JSONP response. And actually, since it will be so general, it could not only give JSONP support to WCF, but also give JSONP support to any existing JSON response services, such as Web services and Http handler services. The JSONPModule class below is part of NIntegrate framework (BSD license), but it has no dependency. So you could use it freely and independently.

    JSONPModule.cs
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Web;

    namespace NIntegrate.Web
    {
        
    public class JSONPModule : IHttpModule
        {
            
    private const string JSON_CONTENT_TYPE = "application/json";
            
    private const string JS_CONTENT_TYPE = "text/javascript";

            
    #region IHttpModule Members

            
    public void Dispose()
            {
            }

            
    public void Init(HttpApplication app)
            {
                app.ReleaseRequestState 
    += OnReleaseRequestState;
            }

            
    #endregion

            
    public void OnReleaseRequestState(object sender, EventArgs e)
            {
                HttpApplication app 
    = (HttpApplication)sender;
                HttpResponse response 
    = app.Response;
                
    if (response.ContentType.ToLowerInvariant().Contains(JSON_CONTENT_TYPE)
                    
    && !string.IsNullOrEmpty(app.Request.Params["jsoncallback"]))
                {
                    response.ContentType 
    = JS_CONTENT_TYPE;
                    response.Filter 
    = new JsonResponseFilter(response.Filter);
                }
            }
        }

        
    public class JsonResponseFilter : Stream
        {
            
    private readonly Stream _responseStream;
            
    private long _position;

            
    private bool _isContinueBuffer;

            
    public JsonResponseFilter(Stream responseStream)
            {
                _responseStream 
    = responseStream;
            }

            
    public override bool CanRead { get { return true; } }

            
    public override bool CanSeek { get { return true; } }

            
    public override bool CanWrite { get { return true; } }

            
    public override long Length { get { return 0; } }

            
    public override long Position { get { return _position; } set { _position = value; } }

            
    public override void Write(byte[] buffer, int offset, int count)
            {
                
    string strBuffer = Encoding.UTF8.GetString(buffer, offset, count);
                strBuffer 
    = AppendJsonpCallback(strBuffer, HttpContext.Current.Request);
                
    byte[] data = Encoding.UTF8.GetBytes(strBuffer);
                _responseStream.Write(data, 
    0, data.Length);
            }

            
    private string AppendJsonpCallback(string strBuffer, HttpRequest request)
            {
                
    string prefix = string.Empty;

                
    if (!_isContinueBuffer)
                {
                    prefix 
    = request.Params["jsoncallback"+ "(";
                    _isContinueBuffer 
    = true;
                }

                
    return prefix + strBuffer;
            }

            
    public override void Close()
            {
                
    string suffix = ");";
                
    byte[] data = Encoding.UTF8.GetBytes(suffix);
                _responseStream.Write(data, 
    0, data.Length);

                _responseStream.Close();
            }

            
    public override void Flush()
            {
                _responseStream.Flush();
            }

            
    public override long Seek(long offset, SeekOrigin origin)
            {
                
    return _responseStream.Seek(offset, origin);
            }

            
    public override void SetLength(long length)
            {
                _responseStream.SetLength(length);
            }

            
    public override int Read(byte[] buffer, int offset, int count)
            {
                
    return _responseStream.Read(buffer, offset, count);
            }
        }
    }

    Sample

    The sample in this chapter is a unit test of NIntegrate for the JSONPModule. Imagine we have an AJAX enabled WCF service – TestAjaxClientService.svc, which could be called by jQuery like below:

           jQuery.getJSON('http://localhost:2166/TestAjaxClientService.svc/Hello'function(data) { alert('inner-domain called by jQuery through normal JSON protocol: ' + data.d); });

    With the JSONPModule configured like below:

     <system.web>
       ...
       
    <httpModules>
         ...
         
    <add name="JSONPModule" type="NIntegrate.Web.JSONPModule, NIntegrate, Version=X.X.X.X, Culture=neutral, PublicKeyToken=e2b9e2165dbdd5e6"/>
       
    </httpModules>
     
    </system.web>
     ...
     
    <system.webServer>
       ...
       
    <modules>
         ...
         
    <add name="JSONPModule" preCondition="managedHandler" type="NIntegrate.Web.JSONPModule, NIntegrate, Version=X.X.X.X, Culture=neutral, PublicKeyToken=e2b9e2165dbdd5e6"/>
       
    </modules>
       ...
     
    </system.webServer>

    We can cross-domain call the TestAjaxClientService.svc like:

           jQuery.getJSON('http://127.0.0.1:2166/TestAjaxClientService.svc/Hello?jsoncallback=?'function(data) { alert('cross-domain called by jQuery through JSONP protocol (no cache): ' + data.d); });
          
    function jsonpCallback(data) {
               alert(
    'cross-domain called by jQuery through JSONP protocol (cached): ' + data.d);
           }
           jQuery.ajaxSetup({ cache: 
    true });
           jQuery.getScript(
    'http://127.0.0.1:2166/TestAjaxClientService.svc/Hello?jsoncallback=jsonpCallback');
           jQuery.ajaxSetup({ cache: 
    false });
  • 相关阅读:
    AIO5岗位桌面主页【我的收藏夹】只显示8行,怎样增加显示行?
    已设置了参考编号的编码规则定义,但是新增单据的时候,没有出来自动编号是什么原因?
    10个TWaver 网页3D可视化精彩案例
    HTML5大数据可视化效果(二)可交互地铁线路图
    无插件纯web 3D机房 (第四季:大型园区、地球仪效果和其他扩展应用)
    一款基于HTML5的Web 3D开发工具
    Legolas工业自动化平台入门(三)交互事件响应动作
    Legolas工业自动化平台入门(二)数据响应动作
    Legolas工业自动化平台入门(一)搭建应用
    Legolas工业自动化平台案例 —— 水源地自动化监控系统
  • 原文地址:https://www.cnblogs.com/teddyma/p/1679982.html
Copyright © 2011-2022 走看看