using System; using System.Collections.Generic; namespace BestHTTP.SignalRCore.Messages { public sealed class SupportedTransport { /// /// Name of the transport. /// public string Name { get; private set; } /// /// Supported transfer formats of the transport. /// public List SupportedFormats { get; private set; } internal SupportedTransport(string transportName, List transferFormats) { this.Name = transportName; this.SupportedFormats = transferFormats; } } /// /// Negotiation result of the /negotiation request. /// /// public sealed class NegotiationResult { /// /// The connectionId which is required by the Long Polling and Server-Sent Events transports (in order to correlate sends and receives). /// public string ConnectionId { get; private set; } /// /// The availableTransports list which describes the transports the server supports. For each transport, the name of the transport (transport) is listed, as is a list of "transfer formats" supported by the transport (transferFormats) /// public List SupportedTransports { get; private set; } /// /// The url which is the URL the client should connect to. /// public Uri Url { get; private set; } /// /// The accessToken which is an optional bearer token for accessing the specified url. /// public string AccessToken { get; private set; } internal static NegotiationResult Parse(string json, out string error, HubConnection hub) { error = null; Dictionary response = BestHTTP.JSON.Json.Decode(json) as Dictionary; if (response == null) { error = "Json decoding failed!"; return null; } try { NegotiationResult result = new NegotiationResult(); object value; if (response.TryGetValue("connectionId", out value)) result.ConnectionId = value.ToString(); if (response.TryGetValue("availableTransports", out value)) { List transports = value as List; if (transports != null) { List supportedTransports = new List(transports.Count); foreach (Dictionary transport in transports) { string transportName = string.Empty; List transferModes = null; if (transport.TryGetValue("transport", out value)) transportName = value.ToString(); if (transport.TryGetValue("transferFormats", out value)) { List transferFormats = value as List; if (transferFormats != null) { transferModes = new List(transferFormats.Count); foreach (var mode in transferFormats) transferModes.Add(mode.ToString()); } } supportedTransports.Add(new SupportedTransport(transportName, transferModes)); } result.SupportedTransports = supportedTransports; } } if (response.TryGetValue("url", out value)) { string uriStr = value.ToString(); Uri redirectUri; // Here we will try to parse the received url. If TryCreate fails, we will throw an exception // as it should be able to successfully parse whole (absolute) urls (like "https://server:url/path") // and relative ones (like "/path"). if (!Uri.TryCreate(uriStr, UriKind.RelativeOrAbsolute, out redirectUri)) throw new Exception(string.Format("Couldn't parse url: '{0}'", uriStr)); // If received a relative url we will use the hub's current url to append the new path to it. if (!redirectUri.IsAbsoluteUri) { Uri oldUri = hub.Uri; var builder = new UriBuilder(oldUri); builder.Path = uriStr; redirectUri = builder.Uri; } result.Url = redirectUri; } if (response.TryGetValue("accessToken", out value)) result.AccessToken = value.ToString(); else if (hub.NegotiationResult != null) result.AccessToken = hub.NegotiationResult.AccessToken; return result; } catch (Exception ex) { error = "Error while parsing result: " + ex.Message + " StackTrace: " + ex.StackTrace; return null; } } } }