Created
March 17, 2017 23:11
-
-
Save dfch/884945aa6f9581e99ed4d7a351656749 to your computer and use it in GitHub Desktop.
Creating SignalR Hub Classes on the fly - http://d-fens.ch/2017/03/17/creating-signalr-hub-classes-on-the-fly/ - d-fens.ch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
using System.Collections.Generic; | |
using System.Configuration; | |
using System.Diagnostics; | |
using System.Diagnostics.Contracts; | |
using System.Linq; | |
using System.Reflection; | |
using biz.dfch.CS.Commons.Diagnostics; | |
using biz.dfch.CS.Commons.Linq; | |
using Microsoft.AspNet.SignalR; | |
using Microsoft.AspNet.SignalR.Hubs; | |
using Net.Appclusive.Public.Constants; | |
using Net.Appclusive.Public.SignalR; | |
using Owin; | |
namespace Net.Appclusive.WebApi.SignalR | |
{ | |
public static class SignalRConfiguration | |
{ | |
public static IDictionary<string, IHubContext<IWorkerClient>> HubMap; | |
public static void Configure(IAppBuilder app) | |
{ | |
Contract.Requires(null != app); | |
Logger.Get(Logging.TraceSourceName.WEB_API).TraceEvent(TraceEventType.Start, (int)Logging.EventId.Start, Message.SignalRConfiguration_Configure__START); | |
var connectionStringSettings = ConfigurationManager.ConnectionStrings[typeof(SignalRConfiguration).FullName]; | |
Contract.Assert(null != connectionStringSettings); | |
GlobalHost.DependencyResolver.UseSqlServer(connectionStringSettings.ConnectionString); | |
var hubFactory = new HubFactory<WorkerHubBase, IWorkerClient>(Core.Messaging.Hub.Queues.Keys, true); | |
var hubConfiguration = new HubConfiguration | |
{ | |
Resolver = hubFactory.DependencyResolver, | |
}; | |
app.MapSignalR(hubConfiguration); | |
HubMap = hubFactory.GetHubContextMap(); | |
Logger.Get(Logging.TraceSourceName.WEB_API).TraceEvent(TraceEventType.Stop, (int)Logging.EventId.Stop, Message.SignalRConfiguration_Configure__SUCCEEDED); | |
Sender.Initialise(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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.Threading.Tasks; | |
using Microsoft.AspNet.SignalR; | |
using Net.Appclusive.Public.SignalR; | |
namespace Net.Appclusive.WebApi.SignalR | |
{ | |
public class WorkerHubBase : Hub<IWorkerClient>, IWorkerHub | |
{ | |
public async void NotifyServer(string message) | |
{ | |
await Task.Yield(); | |
var x = message; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment