Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MvcActionValueBinder Execption in post #136

Open
allnnde opened this issue Dec 6, 2016 · 9 comments
Open

MvcActionValueBinder Execption in post #136

allnnde opened this issue Dec 6, 2016 · 9 comments

Comments

@allnnde
Copy link

allnnde commented Dec 6, 2016

Hi, i have a problem in angular when send data in post method, in my client

this.prueba = function (id, nombre) {
        return $http.post(ApiURL + "AEmpleado/prueba", { id: id, nombre: nombre })
            .then(
                function (respuesta) {
                    MensajeServices.MostarMensaje("", "Se elimino el Registro Correctamente", "success", null);
                    //vm.CargarTabla();
                    return respuesta
                },
                function (respuesta) {
                    console.log(respuesta.data.Message);
                    return false;
                }
        );
}

in my server

[RoutePrefix("api/AEmpleado")]
[MvcStyleBinding]
public class AEmpleadoController : ApiController
{   
    [HttpPost, Route("prueba")]
    public IHttpActionResult prueba(int id, string nombre)
    {
        return Ok();
    }
}

The error is:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Net.Http.Formatting.FormDataCollection' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'id', line 1, position 6.

in

private class MvcActionBinding : HttpActionBinding
{
    // Read the body upfront , add as a ValueProvider
    public override Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        HttpRequestMessage request = actionContext.ControllerContext.Request;
        HttpContent content = request.Content;
        if (content != null)
        {
            FormDataCollection fd = content.ReadAsAsync<FormDataCollection>().Result;
            if (fd != null)
            {
                IValueProvider vp = new NameValuePairsValueProvider(fd, CultureInfo.InvariantCulture);
                request.Properties.Add(Key, vp);
            }
        }

        return base.ExecuteBindingAsync(actionContext, cancellationToken);
    }
}

anybody help?
Sorry for my english

@abatishchev
Copy link
Contributor

abatishchev commented Dec 6, 2016

I see inconsistence: you're using [MvcStyleBinding] or [MvcActionBinding] or both ?

@allnnde
Copy link
Author

allnnde commented Dec 7, 2016

in the IHttpActionResult ? i'm use [MvcStyleBinding]

@abatishchev
Copy link
Contributor

But the error occurs in private class MvcActionBinding?

@allnnde
Copy link
Author

allnnde commented Dec 7, 2016

Yes, the complete class is:

public class MvcActionValueBinder : DefaultActionValueBinder
 {
        // Per-request storage, uses the Request.Properties bag. We need a unique key into the bag.
        private const string Key = "{5DC187FB-BFA0-462A-AB93-9E8036871EC8}";

        public override HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor)
        {
            var actionBinding = new MvcActionBinding();

            HttpParameterDescriptor[] parameters = actionDescriptor.GetParameters().ToArray();
            HttpParameterBinding[] binders = Array.ConvertAll(parameters, DetermineBinding);

            actionBinding.ParameterBindings = binders;

            return actionBinding;
        }

        private HttpParameterBinding DetermineBinding(HttpParameterDescriptor parameter)
        {
            HttpConfiguration config = parameter.Configuration;
            var attr = new ModelBinderAttribute(); // use default settings

            ModelBinderProvider provider = attr.GetModelBinderProvider(config);
            IModelBinder binder = provider.GetBinder(config, parameter.ParameterType);

            // Alternatively, we could put this ValueProviderFactory in the global config.
            var vpfs = new List<ValueProviderFactory>(attr.GetValueProviderFactories(config)) { new BodyValueProviderFactory() };
            return new ModelBinderParameterBinding(parameter, binder, vpfs);
        }

        // Derive from ActionBinding so that we have a chance to read the body once and then share that with all the parameters.
        private class MvcActionBinding : HttpActionBinding
        {
            // Read the body upfront , add as a ValueProvider
            public override Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
            {
                HttpRequestMessage request = actionContext.ControllerContext.Request;
                HttpContent content = request.Content;
                if (content != null)
                {
                    FormDataCollection fd = content.ReadAsAsync<FormDataCollection>().Result;
                    if (fd != null)
                    {
                        IValueProvider vp = new NameValuePairsValueProvider(fd, CultureInfo.InvariantCulture);
                        request.Properties.Add(Key, vp);
                    }
                }

                return base.ExecuteBindingAsync(actionContext, cancellationToken);
            }
        }

        // Get a value provider over the body. This can be shared by all parameters.
        // This gets the values computed in MvcActionBinding.
        private class BodyValueProviderFactory : ValueProviderFactory
        {
            public override IValueProvider GetValueProvider(HttpActionContext actionContext)
            {
                object vp;
                actionContext.Request.Properties.TryGetValue(Key, out vp);
                return (IValueProvider)vp; // can be null 
            }
        }
    }

@allnnde
Copy link
Author

allnnde commented Dec 7, 2016

hello, i'm chage

FormDataCollection fd = content.ReadAsAsync<FormDataCollection>().Result;

for

var fd = content.ReadAsAsync<IDictionary<string, object>>().Result;

and it work but doesn't when send array :(

@abatishchev
Copy link
Contributor

btw don't use Result, use async/await instead

@allnnde
Copy link
Author

allnnde commented Dec 7, 2016

when? in the content.ReadAsAsync<IDictionary<string, object>>().Result?

@abatishchev
Copy link
Contributor

abatishchev commented Dec 7, 2016

It's unrelated to the problem you're facing but yes, there and elsewhere, calling the Result property blocks current thread so you're not having async operation spite it looks like you will. If shortly, this is incorrect way to use it.

@abatishchev
Copy link
Contributor

abatishchev commented Dec 7, 2016

Regarding your problem, i frankly don't know, I'm not familiar with this part of the codebase. Please ask a question on Stack Overflow and provide a link to the question here, I'll assist if you're facing any issues there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants