|
/** |
|
* Copyright 2017 d-fens GmbH |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics.Contracts; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Reflection; |
|
using System.Reflection.Emit; |
|
using Microsoft.AspNet.SignalR; |
|
using Microsoft.AspNet.SignalR.Hubs; |
|
using Microsoft.AspNet.SignalR.Infrastructure; |
|
|
|
namespace Net.Appclusive.WebApi.SignalR |
|
{ |
|
public class HubFactory<THubBase, THubClient> |
|
where THubBase : Hub<THubClient> |
|
where THubClient : class |
|
{ |
|
private const string NAMESPACE_SEPARATOR = "."; |
|
private const string FILE_EXTENSION = ".dll"; |
|
private readonly bool useTypeFullNameAsHubName; |
|
private IDictionary<string, Type> typeMap; |
|
|
|
public HubFactoryDependencyResolver DependencyResolver => |
|
new HubFactoryDependencyResolver |
|
( |
|
useTypeFullNameAsHubName |
|
? typeMap |
|
: typeMap.Values.ToDictionary(e => e.Name, e => e) |
|
); |
|
|
|
public HubFactory(ICollection<string> hubNames) |
|
: this(hubNames, false) |
|
{ |
|
// N/A |
|
} |
|
|
|
public HubFactory(ICollection<string> hubNames, bool useTypeFullNameAsHubName) |
|
{ |
|
this.useTypeFullNameAsHubName = useTypeFullNameAsHubName; |
|
|
|
CreateHubTypes(hubNames); |
|
} |
|
|
|
private void CreateHubTypes(ICollection<string> hubNames) |
|
{ |
|
Contract.Requires(null != hubNames); |
|
|
|
typeMap = new Dictionary<string, Type>(); |
|
|
|
var path = Path.GetTempPath(); |
|
var assemblyName = string.Concat(GetType().Namespace, NAMESPACE_SEPARATOR, Path.GetRandomFileName()); |
|
var assemblyFileName = assemblyName + FILE_EXTENSION; |
|
var asmName = new AssemblyName(assemblyName); |
|
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave, path); |
|
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName); |
|
|
|
foreach (var hubName in hubNames) |
|
{ |
|
var typeBuilder = moduleBuilder.DefineType(hubName, TypeAttributes.Public, typeof(THubBase)); |
|
var type = typeBuilder.CreateType(); |
|
typeMap.Add(hubName, type); |
|
} |
|
|
|
assemblyBuilder.Save(assemblyFileName); |
|
} |
|
|
|
public IDictionary<string, IHubContext<THubClient>> GetHubContextMap() |
|
{ |
|
Contract.Ensures(null != Contract.Result<IDictionary<string, IHubContext<THubClient>>>()); |
|
|
|
const int METHOD_GENERIC_ARGUMENTS_COUNT = 2; |
|
|
|
var result = new Dictionary<string, IHubContext<THubClient>>(); |
|
|
|
var methodInfos = GlobalHost.ConnectionManager.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); |
|
var genericMethodInfoGetHubContext = methodInfos.FirstOrDefault(e => |
|
e.IsGenericMethod |
|
&& e.ContainsGenericParameters |
|
&& METHOD_GENERIC_ARGUMENTS_COUNT == e.GetGenericArguments().Length |
|
&& typeof(IHub).IsAssignableFrom(e.GetGenericArguments().First()) |
|
&& e.Name == nameof(ConnectionManager.GetHubContext)); |
|
Contract.Assert(null != genericMethodInfoGetHubContext); |
|
|
|
foreach (var kvp in typeMap) |
|
{ |
|
var hubName = kvp.Key; |
|
var hubType = kvp.Value; |
|
|
|
var methodInfo = genericMethodInfoGetHubContext.MakeGenericMethod(hubType, typeof(THubClient)); |
|
var hubContext = (IHubContext<THubClient>) methodInfo.Invoke(GlobalHost.ConnectionManager, null); |
|
|
|
result.Add(hubName, hubContext); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
public class HubFactoryDependencyResolver : DefaultDependencyResolver |
|
{ |
|
private readonly IDictionary<string, Type> typeMap; |
|
|
|
internal HubFactoryDependencyResolver(IDictionary<string, Type> typeMap) |
|
{ |
|
Contract.Requires(null != typeMap); |
|
|
|
this.typeMap = typeMap; |
|
} |
|
|
|
public override IEnumerable<object> GetServices(Type serviceType) |
|
{ |
|
var services = base.GetServices(serviceType).ToList(); |
|
if (typeof(IHubDescriptorProvider).IsAssignableFrom(serviceType)) |
|
{ |
|
services.Add(new HubFactoryHubDescriptorProvider(typeMap)); |
|
} |
|
return services; |
|
} |
|
|
|
public class HubFactoryHubDescriptorProvider : IHubDescriptorProvider |
|
{ |
|
private readonly IDictionary<string, Type> typeMap; |
|
|
|
public HubFactoryHubDescriptorProvider(IDictionary<string, Type> typeMap) |
|
{ |
|
Contract.Requires(null != typeMap); |
|
|
|
this.typeMap = typeMap; |
|
} |
|
|
|
public IList<HubDescriptor> GetHubs() |
|
{ |
|
return typeMap |
|
.Select(e => new HubDescriptor |
|
{ |
|
Name = e.Key, |
|
NameSpecified = true, |
|
HubType = e.Value |
|
}) |
|
.ToList(); |
|
} |
|
|
|
public bool TryGetHub(string hubName, out HubDescriptor descriptor) |
|
{ |
|
if (!typeMap.ContainsKey(hubName)) |
|
{ |
|
descriptor = default(HubDescriptor); |
|
return false; |
|
} |
|
|
|
descriptor = new HubDescriptor |
|
{ |
|
Name = hubName, |
|
NameSpecified = true, |
|
HubType = typeMap[hubName] |
|
}; |
|
return true; |
|
} |
|
} |
|
} |
|
} |
|
} |