这是一个修改后的 DefaultJavaScriptProxyGenerator,有以下变化:
- 它将使用新的 [HubMethodExcludeFromProxy] 属性从 Javascript 代理生成中排除函数。
-
private static 函数已更改为 protected virtual 以供未来衍生。
-
GenerateProxy( ) 函数具有包含 DocComments 的重载,但它不像非 DocComments 版本那样缓存结果。现在它们都缓存了。
- 两个资源,Resources.DynamicComment_CallsMethodOnServerSideDeferredPromise 和 Resources.DynamicComment_ServerSideTypeIs 是另一个程序集的私有资源,所以为了编译,我直接从资源文件中复制了文本。仅当 DocComments 为 true 时才使用这两个资源。
- 所有 DefaultJavaScriptProxyGenerator 引用都更改为 CustomJavaScriptProxyGenerator,除了一个用于定位资源脚本 Microsoft.AspNet.SignalR.Scripts.hubs .js,位于不同的程序集中。
首先,您需要更新依赖解析器以使用新的 CustomJavaScriptProxyGenerator 用于 IJavaScriptProxyGenerator 接口。如果您使用的是默认解析器,您可以像这样设置自定义解析器:
map.RunSignalR(
新的 HubConfiguration() {
解析器 = 新的 CustomDependencyResolver()
}
);
这是一个从 DefaultDependecyResolver 派生的自定义解析器:
命名空间 Microsoft.AspNet.SignalR
{
公共类 CustomDependencyResolver : DefaultDependencyResolver
{
MyDependencyResolver() : 基础()
{
var proxyGenerator = new Lazy(() => new CustomJavaScriptProxyGenerator(this));
Register(typeof(IJavaScriptProxyGenerator), () => proxyGenerator.Value);
}
}
}
最后,这是新的 CustomJavaScriptProxyGenerator.cs 文件(HubMethodExcludeFromProxyAttribute 类在底部):
// 版权所有 (c) .NET 基金会。版权所有。
// 根据 Apache 许可证 2.0 版获得许可。有关许可证信息,请参阅项目根目录中的 License.txt。
// Brain2000 的模组
使用系统;
使用 System.Collections;
使用 System.Collections.Generic;
使用 System.Globalization;
使用 System.IO;
使用 System.Linq;
使用 System.Text;
使用 Microsoft.AspNet.SignalR.Json;
使用 Microsoft.AspNet.SignalR.Hubs;
使用 Newtonsoft.Json;
命名空间 Microsoft.AspNet.SignalR.Hubs
{
公共类 CustomJavaScriptProxyGenerator : IJavaScriptProxyGenerator
{
protected static readonly Lazy _templateFromResource = new Lazy(GetTemplateFromResource);
protected static readonly Type[] _numberTypes = new[] { typeof(byte), typeof(short), typeof(int), typeof(long), typeof(float), typeof(decimal), typeof(double) };
protected static readonly Type[] _dateTypes = new[] { typeof(DateTime), typeof(DateTimeOffset) };
protected const string ScriptResource = "Microsoft.AspNet.SignalR.Scripts.hubs.js";
受保护的只读 IHubManager _manager;
受保护的只读 IJavaScriptMinifier _javaScriptMinifier;
protected readonly Lazy _generatedTemplate;
受保护的只读 Lazy _generatedTemplateWithComments;
公共 CustomJavaScriptProxyGenerator(IDependencyResolver 解析器):
这(解析器。解析(),
解析器.Resolve())
{
}
公共 CustomJavaScriptProxyGenerator(IHubManager 管理器,IJavaScriptMinifier javaScriptMinifier)
{
_manager = 经理;
_javaScriptMinifier = javaScriptMinifier ?? NullJavaScriptMinifier.Instance;
_generatedTemplate = new Lazy(() => GenerateProxy(_manager, _javaScriptMinifier, includeDocComments: false));
_generatedTemplateWithComments = new Lazy(() => GenerateProxy(_manager, _javaScriptMinifier, includeDocComments: true));
}
公共字符串 GenerateProxy(字符串 serviceUrl)
{
serviceUrl = JavaScriptEncode(serviceUrl);
return _generatedTemplate.Value.Replace("{serviceUrl}", serviceUrl);
}
公共字符串 GenerateProxy(string serviceUrl, bool includeDocComments)
{
if (!includeDocComments) return GenerateProxy(serviceUrl); //使用 includeDocComments: false 缓存版本
serviceUrl = JavaScriptEncode(serviceUrl);
return _generatedTemplateWithComments.Value.Replace("{serviceUrl}", serviceUrl);
}
受保护的虚拟字符串 GenerateProxy(IHubManager hubManager, IJavaScriptMinifier javaScriptMinifier, bool includeDocComments)
{
字符串脚本 = _templateFromResource.Value;
var hubs = new StringBuilder();
var first = true;
foreach(hubManager.GetHubs().OrderBy(h => h.Name) 中的 var 描述符)
{
如果(!第一)
{
hubs.AppendLine(";");
hubs.AppendLine();
hubs.Append("");
}
GenerateType(hubManager, hubs, 描述符, includeDocComments);
第一=假;
}
if (hubs.Length > 0)
{
hubs.Append(";");
}
script = script.Replace("/*hubs*/", hubs.ToString());
返回 javaScriptMinifier.Minify(脚本);
}
protected virtual void GenerateType(IHubManager hubManager, StringBuilder sb, HubDescriptor 描述符, bool includeDocComments)
{
// 仅获取具有最少参数数量的操作。
var 方法 = GetMethods(hubManager, 描述符);
var hubName = GetDescriptorName(描述符);
sb.AppendFormat(" proxies['{0}'] = this.createHubProxy('{1}'); ", hubName, hubName).AppendLine();
sb.AppendFormat("代理['{0}'].client = {{ }};", hubName).AppendLine();
sb.AppendFormat("代理['{0}'].server = {{", hubName);
布尔优先=真;
foreach(方法中的var方法)
{
如果(!第一)
{
sb.Append(",").AppendLine();
}
GenerateMethod(sb, method, includeDocComments, hubName);
第一=假;
}
sb.AppendLine();
sb.Append(" }");
}
受保护的虚拟字符串 GetDescriptorName(描述符描述符)
{
如果(描述符 == 空)
{
抛出新的 ArgumentNullException("descriptor");
}
字符串名称 = 描述符。名称;
// 如果未指定名称,则不要使用驼峰式大小写
if (!descriptor.NameSpecified)
{
名称 = JsonUtility.CamelCase(名称);
}
返回名称;
}
受保护的虚拟 IEnumerable GetMethods(IHubManager 管理器,HubDescriptor 描述符)
{
从 manager.GetHubMethods(descriptor.Name).Where(md => md.Attributes.FirstOrDefault(a => (a.GetType() == typeof(HubMethodExcludeFromProxyAttribute))) == null) 中的方法返回
按 method.Name 将方法分组为重载
让 oload = (从重载中的重载
orderby 重载.Parameters.Count
选择重载).FirstOrDefault()
orderby oload.Name
选择负载;
}
protected virtual void GenerateMethod(StringBuilder sb, MethodDescriptor method, bool includeDocComments, string hubName)
{
var parameterNames = method.Parameters.Select(p => p.Name).ToList();
sb.AppendLine();
sb.AppendFormat(" {0}: function ({1}) {{", GetDescriptorName(method), Commas(parameterNames)).AppendLine();
if (includeDocComments)
{
sb.AppendFormat(" /// 调用服务器端 {1} 集线器上的 {0} 方法。\n返回 jQuery.Deferred() 承诺。", method.Name, method.Hub.Name).AppendLine() ;
var parameterDoc = method.Parameters.Select(p => String.Format(CultureInfo.CurrentCulture, " /// 服务器端类型为 {2}", p.Name, MapToJavaScriptType(p.ParameterType), p.ParameterType))。列表();
如果(参数Doc.Any())
{
sb.AppendLine(String.Join(Environment.NewLine, parameterDoc));
}
}
sb.AppendFormat(" return proxies['{0}'].invoke.apply(proxies['{0}'], $.merge([\"{1}\"], $.makeArray(arguments))) ;", hubName, method.Name).AppendLine();
sb.Append(" }");
}
受保护的虚拟字符串 MapToJavaScriptType(类型类型)
{
if (!type.IsPrimitive && !(type == typeof(string)))
{
返回“对象”;
}
if (type == typeof(string))
{
返回“字符串”;
}
if (_numberTypes.Contains(type))
{
返回“数字”;
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
返回“数组”;
}
if (_dateTypes.Contains(type))
{
归期”;
}
返回字符串。空;
}
受保护的虚拟字符串逗号(IEnumerable 值)
{
返回逗号(值,v => v);
}
受保护的虚拟字符串逗号(IEnumerable 值,Func 选择器)
{
返回 String.Join(", ", values.Select(selector));
}
受保护的静态字符串 GetTemplateFromResource()
{
//这必须保留为“DefaultJavaScriptProxyGenerator”,因为资源“Microsoft.AspNet.SignalR.Scripts.hubs.js”在那里
使用 (Stream resourceStream = typeof(DefaultJavaScriptProxyGenerator).Assembly.GetManifestResourceStream(ScriptResource))
{
var reader = new StreamReader(resourceStream);
返回 reader.ReadToEnd();
}
}
受保护的虚拟字符串 JavaScriptEncode(字符串值)
{
值 = JsonConvert.SerializeObject(值);
// 删除引号
返回 value.Substring(1, value.Length - 2);
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
公共密封类 HubMethodExcludeFromProxyAttribute :属性
{
}
}
现在您需要做的就是为您的 hub 方法添加一个装饰器,例如:
公共类 MyHub : 集线器
{
[HubMethodExcludeFromProxy]
公共无效NotGeneratedOnClient()
{
}
公共无效 GeneratedOnClient()
{
}
}
编辑:依赖注入存在一个问题,如果您有两个不同的解析器实例,一个在 GlobalHost.DependencyResolver 中,一个在 Signalr 配置中,有时会导致远程方法不行。这是修复:
//仅使用!一个!解析器的实例,或远程 SignalR 函数可能无法运行!
var resolver = new CustomDependencyResolver();
GlobalHost.Configuration.DependencyResolver = 解析器;
map.RunSignalR(
新的 HubConfiguration() {
解析器=解析器;
}
);
参考:https://github.com/SignalR/SignalR/issues/2807