Atlassian already have some documentation on how to integrate IIS and JIRA.

Unfortunately it requires installing some ISAPI components, and a whole lot of fiddling around.

I wanted to see if I could get Application Request Routing to do the same job. Turns out, yes, you can – here’s how.

1. Make sure JIRA is installed and working on your server.

Let’s say that it’s at http://example.com:8080/

I want to access JIRA via: http://jira.example.com/ – but IIS7 is already using port 80 on that server.

2. Alter your conf/server.xml file in JIRA.

Find the /Server/Service/Connector element, and add two attributes:

proxyName=”jira.example.com”

proxyPort=”80″

The Connector element should now look something like

 <Connector port="8080" enableLookups="false" proxyName="jira.example.com" proxyPort="80">

3. Restart the JIRA Service.

4. Install, if you havn’t already, Application Request Routing 2.0, along with URL Rewriting 2.0

5. Enable Proxying on ARR:

  • From the IIS7 Console, click on {ServerName}.
  • Open Application Request Routing.
  • From the Actions pane on the right hand side, Select  ‘Server Proxy Settings’
  • Check ‘Enable Proxy’
  • Set HTTP Version to ‘HTTP/1.1′

6. Add a new site ‘jira.example.com’, with bindings for http://jira.example.com

7. Add a new URL Rewrite Rule for jira.example.com

  • From the IIS7 Console, click on jira.example.com
  • Open URL Rewrite
  • From the Actions pane on the right hand side, select ‘Add Rules’
  • Choose ‘Blank Rule’
  • Set Match Rule to:
  • Requested URL Matches the Pattern
  • Using Regular Expressions
  • Pattern: (.*)
  • Ignore Case: checked
  • Set Action to:
  • Action Type: Rewrite
  • Rewrite URL: http://example.com:8080/{R:1}
  • Append query string: checked
  • Stop processing of subsequent rules: checked

8. Now, with any luck – you should be able to access JIRA via http://jira.example.com  - if not, something isn’t set correctly.

Setting up Fisheye is almost as simple.

Say Fisheye is set up on http://example.com:8060 and I want to access it via http://fisheye.example.com

Repeat steps 4-8 above, substituting ‘fisheye’ for ‘jira’, and then verify you can access fisheye from http://fisheye.example.com

If you’re also doing .NET Development, or have .cs/.aspx/.asmx files in your repository, then you’ll also need to do the following.

Edit the web.config for fisheye.jira.com

Add the following to just before </system.webServer>

<handlers>
 <remove name="WebServiceHandlerFactory-ISAPI-2.0-64" />
 <remove name="WebServiceHandlerFactory-ISAPI-2.0" />
 <remove name="PageHandlerFactory-ISAPI-2.0" />
 <remove name="PageHandlerFactory-ISAPI-2.0-64" />
 <remove name="PageHandlerFactory-Integrated" />
 <remove name="WebServiceHandlerFactory-Integrated" />
 <remove name="SimpleHandlerFactory-ISAPI-2.0-64" />
 <remove name="SimpleHandlerFactory-ISAPI-2.0" />
 <remove name="SimpleHandlerFactory-Integrated" />
 <remove name="CGI-exe" />
 <remove name="ISAPI-dll" />
</handlers>
<staticContent>
 <mimeMap fileExtension=".cs" mimeType="text/plain" />
</staticContent>
<security>
 <requestFiltering>
  <fileExtensions>
   <remove fileExtension=".config" />
   <remove fileExtension=".csproj" />
   <remove fileExtension=".cs" />
   <add fileExtension=".cs" allowed="true" />
   <add fileExtension=".csproj" allowed="true" />
   <add fileExtension=".config" allowed="true" />
  </fileExtensions>
 </requestFiltering>
</security>

If there are any additional filetypes that are in your Fisheye repository that generate 404 errors when navigating, then add them to the fileExtensions section. First as a ‘Remove’, and then an ‘Add’ with allowed=true. You’ll also need to probably add a mimeMap entry too.

Thanks to @OhCrap for the pointers on enabling .cs serving with IIS7.

Got a Kindle? Use it outside the US?  You’re probably better off setting the Kindle Region to the US.

But Wait, you might shout – You’ll pay roaming charges for that!  Yes, that’s true – you’ll pay USD$1.99 for each book downloaded to your kindle over Whispernet while you’re outside the US.

The thing Amazon doesn’t tell you is that the international kindle prices are exactly the same.

Don’t believe me? See for yourself on the Amazon site.

First, set your Kindle Region to (say) Australia.

Kindle Region is Australia

Now, take a look at some book you’re interested in.

Helfort's War Book 2: The Battle of the Hammer Planets. International Kindle Store Price: USD$8.39, includes Whispernet International Delivery

Setting my kindle region to the USA for a moment and refreshing the page shows me the US Kindle Price

Same book, but on the US Kindle Site. Price? USD$6.39.

As you can see, for this book it’s USD$6.39 on the US Kindle Store. Add in USD$1.99 for International Whispernet Delivery, and it comes to USD$8.38  - You make a saving of USD 1c by doing this.

Things are much the same it seems for magazine subscriptions. Although, I’ve only checked the prices for two monthly magazines, the price differences are about the same.

International Kindle Store Price: USD$5.99, with International Whispernet Delivery

US Kindle Store Price: USD$2.99/month

Plus – there is significantly MORE books available on the US Kindle Store than the Australian version.

It’s well worth checking out.

NB: If you have any magazine/newspaper subscriptions, and especially any daily/weekly ones – then read the roaming letter they send you carefully, it includes information about per-item delivery costs.

Edit: Can I use any address in the USA, Or do I need a valid US Billing Address?

Don’t edit your billing address, just your Kindle Region – in the section marked ‘Your Country’. And yes, any address in the USA Works, as long as you have a valid Zip Code.

0 comments

Streaming Twitter API

I’ve been playing with Twitter’s new Streaming API over the last few days.

The old XMPP protocol provided your traditional ‘Following’ stream, plus keyword searching with ‘track’.  All of it being delivered in near-real-time (i.e, immediately after the Tweets were sent).

The new Streaming API uses Comet to deliver a similar set of functionality.

I’ve created a prototype client that uses these functions, so that we can experiment with the new API, the plan being to bring that into MahTweets at some point.

There is some interesting behaviour with the API, particularly with regards to following people.  There was a change to the Web API some months ago, where Twitter disabled the ability to see all tweets your friends make. Basicly they set it so that you can ONLY see the Tweets your friends make, if they’re either Open (not replies), or Replies to someone else you follow.

An example might be that you follow Amy and Barry. It might not be such a big deal for you that you don’t see their tweets to Christine  – but if you, Amy and Barry were discussing something – replies to Christine (even in the same conversation) won’t be seen by you.

Well, the new Streaming API changes that – not only does it bring back that old @replies functionality, it also adds an interesting twist.

Under the Streaming API you also see public @replies to anyone you follow. That is: If Christine were replying to Amy or Bob – you’d see those tweets, even though you don’t follow Christine.

There are some restrictions with the API – you need a reasonably fast and stable connection (Dialup, Satellite, or dodgey wireless connections need not apply), you can’t have more than one streaming connection open per account, and you can’t rapidly change the stream settings.  You also need to explicitly define what keywords and user IDs you want to recieve updates for. That’s currently limited to following 400 users, and/or tracking 200 keywords.

Still… it’s a bunch of fun, and can lead to some interesting scenarios.

Here’s a screencap from the demo client. I’m tracking Aeoth’s UID here, but also getting replies to @aeoth

Test Client - Full Follow Stream

Test Client - Full Follow Stream

A few months ago for some unknown reason the Output pane in Visual Studio stopped displaying output from my application.

I’d get the build notices, exceptions, and thread/process exit information but any calls to Debug or Console to output information wouldn’t display.

tickprogramoutputIt turns out that you can de-select “Program Output” – and somehow it’d become deselected. Even now it still turns itself off, apparently by random.

Right clicking in the Output pane should let you re-select that value.

0 comments

Test Post

ignore me :)

Dear New York Times,

Whilst I understand you’ve been around some considerable time, and that you do have journalists to fire, you do need to know your nag screen is incredibly annoying. It’s probably also not helping with your ad impressions either.

nytfail

Sure, it might only take a minute to sign up – but it’s really not worth it for me. It’s actually quicker just do add your entire domain to my DNS Block List.

image

That way I don’t have to see your annoying sign-in page ever again.

Have fun with that print media business. I hear it’s a raging success. Oh, wait.

Sincerely,

Will

  • Are you new to Social Media?
  • Are you trying to recruit folks in IT, or related industries?
  • Do you think Twitter might be a great way to get more leads to fill roles?

If you answered yes to the above, then you need to pause for a moment, because Twitter is really not what you think it is.

Think of Twitter more like a 24-7 party where everyone mixes and mingles and interacts however they want – you suddnely turning up and jumping on the Mic demanding attention to pitch people on some “Exciting new Role” is just going to piss people off.

If you’re going to engage with folks, make it PERSONAL – They’re not on Twitter so you can sell them a product, they’re there to interact with other folks.

Spend five minutes or so looking at their profile, their previous tweets, and sites they link to and/or personal site. Interact with them on things that you might have a common interest on, and after you’ve got some sort of relationship (This takes more than 15 minutes) – it might be appropriate to send them a private message about the role.

If they’re not following you, you won’t be able to send them a private message, so that’s probably a good indication they’re Just Not Interested.

Yes, I’ve blogged about this before – but I’m writing it again, because it’s still relevant.

5 comments

Star Trek XI

I got home not too long ago from seeing the Star Trek reboot film by JJ Abrams.

SPOILER WARNING: If you have not seen the film, and you have any intention of doing so – do not continue reading.  The no-spoilers review is: It’s good, go see it.

Read the rest of this entry »

Edit: This post was linked from Stack Overflow – you might want to check back there for more/better discussion about the topic.

Recently Jeff Attwood wrote about how they are using ELMAH to get more information about the types of errors occurring in Stack Overflow.

Effectively ELMAH is designed as a ‘drop in’ fault capturing system for ASP.NET. It works really well there, and for many situations you can get along just fine without even needing to recompile your application (it does need some editing of the web.config though).

I wanted a way to capture more detail about the faults occurring in our dev and production environments, especially when working with WCF – since a lot of error detail tends to be hidden, or is difficult to reproduce.

Dropping in ELMAH into a WCF application will by default mean you miss the vast majority of errors – WCF swallows the error, and doesn’t let it get back up to ASP.NET.

There’s two ways you can go about fixing this:
Side Note: If you’re not hosting WCF in ASP.NET, then Option 2 may not be directly possible for you without some modification.

#1 – Wrap everything in try/catch blocks (if you didn’t already) and sprinkle this line around everywhere:

Elmah.ErrorSignal.FromCurrentContext().Raise(YourExceptionHere);

#2 Add a HttpHandler, and Decorate your Service(s) with an Error Handling attribute.

I borrowed the ServiceErrorBehaviourAttribute code from somewhere else, and I can’t find the source of it at the moment. Effectively this was so I could manipulate the HTTP Status Codes going back to the client when there was an error. It just so happens that this is a great way of capturing Exceptions and sending them to ELMAH at the same time.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.Net;
using System.Web;
using System.IO;
using Elmah;
namespace YourApplication
{
	/// <summary>
	/// Your handler to actually tell ELMAH about the problem.
	/// </summary>
    public class HttpErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            if (error != null ) // Notify ELMAH of the exception.
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(error);
            }
        }
    }
	/// <summary>
	/// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
	/// ...and errors reported to ELMAH
	/// </summary>
	public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;

        public ServiceErrorBehaviourAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }

        public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection parameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;
            errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }
}

Once you’ve added that, then it’s just a matter of decorating your Service like so:

    [ServiceContract(Namespace = "http://example.com/api/v1.0/")]
    [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
    public class MyServiceService
    {
      // ...
    }

…and then making sure ELMAH is added as a reference, and adding it’s entries to your web.config.

Then you’ll be getting a whole stack of errors you otherwise may not have seen.

It’s also possible to log exceptions from higher up the chain (eg Databases, Files, etc) by using the line of code from Option 1.

Issues

Whilst ELMAH is great for capturing information about the request, I havn’t yet found any way to capture the original HTTP Request – this would be the ultimate goal for me.

It’s also not particularly easy to capture additional information (such as database records, or objects in cache, etc) without rolling your own copy of ELMAH.

All in all though – for a few minutes work, it’s one additional way to capture errors that your existing code may not be able to.

Yes, ELMAH even captures errors (in most situations) when your WCF services can’t start up (eg your fubar’ed some attributes).

Hope that helps.

NB: Use this code at your own risk, don’t blame me if it brings down your multi-million-dollar-per-hour application and causes you to go bankrupt.

Caprica-1