internal static bool ValidateObject(object o, List<ValidationResultInfo> validationErrors, HttpActionContext actionContext)
        {
            // create a model validation node for the object
            ModelMetadataProvider metadataProvider = actionContext.GetMetadataProvider();
            string modelStateKey = String.Empty;
            ModelValidationNode validationNode = CreateModelValidationNode(o, metadataProvider, actionContext.ModelState, modelStateKey);
            validationNode.ValidateAllProperties = true;

            // add the node to model state
            ModelState modelState = new ModelState();
            modelState.Value = new ValueProviderResult(o, String.Empty, CultureInfo.CurrentCulture);
            actionContext.ModelState.Add(modelStateKey, modelState);

            // invoke validation
            validationNode.Validate(actionContext);

            if (!actionContext.ModelState.IsValid)
            {
                foreach (var modelStateItem in actionContext.ModelState)
                {
                    foreach (ModelError modelError in modelStateItem.Value.Errors)
                    {
                        validationErrors.Add(new ValidationResultInfo(modelError.ErrorMessage, new string[] { modelStateItem.Key }));
                    }
                }
            }

            return actionContext.ModelState.IsValid;
        }
        public void OnActionExecuting_HandlesModelStateSuccess()
        {
            // Arrange
            ModelState state = new ModelState();
            _actionContext.ModelState.Add("m1", state);

            // Act
            _validater.OnActionExecuting(_actionContext);

            // Assert
            Assert.Null(_actionContext.Response);
        }
        public async Task OnActionExecuting_HandlesModelStateErrors()
        {
            // Arrange
            ModelState state = new ModelState();
            state.Errors.Add(new Exception("Model Error!"));
            _actionContext.ModelState.Add("m1", state);

            // Act
            _validater.OnActionExecuting(_actionContext);
            HttpError error = await _actionContext.Response.Content.ReadAsAsync<HttpError>();

            // Assert
            Assert.NotNull(error);
        }
        private static void CreateModelValidationNodeRecursive(object o, ModelValidationNode parentNode, ModelMetadataProvider metadataProvider, ModelMetadata metadata, ModelStateDictionary modelStateDictionary, string modelStateKey, HashSet<object> visited)
        {
            if (visited.Contains(o))
            {
                return;
            }
            visited.Add(o);

            foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(o))
            {
                // append the current property name to the model state path
                string propertyKey = modelStateKey;
                if (propertyKey.Length > 0)
                {
                    propertyKey += ".";
                }
                propertyKey += property.Name;

                // create the node for this property and add to the parent node
                object propertyValue = property.GetValue(o);
                metadata = metadataProvider.GetMetadataForProperty(() =>
                {
                    return propertyValue;
                }, o.GetType(), property.Name);
                ModelValidationNode childNode = new ModelValidationNode(metadata, propertyKey);
                parentNode.ChildNodes.Add(childNode);

                // add the property node to model state
                ModelState modelState = new ModelState();
                modelState.Value = new ValueProviderResult(propertyValue, null, CultureInfo.CurrentCulture);
                modelStateDictionary.Add(propertyKey, modelState);

                if (propertyValue != null)
                {
                    CreateModelValidationNodeRecursive(propertyValue, childNode, metadataProvider, metadata, modelStateDictionary, propertyKey, visited);
                }
            }
        }
        public void ExecuteAsync_ReturnsCorrectResponse_WhenContentNegotiationSucceedsAndIncludeErrorDetailIsFalse()
        {
            // Arrange
            ModelStateDictionary modelState = CreateModelState();
            string expectedModelStateKey = "ModelStateKey";
            string expectedModelStateErrorMessage = "ModelStateErrorMessage";
            ModelState originalModelStateItem = new ModelState();
            originalModelStateItem.Errors.Add(new ModelError(new InvalidOperationException(),
                expectedModelStateErrorMessage));
            modelState.Add(expectedModelStateKey, originalModelStateItem);
            bool includeErrorDetail = false;
            MediaTypeFormatter expectedFormatter = CreateFormatter();
            MediaTypeHeaderValue expectedMediaType = CreateMediaType();
            ContentNegotiationResult negotiationResult = new ContentNegotiationResult(expectedFormatter,
                expectedMediaType);

            using (HttpRequestMessage expectedRequest = CreateRequest())
            {
                IEnumerable<MediaTypeFormatter> expectedFormatters = CreateFormatters();

                Mock<IContentNegotiator> spy = new Mock<IContentNegotiator>();
                spy.Setup(n => n.Negotiate(typeof(HttpError), expectedRequest, expectedFormatters)).Returns(
                    negotiationResult);
                IContentNegotiator contentNegotiator = spy.Object;

                IHttpActionResult result = CreateProductUnderTest(modelState, includeErrorDetail, contentNegotiator,
                    expectedRequest, expectedFormatters);

                // Act
                Task<HttpResponseMessage> task = result.ExecuteAsync(CancellationToken.None);

                // Assert
                Assert.NotNull(task);
                task.WaitUntilCompleted();

                using (HttpResponseMessage response = task.Result)
                {
                    Assert.NotNull(response);
                    Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
                    HttpContent content = response.Content;
                    Assert.IsType<ObjectContent<HttpError>>(content);
                    ObjectContent<HttpError> typedContent = (ObjectContent<HttpError>)content;
                    HttpError error = (HttpError)typedContent.Value;
                    Assert.NotNull(error);
                    HttpError modelStateError = error.ModelState;
                    Assert.NotNull(modelStateError);
                    Assert.True(modelState.ContainsKey(expectedModelStateKey));
                    object modelStateValue = modelStateError[expectedModelStateKey];
                    Assert.IsType(typeof(string[]), modelStateValue);
                    string[] typedModelStateValue = (string[])modelStateValue;
                    Assert.Equal(1, typedModelStateValue.Length);
                    Assert.Same(expectedModelStateErrorMessage, typedModelStateValue[0]);
                    Assert.Same(expectedFormatter, typedContent.Formatter);
                    Assert.NotNull(typedContent.Headers);
                    Assert.Equal(expectedMediaType, typedContent.Headers.ContentType);
                    Assert.Same(expectedRequest, response.RequestMessage);
                }
            }
        }
        public void TranslateHttpResponseException_Unpacks_ModelState_Errors()
        {
            // Arrange
            HttpRequestMessage request = new HttpRequestMessage
            {
                RequestUri = new Uri("http://localhost"),
                Method = HttpMethod.Get
            };

            ModelStateDictionary modelStateDictionary = new ModelStateDictionary();
            ModelState modelState1 = new ModelState();
            modelState1.Errors.Add("modelState1.Error1");
            modelState1.Errors.Add("modelState1.Error2");
            modelStateDictionary["key1"] = modelState1;

            ModelState modelState2 = new ModelState();
            modelState2.Errors.Add("modelState2.Error1");
            modelState2.Errors.Add("modelState2.Error2");
            modelStateDictionary["key2"] = modelState2;

            HttpError httpError = new HttpError(modelStateDictionary, includeErrorDetail: true);
            HttpResponseMessage errorResponse = request.CreateResponse(HttpStatusCode.BadRequest);
            errorResponse.Content = new ObjectContent<HttpError>(httpError, new JsonMediaTypeFormatter());

            TraceRecord traceRecord = new TraceRecord(request, "System.Web.Http.Request", TraceLevel.Error)
            {
                Exception = new HttpResponseException(errorResponse)
            };

            // Act
            new SystemDiagnosticsTraceWriter().TranslateHttpResponseException(traceRecord);

            // Assert
            Assert.Equal(TraceLevel.Warn, traceRecord.Level);

            string message = ExtractModelStateErrorString(traceRecord.Message);

            AssertContainsExactly(message, new Dictionary<string, string>()
            {
                { "key1", "[modelState1.Error1, modelState1.Error2]" },
                { "key2", "[modelState2.Error1, modelState2.Error2]" },
            });
        }