wake-up-neo.com

Die Eigenschaften komplexer Web-API-Parameter sind alle null

Ich habe einen Web-API-Dienstaufruf, der die Einstellungen eines Benutzers aktualisiert. Wenn ich diese POST - Methode von einem jQuery-ajax-Aufruf aus aufrufe, sind die Eigenschaften des Anforderungsparameterobjekts leider immer NULL (oder Standardwerte) und nicht die übergebenen. Wenn ich dieselbe Methode mit REST client (ich verwende Postman), es funktioniert wunderbar. Ich kann nicht herausfinden, was ich falsch damit mache, aber ich hoffe, jemand hat das schon mal gesehen. Es ist ziemlich einfach ...

Hier ist mein Anfrageobjekt: 

public class PreferenceRequest
{
    [Required]
    public int UserId;

    public bool usePopups;
    public bool useTheme;
    public int recentCount;
    public string[] detailsSections;
}

Hier ist meine Controller-Methode in der UserController-Klasse: 

    public HttpResponseMessage Post([FromBody]PreferenceRequest request)
    {
        if (request.systemsUserId > 0)
        {
            TheRepository.UpdateUserPreferences(request.UserId, request.usePopups, request.useTheme,
                                         request.recentCount, request.detailsSections);

            return Request.CreateResponse(HttpStatusCode.OK, "Preferences Updated");                
        }
        else
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "You must provide User ID");
        }
    }

Hier ist mein Ajax-Anruf:

var request = {
    UserId: userId,
    usePopups: usePopups,
    useTheme: useTheme,
    recentCount: recentCount,
    detailsSections: details
};

$.ajax({
    type: "POST",
    data: request,
    url: "http://localhost:1111/service/User",
    success: function (data) {
        return callback(data);
    },
    error: function (error, statusText) {
        return callback(error);
    }
});

Ich habe versucht, dataType & contentType auf verschiedene Dinge einzustellen ('json', 'application/json' usw.), aber die Eigenschaften des Anforderungsobjekts sind immer voreingestellt oder null. Wenn ich zum Beispiel dieses Objekt übergebe:

var request = {
  UserId: 58576,
  usePopups: false,
  useTheme: true,
  recentCount: 10,
  detailsSections: ['addresses', 'aliases', 'arrests', 'events', 'classifications', 'custody', 'identifiers', 'phone', 'remarks', 'watches']
}

Ich kann ein vollständig aufgefülltes Anforderungsobjekt mit den gültigen Werten wie oben aufgeführt sehen. Im Web-API-Controller ist die Anforderung jedoch vorhanden, die Eigenschaften lauten jedoch wie folgt:

  UserId: 0,
  usePopups: false,
  useTheme: false,
  recentCount: 0,
  detailsSections: null

Zu Ihrer Information - Ich mache mit diesem Projekt keine ASP.Net MVC- oder ASP.NET-Seiten. Ich verwende nur die Web-API als Dienst und mache alle Aufrufe mit jQuery $ .ajax.

Irgendeine Idee, was ich hier falsch mache? Vielen Dank!

UPDATE: Ich möchte nur anmerken, dass ich in diesem Web-API-Projekt viele Methoden in anderen Controllern habe, die dies tun genau dasselbe und ich die exakt gleiche Weise und benenne Sie arbeiten einwandfrei! Ich habe den Morgen damit verbracht, die verschiedenen Aufrufe zu vergleichen, und es scheint keinen Unterschied in der Methode oder in den Kopfzeilen zu geben, und trotzdem funktioniert es bei dieser bestimmten Methode einfach nicht. 

Ich habe auch versucht, zu einer Put-Methode zu wechseln, aber ich erhalte genau dieselben Ergebnisse - das Anforderungsobjekt kommt zwar herein, wird aber nicht mit den korrekten Werten gefüllt. Was so frustrierend ist, ist, dass ich ungefähr 20 Controller-Klassen in diesem Projekt habe und die Posts in all diesen ...

32
Eddie

