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

    להגיב