Sabre API Updates For PCI TLS v1.2 + High Availability URLs

I’ve been receiving email from Sabre regarding Payment Card Industry (PCI) TLS v1.2 security deadlines and Sabre’s High Availability (HA) infrastructure. (Sabre has introduced new URLs for use with Sabre APIs).

I’ve navigated a maze of URLs and PDFs from Sabre. The majority of these were not helpful to me but I muddled through and reduced the upgrade process to a few steps. Note that these steps handle both the high availability URL updates and the TLS v1.2 updates.

The steps below are accomplished using Visual Studio Professional 2017. If you’re not using it yet, you should be.

Step 1 – Update to use the High Availability URLs

In VS, Find and Replace in the entire solution (*.cs files only)
From this : https://webservices.sabre.com
To this : https://webservices.havail.sabre.com

At this point, I tried to run against the new HA URLs .. but no luck, here’s the error:
Exception Message : The request was aborted: Could not create SSL/TLS secure channel.

Step 2 – Update to the .NET Framework 4.6.1

I updated ALL of my projects to .NET Framework 4.6.1, this handles the TLS v1.2 upgrade.

Step 3 – Recompile and Run

Nothing else to do, I’m running now with the new HA URLs and also using TLS v1.2.

This is not news!

I saw this on the local news the other day… a report on a new FB feature. WTF?! Why is this newsworthy?

It makes me nuts to see the news “go to social media”… how is this news? How is garbage that random people post/tweet ever newsworthy?

Same goes for any celebrity – why does the news have to “report” this nonsense? I don’t care what they have to say on social media! If I cared, I would follow them on whichever social media outlet they spout their nonsense. This is not news! Please let TMZ handle the lowest common denominator.

Where’s my seat?

Summary: Sabre TravelItineraryReadService TravelItineraryReadRQ version 2.2.0 returns incomplete Seat data. TravelItineraryReadRQ version 3.4.0 returns all of the Seat data.

I had bug in my PNR capture code – it was throwing an exception on my persist flight details stored procedure call because I wasn’t giving it a required seat number. It was a trivial code fix, I needed to pass an empty string to the stored procedure (not a null value).

But did I have a bug further upstream in my TravelItineraryReadRS parsing and mapping code? Or is the data really missing?

My current version of the TravelItineraryReadService is using TravelItineraryReadRQ version 2.2.0. Below is the snippet from the TravelItineraryReadRS. You can see that it’s only returning a seat number for segment 2, all of the other segments have no value for the seat number – the attribute is missing entirely. So I don’t have any parsing/mapping issues, sabre isn’t giving me the data.

<TravelItineraryReadRS Version="2.2.0">
...
  <Seats>
	<Seat NameNumber="01.01" SegmentNumber="0001" Status="HRQ">
	  <FlightSegment>
		<DestinationLocation LocationCode="PHX" />
		<OriginLocation LocationCode="SBA" />
	  </FlightSegment>
	</Seat>
	<Seat Changed="N" NameNumber="01.01" Number="04A" SegmentNumber="0002" SegmentStatus="HK" SmokingPreference="N" Status="HRS" TypeTwo="WLMI">
	  <FlightSegment>
		<DestinationLocation LocationCode="ORD" />
		<OriginLocation LocationCode="PHX" />
	  </FlightSegment>
	</Seat>
	<Seat NameNumber="01.01" SegmentNumber="0003" Status="HRQ">
	  <FlightSegment>
		<DestinationLocation LocationCode="PHX" />
		<OriginLocation LocationCode="ORD" />
	  </FlightSegment>
	</Seat>
	<Seat NameNumber="01.01" SegmentNumber="0004" Status="HRQ">
	  <FlightSegment>
		<DestinationLocation LocationCode="SBA" />
		<OriginLocation LocationCode="PHX" />
	  </FlightSegment>
	</Seat>
  </Seats>
...
</TravelItineraryReadRS>

I’m in the middle of evaluating (and implementing) TravelItineraryReadRQ version 3.4.0. Cool, it has my seat data! Maybe I need to roll this into production sooner than planned…

<TravelItineraryReadRS Version="3.4.0">
...
  <Seats>
	<Seat Changed="N" NameNumber="01.01" Number="02A" SegmentNumber="0001" SegmentStatus="PN" SmokingPreference="N" Status="HRS" TypeTwo="">
	  <FlightSegment>
		<DestinationLocation LocationCode="PHX" />
		<OriginLocation LocationCode="SBA" />
	  </FlightSegment>
	</Seat>
	<Seat Changed="N" NameNumber="01.01" Number="04A" SegmentNumber="0002" SegmentStatus="HK" SmokingPreference="N" Status="HRS" TypeTwo="WLMI">
	  <FlightSegment>
		<DestinationLocation LocationCode="ORD" />
		<OriginLocation LocationCode="PHX" />
	  </FlightSegment>
	</Seat>
	<Seat Changed="N" NameNumber="01.01" Number="03A" SegmentNumber="0003" SegmentStatus="PN" SmokingPreference="N" Status="HRS" TypeTwo="">
	  <FlightSegment>
		<DestinationLocation LocationCode="PHX" />
		<OriginLocation LocationCode="ORD" />
	  </FlightSegment>
	</Seat>
	<Seat Changed="N" NameNumber="01.01" Number="03F" SegmentNumber="0004" SegmentStatus="PN" SmokingPreference="N" Status="HRS" TypeTwo="">
	  <FlightSegment>
		<DestinationLocation LocationCode="SBA" />
		<OriginLocation LocationCode="PHX" />
	  </FlightSegment>
	</Seat>
  </Seats>
...
</TravelItineraryReadRS>

Singleton Application With NotifyIcon

I recently had to implement 2 changes to a winforms application I’m working on, here’s the general requirements:

  • Can only have 1 instance of the application running – make it a singleton application
  • The user can close (hide) the application but it remains running until exited – utilize the notify icon (tray icon)

I searched google and found a bunch of helpful sources for both, this is a melding of several of them to fit my needs.

Here are the guts of the winform that deals with the notifyIcon:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Windows.Forms;
 
namespace SingletonAppWithNotifyIcon
{
    public partial class MainForm2 : Form
    {
        private bool IsQuit { get; set; }
 
        public MainForm2()
        {
            InitializeComponent();
        }
 
        private void MyFormClosing(object sender, FormClosingEventArgs e)
        {
            if (IsQuit)
                return;
 
            HideMe();
            e.Cancel = true;
        }
 
        private void HideMe()
        {
            Hide();
        }
 
        public void ShowMe()
        {
            WindowState = FormWindowState.Normal;
            Visible = true;
            Activate();
        }
 
        private void QuitMe()
        {
            IsQuit = true;
            Application.Exit();
        }
 
        private void MainForm2_Load(object sender, EventArgs e)
        {
            notifyIcon1.ContextMenu = new ContextMenu();
            notifyIcon1.ContextMenu.MenuItems.Add(new MenuItem("Quit My Fancy App", NotifyIconQuit));
        }
 
        private void NotifyIconQuit(object sender, EventArgs e)
        {
            QuitMe();
        }
 
        private void NotifyClick(object sender, EventArgs e)
        {
            ShowMe();
        }
 
        private void CloseClick(object sender, EventArgs e)
        {
            HideMe();
        }
 
        private void QuitClick(object sender, EventArgs e)
        {
            QuitMe();
        }
    }
}

Here the highlights for the singleton application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
 
namespace SingletonAppWithNotifyIcon
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
 
            SingleInstanceAppStarter.Start(new MainForm2(), StartNewInstance);
        }
 
        static void StartNewInstance(object sender, StartupNextInstanceEventArgs e)
        {
            var forms = Application.OpenForms;
            var frm = forms["MainForm2"] as MainForm2;
            if (frm != null)
            {
                frm.ShowMe();
            }
            else
            {
                var f = new MainForm2();
                f.ShowDialog();
            }
        }
    }
 
    class SingleInstanceApp : WindowsFormsApplicationBase
    {
        public SingleInstanceApp() { }
 
        public SingleInstanceApp(Form f)
        {
            IsSingleInstance = true;
            MainForm = f;
        }
    }
 
    public class SingleInstanceAppStarter
    {
        static SingleInstanceApp _app;
 
        public static void Start(Form f, StartupNextInstanceEventHandler handler)
        {
            if (_app == null && f != null)
            {
                _app = new SingleInstanceApp(f);
            }
 
            if (_app == null) return;
 
            _app.StartupNextInstance += handler;
            _app.Run(Environment.GetCommandLineArgs());
        }
    }	
}

Here’s a sample solution (nice and simple) for you to download and experiment with…
SingletonAppWithNotifyIcon.zip