Enabling JSONP in WCF

Before this week I never really bothered much with WCF. My reasons were two fold, one it always seemed like a pain to configure and the second reason was the fact that it was overkill for the projects that I was working on. That being said, I finally hit a project where it made sense to use it. I needed things like the ability to easily do JSON and XML requests, access through more than just a web request, etc. Anyway, I set myself up with a new project space, followed a couple tutorials, figured out how to host the services in a web app seperate from my other apps so that the services would be centralized, etc. Basically everything was going fine... Well until I tried to make my requests from web app 1 (the project that needed access to the service) to web app 2 (the app actually holding the service). It kept coming back with a failure message.

How could this be? I set up my service contract correctly, my function even had the necessary WebGet attribute:

[WebGet(ResponseFormat=WebMessageFormat.Json)]

That one attribute attached to my function should set it up for JSON. I had my service reference set up in my script manager. I even had the WCF Service file set up correctly using the WebScriptServiceHostFactory:

<%@ ServiceHost Service="Services.MyService" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>

According to the documentation I wouldn't even need to bother with configuring the config file. I could strip out the system.serviceModel portion and that factory should handle things for me. Hell if I called it in the browser, it passed back the JSON correctly so what the hell was going on? JSONP... That's right, in all of my haste I had completely forgotten about JSONP (JSON with Padding). JSONP, in a very basic description, is a usage pattern that allows a secondary server (not the primary server) to use JSON in a meaningful way. In otherwords think cross site scripting, which is exactly what I was trying to do. My calls from Sys.Net.WebServiceProxy.invoke (long story as to why I'm not able to simply use jQuery) were requesting JSONP to be sent back and were failing when it didn't receive it. So I went searching online as to how to enable it in WCF.

Apparently I'm the only person out there who has decided to work with .Net 4.0 on anything and especially WCF. Well either that or no one wanted to talk about it. Anyway, after about 2 hours of digging, I finally found some semblence of help on this subject. You see prior to 4.0, the way you were suppose to set up JSONP was that you had to define a number of classes including a message encoder, a message encoder factory, an operationbehaviorattribute, etc. It was a pain and every post about it said just wait until 4 comes out as it will have it by default... Well it does:

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="false" targetFramework="4.0" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingJsonP" crossDomainScriptAccessEnabled="true"></binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="Services.MyService">
        <clear />
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBindingJsonP"
                  contract="Services.Interfaces.IMyService" behaviorConfiguration="webHttpBehavior" />
        <host>
          <baseAddresses>
            <add baseAddress="http://SERVICELOCATION" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

The bit above is the web.config file for the service web app. It turns out the whole Factory attribute in the svc file is kind of lie, you do indeed need the system.serviceModel section. Anyway, in it we define a endpoint behavior for webHttpBehavior and a binding that uses webHttpBinding called webHttpBindingWithJsonP. The special thing about the binding is the crossDomainScriptAccessEnabled attribute is set to true. This one item enables it. Past that we just set up our service and an endpoint using the binding that we've created and that's it (and of course set up the base address). Two hours and that's all I needed to do. Anyway, I hope it helps someone out there so you don't have to deal with the headache that I've had today. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/23/2010 at 2:51 PM
Tags: , ,
Categories: AJAX | ASP.Net
Post Information: Permalink | Comments (3) | Post RSSRSS comment feed

Copy to Clipboard AJAX Control

This is actually the same code that I used for the BlogEngine.Net extension that I created a while back. However I needed it to be a bit more generic (not BlogEngine specific) and take the code from a text box so I ended up creating an AJAX extender:

CopyToClipboardExtender.zip (2.07 kb)

It's rather basic. The targetID is the link you want them to click on to copy the text. The CopyID is the text box's ID. It most likely will not work in Firefox, etc. and is really only IE specific. However it's better than nothing. 

As far as setting it up, sometimes I get a bit lazy when it comes to explaining how to use some of the code on here. In the case of the AJAX controls, I usually leave out the fact that you need to download the AJAX Control Toolkit. Once you have that and you've added the templates, etc. like it says in the setup, you need to create an ASP.Net AJAX Control Project (I've used the name of AJAXControls, so if you use something different you'll need to potentially change some of the code to point to the correct namespace). From there, you add the code (making sure to have the js file as an embedded resource). Compile and you're ready to go...

Now that jQuery is going to be the norm, the setup process will probably change in the future. Plus I plan on packaging these up at some point like the utilities. For now though I leave you with the code. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 12/12/2008 at 10:00 AM
Tags: , , ,
Categories: AJAX | ASP.Net | Web Design
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Windows Authentication, Delegation, C#, and Exchange

You know, setting up an intranet to use windows authentication SHOULD be easy. And actually it is, you just set authentication="windows", impersonation to true, set up the browsers correctly so that they see the server as part of the intranet so it will automatically send the credentials (and God help you if you're using IE and the settings get corrupted. You'll have to reset everything to the factory defaults.), etc. It gets a bit more complicated though when you want to set up your intranet site such that people can access their exchange/outlook accounts. At that point you need to set up Kerberos on your intranet.

I'm not going to go over how to do that since this article describes it fairly well. There are a few things that you'll need to do if you're using a newer version of IIS though (namely set it up for constrained delegation, which just requires picking that option, finding your exchange server, and picking http from the list of services if you're going to be doing WebDAV calls against it). But to be honest, that's all there is to it... Well you might also need to set up the SPN for the intranet server properly (HOST/server name that people use to get to it). Because if that isn't set up, then the browser wont trust the server and it wont send the info... But that's about it.

Anyway, once you get past all of that you may want to do some simple queries against the Exchange server that you just spent a couple hours getting set up... And if you're using the code that I provide on my site (or potentially your own), most likely you'll run into an issue. Mainly the code I have (and that is used most often out there) wasn't set up for windows authentication (it assumed that you knew the user name and password). However there is an easy fix. The network credential cache needs to have a couple entries switched:

        System.Net.CredentialCache MyCredentialCache = new System.Net.CredentialCache();
        MyCredentialCache.Add(new System.Uri(uri)
                               "Negotiate",
                               (System.Net.NetworkCredential)CredentialCache.DefaultCredentials);

You'll notice two changes the second item when we're adding to the credential cache is normally NTLM. We've switched it to Negotiate (basically telling the system that we're going to be using Kerberos). The third item in the add function is no longer a new networkcredential object containing our user name and password. Instead it uses the default credentials. The reason for this is fairly simple. The DefaultCredentials contains the current user's information. That's all that needs to change in our bit of code. So hopefully this little bit of code will help someone out as it took me a bit to track down what my issue was (I didn't change from NTLM to Negotiate)...

Also, in other news I've moved my utility library over to CodePlex. I also ended up adding a few bits of code, including classes to help with:

  • Serialization
  • File management
  • HTML, added functions to dump request/response variables
  • XMDP
  • OPML
  • Active Directory queries
  • Exchange queries
  • iCalendar/Appointment management in Exchange
  • APML
  • hCalendar
  • hCard

Plus a couple of other bits here and there. I'm also trying to improve the structure a bit and try to make things a bit more logical. So hopefully it will help someone out. Anyway, try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 11/14/2008 at 1:47 PM
Tags: , , , ,
Categories: AJAX | ASP.Net | C# | General | Web Design
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed