mirror of https://github.com/abpframework/abp.git
11 changed files with 340 additions and 1 deletions
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,27 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53900/", |
|||
"sslPort": 44362 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.SignalR": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<AssemblyName>Volo.Abp.AspNetCore.SignalR</AssemblyName> |
|||
<PackageId>Volo.Abp.AspNetCore.SignalR</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<IsPackable>true</IsPackable> |
|||
<OutputType>Library</OutputType> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.AspNetCore\Volo.Abp.AspNetCore.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,115 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http.Connections; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.AspNetCore.SignalR; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAspNetCoreModule) |
|||
)] |
|||
public class AbpAspNetCoreSignalRModule : AbpModule |
|||
{ |
|||
private static readonly MethodInfo MapHubGenericMethodInfo = |
|||
typeof(AbpAspNetCoreSignalRModule) |
|||
.GetMethod("MapHub", BindingFlags.Static | BindingFlags.NonPublic); |
|||
|
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddConventionalRegistrar(new AbpSignalRConventionalRegistrar()); |
|||
|
|||
AutoAddHubTypes(context.Services); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddSignalR(); |
|||
|
|||
Configure<AbpEndpointRouterOptions>(options => |
|||
{ |
|||
options.EndpointConfigureActions.Add(endpointContext => |
|||
{ |
|||
var signalROptions = endpointContext |
|||
.ScopeServiceProvider |
|||
.GetRequiredService<IOptions<AbpSignalROptions>>() |
|||
.Value; |
|||
|
|||
foreach (var hubConfig in signalROptions.Hubs) |
|||
{ |
|||
MapHubType( |
|||
hubConfig.HubType, |
|||
endpointContext.Endpoints, |
|||
hubConfig.RoutePattern, |
|||
opts => |
|||
{ |
|||
foreach (var configureAction in hubConfig.ConfigureActions) |
|||
{ |
|||
configureAction(opts); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
private void AutoAddHubTypes(IServiceCollection services) |
|||
{ |
|||
var hubTypes = new List<Type>(); |
|||
|
|||
services.OnRegistred(context => |
|||
{ |
|||
if (typeof(Hub).IsAssignableFrom(context.ImplementationType)) |
|||
{ |
|||
hubTypes.Add(context.ImplementationType); |
|||
} |
|||
}); |
|||
|
|||
services.Configure<AbpSignalROptions>(options => |
|||
{ |
|||
foreach (var hubType in hubTypes) |
|||
{ |
|||
options.Hubs.Add(HubConfig.Create(hubType)); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private void MapHubType( |
|||
Type hubType, |
|||
IEndpointRouteBuilder endpoints, |
|||
string pattern, |
|||
Action<HttpConnectionDispatcherOptions> configureOptions) |
|||
{ |
|||
MapHubGenericMethodInfo |
|||
.MakeGenericMethod(hubType) |
|||
.Invoke( |
|||
this, |
|||
new object[] |
|||
{ |
|||
endpoints, |
|||
pattern, |
|||
configureOptions |
|||
} |
|||
); |
|||
} |
|||
|
|||
// ReSharper disable once UnusedMember.Local (used via reflection)
|
|||
private static void MapHub<THub>( |
|||
IEndpointRouteBuilder endpoints, |
|||
string pattern, |
|||
Action<HttpConnectionDispatcherOptions> configureOptions) |
|||
where THub : Hub |
|||
{ |
|||
endpoints.MapHub<THub>( |
|||
pattern, |
|||
configureOptions |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using Microsoft.AspNetCore.SignalR; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
public class AbpSignalRConventionalRegistrar : ConventionalRegistrarBase |
|||
{ |
|||
public override void AddType(IServiceCollection services, Type type) |
|||
{ |
|||
if (IsConventionalRegistrationDisabled(type)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (!IsHub(type)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type); |
|||
|
|||
TriggerServiceExposing(services, type, serviceTypes); |
|||
|
|||
foreach (var serviceType in serviceTypes) |
|||
{ |
|||
services.Add( |
|||
ServiceDescriptor.Describe( |
|||
serviceType, |
|||
type, |
|||
ServiceLifetime.Transient |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
private static bool IsHub(Type type) |
|||
{ |
|||
return typeof(Hub).IsAssignableFrom(type); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
public class AbpSignalROptions |
|||
{ |
|||
public List<HubConfig> Hubs { get; } |
|||
|
|||
public AbpSignalROptions() |
|||
{ |
|||
Hubs = new List<HubConfig>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.AspNetCore.Http.Connections; |
|||
using Microsoft.AspNetCore.SignalR; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
public class HubConfig |
|||
{ |
|||
[NotNull] |
|||
public Type HubType { get; } |
|||
|
|||
[NotNull] |
|||
public string RoutePattern { get; set; } |
|||
|
|||
[NotNull] |
|||
public List<Action<HttpConnectionDispatcherOptions>> ConfigureActions { get; set; } |
|||
|
|||
public HubConfig( |
|||
[NotNull] Type hubType, |
|||
[NotNull] string routePattern) |
|||
{ |
|||
HubType = Check.NotNull(hubType, nameof(hubType)); |
|||
RoutePattern = Check.NotNullOrWhiteSpace(routePattern, nameof(routePattern)); |
|||
ConfigureActions = new List<Action<HttpConnectionDispatcherOptions>>(); |
|||
} |
|||
|
|||
public static HubConfig Create<THub>() |
|||
where THub : Hub |
|||
{ |
|||
return Create(typeof(THub)); |
|||
} |
|||
|
|||
public static HubConfig Create(Type hubType) |
|||
{ |
|||
return new HubConfig( |
|||
hubType, |
|||
HubRouteAttribute.GetRoutePattern(hubType) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using Microsoft.AspNetCore.SignalR; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
public class HubRouteAttribute : Attribute |
|||
{ |
|||
public string RoutePattern { get; set; } |
|||
|
|||
public HubRouteAttribute(string routePattern) |
|||
{ |
|||
RoutePattern = routePattern; |
|||
} |
|||
|
|||
public static string GetRoutePattern<THub>() |
|||
where THub : Hub |
|||
{ |
|||
return GetRoutePattern(typeof(THub)); |
|||
} |
|||
|
|||
public static string GetRoutePattern(Type hubType) |
|||
{ |
|||
var routeAttribute = hubType.GetSingleAttributeOrNull<HubRouteAttribute>(); |
|||
if (routeAttribute != null) |
|||
{ |
|||
return routeAttribute.RoutePattern; |
|||
} |
|||
|
|||
return "/signalr-hubs/" + hubType.Name.RemovePostFix("Hub").ToKebabCase(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue