/// <summary> /// Defined what other bindings can use and return value. /// </summary> private IReadOnlyDictionary <string, Type> CreateBindingContract(SignalRTriggerAttribute attribute, ParameterInfo parameter) { var contract = new Dictionary <string, Type>(StringComparer.OrdinalIgnoreCase) { { ReturnParameterKey, typeof(object).MakeByRefType() }, }; // Add names in ParameterNames to binding contract, that user can bind to Functions' parameter directly if (attribute.ParameterNames != null) { var parameters = ((MethodInfo)parameter.Member).GetParameters().ToDictionary(p => p.Name, p => p.ParameterType, StringComparer.OrdinalIgnoreCase); foreach (var parameterName in attribute.ParameterNames) { if (parameters.ContainsKey(parameterName)) { contract.Add(parameterName, parameters[parameterName]); } else { contract.Add(parameterName, typeof(object)); } } } return(contract); }
public SignalRTriggerBinding(ParameterInfo parameterInfo, SignalRTriggerAttribute attribute, ISignalRTriggerDispatcher dispatcher) { _parameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo)); _attribute = attribute ?? throw new ArgumentNullException(nameof(attribute)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); BindingDataContract = CreateBindingContract(_attribute, _parameterInfo); }
internal SignalRTriggerAttribute GetParameterResolvedAttribute(SignalRTriggerAttribute attribute, ParameterInfo parameterInfo) { //TODO: AutoResolve more properties in attribute var hubName = attribute.HubName; var category = attribute.Category; var @event = attribute.Event; var parameterNames = attribute.ParameterNames ?? Array.Empty <string>(); var connectionStringSetting = attribute.ConnectionStringSetting; // We have two models for C#, one is function based model which also work in multiple language // Another one is class based model, which is highly close to SignalR itself but must keep some conventions. var method = (MethodInfo)parameterInfo.Member; var declaredType = method.DeclaringType; string[] parameterNamesFromAttribute; if (declaredType != null && IsServerlessHub(declaredType)) { // Class based model if (!string.IsNullOrEmpty(hubName) || !string.IsNullOrEmpty(category) || !string.IsNullOrEmpty(@event) || parameterNames.Length != 0) { throw new ArgumentException($"{nameof(SignalRTriggerAttribute)} must use parameterless constructor in class based model."); } parameterNamesFromAttribute = method.GetParameters().Where(IsLegalClassBasedParameter).Select(p => p.Name).ToArray(); hubName = declaredType.Name; category = GetCategoryFromMethodName(method.Name); @event = GetEventFromMethodName(method.Name, category); connectionStringSetting = declaredType.GetCustomAttribute <SignalRConnectionAttribute>()?.Connection ?? attribute.ConnectionStringSetting; } else { parameterNamesFromAttribute = method.GetParameters(). Where(p => p.GetCustomAttribute <SignalRParameterAttribute>(false) != null). Select(p => p.Name).ToArray(); if (parameterNamesFromAttribute.Length != 0 && parameterNames.Length != 0) { throw new InvalidOperationException( $"{nameof(SignalRTriggerAttribute)}.{nameof(SignalRTriggerAttribute.ParameterNames)} and {nameof(SignalRParameterAttribute)} can not be set in the same Function."); } // If we aren't using the class-based model, make sure we resolve binding expressions for attribute properties here. hubName = _nameResolver.ResolveWholeString(hubName); category = _nameResolver.ResolveWholeString(category); @event = _nameResolver.ResolveWholeString(@event); } parameterNames = parameterNamesFromAttribute.Length != 0 ? parameterNamesFromAttribute : parameterNames; return(new SignalRTriggerAttribute(hubName, category, @event, parameterNames) { ConnectionStringSetting = connectionStringSetting }); }
private static void ValidateSignalRTriggerAttributeBinding(SignalRTriggerAttribute attribute) { if (string.IsNullOrWhiteSpace(attribute.ConnectionStringSetting)) { throw new InvalidOperationException( $"{nameof(SignalRTriggerAttribute)}.{nameof(SignalRConnectionInfoAttribute.ConnectionStringSetting)} is not allowed to be null or whitespace."); } ValidateParameterNames(attribute.ParameterNames); }
private void ValidateSignalRTriggerAttributeBinding(SignalRTriggerAttribute attribute) { if (string.IsNullOrEmpty(attribute.ConnectionStringSetting)) { throw new InvalidOperationException(string.Format(ErrorMessages.EmptyConnectionStringErrorMessageFormat, $"{nameof(SignalRTriggerAttribute)}.{nameof(SignalRConnectionInfoAttribute.ConnectionStringSetting)}")); } ValidateParameterNames(attribute.ParameterNames); }
public SignalRTriggerBinding(ParameterInfo parameterInfo, SignalRTriggerAttribute attribute, ISignalRTriggerDispatcher dispatcher, AccessKey[] accessKeys, ServiceHubContext hubContext) { _parameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo)); _attribute = attribute ?? throw new ArgumentNullException(nameof(attribute)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); _accessKeys = accessKeys ?? throw new ArgumentNullException(nameof(accessKeys)); _hubContext = hubContext; BindingDataContract = CreateBindingContract(_attribute, _parameterInfo); }