Beispiel #1
0
        public static object GetResult(this Task task)
        {
            try
            {
                if (!task.IsCompleted)
                {
                    task.Wait();
                }

                if (task is Task <object> taskObj)
                {
                    return(taskObj.Result);
                }

                var taskType = task.GetType();
                if (!taskType.IsGenericType || taskType.FullName.Contains("VoidTaskResult"))
                {
                    return(null);
                }

                var props = TypeProperties.Get(taskType);
                var fn    = props.GetPublicGetter("Result");
                return(fn?.Invoke(task));
            }
            catch (TypeAccessException)
            {
                return(null); //return null for void Task's
            }
            catch (Exception ex)
            {
                throw ex.UnwrapIfSingleException();
            }
        }
 private static void InitUserFieldDefinition(Type modelType, FieldDefinition fieldDef)
 {
     if (fieldDef.PropertyInfo == null)
     {
         fieldDef.PropertyInfo = TypeProperties.Get(modelType).GetPublicProperty(fieldDef.Name);
     }
 }
        public void Can_use_getter_and_setter_on_ValueTypeProps()
        {
            var typeFields = TypeProperties.Get(typeof(ValueTypeProps));

            var o = (object)new ValueTypeProps {
                S = "foo", I = 1
            };

            typeFields.GetPublicSetter("S")(o, "bar");
            Assert.That(typeFields.GetPublicGetter("S")(o), Is.EqualTo("bar"));

            typeFields.GetPublicSetter("I")(o, 2);
            Assert.That(typeFields.GetPublicGetter("I")(o), Is.EqualTo(2));
        }
        public void Can_get_result_of_Task()
        {
            var tcs  = new TaskCompletionSource <string>();
            var task = tcs.Task;

            tcs.SetResult("foo");

            var fn    = TypeProperties.Get(task.GetType()).GetPublicGetter("Result");
            var value = fn(task);

            Assert.That(value, Is.EqualTo("foo"));

            fn    = TypeProperties.Get(task.GetType()).GetPublicGetter("Result");
            value = fn(task);
            Assert.That(value, Is.EqualTo("foo"));
        }
Beispiel #5
0
        public object GetValue(object instance)
        {
            var type = instance.GetType();

            if (PropertyInfo.DeclaringType?.IsAssignableFrom(type) != true)
            {
                if (instance is IDictionary d)
                {
                    return(d[Name]);
                }

                var accessor = TypeProperties.Get(type).GetAccessor(Name);
                return(accessor?.PublicGetter(instance));
            }

            return(this.GetValueFn?.Invoke(instance));
        }
        public void Can_use_TypedProperties_accessor()
        {
            var runtimeType = typeof(MyType);
            var typeProps   = TypeProperties.Get(runtimeType); //Equivalent to:
            //  typeProps = TypeProperties<MyType>.Instance;

            var instance = runtimeType.CreateInstance();

            var propAccessor = typeProps.GetAccessor("LongProp");

            propAccessor.PublicSetter(instance, 1L);
            Assert.That(propAccessor.PublicGetter(instance), Is.EqualTo(1));

            typeProps.GetPublicSetter("StringProp")(instance, "foo");
            var value = typeProps.GetPublicGetter("StringProp")(instance);

            Assert.That(value, Is.EqualTo("foo"));
        }
Beispiel #7
0
        private static object PropValue(object targetValue, Type targetType, string name)
        {
            var memberFn = TypeProperties.Get(targetType).GetPublicGetter(name)
                           ?? TypeFields.Get(targetType).GetPublicGetter(name);

            if (memberFn != null)
            {
                return(memberFn(targetValue));
            }

            var indexerMethod = targetType.GetInstanceMethod("get_Item");

            if (indexerMethod != null)
            {
                var fn  = indexerMethod.GetInvoker();
                var ret = fn(targetValue, name);
                return(ret ?? JsNull.Value);
            }

            throw new ArgumentException($"'{targetType.Name}' does not have a '{name}' property or field");
        }
        public void Can_cache_ValueTuple_field_accessors()
        {
            var typeProperties = TypeProperties.Get(typeof(RefTypeProps));

            var oTuple = (object)CreateTypedTuple();

            typeProperties.GetPublicSetter("S")(oTuple, "bar");
            typeProperties.GetPublicSetter("I")(oTuple, 10);
            typeProperties.GetPublicSetter("L")(oTuple, 20L);
            typeProperties.GetPublicSetter("D")(oTuple, 4.4d);

            Assert.That(typeProperties.GetPublicGetter("S")(oTuple), Is.EqualTo("bar"));
            Assert.That(typeProperties.GetPublicGetter("I")(oTuple), Is.EqualTo(10));
            Assert.That(typeProperties.GetPublicGetter("L")(oTuple), Is.EqualTo(20));
            Assert.That(typeProperties.GetPublicGetter("D")(oTuple), Is.EqualTo(4.4));

            var tuple = (RefTypeProps)oTuple;

            Assert.That(tuple.S, Is.EqualTo("bar"));
            Assert.That(tuple.I, Is.EqualTo(10));
            Assert.That(tuple.L, Is.EqualTo(20));
            Assert.That(tuple.D, Is.EqualTo(4.4));
        }
Beispiel #9
0
        private static object PropValue(object targetValue, Type targetType, string name)
        {
            var memberFn = TypeProperties.Get(targetType).GetPublicGetter(name)
                           ?? TypeFields.Get(targetType).GetPublicGetter(name);

            if (memberFn != null)
            {
                return(memberFn(targetValue));
            }

            var methods       = targetType.GetInstanceMethods();
            var indexerMethod =
                methods.FirstOrDefault(x => x.Name == "get_Item" && x.GetParameters().Any(p => p.ParameterType == typeof(string))) ??
                methods.FirstOrDefault(x => x.Name == "get_Item" && x.GetParameters().Any(p => p.ParameterType != typeof(string)));

            if (indexerMethod != null)
            {
                var fn  = indexerMethod.GetInvoker();
                var ret = fn(targetValue, name);
                return(ret);
            }

            throw new ArgumentException($"'{targetType.Name}' does not have a '{name}' property or field");
        }
Beispiel #10
0
    public async Task HandleFileUploadsAsync(IRequest req, IResponse res, object dto)
    {
        if (req.Files?.Length > 0)
        {
            var requestType = dto.GetType();
            // ignore unless a Request DTO Property contains [UploadTo] Attribute
            if (!HostContext.Metadata.GetOperation(requestType).RequestPropertyAttributes.Contains(typeof(UploadToAttribute)))
            {
                return;
            }

            var uploadFileAsync = HandleUploadFileAsync
                                  ?? throw new NotSupportedException("AppHost.HandleUploadFileAsync needs to be configured to allow file uploads in " + requestType.Name);

            var dtoProps         = TypeProperties.Get(requestType);
            var uploadedPathsMap = new Dictionary <string, List <(string, IHttpFile)> >();
            foreach (var file in req.Files)
            {
                var uploadedPath = await uploadFileAsync(req, file, default).ConfigAwait();

                if (string.IsNullOrEmpty(uploadedPath))
                {
                    continue;
                }
                if (!uploadedPathsMap.TryGetValue(file.Name, out var uploadedPaths))
                {
                    uploadedPaths = uploadedPathsMap[file.Name] = new List <(string, IHttpFile)>();
                }
                uploadedPaths.Add((uploadedPath, file));
            }

            var dtoValues = new Dictionary <string, object>();
            foreach (var entry in uploadedPathsMap)
            {
                var prop = dtoProps.GetPublicProperty(entry.Key);
                if (prop == null)
                {
                    continue;
                }

                var paths = entry.Value.Map(x => x.Item1);
                if (prop.PropertyType == typeof(string))
                {
                    dtoValues[prop.Name] = paths[0];
                }
                else if (prop.PropertyType.HasInterface(typeof(IEnumerable <string>)))
                {
                    dtoValues[prop.Name] = paths.ConvertTo(prop.PropertyType);
                }
                else
                {
                    var elType = prop.PropertyType.GetCollectionType();
                    if (elType != null && elType != typeof(object))
                    {
                        var to = new List <object>();
                        foreach (var fileEntry in entry.Value)
                        {
                            var el = CreateFromHttpFileInfo(filePath: fileEntry.Item1, file: fileEntry.Item2, elType);
                            to.Add(el);
                        }
                        dtoValues[prop.Name] = to.ConvertTo(prop.PropertyType);
                    }
                    else if (prop.PropertyType != typeof(object) && prop.PropertyType.IsClass)
                    {
                        var fileEntry = entry.Value[0];
                        var to        = CreateFromHttpFileInfo(filePath: fileEntry.Item1, file: fileEntry.Item2, prop.PropertyType);
                        dtoValues[prop.Name] = to;
                    }
                    else
                    {
                        throw new NotSupportedException("Cannot populated uploaded Request.Files metadata to " + prop.PropertyType.Name);
                    }
                }
            }
            dtoValues.PopulateInstance(dto);
        }
    }
