I'am trying to get list of object from query parameter but it's null.
I Added [FromQuery] before it but it's still null
Controller :
[HttpGet("filter")]
public async Task<IActionResult> GetFilteredSperms([FromQuery] List<SpermFilterDTO> filters, [FromQuery] string name)
{
var result = await _mediator.Send(new GetSpermsByFilterQuery { Filters = filters });
foreach (var item in filters)
{
Console.WriteLine($"Index is {item.Index}");
}
Console.WriteLine($"Name is {name}");
return Ok(result);
}
name property is Ok but filters is empty.
It is not recommended (nor really supported) to place complex objects in the query string. A GET action supports a request body and a GET request with a body is not forbidden by any specification or standard.
Thus, moving the object from the query to the body will allow your action to function as intended.
...
public async Task<IActionResult> GetFilteredSperms([FromBody] List<SpermFilterDTO> filters, [FromQuery] string name)
...
Related
I want to hide parameters with the BindNever attribute in actions from SwaggerUI.
My action:
[HttpGet("{id:int}")]
[TryGetUserByIdValidation(GetAsUserReadDto = true, UserArgumentName = "userDto")]
public virtual ActionResult<ApiResult<User>> Get(int id,
[BindNever] UserReadDto userDto)
{
var res = new ApiResult<UserReadDto>()
.WithData(userDto);
return Ok(res);
}
In SwaggerUI I can pass the [BindNever] UserReadDto userDto as JSON in the request body, but the method is GET so I get an error in swaggerUI.
Why do I have a BindNever parameter in my action? I'm filling it with TryGetUserByIdValidation ActionFilter which is above my action. It handles all the mappings and errors. I'm preventing binding for that parameter with BindNever but it is not fully compatible with API so sometimes I have to use it with FromForm or any From... attribute except FromBody.
I have tried this OperationFilter.
public class SwaggerExcludeBindNeverFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var paramsToHide = context.MethodInfo.GetParameters()
.Where(para => para.CustomAttributes.Any(att => att.AttributeType == typeof(BindNeverAttribute)))
.ToList();
if (paramsToHide.Any())
{
// What to do now?
operation.RequestBody.Content.Clear();
}
}
}
And add to swagger:
options.OperationFilter<SwaggerExcludeBindNeverFilter>();
But this code removes all RequestBody.Content and as I said it can be in Form or anywhere else.
Swagger should not send or even show this.
You can tell me which attribute should I use to prevent Binding and show it in swagger.
I'm using Asp.Net Core 5.
In the case that I can't add a service to HttpContext.RequestServices after a request was made and get it in action parameter with [FromServices] attribute (error: this service is not registered).
So I pass the data with the HttpContext.Items[] dictionary.
In TryGetUserByIdValidation ActionFilter:
// pervious code
// context.ActionArguments[UserArgumentName] = user;
context.HttpContext.Items[ItemKey] = user; // < set the item
Action:
[HttpGet("{id:int}")]
[TryGetUserByIdValidation(GetAsUserReadDto = true, ItemKey = "userDto")]
public virtual ActionResult<ApiResult<User>> Get(int id)
{
UserReadDto userDto = HttpContext.Items[nameof(userDto)] as UserReadDto; // < get the item
var res = new ApiResult<UserReadDto>()
.WithData(userDto);
return Ok(res);
}
This is just a whitewash answer, it works for me. It does not have anything to do with Swagger so please post an answer to hide [BindNever] action parameters. To accept that.
I'm building one RESTful API using ASP.NET Core MVC and I want to use querystring parameters to specify filtering and paging on a resource that returns a collection.
In that case, I need to read the values passed in the querystring to filter and select the results to return.
I've already found out that inside the controller Get action accessing HttpContext.Request.Query returns one IQueryCollection.
The problem is that I don't know how it is used to retrieve the values. In truth, I thought the way to do was by using, for example
string page = HttpContext.Request.Query["page"]
The problem is that HttpContext.Request.Query["page"] doesn't return a string, but a StringValues.
Anyway, how does one use the IQueryCollection to actually read the querystring values?
You can use [FromQuery] to bind a particular model to the querystring:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
e.g.
[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}
You could use the ToString method on IQueryCollection which will return the desired value if a single page parameter is specified:
string page = HttpContext.Request.Query["page"].ToString();
if there are multiple values like ?page=1&page=2 then the result of the ToString call will be 1,2
But as #mike-g suggested in his answer you would better use model binding and not directly accessing the HttpContext.Request.Query object.
ASP.NET Core will automatically bind form values, route values and query strings by name. This means you can simply do this:
[HttpGet()]
public IActionResult Get(int page)
{ ... }
MVC will try to bind request data to the action parameters by name ... below is a list of the data sources in the order that model binding looks through them
Form values: These are form values that go in the HTTP request using the POST method. (including jQuery POST requests).
Route values: The set of route values provided by Routing
Query strings: The query string part of the URI.
Source: Model Binding in ASP.NET Core
FYI, you can also combine the automatic and explicit approaches:
[HttpGet()]
public IActionResult Get(int page
, [FromQuery(Name = "page-size")] int pageSize)
{ ... }
Here is a code sample I've used (with a .NET Core view):
#{
Microsoft.Extensions.Primitives.StringValues queryVal;
if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
queryVal.FirstOrDefault() == "yourValue")
{
}
}
You can just create an object like this:
public class SomeQuery
{
public string SomeParameter { get; set; }
public int? SomeParameter2 { get; set; }
}
And then in controller just make something like that:
[HttpGet]
public IActionResult FindSomething([FromQuery] SomeQuery query)
{
// Your implementation goes here..
}
Even better, you can create API model from:
[HttpGet]
public IActionResult GetSomething([FromRoute] int someId, [FromQuery] SomeQuery query)
to:
[HttpGet]
public IActionResult GetSomething(ApiModel model)
public class ApiModel
{
[FromRoute]
public int SomeId { get; set; }
[FromQuery]
public string SomeParameter { get; set; }
[FromQuery]
public int? SomeParameter2 { get; set; }
}
StringValues is an array of strings. You can get your string value by providing an index, e.g. HttpContext.Request.Query["page"][0].
IQueryCollection has a TryGetValue() on it that returns a value with the given key. So, if you had a query parameter called someInt, you could use it like so:
var queryString = httpContext.Request.Query;
StringValues someInt;
queryString.TryGetValue("someInt", out someInt);
var daRealInt = int.Parse(someInt);
Notice that unless you have multiple parameters of the same name, the StringValues type is not an issue.
in .net core if you want to access querystring in our view use it like
#Context.Request.Query["yourKey"]
if we are in location where #Context is not avilable we can inject it like
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#if (HttpContextAccessor.HttpContext.Request.Query.Keys.Contains("yourKey"))
{
<text>do something </text>
}
also for cookies
HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]
Maybe it helps.
For get query string parameter in view
View:
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#{ Context.Request.Query["uid"]}
Startup.cs ConfigureServices :
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I have a better solution for this problem,
request is a member of abstract class ControllerBase
GetSearchParams() is an extension method created in bellow helper
class.
var searchparams = await Request.GetSearchParams();
I have created a static class with few extension methods
public static class HttpRequestExtension
{
public static async Task<SearchParams> GetSearchParams(this HttpRequest request)
{
var parameters = await request.TupledParameters();
try
{
for (var i = 0; i < parameters.Count; i++)
{
if (parameters[i].Item1 == "_count" && parameters[i].Item2 == "0")
{
parameters[i] = new Tuple<string, string>("_summary", "count");
}
}
var searchCommand = SearchParams.FromUriParamList(parameters);
return searchCommand;
}
catch (FormatException formatException)
{
throw new FhirException(formatException.Message, OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Fatal, HttpStatusCode.BadRequest);
}
}
public static async Task<List<Tuple<string, string>>> TupledParameters(this HttpRequest request)
{
var list = new List<Tuple<string, string>>();
var query = request.Query;
foreach (var pair in query)
{
list.Add(new Tuple<string, string>(pair.Key, pair.Value));
}
if (!request.HasFormContentType)
{
return list;
}
var getContent = await request.ReadFormAsync();
if (getContent == null)
{
return list;
}
foreach (var key in getContent.Keys)
{
if (!getContent.TryGetValue(key, out StringValues values))
{
continue;
}
foreach (var value in values)
{
list.Add(new Tuple<string, string>(key, value));
}
}
return list;
}
}
in this way you can easily access all your search parameters. I hope this will help many developers :)
Some of the comments mention this as well, but asp net core does all this work for you.
If you have a query string that matches the name it will be available in the controller.
https://myapi/some-endpoint/123?someQueryString=YayThisWorks
[HttpPost]
[Route("some-endpoint/{someValue}")]
public IActionResult SomeEndpointMethod(int someValue, string someQueryString)
{
Debug.WriteLine(someValue);
Debug.WriteLine(someQueryString);
return Ok();
}
Ouputs:
123
YayThisWorks
Startup.cs add this service
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Your view add inject #inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
get your value
Code
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#{
var id = HttpContextAccessor.HttpContext.Request.RouteValues["id"];
if (id != null)
{
// parameter exist in your URL
}
}
In case you want to access QueryString inside of an asp.net core view you can do it like this:
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#if (Context.Request.Query.Keys.Any())
{
<button>--ClearFilters--</button>
}
we usually can fetch data from routing in 3 way:
1.query string
2.query params
3.hybrid
I describe query string:
exp:
[HttpGet("Home/routing")]
public IActionResult privacy(String name)
{
return ViewModel:name
}
to pass name as querystring:
url:port/Home/routing?name=Alex
I try to trigger a specific method (the second one) in HeroesController class:
[HttpGet]
public IEnumerable<Hero> Get()
{
return Heroes;
}
[HttpGet("/name={term}")]
public IEnumerable<Hero> Get(string term)
{
return Heroes;
}
After calling this URL:
https://localhost:44375/heroes/?name=Spider
The first method is triggered, not the second. Why is that so? How to trigger the second one which receives term parameter?
As pointed out in the comments by King King, the url is not matched, but the best way to do this is;
[HttpGet]
public IEnumerable<Hero> Get([FromQuery] string term)
{
return Heroes;
}
Then the endpoint would be hit if a query parameter, term is passed https://localhost:44375/heroes?term=Spider
There are 2 things to distinguish here - URL parameters versus query parameters. If you want to supply variable while doing you GET HTTP call these are the options:
Variable you want to pass can be part of the URL:
http://localhost:8080/yourResourceName/{varValue}
[HttpGet]
public Task<IActionResult> Get(string varValue)
{
}
Variable you want to pass can be a query parameter:
http://localhost:8080/yourResourceName?varname={varValue}
[HttpGet]
public Task<IActionResult> Get([FromQuery]string varValue)
{
}
How can I read the post form parameter values using the Request in web api? I have a controller
[Route("")]
[HttpPost]
[AuthenticationAttribute]
public void PostQuery()
{
//some code
}
I have defined AuthenticationAttribute class seperately
public class AuthenticationAttribute : Attribute, IAuthenticationFilter
{
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
// I want to read the post paramter values over here
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
return Task.Run(
() =>
{
});
}
public AuthenticationAttribute()
{
}
}
I want to check the post parameter in the AuthenticateAsync function.
I tried doing
context.Request.Content.ReadAsStringAsync().Result;
but this string is empty. I am able to read the query parameters using
context.Request.GetQueryNameValuePairs();
But could not find a way to get the post form parameters. Any help is appreciated.
var reader = new StreamReader(HttpContext.Current.Request.InputStream);
var content = reader.ReadToEnd();
var jObj = (JObject)JsonConvert.DeserializeObject(content);
foreach (JToken token in jObj.Children())
{
if (token is JProperty)
{
var prop = token as JProperty;
if (prop.Name.Equals("skipExternal") && prop.Value.ToString().Equals("True"))
{
// Logic...
}
}
}
This is the code I used. I wanted to check weather the parameter skipExternal was sent as True in post parameters.
I am not familiar with context.Request.GetQueryNameValuePairs(), but from the name, it sounds like it would extract params from the query string. And since you are doing a POST, there are no params in the query string (they are in the POST body).
Try this:
context.HttpContext.Request.Params["groupId"]
Or this:
context.Controller.ValueProvider.GetValue("groupId").AttemptedValue
The use of these will depend on how you are implementing your model and providers.
Use
context.ActionContext.ActionArguments
this will get you a Dictionary<string, object> where the key is the name of the argument and the value is the argument itself.
This assumes the action method is using model binding to bind the incoming POST values to a model.
I'm building one RESTful API using ASP.NET Core MVC and I want to use querystring parameters to specify filtering and paging on a resource that returns a collection.
In that case, I need to read the values passed in the querystring to filter and select the results to return.
I've already found out that inside the controller Get action accessing HttpContext.Request.Query returns one IQueryCollection.
The problem is that I don't know how it is used to retrieve the values. In truth, I thought the way to do was by using, for example
string page = HttpContext.Request.Query["page"]
The problem is that HttpContext.Request.Query["page"] doesn't return a string, but a StringValues.
Anyway, how does one use the IQueryCollection to actually read the querystring values?
You can use [FromQuery] to bind a particular model to the querystring:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
e.g.
[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}
You could use the ToString method on IQueryCollection which will return the desired value if a single page parameter is specified:
string page = HttpContext.Request.Query["page"].ToString();
if there are multiple values like ?page=1&page=2 then the result of the ToString call will be 1,2
But as #mike-g suggested in his answer you would better use model binding and not directly accessing the HttpContext.Request.Query object.
ASP.NET Core will automatically bind form values, route values and query strings by name. This means you can simply do this:
[HttpGet()]
public IActionResult Get(int page)
{ ... }
MVC will try to bind request data to the action parameters by name ... below is a list of the data sources in the order that model binding looks through them
Form values: These are form values that go in the HTTP request using the POST method. (including jQuery POST requests).
Route values: The set of route values provided by Routing
Query strings: The query string part of the URI.
Source: Model Binding in ASP.NET Core
FYI, you can also combine the automatic and explicit approaches:
[HttpGet()]
public IActionResult Get(int page
, [FromQuery(Name = "page-size")] int pageSize)
{ ... }
Here is a code sample I've used (with a .NET Core view):
#{
Microsoft.Extensions.Primitives.StringValues queryVal;
if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
queryVal.FirstOrDefault() == "yourValue")
{
}
}
You can just create an object like this:
public class SomeQuery
{
public string SomeParameter { get; set; }
public int? SomeParameter2 { get; set; }
}
And then in controller just make something like that:
[HttpGet]
public IActionResult FindSomething([FromQuery] SomeQuery query)
{
// Your implementation goes here..
}
Even better, you can create API model from:
[HttpGet]
public IActionResult GetSomething([FromRoute] int someId, [FromQuery] SomeQuery query)
to:
[HttpGet]
public IActionResult GetSomething(ApiModel model)
public class ApiModel
{
[FromRoute]
public int SomeId { get; set; }
[FromQuery]
public string SomeParameter { get; set; }
[FromQuery]
public int? SomeParameter2 { get; set; }
}
StringValues is an array of strings. You can get your string value by providing an index, e.g. HttpContext.Request.Query["page"][0].
IQueryCollection has a TryGetValue() on it that returns a value with the given key. So, if you had a query parameter called someInt, you could use it like so:
var queryString = httpContext.Request.Query;
StringValues someInt;
queryString.TryGetValue("someInt", out someInt);
var daRealInt = int.Parse(someInt);
Notice that unless you have multiple parameters of the same name, the StringValues type is not an issue.
in .net core if you want to access querystring in our view use it like
#Context.Request.Query["yourKey"]
if we are in location where #Context is not avilable we can inject it like
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#if (HttpContextAccessor.HttpContext.Request.Query.Keys.Contains("yourKey"))
{
<text>do something </text>
}
also for cookies
HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]
Maybe it helps.
For get query string parameter in view
View:
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#{ Context.Request.Query["uid"]}
Startup.cs ConfigureServices :
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I have a better solution for this problem,
request is a member of abstract class ControllerBase
GetSearchParams() is an extension method created in bellow helper
class.
var searchparams = await Request.GetSearchParams();
I have created a static class with few extension methods
public static class HttpRequestExtension
{
public static async Task<SearchParams> GetSearchParams(this HttpRequest request)
{
var parameters = await request.TupledParameters();
try
{
for (var i = 0; i < parameters.Count; i++)
{
if (parameters[i].Item1 == "_count" && parameters[i].Item2 == "0")
{
parameters[i] = new Tuple<string, string>("_summary", "count");
}
}
var searchCommand = SearchParams.FromUriParamList(parameters);
return searchCommand;
}
catch (FormatException formatException)
{
throw new FhirException(formatException.Message, OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Fatal, HttpStatusCode.BadRequest);
}
}
public static async Task<List<Tuple<string, string>>> TupledParameters(this HttpRequest request)
{
var list = new List<Tuple<string, string>>();
var query = request.Query;
foreach (var pair in query)
{
list.Add(new Tuple<string, string>(pair.Key, pair.Value));
}
if (!request.HasFormContentType)
{
return list;
}
var getContent = await request.ReadFormAsync();
if (getContent == null)
{
return list;
}
foreach (var key in getContent.Keys)
{
if (!getContent.TryGetValue(key, out StringValues values))
{
continue;
}
foreach (var value in values)
{
list.Add(new Tuple<string, string>(key, value));
}
}
return list;
}
}
in this way you can easily access all your search parameters. I hope this will help many developers :)
Some of the comments mention this as well, but asp net core does all this work for you.
If you have a query string that matches the name it will be available in the controller.
https://myapi/some-endpoint/123?someQueryString=YayThisWorks
[HttpPost]
[Route("some-endpoint/{someValue}")]
public IActionResult SomeEndpointMethod(int someValue, string someQueryString)
{
Debug.WriteLine(someValue);
Debug.WriteLine(someQueryString);
return Ok();
}
Ouputs:
123
YayThisWorks
Startup.cs add this service
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Your view add inject #inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
get your value
Code
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#{
var id = HttpContextAccessor.HttpContext.Request.RouteValues["id"];
if (id != null)
{
// parameter exist in your URL
}
}
In case you want to access QueryString inside of an asp.net core view you can do it like this:
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#if (Context.Request.Query.Keys.Any())
{
<button>--ClearFilters--</button>
}
we usually can fetch data from routing in 3 way:
1.query string
2.query params
3.hybrid
I describe query string:
exp:
[HttpGet("Home/routing")]
public IActionResult privacy(String name)
{
return ViewModel:name
}
to pass name as querystring:
url:port/Home/routing?name=Alex