DCSIMG
July 2011 - Posts - Ido Flatow's Blog Veni Vidi Scripsi

Ido Flatow's Blog

Veni Vidi Scripsi

News

Have you heard me speak?
Powered
<style type='text/css' media='screen' id='sm_css'> #smix {overflow: visible;height: auto;border-radius: 10px;max-width: 250px;background-color: #323232;text-align: left;font-size: 12px;line-height: 16px;font-family:'Lucida Sans Unicode','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;-webkit-border-radius: 10px;-moz-border-radius: 10px;border-radius: 10px;} #smix a {color: #0056CC;text-decoration: none;} #smix .sm_head {color: #fff; line-height: 1em;font-size: 1.4em;padding: 10px;color: #fff;} #smix .sm_lanyard_wrapper {background-color: #fff;;clear: both;width: 97%;margin: 0 auto;margin-bottom: 0px;} #smix .sm_lanyard_content {padding: 7px;}#smix button.sm_rec, #smix a.sm_rec, #smix input[type=submit].sm_rec { padding: 6px 10px; -webkit-border-radius: 2px 2px;-moz-border-radius: 2px; border-radius: 2px; border: solid 1px rgb(153, 153, 153); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(255, 255, 255)), to(rgb(221, 221, 221))); color: #333; text-decoration: none; cursor: pointer; display: inline-block; text-align: center; text-shadow: 0px 1px 1px rgba(255,255,255,1); line-height: 1; }#smix .sm_rec:hover { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(248, 248, 248)), to(rgb(221, 221, 221))); }#smix .sm_rec:active { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(204, 204, 204)), to(rgb(221, 221, 221))); }#smix .sm_rec.medium { padding: 3px 7px; font-size: 13px; }#smix .sm_rec span.icon.thumbs_up {background-position: 0px 36px;vertical-align: text-top;display: inline-block;margin-right: 4px;height: 18px;width: 16px;background-image: url(http://speakermix.com/images/new/thumbsold.png);}#smix .sm_rec:hover span.icon.thumbs_up {background-position: 0px 18px;} #smix .sm_events {padding:2px 0px 4px 0px;} #smix .sm_section {font-size: 10px; border-bottom: 1px solid silver; margin-bottom: 6px;} #smix .sm_subline {font-size:120%;margin-top:4px;font-weight:bold} #smix .powered {text-align: right} #smix .powered img {margin: 7px} </style>
Sela Technology Center

Advertisement

July 2011 - Posts

Web Developers Community (WDC) updates

If you are not familiar with our user group, the Israeli WDC user group is a meeting place for web developers, designers, and architects, where we discuss new and existing web technologies, best practices in web development, and any other interesting stuff that relates to the web world. The user group is managed by Gal Kogman and yours truly, with the support of Microsoft Israel.

You can read more about the user group on our Microsoft page (a bit outdated), and for the latest news and information, I suggest you visit our Facebook page.

The first reason I’m writing this post is to let you know that our next meeting will be in September 7th in Microsoft Ra’anana. If you register in the community’s Facebook page, you’ll get more information later on regarding the hours and the topics of the presentations. Attendance is free.

The second reason I’m writing this post is to let you know that we are always looking for potential speakers - the field of web development is very vast, and many of us deal with all sorts of web technologies and techniques, so if you think you have worked with a special technology you want to share with the community by presenting it in one of the meetings, please let me know by email or by writing in our Facebook wall. You don’t need to be an experienced speaker to present at the meetings, just make sure you don’t have stage freight beforehand Smile.

kick it on DotNetKicks.com Shout it

Cross-Origin Resource Sharing (CORS) and WCF

Yesterday I encountered the following question in the MSDN forums about calling a cross-domain WCF RESTful service from Chrome.

The problem with doing the above is because there is a cross-domain call to a WCF service. When you are using Chrome, the browser tries to find out if it can do the call by sending a cross-origin resource sharing (CORS) request, as explained in this article. In IE, you will most likely get a cross-domain exception.

After searching the web a bit, I found that the immediate solution is to change the supported HTTP method of the operation to “*”, and to add the special cross-origin headers to the outputted response, like so:

WebOperationContext.Current.OutgoingResponse.Headers.Add(
  "Access-Control-Allow-Origin", "*"); WebOperationContext.Current.OutgoingResponse.Headers.Add(
  "Access-Control-Allow-Methods", "POST"); WebOperationContext.Current.OutgoingResponse.Headers.Add(
  "Access-Control-Allow-Headers", "Content-Type, Accept");

There are two problems with this solution:

  1. You need to repeat these lines in each of your service methods.
  2. The service method is called twice, once for the “preflight” request (the request with the OPTIONS HTTP verb), and a second time for the invocation itself.

So I took the time and written a special endpoint behavior that can be attached to any webHttpBinding based endpoint.

The code does the following:

1. Every response message gets the “Access-Control-Allow-Origin” header with the value of “*”, to tell the client that the service allowed the request from the client.

2. If the client sends a request to the service with the verb OPTIONS (this is referred to as a “preflight” request), the service will automatically return a 200 (ok) response with the required headers: “Access-Control-Allow-Headers” and “Access-Control-Allow-Methods” (in addition to the allow-origin header). Clients that look for the “allow” headers in the response will then send the original required request to the service.

The benefits of using this behavior is:

  1. The code that returns the message with the headers is located in the behavior itself – no need to place it in each service method.
  2. The behavior catches the OPTIONS request, and does not require running the service method twice.
  3. You do not need to change any part of your service contract or service implementation. The behavior is only needed to be applied using configuration.

To implement this behavior I used a message inspector that checks the request and changes the response, and an operation invoker that wraps the unhandled operation invoker. The custom operation invoker handles the OPTIONS message requests, which otherwise would have caused the service to return an error message (because no method is set to handle “Options” requests).

The endpoint behavior can be attached to the endpoint through configuration, like so:

<behaviors>
  <endpointBehaviors>
    <behavior name="webSupport">
      <webHttp />
      <CorsSupport />
    </behavior>
  </endpointBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
<services>
  <service name="Service.JSonService">
    <endpoint address="http://localhost:8080" behaviorConfiguration="webSupport” binding="webHttpBinding" contract="Service.IJSonService" />
  </service>
</services>

Or, if you are using IIS to host your services, I also created a service host factory that creates a WebServiceHost and adds the behavior to every webHttpBinding based endpoint created by the host. To use it in your .svc file, just write something like this:

<%@ ServiceHost Language="C#" Debug="true" Service="Service.JSonService, Service" Factory="WebHttpCors.CorsWebServiceHostFactory, WebHttpCors" %>

You can download the behavior code + two sample hosts (IIS and self-hosted) that shows how to use the behavior from my skydrive.

To test the two hosts, open the webform1.aspx and change the target URL to access the IIS/self-hosted service.

Enjoy.

kick it on DotNetKicks.com