//******************************************************************************************************
// HubClientOperationsBase.cs - Gbtc
//
// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
// file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 08/16/2016 - J. Ritchie Carroll
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Collections.Concurrent;
using Microsoft.AspNet.SignalR.Hubs;
namespace GSF.Web.Hubs
{
///
/// Represents a base class for SignalR hub operations that need to track session based clients.
///
/// Type of for hub operations.
public abstract class HubClientOperationsBase where T : class, IHubClient, new()
{
#region [ Members ]
// Fields
private readonly IHub m_hub;
private readonly Action m_logStatusMessageFunction;
private readonly Action m_logExceptionFunction;
private T m_hubClient;
#endregion
#region [ Constructors ]
///
/// Creates a new instance.
///
///
/// Delegate to use to log status messages, if any.
/// Delegate to use to log exceptions, if any.
protected HubClientOperationsBase(IHub hub, Action logStatusMessageFunction = null, Action logExceptionFunction = null)
{
m_hub = hub;
m_logStatusMessageFunction = logStatusMessageFunction;
m_logExceptionFunction = logExceptionFunction;
}
#endregion
#region [ Properties ]
///
/// Gets instance of hub client for current SignalR session.
///
protected T HubClient
{
get
{
if ((object)m_hubClient != null)
return m_hubClient;
// Attempt to get connection ID from active hub context
string connectionID = m_hub?.Context?.ConnectionId;
if (string.IsNullOrEmpty(connectionID))
{
// If no connection ID was available, check to see if base hub is a record operations hub,
// if so, see if there is an assigned connection ID to use, such as may be the case if the
// hub instance is being used outside of a SignalR context, like an IHostedHttpHandler
IRecordOperationsHub recordOperationsHub = m_hub as IRecordOperationsHub;
connectionID = recordOperationsHub?.ConnectionID;
if (string.IsNullOrEmpty(connectionID))
return null;
}
m_hubClient = s_hubClients.GetOrAdd(connectionID, id => new T
{
HubInstance = m_hub,
ConnectionID = connectionID,
LogStatusMessageFunction = m_logStatusMessageFunction,
LogExceptionFunction = m_logExceptionFunction
});
return m_hubClient;
}
}
///
/// Disposes any associated when SignalR session is disconnected.
///
///
/// This method should be called within implementing SignalR hub when stop is called.
///
public virtual void EndSession()
{
EndSession(m_hub?.Context?.ConnectionId);
}
#endregion
#region [ Static ]
// Static Fields
// References to session based IHubClient implementations - since a SignalR session can persist through
// any number of hub instances, this dictionary is used to track IHubClient instances
private static readonly ConcurrentDictionary s_hubClients;
// Static Constructor
static HubClientOperationsBase()
{
s_hubClients = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
}
// Static Methods
///
/// Disposes any associated when SignalR session is disconnected.
///
/// SignalR connection ID.
///
/// This method should be called within implementing SignalR hub when stop is called.
///
public static void EndSession(string connectionID)
{
T client;
// Dispose of hub client when SignalR session is disconnected
if (!string.IsNullOrEmpty(connectionID) && s_hubClients.TryRemove(connectionID, out client))
client?.Dispose();
}
#endregion
}
}