Dies scheint ein allgemeines Problem in Bezug auf Asp.Net WebAPI zu sein.
Die Ursache für Nullobjekte ist im Allgemeinen die Deserialisierung des Json-Objekts in das C # -Objekt. Leider ist das Debuggen sehr schwierig - und Sie können herausfinden, wo Ihr Problem liegt.
Ich ziehe es vor, einfach den vollständigen Json als Objekt zu senden und dann manuell zu deserialisieren. Zumindest auf diese Weise erhalten Sie echte Fehler anstelle von Nullen.
Wenn Sie Ihre Methodensignatur ändern, um ein Objekt zu akzeptieren, verwenden Sie JsonConvert:

public HttpResponseMessage Post(Object model)
        {
            var jsonString = model.ToString();
            PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
        }
50
blorkfish

Vielleicht hilft es, ich hatte das gleiche Problem.

Alles funktionierte gut, und plötzlich waren alle Eigenschaften standardmäßig aktiviert.

Nach einem kurzen Test stellte ich fest, dass es das [Serializable] war, das das Problem verursachte :

public IHttpActionResult Post(MyComplexClass myTaskObject)
{
    //MyTaskObject is not null, but every member are (the constructor get called).
}

und hier war ein Ausschnitt aus meiner Klasse:

[Serializable]  <-- have to remove that [if it was added for any reason..]
public class MyComplexClass()
{
     public MyComplexClass ()
     {
        ..initiate my variables..
     }

     public string blabla {get;set;}
     public int intTest {get;set;
}
11
Simon

Mit dieser von @blorkfish geposteten Technik hat es gut funktioniert:

public HttpResponseMessage Post(Object model)
    {
        var jsonString = model.ToString();
        PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
    }

Ich hatte ein Parameterobjekt, das einige native Typen und einige weitere Objekte als Eigenschaften hatte. Die Objekte hatten interne Konstruktoren und der JsonConvert.DeserializedObject-Aufruf auf dem JsonString hat den Fehler ausgegeben: 

Konnte keinen Konstruktor für den Typ ChildObjectB finden. Eine Klasse sollte entweder einen Standardkonstruktor haben, einen Konstruktor mit Argumente oder ein Konstruktor, der mit dem JsonConstructor-Attribut markiert ist.

Ich habe die Konstruktoren in public geändert, und das Parameterobjekt wird jetzt aufgefüllt, wenn der Objektmodellparameter durch das reale Objekt ersetzt wird. Vielen Dank!

4
Russell D

Ich denke, das Problem ist, dass Ihr Controller den Inhaltstyp [FromBody] erwartet. Versuchen Sie, Ihren Controller in zu ändern 

public HttpResponseMessage Post(PreferenceRequest request)

und Ajax zu 

$.ajax({
    type: "POST",
    data: JSON.stringify(request);,
    dataType: 'json',
    contentType: "application/json",
    url: "http://localhost:1111/service/User",

Übrigens kann das Erstellen von Modellen in Javascript nicht die beste Methode sein.

4
Anshul Nigam

Es gibt also 3 mögliche Probleme, bei denen der Wert nicht bindet:

  1. kein public parameterless ctor
  2. eigenschaften sind nicht öffentlich einstellbar
  3. Es gibt einen Bindungsfehler, der zu einem ModelState.Valid == false - führt. Typische Probleme sind: Nicht kompatible Werttypen (Json-Objekt in Zeichenfolge, Nicht-GUID usw.)

Ich überlege, ob API-Aufrufe einen Filter anwenden sollten, der einen Fehler zurückgibt, wenn die Bindung einen Fehler ergibt!

2
baHI

Ich bin auch mit diesem Problem konfrontiert und nach vielen Stunden von Debbug und Recherchen kann feststellen, dass das Problem nicht durch die Attribute Content-Type oder Type $ Ajax verursacht wurde. Das Problem wurde durch NULL-Werte für mein JSON-Objekt verursacht POST macht auch nichts, aber sobald die NULL-Werte festgelegt wurden, war POST in Ordnung und wurde nativ in meine Klasse "respuestaComparacion" eingefügt. Hier der Code:

JSON

 respuestaComparacion: {
                            anioRegistro: NULL, --> cannot cast to BOOL
                            claveElector: NULL, --> cannot cast to BOOL
                            apellidoPaterno: true,
                            numeroEmisionCredencial: false,
                            nombre: true,
                            curp: NULL, --> cannot cast to BOOL
                            apellidoMaterno: true,
                            ocr: true
                        }

Regler

[Route("Similitud")]
[HttpPost]
[AllowAnonymous]

public IHttpActionResult SimilitudResult([FromBody] RespuestaComparacion req)
{
   var nombre = req.nombre;
}

Klasse

public class RespuestaComparacion
    {
        public bool anioRegistro { get; set; }
        public bool claveElector { get; set; }
        public bool apellidoPaterno { get; set; }
        public bool numeroEmisionCredencial { get; set; }
        public bool nombre { get; set; }
        public bool curp { get; set; }
        public bool apellidoMaterno { get; set; }
        public bool ocr { get; set; }
    }

Ich hoffe das hilft.

2
Jorge Solano

Ein bisschen zu spät zur Party, aber ich hatte das gleiche Problem und der Fix deklarierte den contentType in Ihrem Ajax-Aufruf:

    var settings = {
        HelpText: $('#help-text').val(),
        BranchId: $("#branch-select").val(),
        Department: $('input[name=departmentRadios]:checked').val()

    };

$.ajax({
        url: 'http://localhost:25131/api/test/updatesettings',
        type: 'POST',
        data: JSON.stringify(settings),
        contentType: "application/json;charset=utf-8",
        success: function (data) {
            alert('Success');
        },
        error: function (x, y, z) {
            alert(x + '\n' + y + '\n' + z);
        }
    });

Und Ihr API-Controller kann folgendermaßen eingerichtet werden:

    [System.Web.Http.HttpPost]
    public IHttpActionResult UpdateSettings([FromBody()] UserSettings settings)
    {
//do stuff with your UserSettings object now
        return Ok("Successfully updated settings");
    }
2
Dan

Ich weiß, das ist ein bisschen spät, aber ich bin gerade auf das gleiche Problem gestoßen. @Blorkfishs Antwort funktionierte auch für mich, führte mich jedoch zu einer anderen Lösung. Einem der Teile meines komplexen Objekts fehlte ein parameterloser Konstruktor. Nach dem Hinzufügen dieses Konstruktors funktionierten sowohl die Put- als auch die Post-Anforderung wie erwartet.

2
Storm

Ich bin auf das gleiche Problem gestoßen. Die erforderliche Korrektur bestand darin, sicherzustellen, dass alle serialisierbaren Eigenschaften für die JSON-Parameterklasse erhalten wurden. einstellen; explizit definierte Methoden. Verlassen Sie sich nicht auf die automatische Eigenschafts-Syntax von C #! Hoffe, das wird in späteren Versionen von asp.net behoben.

1
Rams Ramanathan

In meinem Fall wurde das Problem gelöst, als ich hinzufügte

hol {} set {}

zur Definition der Parameterklasse:

public class PreferenceRequest
{
    public int UserId;
    public bool usePopups {get; set;}
    public bool useTheme {get; set;}
    public int recentCount {get; set;}
    public string[] detailsSections {get;set;}
}

statt:

   public class PreferenceRequest
    {
        [Required]
        public int UserId;
        public bool usePopups;
        public bool useTheme;
        public int recentCount;
        public string[] detailsSections;
    }
0
alexey

Ich bin auf das gleiche Problem gestoßen, die Lösung für mich bestand darin, sicherzustellen, dass die Typen meiner Klassenattribute mit den json-Attributen übereinstimmen, meine ich

Json: "attribute": "true"

Sollte als Zeichenfolge und nicht als boolean behandelt werden, sieht aus, als würden bei einem solchen Problem alle Attribute unter dem fehlerhaften Attribut auf null gesetzt

0
Igor Vargas

Mein Problem wurde durch keine der anderen Antworten gelöst, daher ist diese Lösung eine Überlegung wert:

Ich hatte die folgende DTO- und Controller-Methode:

public class ProjectDetailedOverviewDto
{
    public int PropertyPlanId { get; set; }

    public int ProjectId { get; set; }

    public string DetailedOverview { get; set; }
}

public JsonNetResult SaveDetailedOverview(ProjectDetailedOverviewDto detailedOverview) { ... }

Da mein DTO eine Eigenschaft mit dem gleichen Namen wie der Parameter hatte (detailOverview), wurde der Deserialisierer verwirrt und versuchte, den Parameter mit dem String und nicht mit dem gesamten komplexen Objekt zu füllen. Die Lösung bestand darin, den Namen des Parameterparameter des Controllers auf 'overview', sodass der Deserialiser wusste, dass ich nicht versucht habe, auf die Eigenschaft zuzugreifen.

0
Delorian

Ich stehe vor diesem Problem 

  1. verwenden Sie das Attribut [JsonProperty ("Eigenschaftsname wie in der Json-Anforderung")] in Ihrem Modell vom Nuget-Paket Newton 
  2. wenn Sie das Objekt serialisieren, rufen Sie nur PostAsync auf

so wie das

var json = JsonConvert.SerializeObject(yourobject);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var response = await client.PostAsync ("apiURL", stringContent);
  1. wenn nicht, entfernen Sie [aus dem Körper] von Ihrem API
0
Mostafa Elzaref

Ich bin heute auch auf das gleiche Problem gestoßen. Nachdem Sie alle diese Funktionen ausprobiert, die API von Azure und die Xamarin Android-App debuggt haben, stellt sich heraus, dass es sich um ein Referenz-Update-Problem handelt. Denken Sie daran, sicherzustellen, dass das Newtonsoft.JSON NUGET-Paket für Ihre API aktualisiert wurde (falls Sie dies verwenden). 

0
SHOTdeJAGER

HttpGet

public object Get([FromBody]object requestModel)
{
    var jsonstring = JsonConvert.SerializeObject(requestModel);
    RequestModel model = JsonConvert.DeserializeObject<RequestModel>(jsonstring);
}
0
Tarrah Arshad

Heute habe ich das gleiche Problem wie du. Wenn ich eine POST-Anforderung von ajax sende, erhält der Controller ein leeres Objekt mit Null und Standardeigenschaftswerten . Die Methode lautet:

[HttpPost]
public async Task<IActionResult> SaveDrawing([FromBody]DrawingModel drawing)
{


    try
    {

        await Task.Factory.StartNew(() =>
        {
            //Logic
        });
        return Ok();
    }
    catch(Exception e)
    {
        return BadRequest();
    }
}

Mein Content-Type war korrekt und alles andere war auch korrekt. Nachdem ich viele Dinge ausprobiert hatte, stellte ich fest, dass das Objekt folgendermaßen gesendet wurde:

$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: dataToPost
}).done((response) => { }); 

Funktioniert nicht, aber das Senden auf diese Weise hat stattdessen funktioniert:

$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(dataToPost)
}).done((response) => { }); 

