Why is the IDictionary<string, string> data in API Controller coming in as null?
I am using HttpClient GetAsync to make a call to the APi Controller.I am sending a one parameter as a querystring https://localhost:44384/my/types?token=NbLeZVEEksQ0GTIY2clmM50uRfZ9%252bWY895mfS25R1zI%253d
On the API Controller side, I am using [FromQuery] to receive the token as a keyvale pair. But its coming in as null. I tried the same on postman
If I use [FromQuery] string token instead of [FromQuery] IDictionary<string,string> it works just fine. But I would like the arguments in keyvalue pair format.
I need that [FromQuery] to work if I wanted to pass multiple arguments. Currently I am passing only the token but I also need the ID. Hoping to have this keyvalue pair working.
https://localhost:44384/note/types?token=73UtMF24W1%252fpUbO5TlF%252bOJ0uRfZ9%252bWY895mfS25R1zI%253d&custid=1}
using (var client = new HttpClient())
{
string targetUrl = string.Format("{0}{1}", "http://localhost:4451", "my/types");
var builder = new UriBuilder(targetUrl);
var query = HttpUtility.ParseQueryString(builder.Query);
query["token"] = encodedSSo;
query["custid"] = "1";
builder.Query = query.ToString();
;
using (var response = await client.GetAsync(builder.ToString()))
{
if (response.StatusCode == HttpStatusCode.OK)
{
responseBody = await response.Content.ReadAsStringAsync();
}
}
using (var response = await client.GetAsync(builder.ToString()))
{
if (response.StatusCode == HttpStatusCode.OK)
{
responseBody = await response.Content.ReadAsStringAsync();
}
}
return Ok(repo.result);
}
API controller
[Route("my/types")]
[HttpGet]
public IHttpActionResult GetTypesAsync([FromQuery] IDictionary<string, string> data) ///why is the data here null. Should it not be a keyvalue pair because HttpClient GetAsync is sending a keyvalue pair? [FromQuery] string data.. works just fine.
{
try
{
//do something
return Ok(report);
}
catch (Exception ex)
{
IHttpActionResult response;
}
}
When you send the KeyValuePairs you are assigning the parameter values. Like you saw parameter:"token" value: "your token value".
So you don't receive it like IDictionary you should receive it as string parameter.
Try to change this line to
public IHttpActionResult GetTypesAsync([FromQuery] string token)
If you what to get list of keyvaluepair from GET request it is the only way you can get it. If you don't like it then use POST
[HttpGet("~/my/types")]
public IHttpActionResult GetTypesAsync(string token)
{
var data = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("token", token)
};
....
result
[{"Key":"token","Value":"NbLeZVEEksQ0GTIY2clmM50uRfZ9%252bWY895mfS25R1zI%253d"}]
and code
var url=#"https://localhost:44384/my/types?token=NbLeZVEEksQ0GTIY2clmM50uRfZ9%252bWY895mfS25R1zI%253";
using (var response = await client.GetAsync(url))
{
...
UPDATE
if you want to use more params , your action should be
[HttpGet("~/my/types")]
public IHttpActionResult GetTypesAsync(Dictionary<string, string> data)
but the url still should be like this
var url=#"https://localhost:44384/my/types?token=NbLeZVEEks&Id=Id";
Related
I have one API endpoint for login. Once we enter correct username and password then we are getting following details :
{
"accessToken": "Some_Value",
"accessTokenExpireAt": "Some_Value",
"refreshToken": "Some_Value",
"userID": "Some_Value"
}
Once user click on Submit button then below code will be executed.
public async Task<ActionResult> Index(LoginModel loginModel)
{
using (var client = new HttpClient())
{
string url = "URL_ENDPOINT_FOR_LOGIN";
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.PostAsJsonAsync(url, loginModel);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync();
//Here I am getting all values in JSON in result. Now I want to redirect to user to profile page and on that page need to call another API which will fetch all details of that user. In Result I am getting userId.
}
else
{
ModelState.AddModelError("", "Wrong details");
}
}
return View(loginModel);
}
Now I have one more API end point, when we call that then we are getting that user details like firstname, email id and so on.
I need to display that all user details in View, but only if that accessToken is coming.
So I want to know how I can pass this accessToken and userId to another action and all API url from there.
I did something similar before in a Web API.
Can you try this in your API method:
return RedirectToAction("RedirectedAction",
"ControllerName",
new { val = value1, ..., val = valueN });
Where value1, ... valueN are the parameters you pass onto the next API method.
The redirected method stub is then:
public async Task<ActionResult> RedirectedAction(
string value1, string value2, ...)
{
...
}
(Adjust your parameter types as required.)
You can simply call by parameter and send json string to the action and in that action you can deserialize the Json string.
public async Task<ActionResult> Index(LoginModel loginModel)
{
using (var client = new HttpClient())
{
string url = "URL_ENDPOINT_FOR_LOGIN";
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.PostAsJsonAsync(url, loginModel);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync();
string JsonString=result.Result;
return RedirectToAction("YourAction", new { YourParam= JsonString });
}
else
{
ModelState.AddModelError("", "Wrong details");
}
}
return View(loginModel);
}
In the Other Action Your Can simply Deserialize using NewtonSoft.Json if not included you can download from nuget.
public ActionResult YourAction(string YourParam)
{
YourClass clsObj= JsonConvert.DeserializeObject<YourClass>(JsonString /*YourParam in this case*/);
// Do your Work Here
}
Also you can remove async task from your action to load your view after completing API request.
Just add
System.Threading.Tasks.Task<HttpResponseMessage> response = client.PostAsJsonAsync(url, loginModel);
response.Wait();
in place of
var response = await client.PostAsJsonAsync(url, loginModel);
Also in action prototype
public ActionResult Index(LoginModel loginModel)
I am starting WebApi tutorial but I just faced a problem that parameter in action is a null.
Below is the tutorial code.
WebApi
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var raw = Request.Content.ReadAsStringAsync();
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, Result.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
WebApi Client
static string Register(string email, string password)
{
var Result = new RegisterBindingModel()
{
Email = email,
Password = password,
ConfirmPassword = password
};
using (var client = new HttpClient())
{
var response = client.PostAsJsonAsync(
"http://localhost:7399/api/Account/Register",
Result).Result;
return response.StatusCode.ToString();
}
}
Register action receives http request but model is always null. So the raw variable shows like this
{"Email":"test#gmail.com","Password":"Test#123","ConfirmPassword":"Test#123"}
But when I tried sending http request using Postman it worked. As request body was read for model binding. The raw variable was empty. I don't know what's wrong with my client. I followed exactly tutorial code. Should I specify content-type?
make variable name same i.e. in Register method change var Result to var model and have a try.
it should be frombody , i.e. get parameter value from post body
[HttpPost]
public async Task<IHttpActionResult> Register([FromBody]RegisterBindingModel model)
Add HttpPost And Use below Methods
[AllowAnonymous]
[HttpPost]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
//your code
}
Use this Methods:-
public static async Task<HttpResponseMessage> PostAsJsonAsync(this HttpClient client,
string requestUri, object requestObject, Dictionary<string, string> requestHeaders = null,
int? timeoutMilliSeconds = null)
{
var jsonContent = JsonConvert.SerializeObject(requestObject);
var requestContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
return await SendAsync(client, requestUri, HttpMethod.Post,
requestContent, requestHeaders, timeoutMilliSeconds);
}
public static async Task<HttpResponseMessage> SendAsync(
this HttpClient client,
string requestUri, HttpMethod httpMethod, HttpContent requestContent = null,
Dictionary<string, string> requestHeaders = null, int? timeoutMilliSeconds = null)
{
var httpRequestMessage = new HttpRequestMessage
{
RequestUri = new Uri(requestUri),
Method = httpMethod,
Content = requestContent
};
if (requestHeaders != null)
{
foreach (var requestHeader in requestHeaders)
{
httpRequestMessage.Headers.Add(requestHeader.Key, requestHeader.Value);
}
}
if (timeoutMilliSeconds.HasValue)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(new TimeSpan(0, 0, 0, 0, timeoutMilliSeconds.Value));
return await client.SendAsync(httpRequestMessage, cts.Token);
}
else
{
return await client.SendAsync(httpRequestMessage);
}
}
The client application accesses a web api controller to get a set of data , the controller has a list as parameter.
static void Main(string[] args)
{
Program p = new Program();
p.getdata().Wait();
}
public async Task getdata()
{
List<string> datelist = new List<string>();
datelist.Add("12/05/2017");
datelist.Add("14/05/2017");
datelist.Add("18/05/2017");
HttpClient host = new HttpClient();
host.BaseAddress = new Uri("http://localhost/widgetApi/");
host.DefaultRequestHeaders.Clear();
host.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
StringContent content = new StringContent(JsonConvert.SerializeObject(datelist), Encoding.UTF8, "application/json");
HttpResponseMessage response = await host.GetAsync("api/dataAccessApi?"+ datelist);
response.EnsureSuccessStatusCode();
if( response.IsSuccessStatusCode)
{
Console.Read();
}
}
The controller is
public HttpResponseMessage Get([FromBody] List<string> dates)
{
..... function going here
}
My question is how can I pass datelist to the web api ??
GET requests do not have a BODY, you can use query string values. ?dates='{UrlEncoded date}'&dates='{UrlEncoded date}'...
public HttpResponseMessage Get([FromUri] List<string> dates) {
//..... function going here
}
On the client side you would need to construct the query string and append it to the Uri
var dates = datelist.Select(d => string.Format("dates={0}", UrlEncode(d));
var query = string.Join("&", dates);
var uri = "api/dataAccessApi?" + query;
With UrlEncode looking like this
/// <summary>Escape RFC3986 String</summary>
static string UrlEncode(string stringToEscape) {
return stringToEscape != null ? Uri.EscapeDataString(stringToEscape)
.Replace("!", "%21")
.Replace("'", "%27")
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("*", "%2A") : string.Empty;
}
For Asp.Net Core consider to use [FromQuery] instead of [FromUri]
I'm trying to read a JSON string from Web API controller that is send through a HttpClient.PostAsync() method. But for some reason the RequestBody is always null.
My Request looks like this:
public string SendRequest(string requestUrl, StringContent content, HttpMethod httpMethod)
{
var client = new HttpClient { BaseAddress = new Uri(ServerUrl) };
var uri = new Uri(ServerUrl + requestUrl); // http://localhost/api/test
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response;
response = client.PostAsync(uri, content).Result;
if (!response.IsSuccessStatusCode)
{
throw new ApplicationException(response.ToString());
}
string stringResult = response.Content.ReadAsStringAsync().Result;
return stringResult;
}
I call this method like this
var content = new StringContent(JsonConvert.SerializeObject(testObj), Encoding.UTF8, "application/json");
string result = Request.SendRequest("/api/test", content, HttpMethod.Post);
Now currently my Web API controller method reads the send data like this:
[HttpPost]
public string PostContract()
{
string httpContent = Request.Content.ReadAsStringAsync().Result;
return httpContent;
}
This works fine. The stringResult property contains the string returned by the controller method. But I'd like to have my controller method like this:
[HttpPost]
public string PostContract([FromBody] string httpContent)
{
return httpContent;
}
The request seems to be working, getting a 200 - OK, but the stringResult from the SendRequest method is always null.
Why isn't the method where I'm using the RequestBody as parameter not working?
Since you're posting as application/json, the framework is attempting to deserialize it rather than providing the raw string. Whatever the type of testObj is in your sample, use that type for your controller action parameter and return type instead of string:
[HttpPost]
public MyTestType PostContract([FromBody] MyTestType testObj)
{
return testObj;
}
We have a REST Service created in Mvc4
I am trying to add ETag Header in the Response from my WebApi method. It is added in the Header collection without any error but when I check the response header in the Fiddler it is not there.
Here is the method that I used to write header in the response:
internal static HttpResponseMessage<T> GetResponse<T>(Tuple<T, Dictionary<string, string>> response)
{
HttpResponseMessage<T> httpResponse = new HttpResponseMessage<T>(response.Item1, HttpStatusCode.OK);
if (response.Item2 != null)
{
foreach (var responseHeader in response.Item2)
{
if (string.Compare(responseHeader.Key, "ETAG", StringComparison.OrdinalIgnoreCase) == 0)
{
httpResponse.Headers.ETag = new System.Net.Http.Headers.EntityTagHeaderValue("\"" + responseHeader.Value + "\"");
}
else
{
httpResponse.Headers.Add(responseHeader.Key, responseHeader.Value);
}
}
}
return httpResponse;
}
You can do it 2 ways, you can either set the ETag in an ActionFilter.OnActionExecuted method like this:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
actionExecutedContext.ActionContext.Response.Headers.ETag = new EntityTagHeaderValue(...);
}
But there's no way to easily pass the desired value from your controller to the ActionFilter. The second way is to change your WebAPI Action. Instead of returning a model type, return an HttpResponseMessage:
[HttpGet]
public HttpResponseMessage MyActionMethod() {
var result = // response data
var response = Request.CreateResponse<MyType>(HttpStatusCode.OK, result);
response.Headers.Add("Last Modified", result.Modified.ToString("R"));
response.Headers.ETag = new System.Net.Http.Headers.EntityTagHeaderValue(CreateEtag(result));
return response;
}