Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

WCF REST Configuration for ASP.NET AJAX and plain REST Services


:P
On this page:

If you've been thinking about using ASP.NET Ajax in combination with WCF, life got a lot easier with .NET 3.5 and the new REST support. The webHttp binding along with the ASP.NET AJAX specific version makes it easy to use WCF instead of ASMX services with ASP.NET AJAX.

A valid question to ask though is: Do I need to use WCF or should I continue to use ASMX?

If ASMX services are working fine for you as is with MS AJAX you probably don't have to switch. In fact if your services are purely based on making AJAX callbacks from a pure Web app and you don't plan on reusing existing services, there's not much of an advantage using  WCF over ASMX services. ASMX services continue to be easier to set up and work with and maybe more importantly they don't require .NET 3.5.

WCF REST services however provide features that ASMX does not, such as the ability to serve raw non-ASP.NET AJAX formatted data in 'bare' format. If you're working with non-ASP.NET AJAX clients like jQuery or Prototype this can be a bonus and lets you avoid using the MS AJax client libraries and ScriptManager. WCF REST also supports raw XML based access to services which is also useful and can't be directly accomplished with ASMX.

Another consideration: If you have existing services that rely on HttpContext, realize that WCF by default doesn't support access to the underlying 'host platform'. WCF is supposed to be host agnostic and WCF services can in fact be running outside of IIS. If you have existing code that relies on HttpContext access to the Request or Session object which is common , it's probably best to leave it in ASMX (although WCF has a way to do that as well).

But if you're starting a new app and you're using .NET 3.5 on the server anyway you might as well take advantage of WCF's REST/Ajax features and the wider range of options available to publish data.

Configuration, Configuration, Configuration

The biggest issue with any WCF application is configuration. Fortunately Microsoft figured this one for .NET 3.5 out and created a number of WebService Host Factories that provide default settings that apply to the most common service implementations. With these Service factories only a Factory tag is required on the Service, without any further configuration in web.config.

You can create a new WCF service and add the following Factory tag to the generated .SVC file:

<%@ ServiceHost Language="C#"       
                Service="WcfAjax.MsAjaxStockService"  
                CodeBehind="MsAjaxStockService.svc.cs"    
                Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
%>

For MS AJAX style Web Service the factory is WebScriptServiceFactory. If you want to provide other REST services such as for raw (un-wrapped) AJAX, XML or raw data there's a WebServiceHostFactory. When used no web.config settings need to be set manually and if there are settings in Web.config that apply to this service they are in fact ignored.

To put this into perspective here's a small service contract:

namespace WcfAjax
{
  [ServiceContract(Name="StockService",Namespace="MsAjaxStockService")]    
  public interface IMsAjaxStockService
  {
    [OperationContract]          
    StockQuote GetStockQuote(string symbol);
 
    [OperationContract]
    StockQuote[] GetStockQuotes(string[] symbols);
 
    [OperationContract]        
    StockHistory[] GetStockHistory(string symbol, int years);
 
    [OperationContract()]
    [WebInvoke(Method = "GET")]
    Stream GetStockHistoryGraph(string[] symbol, string title, int width, int height, int years);
 
    [OperationContract()]
    [WebInvoke(Method = "GET")]
    Stream GetStockHistoryGraphSingle(string symbol, string title, int width, int height, int years);
}
}

and its implementation class that implements the contract:

    public class MsAjaxStockService : IMsAjaxStockService

    {
        private StockServer Stocks = new StockServer();        
 
        public StockQuote GetStockQuote(string symbol)
        {
            string path = HttpContext.Current.Request.Path;
            return Stocks.GetStockQuote(symbol);
        }
 
        public StockQuote[] GetStockQuotes(string[] symbols)
        {
            return GetStockQuotes(symbols);
        }
 
        public StockQuote[] GetStockQuotesSafe(string symbolList)
        {
            string[] symbols = symbolList.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            return Stocks.GetStockQuotes(symbols);
        }
 
        public StockHistory[] GetStockHistory(string symbol, int years)
        {
            return Stocks.GetStockHistory(symbol, years);
        }
 
        public Stream GetStockHistoryGraph(string[] symbols, string title, int width, int height, int years)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";    
 
            byte[] imgData =  Stocks.GetStockHistoryGraph(symbols, title, width, height, years);          
            MemoryStream ms = new MemoryStream(imgData);
            return ms;
        }
 
 
        public Stream GetStockHistoryGraphSafe(string symbolList, string title, int width, int height, int years)
        {
            string[] symbols = symbolList.Split(new  char[1] {','},StringSplitOptions.RemoveEmptyEntries);
            return this.GetStockHistoryGraph(symbols,title,width,height,years);
        }
 
 
        public Stream GetStockHistoryGraphSingle(string symbol, string title, int width, int height, int years)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";    
 
            byte[] imgData = Stocks.GetStockHistoryGraph(new string[1] { symbol }, title, width, height, years);
 
            MemoryStream ms = new MemoryStream(imgData);
            return ms;
 
        }
}

With the Web Service Factory defined in the Web Service .SVC file in your web project you are pretty much done. The service can be accessed directly from an ASP.NET AJAX client page that has the script reference to the service embedded via script manager:

<asp:ScriptManager ID="ScriptManager" runat="server">
    <Services>
        <asp:ServiceReference Path="~/MsAjax/MsAjaxStockService.svc" />            
    </Services>
</asp:ScriptManager>

To debug that everything is working right with your service compilation and configuration access the service directly. So

MsAjaxStockService.svc/jsdebug

which is the URL that retrieves the client side JavaScript proxy that you can use to call the Web Service. I also like to look at the .js output in this file because it tells you EXACTLY what the name of the proxy is.

JavaScript Service Proxy Reference Naming

The reason for looking at the JSDEBUG content is that WCF defaults the name of the proxy instance as Namespace.Classname. The name might be a bit unexpected because unlike ASMX which used the .NET class namespace, WCF uses the URI namespace. Check out the generated proxy header for a default Web Service implementation that doesn't have a custom name or namespace set which has a namespace of http://tempuri.org):

Type.registerNamespace('tempuri.org');
tempuri.org.IMsAjaxStockService=function() {
tempuri.org.IMsAjaxStockService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
tempuri.org.IMsAjaxStockService.prototype={
_get_path:function() {
 var p = this.get_path();
 if (p) return p;
 else return tempuri.org.IMsAjaxStockService._staticInstance.get_path();},

GetStockQuote:function(symbol,succeededCallback, failedCallback, userContext) {
..

which results in client code like this for you to call the service from JavaScript client code:

tempuri.org.IMsAjaxStockService.MsAjaxStockService.GetStockQuote
(
            "MSFT",
            function(result)
            {  alert(result.LastPrice); },
            function(error) 
            { alert(result.get_Message()); }
);

which is uhm a bit verbose for the namespace prefix. If you use your own regular URI based namespaces WCF strips out all the slashes and replaces them with dots. Originally I used a custom namespace - http://www.west-wind.com/services/MsAjaxStockService which is a pretty standard format for Web Services. It  ended up in the JavaScript proxy like this:

www.westwind.com.services.MsAjaxStockService.StockService

which is a mouthful to say the least.

Thankfully you can override the naming of the service and namespace on the service contract however, which I applied in the service above:

    [ServiceContract(Name="StockService",Namespace="MsAjaxStockService")] 

This results in the more usable:

MsAjaxStockService.StockService.GetQuote()

If your service is locally consumed in your application only you can set the Namespace attribute to an empty string and skip the namespace altogether. Otherwise using the namespace is probably a good idea to avoid naming conflicts.

What you gain and what you lose

Using AJAX with WCF in this fashion doesn't really bring much in the way of new features over ASMX, but it does bring a more isolated service model by default. Creating a WCF REST service allows you to run your REST service potentially outside of IIS. These REST services can be hosted in any WCF Host container including standalone Windows applications, Services or Console applications.

But this isolated service environment also removes any dependencies on ASP.NET by default. This means that there's no HttpContext.Current available to read input data from the Request object, access the Session object etc. WCF includes its own ServiceContext that provides many of these same features. REST services in addition get a WebOperationRequestContext that allows access to the inbound and outbound HTTP headers.

For example WCF allows streaming of raw binary content to the client as part of the service API which allows you to publish binary data like images, but also arbitrary HTTP content like HTML or even something like an RSS feed. Here's an example of my service publishing a portfolio stock history graph:

public Stream GetStockHistoryGraph(string[] symbols, string title, int width, int height, int years)
{
    WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";    
 
    byte[] imgData =  Stocks.GetStockHistoryGraph(symbols, title, width, height, years);          
    MemoryStream ms = new MemoryStream(imgData);
    return ms;
}

The WebOperationContext is required to set the output content type of the raw stream here. You can also use the OperationContext.Current instance to get addtional information about the service or the security applied to it.

WCF REST also supports accessing the HttpContext from the service by using a configuration setting, but this is generally not recommended because it ties the service directly to ASP.NET and will prevent it from being hosted outside of IIS/WAS.

To add ASP.NET compatibility though you can't use the ServiceHostFactory since it ignores configuration settings. So you need to manually configure the service.

Manual .Config File Configuraion of WCF Script Services

But you can also manually configure the service using traditional serviceModel settings in web.config (or .Config when running outside of IIS). I had a bit of trouble getting these configuration settings just right for this service - there are a few posts and articles out there  (including one of my own <blush>) which are out of date with beta settings so I floundered around a bit.

The service mapping from SVC file to the .Config settings also isn't obvious and not mentioned in hte MSDN configuration documentation. Most of my problems were simply caused by having the wrong service name in web.config.

The following is the manual configuration for the above Script Service, plus it adds support for ASP.NET compatibility:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <services>
    <service name="WcfAjax.MsAjaxStockService">
      <endpoint address=""
                behaviorConfiguration="MsAjaxStockServiceBehavior"
                binding="webHttpBinding"
                contract="WcfAjax.IMsAjaxStockService" />
    </service>
  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="MsAjaxStockServiceBehavior">
        <enableWebScript />                              
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>

The service name must match the name of the service class that implements the service. This should be the same value specified inside of the SVC file's Service="" attribute:

<%@ ServiceHost Language="C#"       
                Service="WcfAjax.MsAjaxStockService"  
                CodeBehind="MsAjaxStockService.svc.cs"    
%>

Note again that if you have both web.config settings and a Factory tag in the service file, the Factory takes precendence and ignores any web.config settings. If things aren't working as you think be sure to check both the service file and the .config to make sure you're running the right configuration code!

The settings above are specific for an ASP.NET AJAX style script service. The MS Ajax implementation provides a few few special features like the ability to access the proxy via the /jsdebug switch of the service url as well as formatting messages using Microsoft's funky JSON formatting that is essentially a wrapped set of all the parameters and a type wrapped response message.

Http Context Usage in WCF Services

Back to this issue once more. If you want to use HttpContext in your WCF REST services you need to

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

to the web.config file. This is a global setting that then applies to all services hosted inside of IIS/ASP.NET.

In addition, you also need to specify that the class either Allows or Requires ASP.NET Compatibility:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MsAjaxStockService : IMsAjaxStockService

Note that once the setting is made in web.config each REST service MUST have this attribute, or ASP.NET will throw an exception to the affect that AspNetCompatibility is not specified. Odd design choice on the WCF team's part - the default should be if not specified to ignore it but apparently the WCF REST folks are very keen on hardcoding everything into attributes (which is not optimal for many things as you'll see in a minute).

Plain REST/Ajax Services

If your goal is to have a plain AJAX client like jQuery call WCF REST services you need to use a slightly different type of service implementation using the webHttp binding. Unlike the webScriptBehavior that MS AJAX uses this mechanism supports a variety of different formats for the data that is sent to the server and how it's returned. There are quite a few more options to specify and there's lots of configurability but it's also a bit more complex to get the configuration right.

Again let's do the easy route first - simply using a service factory like this:

<%@ ServiceHost Language="C#"
    Debug="true" CodeBehind="RestStockService.svc.cs"
    Service="WcfAjax.RestStockService"    
    Factory="System.ServiceModel.Activation.WebServiceHostFactory" 
%>

In order to have both MS Ajax and Raw REST access to the service I have to now implement a complete separate contract. This is - unfortunately - because WCF requires that each service end point operation/method describes EXACTLY what type of data it expects. Here's the contract for the REST interface:

 
namespace WcfAjax
{
 
    [ServiceContract]
    public interface IRestStockService
    {
        [OperationContract]
        [WebInvoke(
            Method="GET",
            RequestFormat =WebMessageFormat.Json,            
            ResponseFormat= WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate= "GetStockQuote/{symbol}")
        ]
        StockQuote GetStockQuote(string symbol);
 
        [OperationContract(Name="GetStockQuotes")]
        [WebInvoke(
            Method = "GET", 
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate="GetStockQuotes/{symbols}")            
        ]
        StockQuote[] GetStockQuotesSafe(string symbols );
 
        // *** This won't work with GET operation
        //StockQuote[] GetStockQuotes(string[] symbols);
 
 
        [OperationContract]
        [WebInvoke(
            Method = "GET",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)
            //UriTemplate = "GetStockHistory/{symbol}/{years}") // doesn't work
        ]
        StockHistory[] GetStockHistory(string symbol, int years);
 
        [OperationContract(Name="GetStockHistoryGraph")]
        [WebInvoke(Method = "GET")]        
        Stream GetStockHistoryGraphSafe(string symbols, string title, int width, int height, int years);
 
        [OperationContract()]
        [WebInvoke(Method = "GET")]
        Stream GetStockHistoryGraphSingle(string symbol, string title, int width, int height, int years);
 
    }

}

The plain REST interface requires that you are very explicit about what type of messages each operation/method can receive. You have to specify explicit GET or POST (or PUT,DELETE or custom) and the service will only respond to that type of message. In addition the body format - JSON or XML basically is also fixed so a single URL cannot serve both JSON and XML.

Even using the cool new UriTemplates which allow you to create more readable URLs, you still can't have one endpoint that serves data in different formats. I suspect that's a fairly common scenario that unfortunately doesn't work.

The implementation of the above interface looks identical to the implementation I showed before. But because WCF doesn't support multiple ServiceContracts implemented on a single type I can't just reuse the existing base class.

So this doesn't work:

public class MsAjaxStockService : IMsAjaxStockService, IRestStockService

Another bummer. But there's a workaround for this with a little trickery and by creating a base class. You still need to create separate contract interfaces for IMsAjaxStockService and IRestStockService, but you can have one base class:

public class StockServiceBase 

{
   // Full implementation code here
}

and then inherit from it with the concrete service implementations:

public class MsAjaxStockService : StockServiceBase, IMsAjaxStockService

{ // no code here }

public class RestStockService : StockServiceBase, IRestStockService
{ // no code here }

Each class now implements its specific service contract interface, but inherits the entire implementation from the StockServiceBase which contains all the implementation details.

Configuration of plain REST Services

REST services - like the MS AJAX style script service - can also be configured either via a service host factory or by configuring the .Config file. The configuration is similar but there are a few differences. Here's the configuration for the above service for the plain REST implementation:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <services>
    <service name="WcfAjax.RestStockService">
      <endpoint address=""
                behaviorConfiguration="RestStockServiceBehavior"
                binding="webHttpBinding"
                contract="WcfAjax.IRestStockService" />
    </service>
  </services>
  <behaviors>
      <behavior name="RestStockServiceBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>

Note again that the SVC Service attribute should match the service name in the configuration. This is how the config settings are found. The key behavior setting here is specification of the <webHttp /> behavior. Without this the service will not work (even though you'd expect simply specifying the webHttpBinding would be enough).

You can of course mix multiple services together. So my particular web.config section that provides both for MS AJax and REST access looks like this:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <services>
    <service name="WcfAjax.MsAjaxStockService">
      <endpoint address=""
                behaviorConfiguration="MsAjaxStockServiceBehavior"
                binding="webHttpBinding"
                contract="WcfAjax.IMsAjaxStockService" />
    </service>

    <service name="WcfAjax.RestStockService">
      <endpoint address=""
                behaviorConfiguration="RestStockServiceBehavior"
                binding="webHttpBinding"
                contract="WcfAjax.IRestStockService" />
    </service>
  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="MsAjaxStockServiceBehavior">
        <enableWebScript />               
      </behavior>
 
      <behavior name="RestStockServiceBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
 
  </behaviors>
</system.serviceModel>

The only real difference between the two modes is in the high level behavior that is used.

It's clear that the Host factory pre-configured settings are the way to go. It's easiers and more portable - one less thing to manually configure. REST services simply won't need a lot of tweaking and configuration since all the protocol issues are driven through HTTP.  I suspect the main reason to not use the Service Factory will be for those that wish to still use HttpContext in their services for which manual configuration is required.

Posted in ASP.NET  WCF  

The Voices of Reason


 

Phil
April 11, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

So for the final (configured) solution you'd end up with two svc files, one for each entry method? Do you have a downloadable solution?
Good post. Hope the waves are good for you. Phil

Rick Strahl
April 11, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

@Phil - you'd end up with one SVC file for each service messaging mechanism *IF* you choose to support multiple type clients.

Not sure how often you would support multiple different types of messages, although it maybe useful. For internal applications I suspect a single message type is no issue. It's for public apps, where you might want to give people the flexibility to access the service either with JSON or XML where I see a potential problem.

However on IIS at least I suppose one could write a module that does URL redirection in such a way that the message format is provided as part of the URL with the module handle the appropriate routing.

For example:
MyService.svc.xml --> Rewrites to Xml Contract
MyService.svc or MyService.svc.json --> Rewrites to Json service

Stephane
April 28, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

I'm confused by your comment:

"But because WCF doesn't support multiple ServiceContracts implemented on a single type I can't just reuse the existing base class."

Actually, you should be able to implement multiple ServiceContracts on a single type. Then just define multiple endpoints on the service configuration, one pointing to the plain REST service contract, the other to the MSAjax contract, and you should be done. I created a project using your code, it seems to be working fine. I have 2 endpoints:

http://localhost/WcfAjax.RestStockService.svc/REST and http://localhost/WcfAjax.RestStockService.svc/MSAjax.

My service class implements both interfaces, and my service definition looks like this:

<service name="WcfAjax.StockService">
<endpoint address="REST" name="REST" behaviorConfiguration="RestStockServiceBehavior" binding="webHttpBinding" contract="WcfAjax.IRestStockService"/>
<endpoint address="MSAjax" name="MSAjax" behaviorConfiguration="MsAjaxStockServiceBehavior" binding="webHttpBinding" contract="WcfAjax.IMsAjaxStockService"/>
</service>

Rick Strahl
April 29, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

When I do this:

StockService : IRestStockService, IJsonStockService


I get an immediate ASP.NET compilation error when accessing the SVC file:

Service 'RestStockService' implements multiple ServiceContract types, and no endpoints are defined in the configuration file. WebServiceHost can set up default endpoints, but only if the service implements only a single ServiceContract. Either change the service to only implement a single ServiceContract, or else define endpoints for the service explicitly in the configuration file.


I can't check this this very second, though - it might be that setting the contract to the interface in the config file rather than the type (which is the default that the Wizard sets up) might do the trick. I tried both I think but maybe not in the right combination.

This also doesn't work if you use the Service Factories because they also point the contract at the concrete class rather than the interface in which case the error behavior above occurs as well.

Rick Strahl
April 29, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

@Stephane - When I do this:

StockService : IRestStockService, IJsonStockService

I get an immediate ASP.NET compilation error when accessing the SVC file:

Service 'RestStockService' implements multiple ServiceContract types, and no endpoints are defined in the configuration file. WebServiceHost can set up default endpoints, but only if the service implements only a single ServiceContract. Either change the service to only implement a single ServiceContract, or else define endpoints for the service explicitly in the configuration file.

That is if the config file points at the concrete service class. If I change that to point at the contract interface the compiler error goes away, but the type mapping from the non-primrary service (ie. a second service that points at the base implementation and doesn't have a codebehind fails to find the endpoint) still fails - I then get endpoint not found. I think what's happening there is that it's actually looking at the first contract and ignoring any of the subsequent ones.

I can't get this to work any way I tried. Only one of the contracts works for me on a given class. <shrug> The only thing that works for me is what I described in the article and create separate classes for each of the interfaces with the classes inheriting a common base services which accomplishes the same thing.

Note that if you use a ServiceHost Factory you also get a compile error if you use a single class with multiple contracts defined on the class, so I think it's probably a good idea to take the safe approach that should work in all scenarios that are supported.

Still would love to see what you're doing different to get a class to work with mutliple contracts.

Stephane
May 03, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Hey Rick,

did you configure multiple named endpoints for your service?
Anyway, here's a zipped up version of my little test project:

http://www.oceg.org/Downloads/tmp/WcfAjax.zip

The main service class only provides hooks for each method implementation, but throws NotImplementationException - I didn't have time to provide actual functionality, just wanted to get a proof of concept working.

I tried http://localhost/WcfService/StockService.svc/MSAjax/js and was able to retrieve the MS Ajax javascript proxy, which seems to indicate that the "MSAjax" endpoint is correctly set up.

If I point my browser to http://localhost/WcfService/StockService.svc/REST/GetStockQuote/MSFT, I'm able to hit a breakpoint inside the service class Get method, which means the IRestStockService UriTemplate is being used when using the "REST" endpoint.

HTH

Stephane

Roger
May 04, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

I'm having good fun with WCF and AJAX and all is swell when I run from within visual studio and the internal cassini web server. But, as soon as I try to host my web app in IIS (I'm on XP, so that'd be IIS 5.1) requests for javascript proxies going to URLs like

http://myhost/myvdir/myservice.svc/jsdebug

are met with a 404 response. Somehow or another, I need to get IIS to understand that jsdebug isn't a real file, but needs to get mapped to .NET so it can figure it out.

But I can't get it to work.

I tried downloading and building the sample posted here previously - http://www.oceg.org/Downloads/tmp/WcfAjax.zip
and its the same result. 404 when requesting the jsdebug file.


Any suggestions?

Thanks

Rick Strahl
May 04, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

You should check the main .SVC file (without the /jsdebug switch) and see if that loads. I'd guess that that file also doesn't load. Make sure you actually have the .SVC file on the server too.

In addition, make sure that .NET 3.5 is installed on the server and just as importantly that the .SVC extension is mapped properly in your extension mappings in IIS. if you're on IIS 6 or 7 you also need to make sure that you explicitly enable ASP.NET in the ISAPI and CGI restrictions... (if ASP.NET works for ASPX pages though this shouldn't be the problem).

Roger
May 05, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Thanks for your reply.
I get a different error when requesting the .svc file:

XML Parsing Error: not well-formed
Location: http://localhost/wcfajax/StockService.svc
Line Number 1, Column 2:<%@ ServiceHost Language="C#" Debug="true" Service="WcfAjax.StockService" CodeBehind="StockService.svc.cs" %>


Which doesn't surprise me because, as you point out, neither the js jsdebug nor *.svc type files have any script mappings within IIS. And that's my problem. On my IIS 5.1 system, I am unable to edit the script maps through the IIS MMC tool. I used the adsutil.vbs script to try and add them, but that doesn't seem to have helped (long story, bottom line - no luck).

Now, I read someplace (i thought here) that .NET 3.5 actually runs as .NET 2.0 in terms of IIS's view of it. So I thought that I didn't need to install 3.5 on the server. It is the same box, and I do have 3.5 installed, at least, whatever came by way of a full visual studio installation. There is no aspnet_regiis application under the my 3.5 framework folder.

I'll suppose I'll try installing the 3.5 runtime and see if that changes anything.

Thanks again

Rick Strahl
May 05, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

The REST services require .NET 3.5 and WCF in general requires .NET 3.0 so yes, you can't just run with 2.0 and hope for the best <g>... you have to install 3.5 on the server for this to work.

Roman Rodov
May 19, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

I am also getting a 404 error when accessing a REST style url when the service is hosted in IIS. http://localhost/TestService/Service.svc/Echo?data=hello returns a 404 error. .NET 3.5 is installed and WCF is registered just fine. http://localhost/TestService/Service.svc can be accessed, just not the REST methods.

<system.serviceModel>
<services>
<service name="TestService.Service" behaviorConfiguration="default">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="default" contract="TestService.IService"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="default">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="default">
<serviceMetadata httpGetEnabled="true" httpsGetUrl="/wsdl"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

and the service contract is
[ServiceContract]
    public interface IService
    {
        [OperationContract,WebGet(UriTemplate="/Echo?test={value}")]
        string Echo(string value);

    }

Scott
June 16, 2008

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

@Roger and Roman

Found this while tracking down the same issue. Hope it helps.


On IIS configuration of extensions mappings, edit the .svc mapping and remove the "Check that file exists" checkbox. If you get Authentication errors, make sure the IIS site is not configured to allow windows integrated security, only anonymous access. In the web.config remove the <authentication mode="windows">.


-s

DotNetShoutout
November 20, 2008

# WCF REST Configuration for ASP.NET AJAX and plain REST Services

Your Story is Submitted - Trackback from DotNetShoutout

Piers Lawson
May 19, 2009

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Have you looked at using ASP.Net MVC for a RESTful webservice? Web services are not its main purpose but with a little work you get a truely RESTful web service, serving up multiple representations with the added benefit of a framework that provides, out of the box, good decoupling between the Model, View and Controller. I really should look more at the WCF implementation, and your article is great, but it just seems to be a lot of effort to get even the basics working! Then again in my series (http://www.shouldersofgiants.co.uk/Blog) about using MVC I did have to write a bit of custom (though reusable) code.

Rick Strahl
May 19, 2009

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

@Piers - if I'm going to be building a custom service type interface I wouldn't use MVC - I'd go straight to a handler or module to do so. There's nothing that MVC provides (routing maybe) that would make this any easier and you just end up with extra overhead of the MVC framework.

mabra
August 02, 2009

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Hi !

Much thanks for that good article!

What make WCF mad for me - in the IIS hosting scenario - it does not allow to specify the asp session type. I have several ajax request on a page, all serverd by WCF. Astoundingly, they are processed only sequentially!!! This is not the case, if the web is configured to be sessionless. In a usual asp page, you would set the session to be readonly, what - so far I've looked up - is not possible with hosting wcf in asp.net. Just another nightmare!

[Sorry, if this apperas twice, I just missed my entry].

br--mabra

Miguel
June 15, 2010

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Hey, rick i have the same problem, the issue is when the IIS is hosting the service, if it is, you cannot have multiple endpoints because the IIS treats the url addressing! Sry my english!

Calvin
October 31, 2010

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

Hi Rick,

Thanks for the write up. The only issue I've come across is how to handle Faults when using REST services - I've setup WCF services to handle it before with a behavior extension but can't find the way to do that with REST (at least not through the web.config settings).

Any ideas?

Thanks!

Intekhab
November 18, 2010

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

How can we call WCF with POST verb on cross domain. I am getting error when it is called using MOZILLA Fire fox.

Rick Strahl
November 18, 2010

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

@intekhab - AFAIK you can't make cross domain POST calls. JSONP is the only 'legal' way to make cross-domain calls and those won't work well with WCF and only support GET operations.

Igor
November 19, 2010

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

tried to follow the example and have a problem of 404, while implementing this solution in IIS 5.1, the wildcard mappings and every other solutions that i found on the net do not help. the thing simply does not work.

as for the factories, they throw an error, about the IIS authorization issues, it seems that it's a bug in the framework (i guess).

szlamany
April 20, 2011

# re: WCF REST Configuration for ASP.NET AJAX and plain REST Services

I am creating a jquery ajax based app talking to asp.net backend - I started with stardard web services but now I'm concerned that I have to use WCF to secure the site.

The site is running under https.

I at first thought I could create my own username/pw-return a GUID concept and validate calls to my services with that guid during the page lifetime.

If I'm only doing POST's after the initial page GET does that make the asmx model secure?

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024