Gil Fink on .Net

Fink about IT

News

Microsoft MVP

MCPD Enterprise Applications Developer

Gil Fink

My Linkedin profile

Locations of visitors to this page

Creative Commons License

Blog Roll

Hebrew MSDN Articles

Index Pages

My OSS Projects

Making Cross-Domain Ajax Requests for a Data Service

Making Cross-Domain Ajax Requests for a Data Service

One problem that exists when Making Cross-Domain Ajax Requests for a Data Service
using ADO.NET data services is
cross-domain requests. For security
reasons, XMLHTTP requests don’t
allow cross-domain HTTP requests.
So what can we do if we want to
make an Ajax call for a data service
that isn’t located in our domain? this post will try to give a solution to this
problem.

Making a Cross-Domain Ajax Request for a Data Service

As stated early in the post’s start, for security reasons, XMLHTTP
requests don’t allow cross-domain HTTP requests. But sometimes we do
want to consume data services that aren’t located on our domain through
Ajax. The solution to making requests to a service outside our domain 
is to implement a cross-domain proxy service. It means to create
a private service in your domain that will act as an intermediary between
your application and the data service. Your application will call the private
service and it will make the HTTP request to the data service.

How to Implement the Solution?

We can use WCF to create an Ajax-enabled endpoint using WebHttpBinding
and JSON serialization. One of the cons for such an implementation is
that we are using a traditional SOAP-based WCF service and not the fully
functionality of the data service.

Example

The following example will help you to understand how to implement the
solution proposed early. You can download the example code from
here.

Building the Data Service
We are going to use the same database that I used in my previous posts
in the data services series. The data service is a school service based upon
the following EDM mapping of entity framework:
School Entity Designer Diagram
The code for the data service is very simple and is only for the demonstration
of the post solution:

namespace SchoolDataService
{
    public class SchoolDataService : DataService<SchoolEntities>
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(IDataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
        }
    }
}

Building the Cross-Domain Proxy Service
In order to build the proxy service we need to build service
contracts and data contracts for every operation and entities
that we want to expose from the consumed data service. In the
following example I’m going to implement the GetCourseByID
operation through the proxy service. The following code demonstrate
how to do so:

namespace ConsumerApplication
{
    [DataContract]
    public class CourseEntity
    {
        [DataMember]
        public int CourseID { get; set; }
 
        [DataMember]
        public string Title { get; set; }
 
        [DataMember]
        public string Days { get; set; }
 
        [DataMember]
        public DateTime Time { get; set; }
 
        [DataMember]
        public string Location { get; set; }
 
        [DataMember]
        public int Credits { get; set; }
    }
 
    [ServiceContract(Namespace = "mysite")]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ProxyService
    {
        #region Members
 
        private SchoolEntities _proxy = new SchoolEntities(
             new Uri("http://localhost:2811/SchoolDataService.svc"));
 
        #endregion
 
        #region Service Methods
 
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public CourseEntity GetCourseByID(int courseID)
        {
            var returningCourse = (from course in _proxy.Course
                                   where course.CourseID == courseID
                                   select course).ToList().First();
            return new CourseEntity
            {
                CourseID = returningCourse.CourseID,
                Credits = returningCourse.Credits,
                Days = returningCourse.Days,
                Location = returningCourse.Location,
                Time = returningCourse.Time,
                Title = returningCourse.Title
            };
        }
 
        #endregion
    }
}

Pay attention that in order to consume the service from client
side you need to configure the host to use the
WebScriptServiceHostFactory. To do so go to the service markup and
write the following code:

<%@ ServiceHost Language="C#" Debug="true" 
Service="ConsumerApplication.ProxyService" CodeBehind="ProxyService.svc.cs" 
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>

Building the Consuming Web Form
The following code demonstrate the consuming page of the
proxy service:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ConsumerApplication._Default" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>   
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Services>
            <asp:ServiceReference Path="~/ProxyService.svc" />
        </Services>
    </asp:ScriptManager>
    <div id="content">        
    </div>
    <script type="text/javascript">
   1:  
   2:         function pageLoad() {
   3:             var proxy = new mysite.ProxyService();
   4:             proxy.GetCourseByID(1045, OnSuccess, onerror)
   5:         }
   6:  
   7:         function OnSuccess(result) {
   8:             var div = $get("content");             
   9:             div.innerText = result.Title;
  10:         }
  11:  
  12:         function OnError(result) {
  13:             // do something about the error
  14:         }
  15:  
  16:         pageLoad();
  17:     
</script>
    </form>
</body>
</html>

Summary

Lets sum up, in today’s post I gave a solution for making cross-domain
Ajax
requests to a data service. The solution has some cons like
using a traditional SOAP-based WCF service but it is ideal if you want
to consume public data service from other domains.

DotNetKicks Image

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# April 20, 2009 3:32 PM

Will Smith said:

The work around is to not use the xmlhttp object, but, instead to use json and script tags.  No need for the proxy service.

www.25hoursaday.com/.../JSONVsXMLBrowserSecurityModel.aspx

www.json.com/.../json-vs-rocky

# April 20, 2009 4:40 PM

Summary 20.04.2009 « Bogdan Brinzarea’s blog said:

Pingback from  Summary 20.04.2009 &laquo;  Bogdan Brinzarea&#8217;s blog

# April 21, 2009 3:51 PM

Kyle Simpson said:

You could use flXHR (http://flxhr.flensed.com) which is a cross-domain capable Ajax solution, with an identical API to the native XHR object. This means it can just be dropped into a page and it just works like normal Ajax, but with cross-domain ability.

# April 22, 2009 9:34 PM

Boris Reitman said:

Hello,

I have implemented a similar solution:

code.google.com/.../crossxhr

# May 3, 2009 4:47 PM

Gil Fink on .Net said:

Making Cross-Domain Ajax Requests for a Data Service Revisited A month ago I released the post Making

# May 19, 2009 1:03 PM