Beispiel #11
0
    /// <summary>
    /// Converts the type of the dump.
    /// </summary>
    /// <param name="target">The target.</param>
    /// <returns>System.Object.</returns>
    internal static object ConvertDumpType(object target)
    {
        var targetType  = target.GetType();
        var genericKvps = targetType.GetTypeWithGenericTypeDefinitionOf(typeof(KeyValuePair <,>));

        if (genericKvps != null)
        {
            var keyGetter   = TypeProperties.Get(targetType).GetPublicGetter("Key");
            var valueGetter = TypeProperties.Get(targetType).GetPublicGetter("Value");
            return(new Dictionary <string, object> {
                { keyGetter(target).ConvertTo <string>(), valueGetter(target) },
            });
        }

        if (target is IEnumerable e)
        {
            //Convert IEnumerable<object> to concrete generic collection so generic args can be inferred
            if (e is IEnumerable <object> enumObjs)
            {
                Type elType = null;
                foreach (var item in enumObjs)
                {
                    elType = item.GetType();
                    break;
                }
                if (elType != null)
                {
                    targetType = typeof(List <>).MakeGenericType(elType);
                    var genericList = (IList)targetType.CreateInstance();
                    foreach (var item in e)
                    {
                        genericList.Add(item.ConvertTo(elType));
                    }
                    target = genericList;
                }
            }

            if (targetType.GetKeyValuePairsTypes(out var keyType, out var valueType, out var kvpType))
            {
                var keyGetter   = TypeProperties.Get(kvpType).GetPublicGetter("Key");
                var valueGetter = TypeProperties.Get(kvpType).GetPublicGetter("Value");

                string key1 = null, key2 = null;
                foreach (var kvp in e)
                {
                    if (key1 == null)
                    {
                        key1 = keyGetter(kvp).ConvertTo <string>();
                        continue;
                    }
                    key2 = keyGetter(kvp).ConvertTo <string>();
                    break;
                }

                var isColumn = key1 == key2;
                if (isColumn)
                {
                    var to = new List <Dictionary <string, object> >();
                    foreach (var kvp in e)
                    {
                        to.Add(new Dictionary <string, object> {
                            { keyGetter(kvp).ConvertTo <string>(), valueGetter(kvp) }
                        });
                    }
                    return(to);
                }

                return(target.ToObjectDictionary());
            }
        }

        return(target);
    }
Beispiel #12
0
        private static async Task RequestFilterAsync(IRequest req, IResponse res, object requestDto,
                                                     bool treatInfoAndWarningsAsErrors)
        {
            var requestType = requestDto.GetType();
            await Validators.AssertTypeValidatorsAsync(req, requestDto, requestType);

            var validator = ValidatorCache.GetValidator(req, requestType);

            if (validator == null)
            {
                return;
            }

            using (validator as IDisposable)
            {
                if (validator is IHasTypeValidators hasTypeValidators && hasTypeValidators.TypeValidators.Count > 0)
                {
                    foreach (var scriptValidator in hasTypeValidators.TypeValidators)
                    {
                        await scriptValidator.ThrowIfNotValidAsync(requestDto, req);
                    }
                }

                try
                {
                    if (req.Verb == HttpMethods.Patch)
                    {
                        // Ignore property rules for AutoCrud Patch operations with default values that aren't reset (which are ignored)
                        if (validator is IServiceStackValidator ssValidator && requestDto is ICrud && requestType.IsOrHasGenericInterfaceTypeOf(typeof(IPatchDb <>)))
                        {
                            var typeProperties         = TypeProperties.Get(requestType);
                            var propsWithDefaultValues = new HashSet <string>();
                            var resetFields            = GetResetFields(req.GetParam(Keywords.reset))?.ToSet(StringComparer.OrdinalIgnoreCase)
                                                         ?? TypeConstants <string> .EmptyHashSet;

                            foreach (var entry in typeProperties.PropertyMap)
                            {
                                if (entry.Value.PublicGetter == null || resetFields.Contains(entry.Key))
                                {
                                    continue;
                                }
                                var defaultValue = entry.Value.PropertyInfo.PropertyType.GetDefaultValue();
                                var propValue    = entry.Value.PublicGetter(requestDto);
                                if (propValue == null || propValue.Equals(defaultValue))
                                {
                                    propsWithDefaultValues.Add(entry.Key);
                                }
                            }
                            if (propsWithDefaultValues.Count > 0)
                            {
                                ssValidator.RemovePropertyRules(rule => propsWithDefaultValues.Contains(rule.PropertyName));
                            }
                        }
                    }

                    var validationResult = await validator.ValidateAsync(req, requestDto);

                    if (treatInfoAndWarningsAsErrors && validationResult.IsValid)
                    {
                        return;
                    }

                    if (!treatInfoAndWarningsAsErrors &&
                        (validationResult.IsValid || validationResult.Errors.All(v => v.Severity != Severity.Error)))
                    {
                        return;
                    }

                    var errorResponse =
                        await HostContext.RaiseServiceException(req, requestDto, validationResult.ToException())
                        ?? DtoUtils.CreateErrorResponse(requestDto, validationResult.ToErrorResult());

                    var autoBatchIndex = req.GetItem(Keywords.AutoBatchIndex)?.ToString();
                    if (autoBatchIndex != null)
                    {
                        var responseStatus = errorResponse.GetResponseStatus();
                        if (responseStatus != null)
                        {
                            if (responseStatus.Meta == null)
                            {
                                responseStatus.Meta = new Dictionary <string, string>();
                            }
                            responseStatus.Meta[Keywords.AutoBatchIndex] = autoBatchIndex;
                        }
                    }

                    var validationFeature = HostContext.GetPlugin <ValidationFeature>();
                    if (validationFeature?.ErrorResponseFilter != null)
                    {
                        errorResponse = validationFeature.ErrorResponseFilter(req, validationResult, errorResponse);
                    }

                    await res.WriteToResponse(req, errorResponse);
                }
                catch (Exception ex)
                {
                    var validationEx = ex.UnwrapIfSingleException();

                    var errorResponse = await HostContext.RaiseServiceException(req, requestDto, validationEx)
                                        ?? DtoUtils.CreateErrorResponse(requestDto, validationEx);

                    await res.WriteToResponse(req, errorResponse);
                }
            }
        }
        private object GetValue(object targetValue, TemplateScopeContext scope)
        {
            if (targetValue == null || targetValue == JsNull.Value)
            {
                return(JsNull.Value);
            }
            var targetType = targetValue.GetType();

            try
            {
                object propValue(string name)
                {
                    var memberFn = TypeProperties.Get(targetType).GetPublicGetter(name)
                                   ?? TypeFields.Get(targetType).GetPublicGetter(name);

                    if (memberFn != null)
                    {
                        return(memberFn(targetValue));
                    }

                    var indexerMethod = targetType.GetInstanceMethod("get_Item");

                    if (indexerMethod != null)
                    {
                        var fn  = indexerMethod.GetInvoker();
                        var ret = fn(targetValue, name);
                        return(ret ?? JsNull.Value);
                    }

                    throw new ArgumentException($"'{targetType.Name}' does not have a '{name}' property or field");
                }

                if (!Computed)
                {
                    if (Property is JsIdentifier identifier)
                    {
                        var ret = propValue(identifier.NameString);

                        // Don't emit member expression on null KeyValuePair
                        if (ret == null && targetType.Name == "KeyValuePair`2")
                        {
                            return(JsNull.Value);
                        }

                        return(ret);
                    }
                }
                else
                {
                    var indexValue = Property.Evaluate(scope);
                    if (indexValue == null)
                    {
                        return(JsNull.Value);
                    }

                    if (targetType.IsArray)
                    {
                        var array = (Array)targetValue;
                        if (indexValue is long l)
                        {
                            return(array.GetValue(l));
                        }
                        var intValue = indexValue.ConvertTo <int>();
                        return(array.GetValue(intValue));
                    }
                    if (targetValue is IDictionary dict)
                    {
                        var ret = dict[indexValue];
                        return(ret ?? JsNull.Value);
                    }
                    if (indexValue is string propName)
                    {
                        return(propValue(propName));
                    }
                    if (targetValue is IList list)
                    {
                        var intValue = indexValue.ConvertTo <int>();
                        return(list[intValue]);
                    }
                    if (targetValue is IEnumerable e)
                    {
                        var intValue = indexValue.ConvertTo <int>();
                        var i        = 0;
                        foreach (var item in e)
                        {
                            if (i++ == intValue)
                            {
                                return(item);
                            }
                        }
                        return(null);
                    }
                    if (DynamicNumber.IsNumber(indexValue.GetType()))
                    {
                        var indexerMethod = targetType.GetInstanceMethod("get_Item");
                        if (indexerMethod != null)
                        {
                            var fn  = indexerMethod.GetInvoker();
                            var ret = fn(targetValue, indexValue);
                            return(ret ?? JsNull.Value);
                        }
                    }
                }
            }
            catch (KeyNotFoundException)
            {
                return(JsNull.Value);
            }
            catch (Exception ex)
            {
                var exResult = scope.PageResult.Format.OnExpressionException(scope.PageResult, ex);
                if (exResult != null)
                {
                    return(exResult);
                }

                var expr = ToRawString();
                throw new BindingExpressionException($"Could not evaluate expression '{expr}'", null, expr, ex);
            }

            throw new NotSupportedException($"'{targetValue.GetType()}' does not support access by '{Property}'");
        }
