WCF and ASP.NET AJAX Integration

26 במאי 2008

תגיות: , , ,
תגובה אחת

WCF and ASP.NET AJAX Integration


This post is part of WCF REST Presentation I show last week at Microsoft. 


I played with the WCF and ASP.NET AJAX integration, and created a sample web site which by can integrate WCF service with Microsoft Virtual Earth.


Virtual Earth: Starbucks Manhattan 


The Service Contract


The following contract is simple service contract with one method GetLocation(). The namespace "Sample.Services" will be used later as a prefix to the generated proxy.


AspNetCompatibilityRequirementsMode allows the service to use ASP.NET features, such as accessing HttpContext object or identity impersonation.



[ServiceContract(Namespace = "Sample.Services")]


[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]


public class MapService


{


    [OperationContract]


    public Location GetLocation(Target target)


    {       


        Double latitude = 0;


        Double longitude = 0;


        if (target.Name == "Starbucks Manhattan")


        {


            latitude = 40.70456;


            longitude = -74.01317;


        }


        Location location = new Location


        {


            Latitude = latitude,


            Longitude = longitude


        };


        return location;


    }


}


[DataContract]


public class Location


{


    [DataMember]


    public Double Latitude


    {


        get;


        set;


    }


    [DataMember]


    public Double Longitude


    {


        get;


        set;


    }


}


[DataContract]


public class Target


{


    [DataMember]


    public String Name


    {


        get;


        set;


    }


}



The Script


The interesting point here is how you access the service itself – by adding the namespace prefix (if not exist use default Tempuri.org).


You can also notice how I'm sending a complex parameter 'target' which is not a basic type, but complex – I use JSON directly .


var map;
var index = 0;



function LoadMap()
{   
    map = new VEMap('VEMap');
    map.LoadMap();   
}



function WebServiceCallBack(response)
{    
    AddPushPin(response);                                     
}


function AddPushPin(point)
{      
    var pin = new VEPushpin(
        index,
        new VELatLong(point.Latitude, point.Longitude),
        null,
        point.Name,
        point.Description); 
        index++;
    map.AddPushpin(pin);        
    map.PanToLatLong(new VELatLong(point.Latitude, point.Longitude));
}


function OnGetTarget()
{
    var target = { "Name" : $get("target").value }; 
    Sample.Services.MapService.GetLocation(target, WebServiceCallBack, OnError);
}


function OnError(result)
{
    alert(result.get_message());
}


Proxy Generation


Try the following URL and you will get the proxy itself:


http://localhost:49814/VirtualEarth/MapService.svc/js


Notice that the proxy created with static methods with the same signature as the methods on the service itself, and as additional, adds callback, error handler and a user context.


Type.registerNamespace('Sample.Services');
Sample.Services.MapService=function() {
Sample.Services.MapService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
Sample.Services.MapService.prototype={
_get_path:function() {
var p = this.get_path();
if (p) return p;
else return Sample.Services.MapService._staticInstance.get_path();},
GetLocation:function(target,succeededCallback, failedCallback, userContext) {
return this._invoke(this._get_path(), 'GetLocation',false,{target:target},succeededCallback,failedCallback,userContext); }}
Sample.Services.MapService.registerClass('Sample.Services.MapService',Sys.Net.WebServiceProxy);
Sample.Services.MapService._staticInstance = new Sample.Services.MapService();
Sample.Services.MapService.set_path = function(value) { Sample.Services.MapService._staticInstance.set_path(value); }
Sample.Services.MapService.get_path = function() { return Sample.Services.MapService._staticInstance.get_path(); }
Sample.Services.MapService.set_timeout = function(value) { Sample.Services.MapService._staticInstance.set_timeout(value); }
Sample.Services.MapService.get_timeout = function() { return Sample.Services.MapService._staticInstance.get_timeout(); }
Sample.Services.MapService.set_defaultUserContext = function(value) { Sample.Services.MapService._staticInstance.set_defaultUserContext(value); }
Sample.Services.MapService.get_defaultUserContext = function() { return Sample.Services.MapService._staticInstance.get_defaultUserContext(); }
Sample.Services.MapService.set_defaultSucceededCallback = function(value) { Sample.Services.MapService._staticInstance.set_defaultSucceededCallback(value); }
Sample.Services.MapService.get_defaultSucceededCallback = function() { return Sample.Services.MapService._staticInstance.get_defaultSucceededCallback(); }
Sample.Services.MapService.set_defaultFailedCallback = function(value) { Sample.Services.MapService._staticInstance.set_defaultFailedCallback(value); }
Sample.Services.MapService.get_defaultFailedCallback = function() { return Sample.Services.MapService._staticInstance.get_defaultFailedCallback(); }
Sample.Services.MapService.set_path("/VirtualEarth/MapService.svc");
Sample.Services.MapService.GetLocation= function(target,onSuccess,onFailed,userContext) {Sample.Services.MapService._staticInstance.GetLocation(target,onSuccess,onFailed,userContext); }
var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;
if (typeof(Target) === 'undefined') {
var Target=gtc("Target:http://schemas.datacontract.org/2004/07/
Target.registerClass('Target');
}
if (typeof(Location) === 'undefined') {
var Location=gtc("Location:http://schemas.datacontract.org/2004/07/
Location.registerClass('Location');
}


The ASP.NET Page


<html xmlns="http://www.w3.org/1999/xhtml >
    <head id="Head1" runat="server">
        <title></title>
    </head>
    <body onload="LoadMap();">


        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Scripts>
                    <asp:ScriptReference Path="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5 />
                    <asp:ScriptReference Path="mapscripts.js" />
                </Scripts>
                <Services>
                    <asp:ServiceReference Path="MapService.svc"  />
                </Services>
            </asp:ScriptManager>
            <div style='width: 800px; height: 500px; position: relative; overflow: hidden;' id='VEMap'></div>   


            Enter target: <input type="text" id="target" />


            <input type="button" value="get target" onclick="OnGetTarget()" /><br />
            <br />
        </form>
    </body>
</html>


The Service File


The WebScriptServiceHostFactory adds ASP.NET AJAX endpoint the the service, and all of this without a line of configuration!!


When you specify the WebScriptServiceHostFactory, it creates a ServiceHost with the appropriate binding and behavior for integration with ASP.NET AJAX.


<%@ ServiceHost Language="C#" Debug="true" Service="MapService" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>


Conclusion


To summarize the WCF and ASP.NET AJAX Integration:



  • Full support in client stack

  • Provides proxy generation

  • Supports GET and POST only

  • Does not support UriTemplates

  • No configuration using WebScriptServiceHostFactory

  • And finally, works in ASP.NET medium trust

The source code of WCF and ASP.NET AJAX Integration.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

תגובה אחת

  1. David9 ביוני 2009 ב 12:57

    Hi mate,
    Thanks for this great article. I followed the same process that you have here but when I publish my WCF service it is asking for username and password. Any idea how to fix this?
    Thanks

    להגיב