Ja, die fehlende JSON.stringify() verursachte das ganze Problem und es war nicht nötig, = oder irgendetwas anderes als Präfix oder Suffix an JSON.stringify..__ zu setzen. Ich habe festgestellt, dass das Format der Anforderungsnutzdaten zwischen den beiden Anforderungen völlig unterschiedlich ist
Dies ist die Anforderungsnutzlast mit JSON.stringify.

 Request payload with JSON.stringify

Und dies ist die Anforderungsnutzlast ohne JSON.stringify

 Request payload without JSON.stringify

Und vergessen Sie nicht, wenn die Dinge magisch werden und Sie Google Chrome verwenden, um Ihre Webanwendung zu testen. Leere Cache und hartes Nachladen von Zeit zu Zeit.

0
Mahmoud

Da mich dieses Thema gestern fast für einen ganzen Arbeitstag beschäftigte, möchte ich etwas hinzufügen, das anderen in derselben Situation helfen könnte.

Ich habe mit Xamarin Studio mein Winkel- und Web-API-Projekt erstellt. Beim Debuggen kam das Objekt manchmal durch Null und zu anderen Zeiten als aufgefülltes Objekt. Erst als ich mit dem Debuggen meines Projekts in Visual Studio begonnen habe, wurde das Objekt bei jeder Post-Anforderung gefüllt. Dies scheint ein Problem beim Debuggen in Xamarin Studio zu sein.

Versuchen Sie bitte, in Visual Studio zu debuggen, wenn dieses Nullparameterproblem mit einer anderen IDE auftritt.

0
tno2007