web-api POST-Body-Objekt immer null

74

Ich lerne immer noch Web-API, also entschuldigen Sie, wenn meine Frage dumm klingt.

Ich habe dies in meinem StudentController:

public HttpResponseMessage PostStudent([FromBody]Models.Student student)
{
    if (DBManager.createStudent(student) != null)
        return Request.CreateResponse(HttpStatusCode.Created, student);
    else
        return Request.CreateResponse(HttpStatusCode.BadRequest, student);
}

Um zu testen, ob dies funktioniert, verwende ich die Google Chrome-Erweiterung "Postman", um die HTTP-POST-Anforderung zum Testen zu erstellen.

Dies ist meine rohe POST-Anfrage:

POST /api/Student HTTP/1.1
Host: localhost:1118
Content-Type: application/json
Cache-Control: no-cache

{"student": [{"name":"John Doe", "age":18, "country":"United States of America"}]}

studentsoll ein Objekt sein, aber wenn ich die Anwendung debugge, empfängt die API das studentObjekt, aber der Inhalt ist immer null.

InnovativeDan
quelle
3
Nur eine Randnotiz für alle, die dies später finden (wie ich es gerade getan habe), während sie sich ein ähnliches Problem ansehen: Die Web-API sollte JSON zurückgeben, das die Ausnahme enthält (als hätten Sie die Ausnahme in Ihrem Code abgefangen), die zur Diagnose verwendet werden kann das Problem. Scheint offensichtlich, aber ich vermute, ich bin nicht die einzige Person, die nicht daran gedacht hat, die Antwort zu überprüfen, und angenommen hat, dass es sich nur um einen Standard-HTTP-Antwortcode handelt!
Jon Story

Antworten:

58

FromBody ist insofern ein seltsames Attribut, als die eingegebenen POST-Werte in einem bestimmten Format vorliegen müssen, damit der Parameter nicht null ist, wenn es sich nicht um einen primitiven Typ handelt. (Student hier)

  1. Versuchen Sie Ihre Anfrage mit {"name":"John Doe", "age":18, "country":"United States of America"}als json.
  2. Entfernen Sie das [FromBody]Attribut und probieren Sie die Lösung aus. Es sollte für nicht-primitive Typen funktionieren. (Schüler)
  3. Mit dem [FromBody]Attribut besteht die andere Option darin, die Werte im =ValueFormat und nicht im Format zu senden key=value. Dies würde bedeuten, dass Ihr Schlüsselwert von studenteine leere Zeichenfolge sein sollte ...

Es gibt auch andere Optionen, um einen benutzerdefinierten Modellordner für die Schülerklasse zu schreiben und den Parameter Ihrem benutzerdefinierten Ordner zuzuordnen.

Raja Nadar
quelle
3
[FromBody] entfernt, funktioniert immer noch nicht. Inhalt des Schülerobjekts immer noch null .. (zB Name = null, Land = null, Alter = null)
InnovativeDan
ES FUNKTIONIERTE! Ich habe nicht erwartet, dass das Problem bei meinem JSON-Format liegt. DANKE, MANN! als Antwort markiert.
InnovativeDan
1
# 1 hat für mich gearbeitet. Vielen Dank :) Ich musste nur den 'Schlüssel' von meinem JSON entfernen und den 'Wert' senden
IsolatedStorage
12
Für andere Leser war das ursprüngliche Problem hier, dass das OP ein JSON-Objekt sendete, das eine Student-Eigenschaft enthielt, anstatt nur das Student-Objekt zu senden, wie es das Webapi erwartete.
Shaun Wilson
3
Es ist ein später Kommentar, aber Ihre Lösung hat mir geholfen, das Problem zu beheben, mit dem ich in den letzten zwei Stunden zu kämpfen hatte. Prost :)
iSahilSharma
57

Ich habe jetzt einige Minuten nach einer Lösung für mein Problem gesucht, also werde ich meine Lösung teilen.

Wenn Sie einen benutzerdefinierten Konstruktor in Ihrem Modell haben, muss Ihr Modell auch einen leeren / Standardkonstruktor haben. Andernfalls kann das Modell natürlich nicht erstellt werden. Seien Sie vorsichtig beim Refactoring.

chrjs
quelle
1
Dies ist eine wichtige Information, die der akzeptierten Antwort hinzugefügt werden sollte.
Youkko
1
das ist einfach nicht genau. Klassen (ein Modell ist eine Klasse) haben einen Standardkonstruktor, auch wenn er nicht angegeben ist und definitiv erstellt werden kann
Andrei Dragotoniu
Ich stimme @AndreiDragotoniu zu. Dies scheint nicht wahr zu sein. Ich hatte dieses Problem und mein Problem war die Tatsache, dass ich schreibgeschützte Eigenschaften hatte. Nach dem Hinzufügen von Setzern zu jedem funktionierte es einwandfrei (auch wenn nur ein nicht leerer Konstruktor angegeben wurde).
Broots Waymb
2
@AndreiDragotoniu Ich denke, das Problem tritt auf, wenn Sie einen Konstruktor erstellt haben, der Argumente erfordert. Wenn Sie dies getan haben, überschreibt dies den Standardkonstruktor. In diesem Fall müssen Sie auch einen zusätzlichen leeren Konstruktor erstellen.
LairdPleng
1
@LairdPleng Danke für die Klarstellung. Ich habe die Antwort entsprechend bearbeitet.
Chrjs
34

Ich verbringe mehrere Stunden mit diesem Problem ... :( Getter und Setter sind in der POST-Parameter-Objektdeklaration ERFORDERLICH. Ich empfehle nicht, einfache Datenobjekte (Zeichenfolge, Int, ...) zu verwenden, da sie ein spezielles Anforderungsformat erfordern.

[HttpPost]
public HttpResponseMessage PostProcedure(EdiconLogFilter filter){
...
}

Funktioniert nicht wenn:

public class EdiconLogFilter
{
    public string fClientName;
    public string fUserName;
    public string fMinutes;
    public string fLogDate;
}

Funktioniert gut, wenn:

public class EdiconLogFilter
{
    public string fClientName { get; set; }
    public string fUserName { get; set; }
    public string fMinutes { get; set; }
    public string fLogDate { get; set; }
}
Milan Švec
quelle
1
Oh wow, ich kann nicht glauben, dass dies tatsächlich mein Problem war ... Vielen Dank.
Chris
Das Benötigen von Eigenschaften mit Getter und Setter hat mein Problem für meine GET-Anfrage behoben, was für ein
nerviges
Vielen Dank! Wenn ich Ihre Antwort nicht gelesen hätte, hätte ich mich nicht darum gekümmert, sie zu überprüfen, und festgestellt, dass die Zugriffsmodifikatoren in den festgelegten Eigenschaften meines DTO vorhanden waren internalund dies das Problem verursachte.
Simon Morgan
Wow, das war auch meine Lösung. Leute, hüte dich vor privaten Setzern! "Privates Set" ersetzen; zu "setzen;" mein Problem behoben.
FBaez51
18

Wenn die Werte des JSON-Objekts der Anforderung nicht den vom Dienst erwarteten Typ haben, lautet das [FromBody]Argument null.

Zum Beispiel, wenn die Alterseigenschaft im json einen floatWert hatte:

"Alter": 18,0

Der API-Dienst erwartet jedoch, dass es sich um eine handelt int

"Alter": 18

dann studentwird es sein null. (In der Antwort werden keine Fehlermeldungen gesendet, es sei denn, es wird keine Nullreferenzprüfung durchgeführt.)

Strahl
quelle
Vielen Dank! Wir haben versucht, ein komplexes Objekt an eine Zeichenfolge zu binden (Gott weiß warum). Nach dem Reparieren hat es funktioniert. Dieses Problem hat mich wahnsinnig gemacht. Was für eine dumme Entscheidung, still zu scheitern und zurückzukehren null ...
Lucas Bragança
13

Dies ist ein wenig alt und meine Antwort wird bis zum letzten Platz gehen, aber trotzdem möchte ich meine Erfahrungen teilen.

Versuchte jeden Vorschlag, hatte aber immer noch den gleichen "Null" -Wert in einem PUT [FromBody].

Schließlich stellte sich heraus, dass es um das Datumsformat ging, während JSON die EndDate-Eigenschaft meines Angular-Objekts serialisierte.

Es wurde kein Fehler ausgegeben, sondern nur ein leeres FromBody-Objekt empfangen.

JoeCool
quelle
3
Ich hatte alle möglichen seltsamen Daten an ihn übergeben und erwartet, dass es in seiner Zuordnung klug ist, aber nein ... Es stirbt und gibt Ihnen nichts als null. Ich habe es noch einmal mit gut erzogenen Daten versucht und hey presto, sortiert. Ihre Antwort hat mich dazu ermutigt!
MGDavies
2
Diese Antwort war sehr nützlich, da die Datumsformatierung die Ursache für einen Fehler war, auf den ich ebenfalls gestoßen bin.
Elijah Lofgren
Vermeiden Sie die Verwendung von [FromBody] vor Parametern, wenn diese im Hauptteil einer POST-Anforderung als JSON übergeben werden. Stellen Sie außerdem sicher, dass der Name der obersten Ebene in Ihrem JSON mit dem Variablennamen Ihres Parameters übereinstimmt.
justdan23
Danke, du bist der wahre Gott.
Hirofumi Okino
9

Wenn Sie Postman verwenden, stellen Sie Folgendes sicher:

  • Sie haben einen "Content-Type" -Header auf "application / json" gesetzt.
  • Sie senden den Körper als "roh"
  • Sie müssen den Parameternamen nirgendwo angeben, wenn Sie [FromBody] verwenden.

Ich habe dumm versucht, meinen JSON als Formulardaten zu senden, duh ...

John M.
quelle
Gleiches Problem für mich. Vielen Dank für die ausführliche Antwort.
goku_da_master
Wie formatieren Sie dann Ihren Körper? Ich meine, wenn ich nur "= Dies ist mein Wert" in den Body (als JSON deklariert) setze, wird mir dies nur sagen, dass der JSON fehlerhaft ist. Möchten Sie ein kleines Beispiel geben? EDIT: Nevermind, habe gerade die Lösung herausgefunden. In meinem Fall musste der "Inhaltstyp" "application / x-www-form-urlencoded" sein und mein Körper ist "roh" vom Typ Text.
Jacks
Wenn Sie [FromBody] NICHT verwenden, sollte Ihr JSON analysiert werden, solange der Name der obersten Ebene in Ihrem JSON mit dem Variablennamen Ihres Parameters übereinstimmt.
Justdan23
Das war genau das Problem für mich! Ich danke dir sehr.
Jay-Gefahr
7

TL; DR: Verwenden Sie nicht [FromBody], sondern rollen Sie Ihre eigene Version mit besserer Fehlerbehandlung. Gründe unten angegeben.

Andere Antworten beschreiben viele mögliche Ursachen für dieses Problem. Die Hauptursache ist jedoch, dass es [FromBody]einfach eine schreckliche Fehlerbehandlung gibt, die es im Produktionscode fast unbrauchbar macht.

Einer der typischsten Gründe für den Parameter nullist beispielsweise, dass der Anforderungshauptteil eine ungültige Syntax aufweist (z. B. ungültiges JSON). In diesem Fall würde eine vernünftige API zurückkehren 400 BAD REQUEST, und ein vernünftiges Webframework würde dies automatisch tun. Die ASP.NET-Web-API ist in dieser Hinsicht jedoch nicht sinnvoll. Es setzt einfach den Parameter auf nullund der Anforderungshandler benötigt dann "manuellen" Code, um zu überprüfen, ob der Parameter ist null.

Viele der hier gegebenen Antworten sind daher in Bezug auf die Fehlerbehandlung unvollständig, und ein fehlerhafter oder böswilliger Client kann auf der Serverseite unerwartetes Verhalten verursachen, indem er eine ungültige Anfrage sendet, die (im besten Fall) eine NullReferenceExceptionirgendwo auslöst und eine falsche zurückgibt Status von 500 INTERNAL SERVER ERRORoder, schlimmer noch, etwas Unerwartetes tun oder abstürzen oder eine Sicherheitslücke aufdecken.

Eine geeignete Lösung wäre, ein benutzerdefiniertes " [FromBody]" Attribut zu schreiben , das die ordnungsgemäße Fehlerbehandlung durchführt und die richtigen Statuscodes zurückgibt, idealerweise mit einigen Diagnoseinformationen, um Cliententwicklern zu helfen.

Eine Lösung, die möglicherweise hilft (noch nicht getestet), besteht darin, die erforderlichen Parameter wie folgt festzulegen : https://stackoverflow.com/a/19322688/2279059

Die folgende ungeschickte Lösung funktioniert auch:

// BAD EXAMPLE, but may work reasonably well for "internal" APIs...

public HttpResponseMessage MyAction([FromBody] JObject json)
{
  // Check if JSON from request body has been parsed correctly
  if (json == null) {
    var response = new HttpResponseMessage(HttpStatusCode.BadRequest) {
      ReasonPhrase = "Invalid JSON"
    };
    throw new HttpResponseException(response);
  }

  MyParameterModel param;
  try {
    param = json.ToObject<MyParameterModel>();
  }
  catch (JsonException e) {
    var response = new HttpResponseMessage(HttpStatusCode.BadRequest) {
      ReasonPhrase = String.Format("Invalid parameter: {0}", e.Message)
    };
    throw new HttpResponseException(response);
  }

  // ... Request handling goes here ...

}

Dies führt (hoffentlich) zu einer ordnungsgemäßen Fehlerbehandlung, ist jedoch weniger deklarativ. Wenn Sie beispielsweise Swagger zum Dokumentieren Ihrer API verwenden, ist der Parametertyp nicht bekannt. Dies bedeutet, dass Sie eine manuelle Problemumgehung finden müssen, um Ihre Parameter zu dokumentieren. Dies soll nur veranschaulichen, was [FromBody]zu tun ist.

BEARBEITEN: Eine weniger umständliche Lösung ist zu überprüfen ModelState: https://stackoverflow.com/a/38515689/2279059

BEARBEITEN: Es scheint, dass ModelState.IsValides nicht wie erwartet auf gesetzt ist, falsewenn JsonPropertymit verwendet wird Required = Required.Alwaysund ein Parameter fehlt. Das ist also auch nutzlos.

Meiner Meinung nach ist jedoch jede Lösung, die das Schreiben von zusätzlichem Code in jeden Anforderungshandler erfordert, nicht akzeptabel. In einer Sprache wie .NET mit leistungsstarken Serialisierungsfunktionen und in einem Framework wie der ASP.NET-Web-API sollte die Anforderungsüberprüfung automatisch und integriert sein und ist vollständig machbar, obwohl Microsoft nicht die erforderlichen integrierten Funktionen bereitstellt Werkzeuge.

Florian Winter
quelle
Ja, durch Hinzufügen des oben genannten Codes genau das, wonach ich gesucht habe! Fügen Sie Code hinzu, um den ModelState zu überprüfen: stackoverflow.com/a/38515689/2279059
Rob Bramhall
@RobBramhall Wenn Sie DataContract- und nicht Newtonsoft.Json-Attribute verwenden, ist die Verwendung von ModelState wahrscheinlich in Ordnung.
Florian Winter
4

Ich habe auch versucht, [FromBody] zu verwenden, aber ich habe versucht, eine Zeichenfolgenvariable zu füllen, da sich die Eingabe ändert und ich sie nur an einen Backend-Dienst weitergeben muss, aber dies war immer null

Post([FromBody]string Input]) 

Also habe ich die Methodensignatur geändert, um eine dynamische Klasse zu verwenden, und diese dann in einen String konvertiert

Post(dynamic DynamicClass)
{
   string Input = JsonConvert.SerializeObject(DynamicClass);

Das funktioniert gut.

Mike
quelle
3

Es kann hilfreich sein, dem json-Serializer TRACING hinzuzufügen, damit Sie sehen können, was los ist, wenn etwas schief geht.

Definieren Sie eine ITraceWriter-Implementierung, um ihre Debug-Ausgabe wie folgt anzuzeigen:

class TraceWriter : Newtonsoft.Json.Serialization.ITraceWriter
{
    public TraceLevel LevelFilter {
        get {
            return TraceLevel.Error;
        }
    }

    public void Trace(TraceLevel level, string message, Exception ex)
    {
        Console.WriteLine("JSON {0} {1}: {2}", level, message, ex);
    }
}

Dann machen Sie in Ihrer WebApiConfig:

    config.Formatters.JsonFormatter.SerializerSettings.TraceWriter = new TraceWriter();

(vielleicht in ein #if DEBUG einwickeln)

Phuo
quelle
3

Nachdem ich drei Tage lang gesucht hatte und keine der oben genannten Lösungen für mich funktioniert hatte, fand ich in diesem Link einen anderen Ansatz für dieses Problem: HttpRequestMessage

Ich habe eine der Lösungen auf dieser Site verwendet

[HttpPost]
public async System.Threading.Tasks.Task<string> Post(HttpRequestMessage request)
{
    string body = await request.Content.ReadAsStringAsync();
    return body;
}
Farid Amiri
quelle
Gute Herren. Dies war 2 Tage Headbangen hier. Vielen Dank!
Yordan Yanakiev
Dies macht keinen Sinn, warum nur der HttpRequestMessage-Parameter funktioniert, mein Controller eine andere Methode verwendet ([FromBody] ICollection <Typ> -Parameter) und es funktioniert perfekt, genau wie alle meine anderen Controller. Und die Aktionsmethode, mit der ich dieses Problem bekam, funktionierte einwandfrei, als ich es vor einigen Tagen zum ersten Mal implementierte. Der Unterschied besteht darin, dass ein .NET-Standard, der auf ein .net-Framework-Projekt verweist, diese Web-API-Methode aufruft Sie fragen sich, ob dies das "unbekannte Gebiet" ist, in dem Sie landen, wenn der .net-Standard auf das .net-Framework verweist? Ich möchte das Projekt einfach nicht wiederholen.
Ninos
2

In meinem Fall war das Problem das DateTimeObjekt, das ich gesendet habe. Ich habe ein DateTimemit "JJJJ-MM-TT" erstellt, und das DateTime, was für das Objekt erforderlich war, dem ich zugeordnet war, benötigte auch "HH- MM- SS". Das Anhängen von "00-00" löste das Problem (der vollständige Eintrag war aus diesem Grund null).

Schocks
quelle
2

Dies ist ein weiteres Problem im Zusammenhang mit ungültigen Eigenschaftswerten in einer Angular Typescript-Anforderung.

Dies hängt mit der Konvertierung zwischen einer Typoskriptnummer in ein int (Int32) in C # zusammen. Ich habe Ticks (UTC-Millisekunden) verwendet, die größer sind als der vorzeichenbehaftete Int32-Bereich (int in C #). Das C # -Modell wurde von int auf long geändert und alles hat gut funktioniert.

Tony Henderson
quelle
1

Ich hatte das gleiche Problem.

In meinem Fall lag das Problem in meinem public int? CreditLimitBasedOn { get; set; }Eigentum.

Mein JSON hatte den Wert, "CreditLimitBasedOn":truewenn es eine ganze Zahl enthalten sollte. Diese Eigenschaft hat verhindert, dass das gesamte Objekt mit meiner API-Methode deserialisiert wird.

Romesh D. Niriella
quelle
1

Vielleicht ist es für jemanden hilfreich: Überprüfen Sie die Zugriffsmodifikatoren für die Eigenschaften Ihrer DTO / Modellklasse. Sie sollten öffentlich sein . In meinem Fall wurden Interna von Objektobjekten während des Refactorings wie folgt in DTO verschoben:

// Domain object
public class MyDomainObject {
    public string Name { get; internal set; }
    public string Info { get; internal set; }
}
// DTO
public class MyDomainObjectDto {
    public Name { get; internal set; } // <-- The problem is in setter access modifier (and carelessly performed refactoring).
    public string Info { get; internal set; }
}

DTO wird fein an den Client übergeben, aber wenn die Zeit gekommen ist, das Objekt an den Server zurückzugeben, hatte es nur leere Felder (Null / Standardwert). Durch das Entfernen von "intern" werden die Dinge in Ordnung gebracht, sodass der Deserialisierungsmechanismus die Eigenschaften des Objekts schreiben kann.

public class MyDomainObjectDto {
    public Name { get; set; }
    public string Info { get; set; }
}
ddolgushin
quelle
Dies war mein Problem. Hatte Mitglieder internalfür mein schlechtes erklärt und es nach zwei Tagen gelöst.
Irfaan
1

Überprüfen Sie, ob JsonPropertyfür die Felder, die als null angegeben sind, ein Attribut festgelegt ist. Möglicherweise werden sie verschiedenen json-Eigenschaftsnamen zugeordnet.

Bashir Magomedov
quelle
Das war auch für mich das Problem. Ich bemerkte auch, dass ich meine Eigenschaften mit [JsonProperty ("myProperty")] dekorieren oder das [DataMember]Attribut verwenden konnte, um meine Eigenschaftenwerte zur Weitergabe zu bringen.
Dan Beaulieu
1

Ich habe dieses Problem so oft getroffen, aber eigentlich ist es ziemlich einfach, die Ursache aufzuspüren.

Hier ist das heutige Beispiel. Ich habe meinen POST-Dienst mit einem AccountRequestObjekt aufgerufen, aber wenn ich am Anfang dieser Funktion einen Haltepunkt gesetzt habe, war der Parameterwert immer null. Aber warum ?!

[ProducesResponseType(typeof(DocumentInfo[]), 201)]
[HttpPost]
public async Task<IActionResult> Post([FromBody] AccountRequest accountRequest)
{
    //  At this point...  accountRequest is null... but why ?!

    //  ... other code ... 
}

Um das Problem zu identifizieren, ändern Sie den Parametertyp in string, fügen Sie eine Zeile hinzu, um JSON.Netdas Objekt in den erwarteten Typ zu deserialisieren, und setzen Sie einen Haltepunkt in diese Zeile:

[ProducesResponseType(typeof(DocumentInfo[]), 201)]
[HttpPost]
public async Task<IActionResult> Post([FromBody] string ar)
{
    //  Put a breakpoint on the following line... what is the value of "ar" ?
    AccountRequest accountRequest = JsonConvert.DeserializeObject<AccountRequest>(ar);

    //  ... other code ...
}

Wenn Sie dies versuchen, wenn der Parameter noch leer ist oder null, rufen Sie den Dienst einfach nicht richtig auf.

Wenn die Zeichenfolge jedoch einen Wert enthält, DeserializeObjectsollte der Sie auf die Ursache des Problems hinweisen und die Zeichenfolge auch nicht in das gewünschte Format konvertieren. Mit den Rohdaten ( string), die deserialisiert werden sollen, sollten Sie jetzt sehen können, was mit Ihrem Parameterwert nicht stimmt.

(In meinem Fall haben wir den Dienst mit einem AccountRequestObjekt angerufen, das versehentlich zweimal serialisiert wurde !)

Mike Gledhill
quelle
1

Ich habe HttpRequestMessage verwendet und mein Problem wurde nach so vielen Recherchen gelöst

[HttpPost]
public HttpResponseMessage PostProcedure(HttpRequestMessage req){
...
}
aejaz ahmad
quelle
1

Nur um meine Geschichte zu diesem Thread hinzuzufügen. Mein Modell:

public class UserProfileResource
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }

    public UserProfileResource()
    {
    }
}

Das obige Objekt konnte in meinem API-Controller nicht serialisiert werden und gab immer null zurück. Das Problem war mit der ID vom Typ Guid : Jedes Mal, wenn ich eine leere Zeichenfolge als ID (die naiv ist, in die sie automatisch konvertiert wird Guid.Empty) von meinem Frontend übergeben habe, habe ich ein Nullobjekt als [FromBody]Parameter erhalten.

Lösung war entweder zu

  • gültigen GuidWert übergeben
  • oder wechseln GuidzuString
Dariusz
quelle
1

In meinem Fall habe ich mit Postman eine DateTime mit ungültigen Trennzeichen (%) gesendet, sodass die Analyse unbeaufsichtigt fehlschlug. Stellen Sie sicher, dass Sie gültige Parameter an Ihren Klassenkonstruktor übergeben.

Sidonai
quelle
1

Keine der oben genannten Lösungen war meine Lösung: In meinem Fall besteht das Problem darin, dass [ApiController] nicht zum Controller hinzugefügt wurde, sodass der Wert Null angegeben wird

[Produces("application/json")]
[Route("api/[controller]")]
[ApiController] // This was my problem, make sure that it is there!
public class OrderController : Controller

...

Adel
quelle
Was ist mit dem Erben von sich ApiControllerselbst?
Zimano
Überprüfen Sie Ihre JSON-Struktur, möglicherweise haben Sie einen ungültigen JSON- Wert
Adel
Wenn Sie mir geantwortet haben: Ich meinte, Ihre Antwort schlägt vor, das ApiControllerAttribut als Klasse hinzuzufügen , während die Klasse von erbt Controller. Ich glaube, Sie können das gleiche Ergebnis erzielen, indem Sie ApiControllerdirekt von erben , was standardmäßig in den Controllern erfolgt, die von einem WebAPI-Projekt in VS generiert wurden.
Zimano
1

Ich bin gerade darauf gestoßen und war frustrierend. Mein Setup: Der Header wurde auf Content-Type: application / JSON gesetzt und übergab die Informationen aus dem Body im JSON-Format und las [FromBody] auf dem Controller.

Alles war gut eingerichtet und ich erwarte, dass es funktioniert, aber das Problem war, dass der JSON gesendet wurde. Da es sich um eine komplexe Struktur handelte, wurde eine meiner Klassen, die als "Zusammenfassung" definiert wurde, nicht initialisiert, und daher wurden die Werte dem Modell nicht ordnungsgemäß zugewiesen. Ich habe das abstrakte Schlüsselwort entfernt und es hat einfach funktioniert .. !!!

Ein Tipp, wie ich das herausfinden konnte, war, Daten in Teilen an meinen Controller zu senden und zu überprüfen, wann sie null werden ... da es sich um ein komplexes Modell handelte, habe ich jeweils ein Modell an meine Anforderungsparameter angehängt. Hoffe, es hilft jemandem, der auf dieses dumme Problem stößt.

Chethan
quelle
0

Es scheint, dass es viele verschiedene Ursachen für dieses Problem geben kann ...

Ich fand heraus, dass das Hinzufügen eines OnDeserializedRückrufs zur Modellklasse dazu führte, dass der Parameter immer war null. Genauer Grund unbekannt.

using System.Runtime.Serialization;

// Validate request
[OnDeserialized]  // TODO: Causes parameter to be null
public void DoAdditionalValidatation() {...}
Florian Winter
quelle
0

Ich hatte dieses Problem in meiner .NET Framework-Web-API, weil mein Modell in einem .NET Standard-Projekt vorhanden war, das auf eine andere Version von Datenanmerkungen verwies.

Durch Hinzufügen der folgenden ReadAsAsync-Zeile wurde die Ursache für mich hervorgehoben:

public async Task<HttpResponseMessage> Register(RegistrationDetails registrationDetails)
{
    var regDetails = await Request.Content.ReadAsAsync<RegistrationDetails>();
Kraeg
quelle
0

Wenn dies darauf zurückzuführen ist, dass bei Web API 2 aufgrund nicht übereinstimmender Datentypen ein Deserialisierungsproblem aufgetreten ist, können Sie anhand des Inhaltsstroms herausfinden, wo dies fehlgeschlagen ist. Es wird gelesen, bis ein Fehler auftritt. Wenn Sie also den Inhalt als Zeichenfolge lesen, sollten Sie die hintere Hälfte der von Ihnen geposteten Daten haben:

string json = await Request.Content.ReadAsStringAsync();

Korrigieren Sie diesen Parameter und er sollte ihn beim nächsten Mal weiter verbessern (oder erfolgreich sein, wenn Sie Glück haben!) ...

Jereme
quelle
Request.Content.ReadAsStringAsync wird betroffen, wenn Ihr Dienst mehr als 1000 Anforderungen pro Sekunde erhält und die Zeichenfolge null wird. wir müssen damit umgehen.
Amol Shiledar
0

In meinem Fall ( .NET Core 3.0 ) musste ich die JSON-Serialisierung konfigurieren, um die camelCase-Eigenschaften mithilfe von AddNewtonsoftJson () aufzulösen :

services.AddMvc(options =>
{
    // (Irrelevant for the answer)
})
.AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});

Tun Sie dies in Ihrem Startup / Dependency Injection-Setup.

user1987392
quelle
-1

Nur noch eine Sache zu sehen ... mein Modell wurde als [serialisierbar] markiert und das verursachte den Fehler.

Ran Davis
quelle