Beispiel #14
0
        internal static IDbCommand SetParameters(this IDbCommand dbCmd, Type type, object anonType, bool excludeDefaults, ref string sql)
        {
            if (anonType == null)
            {
                return(dbCmd);
            }

            dbCmd.Parameters.Clear();

            var modelDef        = type.GetModelDefinition();
            var dialectProvider = dbCmd.GetDialectProvider();
            var fieldMap        = type.IsUserType() //Ensure T != Scalar<int>()
                ? dialectProvider.GetFieldDefinitionMap(modelDef)
                : null;

            var sqlCopy = sql; //C# doesn't allow changing ref params in lambda's
            Dictionary <string, PropertyAccessor> anonTypeProps = null;

            var paramIndex = 0;

            anonType.ToObjectDictionary().ForEachParam(modelDef, excludeDefaults, (propName, columnName, value) =>
            {
                var propType = value?.GetType() ?? ((anonTypeProps ??= TypeProperties.Get(anonType.GetType()).PropertyMap)
                                                    .TryGetValue(propName, out var pType)
                        ? pType.PropertyInfo.PropertyType
                        : typeof(object));
                var inValues = GetMultiValues(value);
                if (inValues != null)
                {
                    var sb = StringBuilderCache.Allocate();
                    foreach (var item in inValues)
                    {
                        var p           = dbCmd.CreateParameter();
                        p.ParameterName = "v" + paramIndex++;

                        if (sb.Length > 0)
                        {
                            sb.Append(',');
                        }
                        sb.Append(dialectProvider.ParamString + p.ParameterName);

                        p.Direction = ParameterDirection.Input;
                        dialectProvider.InitDbParam(p, item.GetType());

                        dialectProvider.SetParamValue(p, item, item.GetType());

                        dbCmd.Parameters.Add(p);
                    }

                    var sqlIn = StringBuilderCache.ReturnAndFree(sb);
                    if (string.IsNullOrEmpty(sqlIn))
                    {
                        sqlIn = "NULL";
                    }
                    sqlCopy = sqlCopy?.Replace(dialectProvider.ParamString + propName, sqlIn);
                    if (dialectProvider.ParamString != "@")
                    {
                        sqlCopy = sqlCopy?.Replace("@" + propName, sqlIn);
                    }
                }
                else
                {
                    var p           = dbCmd.CreateParameter();
                    p.ParameterName = propName;
                    p.Direction     = ParameterDirection.Input;
                    dialectProvider.InitDbParam(p, propType);

                    FieldDefinition fieldDef = null;
                    fieldMap?.TryGetValue(columnName, out fieldDef);

                    dialectProvider.SetParamValue(p, value, propType, fieldDef);

                    dbCmd.Parameters.Add(p);
                }
            });
        protected async Task <Message> ExecuteMessage(Message message, RequestAttributes requestAttributes, IRequest httpReq, IResponse httpRes)
        {
            var soapFeature = requestAttributes.ToSoapFeature();

            appHost.AssertFeatures(soapFeature);

            if (httpReq == null)
            {
                httpReq = HostContext.GetCurrentRequest();
            }

            if (httpRes == null && httpReq != null)
            {
                httpRes = httpReq.Response;
            }

            if (httpReq == null)
            {
                throw new ArgumentNullException(nameof(httpReq));
            }

            if (httpRes == null)
            {
                throw new ArgumentNullException(nameof(httpRes));
            }

            httpReq.UseBufferedStream = true;
            var requestMsg = message ?? GetRequestMessageFromStream(httpReq.InputStream);

            var soapAction = httpReq.GetHeader(HttpHeaders.SOAPAction)
                             ?? GetAction(requestMsg);

            if (soapAction != null)
            {
                httpReq.OperationName = soapAction.Trim('"');
            }

            if (HostContext.ApplyCustomHandlerRequestFilters(httpReq, httpRes))
            {
                return(PrepareEmptyResponse(message, httpReq));
            }

            string requestXml  = GetRequestXml(requestMsg);
            var    requestType = GetRequestType(requestMsg, requestXml);

            httpReq.OperationName = requestType.GetOperationName();
            if (!HostContext.Metadata.CanAccess(requestAttributes, soapFeature.ToFormat(), requestType.GetOperationName()))
            {
                throw HostContext.UnauthorizedAccess(requestAttributes);
            }

            try
            {
                var useXmlSerializerRequest = requestType.HasAttribute <XmlSerializerFormatAttribute>();

                var request = appHost.ApplyRequestConvertersAsync(httpReq,
                                                                  useXmlSerializerRequest
                        ? XmlSerializableSerializer.Instance.DeserializeFromString(requestXml, requestType)
                        : Serialization.DataContractSerializer.Instance.DeserializeFromString(requestXml, requestType)
                                                                  ).Result;

                httpReq.Dto = request;

                if (request is IRequiresSoapMessage requiresSoapMessage)
                {
                    requiresSoapMessage.Message = requestMsg;
                }

                httpReq.SetItem(Keywords.SoapMessage, requestMsg);

                httpRes.ContentType = GetSoapContentType(httpReq.ContentType);

                var hasRequestFilters = HostContext.AppHost.GlobalRequestFiltersArray.Length > 0 ||
                                        HostContext.AppHost.GlobalRequestFiltersAsyncArray.Length > 0 ||
                                        FilterAttributeCache.GetRequestFilterAttributes(request.GetType()).Any();

                if (hasRequestFilters)
                {
                    HostContext.ApplyRequestFiltersAsync(httpReq, httpRes, request).Wait();
                    if (httpRes.IsClosed)
                    {
                        return(EmptyResponse(requestMsg, requestType));
                    }
                }

                httpReq.RequestAttributes |= requestAttributes;
                var response = await GetResponseAsync(httpReq, request);

                response = appHost.ApplyResponseConvertersAsync(httpReq, response).Result;

                appHost.ApplyResponseFiltersAsync(httpReq, httpRes, response).Wait();
                if (httpRes.IsClosed)
                {
                    return(EmptyResponse(requestMsg, requestType));
                }

                var httpResult = response as IHttpResult;
                if (httpResult != null)
                {
                    response = httpResult.Response;
                }

                var noMsgAction = requestMsg.Headers.Action == null;
                var responseMsg = CreateResponseMessage(response, requestMsg.Version, requestType, noMsgAction);

                if (httpResult != null)
                {
                    SetErrorStatusIfAny(httpReq.Response, responseMsg, httpResult.Status);
                }

                return(responseMsg);
            }
            catch (Exception ex)
            {
                try
                {
                    if (httpReq.Dto != null)
                    {
                        HostContext.RaiseServiceException(httpReq, httpReq.Dto, ex).Wait();
                    }
                    else
                    {
                        HostContext.RaiseUncaughtException(httpReq, httpRes, httpReq.OperationName, ex).Wait();
                    }

                    throw new SerializationException($"Error trying to deserialize requestType: {requestType}, xml body: {requestXml}", ex);
                }
                catch (Exception useEx)
                {
                    var responseType = HostContext.Metadata.GetOperation(requestType).ResponseType
                                       ?? typeof(ErrorResponse);

                    var responseStatus = useEx.ToResponseStatus();
                    var response       = responseType.CreateInstance();
                    var setter         = TypeProperties.Get(responseType).GetPublicSetter(nameof(IHasResponseStatus.ResponseStatus));
                    setter(response, responseStatus);

                    var noMsgAction = requestMsg.Headers.Action == null;
                    var responseMsg = CreateResponseMessage(response, requestMsg.Version, requestType, noMsgAction);

                    SetErrorStatusIfAny(httpReq.Response, responseMsg, useEx.ToStatusCode());
                    return(responseMsg);
                }
            }
        }
        public async Task Any(ModifyValidationRules request)
        {
            var appHost = HostContext.AssertAppHost();
            var feature = appHost.AssertPlugin <ValidationFeature>();
            await RequestUtils.AssertAccessRoleAsync(base.Request, accessRole : feature.AccessRole, authSecret : request.AuthSecret);

            var utcNow   = DateTime.UtcNow;
            var userName = (await base.GetSessionAsync()).GetUserAuthName();
            var rules    = request.SaveRules;

            if (!rules.IsEmpty())
            {
                foreach (var rule in rules)
                {
                    if (rule.Type == null)
                    {
                        throw new ArgumentNullException(nameof(rule.Type));
                    }

                    var existingType = appHost.Metadata.FindDtoType(rule.Type);
                    if (existingType == null)
                    {
                        throw new ArgumentException(@$ "{rule.Type} does not exist", nameof(rule.Type));
                    }

                    if (rule.Validator == "")
                    {
                        rule.Validator = null;
                    }
                    if (rule.Condition == "")
                    {
                        rule.Condition = null;
                    }
                    if (rule.Field == "")
                    {
                        rule.Field = null;
                    }
                    if (rule.ErrorCode == "")
                    {
                        rule.ErrorCode = null;
                    }
                    if (rule.Message == "")
                    {
                        rule.Message = null;
                    }
                    if (rule.Notes == "")
                    {
                        rule.Notes = null;
                    }

                    if (rule.Field != null && TypeProperties.Get(existingType).GetAccessor(rule.Field) == null)
                    {
                        throw new ArgumentException(@$ "{rule.Field} does not exist on {rule.Type}", nameof(rule.Field));
                    }

                    if (rule.Validator != null)
                    {
                        object validator;
                        try
                        {
                            validator = appHost.EvalExpression(rule.Validator);
                            if (validator == null)
                            {
                                throw new ArgumentException(@$ "Validator does not exist", nameof(rule.Validator));
                            }
                        }
                        catch (Exception e)
                        {
                            throw new ArgumentException(@$ "Invalid Validator: " + e.Message, nameof(rule.Validator));
                        }

                        var validators     = (validator as List <object>) ?? TypeConstants.EmptyObjectList;
                        var firstValidator = validator is IPropertyValidator pv
                            ? pv
                            : validator is ITypeValidator tv
                            ? tv
                            : validators?.FirstOrDefault() ?? validator;

                        if (rule.Field != null && !(firstValidator is IPropertyValidator && validators.All(v => v is IPropertyValidator)))
                        {
                            throw new ArgumentException(@$ "{nameof(IPropertyValidator)} is expected but was {(validators?.FirstOrDefault(v => !(v is IPropertyValidator)) ?? firstValidator).GetType().Name}", nameof(rule.Validator));
                        }

                        if (rule.Field == null && !(firstValidator is ITypeValidator && validators.All(v => v is ITypeValidator)))
                        {
                            throw new ArgumentException(@$ "{nameof(ITypeValidator)} is expected but was {(validators?.FirstOrDefault(v => !(v is IPropertyValidator)) ?? firstValidator).GetType().Name}", nameof(rule.Validator));
                        }

                        if (rule.Condition != null)
                        {
                            throw new ArgumentException(@$ "Only {nameof(rule.Validator)} or {nameof(rule.Condition)} can be specified, not both", nameof(rule.Condition));
                        }
                    }
                    else
                    {
                        if (rule.Condition == null)
                        {
                            throw new ArgumentNullException(nameof(rule.Validator), @$ "{nameof(rule.Validator)} or {nameof(rule.Condition)} is required");
                        }

                        try
                        {
                            var ast = Validators.ParseCondition(appHost.ScriptContext, rule.Condition);
                            await ast.Init().ConfigAwait();
                        }
                        catch (Exception e)
                        {
                            var useEx = e is ScriptException se ? se.InnerException ?? e : e;
                            throw new ArgumentException(useEx.Message, nameof(rule.Condition));
                        }
                    }

                    if (rule.CreatedBy == null)
                    {
                        rule.CreatedBy   = userName;
                        rule.CreatedDate = utcNow;
                    }
                    rule.ModifiedBy   = userName;
                    rule.ModifiedDate = utcNow;
                }

                await ValidationSource.SaveValidationRulesAsync(rules).ConfigAwait();
            }

            if (!request.SuspendRuleIds.IsEmpty())
            {
                var suspendRules = await ValidationSource.GetValidateRulesByIdsAsync(request.SuspendRuleIds).ConfigAwait();

                foreach (var suspendRule in suspendRules)
                {
                    suspendRule.SuspendedBy   = userName;
                    suspendRule.SuspendedDate = utcNow;
                }

                await ValidationSource.SaveValidationRulesAsync(suspendRules).ConfigAwait();
            }

            if (!request.UnsuspendRuleIds.IsEmpty())
            {
                var unsuspendRules = await ValidationSource.GetValidateRulesByIdsAsync(request.UnsuspendRuleIds).ConfigAwait();

                foreach (var unsuspendRule in unsuspendRules)
                {
                    unsuspendRule.SuspendedBy   = null;
                    unsuspendRule.SuspendedDate = null;
                }

                await ValidationSource.SaveValidationRulesAsync(unsuspendRules).ConfigAwait();
            }

            if (!request.DeleteRuleIds.IsEmpty())
            {
                await ValidationSource.DeleteValidationRulesAsync(request.DeleteRuleIds.ToArray()).ConfigAwait();
            }

            if (request.ClearCache.GetValueOrDefault())
            {
                await ValidationSource.ClearCacheAsync().ConfigAwait();
            }
        }
        private static bool HasCircularReferences(object value, Stack <object> parentValues)
        {
            var type = value?.GetType();

            if (type == null || !type.IsClass || value is string)
            {
                return(false);
            }

            if (parentValues == null)
            {
                parentValues = new Stack <object>();
                parentValues.Push(value);
            }

            bool CheckValue(object key)
            {
                if (parentValues.Contains(key))
                {
                    return(true);
                }

                parentValues.Push(key);

                if (HasCircularReferences(key, parentValues))
                {
                    return(true);
                }

                parentValues.Pop();
                return(false);
            }

            if (value is IEnumerable valueEnumerable)
            {
                foreach (var item in valueEnumerable)
                {
                    if (item == null)
                    {
                        continue;
                    }

                    var itemType = item.GetType();
                    if (itemType.IsGenericType && itemType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
                    {
                        var props = TypeProperties.Get(itemType);
                        var key   = props.GetPublicGetter("Key")(item);

                        if (CheckValue(key))
                        {
                            return(true);
                        }

                        var val = props.GetPublicGetter("Value")(item);

                        if (CheckValue(val))
                        {
                            return(true);
                        }
                    }

                    if (CheckValue(item))
                    {
                        return(true);
                    }
                }
            }
            else
            {
                var props = type.GetSerializableProperties();

                foreach (var pi in props)
                {
                    if (pi.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    var mi     = pi.GetGetMethod(nonPublic: false);
                    var pValue = mi != null?mi.Invoke(value, null) : null;

                    if (pValue == null)
                    {
                        continue;
                    }

                    if (CheckValue(pValue))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }