Getting exception while retrieving data from POST method? - c#

I am getting an exception while reading the post data.
I get error on this line:
HttpContext.Current.Request.Form["UserID"].ToString();
And the error is :
System.Collections.Specialized.NameValueCollection.this[string].get
returned null.
In method I have put this code :
StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream);
string requestFromPost = reader.ReadToEnd();
and data comes in that properly like this:
{
"UserID": "1000",
"Password": "ABCD"
}
Why I am not getting value in this HttpContext.Current.Request.Form["UserID"].ToString()? I also tried Request.QueryString but no success here.
Where am I doing wrong? Any help or suggestion would be much appreciated. Thanks!

There is no Form on this request. For a request body to be interpreted as form data, it must:
have a content type of x-www-form-urlencoded
be actually formatted as form encoded values, i.e. UserID=foo&Password=bar
JSON content is JSON, it will not be interpreted as form-data.
Web API should already take care of this for you. Given an action method:
public void Action(Credentials credentials)
where the Credentials class looks something like:
public class Credentials
{
string UserID { get; set;}
string Password { get; set; }
}
You shouldn't have to do anything else to have the framework turn this incoming JSON data into an instance of Credentials and pass it to the action method. This is automatic unless you've done something strange that breaks the conventions that WebAPI expects.

Related

How to bind to a web api model when the request body includes escape characters?

I have an endpoint that looks like:
public IHttpActionResult SignUp([FromBody] AuthInput input)
Whenever the request body includes an escape character "\" the API fails to bind the data to the model. I have a guess that this is because the JSON would be considered "malformed."
I'd like to format the request body before the API attempts to bind it to the model and change all "\" to "\\"
Request body
{
"email": "mrsmith#usa.com",
"password": "badpassword\",
"firstName": "John",
"lastName": "Smith"
}
The backspace makes the input object "null"
Using c# ASP.NET 4.6.2
If you're generating the request body yourself:
Ideally you should be generating your Request Body JSON payload by serializing an existing DTO class.
If you can't do that, then you should safely escape string-values for use in directly-rendered JSON using .NET's built-in JavaScript string-escape utility methods:
In the .NET Framework Full Profile (so not .NET Core, .NET Standard, or .NET Framework Client Profile) you can use System.Web.HttpUtility.JavaScriptStringEncode.
Otherwise, use System.Text.Encodings.Web.JavaScriptEncoder.
If you're receiving bad input that you have no control over:
Approach 1: Work with the request-body directly:
This is the simplest approach, but requires you to do it for every controller action that receives malformed JSON:
public async Task<IHttpActionResult> SignUp()
{
String requestBody;
using( StreamReader rdr = new StreamReader( this.Request.Body ) )
{
requestBody = await rdr.ReadToEndAsync();
}
//
// Tweak the raw JSON text to make it parseable:
String requestBodyTweaked = requestBody.Replace( "\\\",", "\"," );
// Parse it and pass it on to the original `SignUp` method:
AuthInput dto = JsonConvert.DeserializeObject<AuthInput>( requestBodyTweaked );
return this.SignUp( dto );
}
// This is your current SignUp action method, it's unchanged except it's now `private`:
private IHttpActionResult SignUp( AuthInput input)
{
}
Approach 2: Middleware to intercept and modify all request bodies:
You could mitigate this using a middleware layer that intercepts the request body - but be very careful.
See this QA for instructions on how to intercept and modify an incoming request body: ASP NET Core modify/substitute a request body
I assume you'd want to edit the raw JSON text rather than parse it:

Insert in DB a JSON object from a URL

I'm new to the REST API world. I explain my need: at a specific URL I have a raw JSON text, I would like this text to be acquired by my application and inserted later in the DB as a model I created previously through EF. C# NET-CORE 2.2.
if I wasn't clear enough, don't hesitate to ask me for more details.
Thanks in advance!
Edit:
I'm sorry if it' was unclear, I will provide more detail:
Actually, i have a JSON string downloaded from an url. I did it with the following code:
var client = new WebClient();
var jsonFull = client.DownloadString(string.Format("https://url"));
It's working fine. Now, I need to take from this string only a little part of the JSON, so i did:
using var jsonDoc = JsonDocument.Parse(jsonFull);
var jsonParsed = jsonDoc.RootElement;
var myCV = jsonParsed.GetProperty("cv");
CVE is an object of this JSON, and I succesfully take it.
Inside this object, there is another one called CV_data, so I extract this:
var myCVLE = myCV.GetProperty("CV_data_meta");
The result is a var with inside
ValueKind = Object : "{
"ID": "CV-2019",
"ASS": "cv#ms.org"
}"
Now, I have a class like that
public class CV_data_meta
{
[JsonPropertyName ("ID")]
public string ID { get; set; }
[JsonPropertyName("ASS")]
public string ASS { get; set; }
}
The question is: how i can put the value in the var myCVLE in the class CV_data_meta?
I tried with
var myCVClass = JsonSerializer.Deserialize<CV_data_meta>(myCVLE);
But I get an error.
Note: I can't deserialize all the string JSON into an object, because there are a lot of information that I don't need.
Thanks in advance all!
As I understand from your question, it follows:
You first need to create the JSON object mapping (class) that the API URL will return.
Then consume the API url like this:
var client = new WebClient();
var reply =
client.DownloadString(
string.Format("https://www.yourapi.com/yourpath?yourkey={0}", yourkey));
receive and map object with mapped class
var yourvar = JsonConvert.DeserializeObject<yourclass>(reply);
Now you have the API return mapped to a class in your application, you can do whatever you want with it, including saving to a database.

.NET Core Web API: return a custom HTTP status code with Content Type application/problem+json

ControllerBase contains methods such as Conflict() that return a ConflictResult object (representing an HTTP 409 response) that is derived from StatusCodeResult. The resulting response body has content type application/problem+json and looks like this:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"traceId": "0HLO99QHFC9QI:00000001"
}
There is no in-built method/class for an HTTP 410 response, so I made one:
[DefaultStatusCode(410)]
public class GoneResult : StatusCodeResult
{
public GoneResult() : base(410)
{}
}
...
public static class ControllerBaseExtensions
{
public static GoneResult Gone(this ControllerBase controllerBase) // this doesn't give all the problem+JSON attributes
{
return new GoneResult();
}
}
However, this gives
{
"type": "about:blank",
"status": 410
}
i.e., the type value is different and the title and traceId fields are missing.
I'd also like to create a custom class for an HTTP 500 response that includes a message field with the error message. I've tried returning StatusCode(StatusCodes.Status500InternalServerError), which gives me the same minimal application/problem+json response as my Gone() method; I've also tried returning StatusCode(StatusCodes.Status500InternalServerError, message), which gives me my error message but formats the response as text/plain.
The code that generates the ProblemDetails response isn't aware of the 410 status-code, so it doesn't have an associated Link and Title property to use when building the response object. To add this awareness, configure ApiBehaviorOptions in ConfigureServices, like this:
services.Configure<ApiBehaviorOptions>(options =>
{
options.ClientErrorMapping[410] = new ClientErrorData
{
Title = "Gone",
Link = "https://tools.ietf.org/html/rfc7231#section-6.5.9"
};
});
ClientErrorMapping is a dictionary of int (status-code) to ClientErrorData. Note that the value I've used for Link above does point to the correct section of the RFC.
Simply, you have to actually return a ProblemDetails response body. I'd have to dig through the code to be sure, but I think ASP.NET Core is doing this via middleware only for particular results. They say anything in the 4xx range, but I think that's actually just confined to the built-in result types that return status codes in that range, not any result with a 4xx status code. Again, this is conjecture, as I haven't looked at exactly what they're doing, although it's not happening as part of the actual result class.
For your purposes, there's a few different ways you can handle this. You can write your own middleware to catch outbound responses and rewrite them. You can use an custom exception handler. You could simply inherit from ObjectResult instead, and then just create a ProblemDetails instance yourself and drop that into the base. You could even just return ProblemDetails directly from your action (though, that's obviously the least optimal way).

Postman Testing send string to Web Api accepting string is null

I have been testing all the Get,Create,Update methods with Postman in which the Get passes in nothing. The Create and Update passes in raw json with Activity object with several properties that do match up with the C# class
So this signature for Create and Update works fine
[HttpPost]
public IHttpActionResult UpdateActivity(Activity activity)
Above works with Postman passing in JSON content type with all the properties. I have done this on OTHER projects.
HOWEVER
I'm trying to simply pass in a string and it is null no matter what
public IHttpActionResult DeleteActivity([FromBody]string Id)
{
// delete
var del = ActivityService.DeleteActivity(Id);
return Ok(del);
}
Postman I tried MANY ways
http://localhost:49810/api/activityapi/deleteactivity
I have tried MANY many ways based on blogs and google search one such example
{ "Id" = "5808786fa3e9ec79546b3c71" }
I know this is an older question but I wanted to help those who might have a similar problem as I was able to get this working.
In WebAPI Controller my method is setup as
[HttpPost]
public IHttpActionResult Create([FromBody] int eventId)
{
....
}
In order to get this to test properly in Postman you have to: In body, set to raw, make sure JSON (application/json) is set and then just add value like 2 that's it.. not like { "eventId":2 } which is proper JSON just the value and then it will work.
So in original poster's case, in Postman, if you set Body to raw, JSON (application/json) then "5808786fa3e9ec79546b3c71" as value it will work.
In Postman ensure the body is set to raw and select json and in the body just write "your string" in quotes. Do not use {} to surround it because that is to make a complex object
Try the following in the body, with the content-type as application/json
{ "5808786fa3e9ec79546b3c71" }
As when you specify it like so, it will attempt to de-serialize into a complex type with a property of Id
{ "Id" : "5808786fa3e9ec79546b3c71" }
Old question, but for those still wondering, I would recommend sending your string as a query parameter. Take a method like this for example:
[AllowAnonymous]
[HttpGet("resendEmailConfirmtionLink")]
public async Task<IActionResult> ResendEmailConfirmationLink(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null) return Unauthorized();
var origin = Request.Headers["origin"];
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
var verifyUrl = $"{origin}/verifyEmail?token={token}&email={user.Email}";
var message = $"<p>Please click the below link to verify your email address:</p><p><a href='{verifyUrl}'>Click to verify email</a></p>";
await _emailSender.SendEmailAsync(user.Email, "Please verify email", message);
return Ok("Email verification link resent");
}
This method expects a key value pair of a string called email. You can send your request like "http://localhost:5000/api/account/verifyEmail?email=myemail#test.com" or, in Postman, add it as a parameter like this:
postman query params
Your payload is not valid.
Change-->
{ "Id" = "5808786fa3e9ec79546b3c71" }
To-->
{ "Id" : "5808786fa3e9ec79546b3c71" }
[HttpPost]
public IHttpActionResult Create(int eventId)
{
....
}
Use form-data instead of raw-json
Key - eventId
Value - "5808786fa3e9ec79546b3c71"
This worked for me.

ASP.NET Web Api - multiple params 500 error

' trying to make an web api controller with two parameters: one model object and string.
public string AddDevice(Device device, [FromBody] string userName)
{
// Some operations here
}
When I try it with one parameter on fiddler:
For Device object (body request):
{
"DeviceName":"name,
"StolenFlag":false
}
For string "[FromBody] string userName" (body request):
"userName"
It works fine. I just do not know how to make this method works with those two parameters. When I try connecting request body on fiddler like that:
{
"DeviceName":"name,
"StolenFlag":false
}
"userName"
I get an 500 error. It means, that server finds correct controller method but can't handle request. Any ideas?
First add the following line to WebApiConfig.cs in your App_Start folder.
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
It goes inside this function:
public static void Register(HttpConfiguration config)
Build your API and read the full error message from the Response. This should tell you exactly what's happening.
Since you can have only one parameter in the Request body you can change the method to accept username in the URI.
public string AddDevice([FromBody] Device device, string userName)
{
// Some operations here
return "";
}

Categories

Resources