This hits the corresponding method:
https://localhost:44379/annotation/getbytarget/https%3a%2f%2f
whereas this one causes 404:
https://localhost:44379/annotation/getbytarget/https%3a%2f%2fa
The only difference between the two URLs is that the latter has one extra letter (a) at the end. I am calling these URLs from the browser. But firstly, I had tried HttpClient's GetStringAsync method. No difference.
My goal is to call this URL:
https://localhost:44379/annotation/getbytarget/https://analyzer.app/analysis/60be725a980f947a351e2e97
I am encoding this URL so it becomes:
https://localhost:44379/annotation/getbytarget/https%3a%2f%2fanalyzer.app%2fanalysis%2f60be725a980f947a351e2e97
What could be the reason for this error?
This is an ASP.NET Core 3.1 Web API application and the corresponding Web API method is as follows:
[HttpGet("{id}")]
public ActionResult<List<Annotation>> GetByTarget(string id)
{
var annotations = _annotationService.GetByTarget(id);
if (annotations == null)
{
return NotFound();
}
return annotations;
}
I have solved the issue by changing the Web API method's routing signature (I am not sure if routing signature is the correct term). Notice that I have commented out the [HttpGet("{id}")] attribute:
//[HttpGet("{id}")]
public ActionResult<List<Annotation>> GetByTarget(string id)
{
var annotations = _annotationService.GetByTarget(id);
if (annotations == null)
{
return NotFound();
}
return annotations;
}
Now the method accepts calls this way (notice the id parameter):
https://localhost:44379/annotation/getbytarget?id=https%3a%2f%2fanalyzer.app%2fanalysis%2f
Related
Consider this simple controller action:
[HttpGet("{imageId}")]
[ResponseCache(Duration = 604800)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Produces("image/jpeg")]
public async Task<IActionResult> GetImageAsync(int imageId)
{
if (imageId <= 0)
{
return NotFound();
}
byte[] imageBytes = await _imageProvider.GetImageAsync(
imageId,
Request.HttpContext.RequestAborted).ConfigureAwait(false);
if (imageBytes is null)
{
return NotFound();
}
return File(imageBytes, MediaTypeNames.Image.Jpeg);
}
This method works fine, however in telemetry I am getting this for every call:
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor: Warning: No output formatter was found for content types 'image/jpeg, image/jpeg' to write the response.
Simply commenting out the ProducesAttribute prevents the telemetry from being logged.
I want to keep ProducesAttribute because it enables my Swagger UI page to work. In Swagger it shows this API has an expected output media type of image/jpeg. If I remove the attribute it changes to text/plain and it doesn't render correctly.
So the question is, how can I fix this controller action to not create a bunch of unnecessary telemetry, while also allowing Swagger UI to work correctly?
I'm using asp.net core 2.1 and I have a problem on redirect.
My URL is like:
HTTP://localhost:60695/ShowProduct/2/شال-آبی
the last parameter is in Persian.
and it throws below error:
InvalidOperationException: Invalid non-ASCII or control character in header: 0x0634
but when I change the last parameter in English like:
HTTP://localhost:60695/ShowProduct/2/scarf-blue
it works and everything is OK.
I'm using below codes for redirecting:
[HttpPost]
[Route("Login")]
public IActionResult Login(LoginViewModel login, string returnUrl)
{
if (!ModelState.IsValid)
{
ViewBag.ReturnUrl = returnUrl;
return View(login);
}
//SignIn Codes is hidden
if (Url.IsLocalUrl(returnUrl) && !string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
if (permissionService.CheckUserIsInRole(user.UserId, "Admin"))
{
return Redirect("/Admin/Dashboard");
}
ViewBag.IsSuccess = true;
return View();
}
how can I fix the problem?
General speaking, it is caused by the Redirect(returnUrl). This method will return a RedirectResult(url) and finally set the Response.Headers["Location"] as below :
Response.Headers[HeaderNames.Location] = returnUrl;
But the Headers of HTTP doesn't accept non-ASCII characters.
There're already some issues(#2678 , #4919) suggesting to encode the URL by default. But there's no such a out-of-box function yet.
A quick fix to your issue:
var host= "http://localhost:60695";
var path = "/ShowProduct/2/شال-آبی";
path=String.Join(
"/",
path.Split("/").Select(s => System.Net.WebUtility.UrlEncode(s))
);
return Redirect(host+path);
Another simpler option (works for me):
var uri = new Uri(urlStr);
return Redirect(uri.AbsoluteUri);
I use Flurl
var encoded = Flurl.Url.EncodeIllegalCharacters(url);
return base.Redirect(encoded);
This works well for absolute and relative URLs.
The option that worked for us was to use UriHelper.Encode. This method correctly works with relative and absolute URLs and also URLs containing international domain names.
In our case URLs were always absolute and redirect code looked like:
if (Uri.TryCreate(redirectUrl, UriKind.Absolute, out var uri))
{
return Redirect(UriHelper.Encode(uri));
}
You can apply URL encoding to it for storing it on response header:
string urlEncodedValue = WebUtility.UrlEncode(value);
Vice versa to decode it:
string value = WebUtility.UrlDecode(urlEncodedValue);
This first method is fine. But when I add the second method the body of the SWAGGER UI is a bunch of html gibberish. And I creating the route the wrong way?
// GET api/checklist/1288
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var model = _checkListService.Get(id);
return Ok(model);
}
// http://localhost:64783/api/checklist/GetDelinquentItems?id=1288
[Route("GetDelinquentItems")]
public async Task<IActionResult> GetDelinquentItems(int id)
{
var model = _checkListService.GetDelinquentItems(id);
return Ok(model);
}
That 'html gibberish' (indeed not the most elegant way to show an error) still contains some useful information. The first line says:
500 internal server error
and in the last three lines you can read:
Ambiguos HTTP method for action...CheckListController.GetDelinquentItems... Actions require explicit HttpMethod binding for Swagger
therefore another
[HttpGet("{id}")]
before the GetDelinquentItems() method should solve the problem.
I would like to configure one (and only one) of my Controller to accept only application/xml requests.
In the past i used IControllerConfiguration to do that like described here (Per-Controller configuration).
How can i do that in Aspnet Core ?
You can use the Consumes-Annotation together with the accepted content type on Controller or Action level.
With
[Consumes("application/xml")]
public class MyController : Controller
{
public IActionResult MyAction([FromBody] CallModel model)
{
....
}
}
calls to this controller will only succeed if the client provides Content-Type header of application/xml. Otherwise a 415 (Unsupported Media Type) will be returned.
You may simply check Request AcceptTypes / Content-Type headers (like if request.AcceptTypes.Contains("application/xml")) and stop request processing.
Accordingly to link you provided, seems like you just want to ignore content type and always return an XML result. In this case you may use a new Produces attribute.
A filter that specifies the expected System.Type the action will return and the supported response content types. The Microsoft.AspNetCore.Mvc.ProducesAttribute.ContentTypes value is used to set Microsoft.AspNetCore.Mvc.ObjectResult.ContentTypes.
Apply attribute to your controller
[Produces("application/xml")]
public YourXmlController : Controller { }
or only to specific controller action:
[Produces("application/xml")]
public Object ControllerAction()
{
return new { text = "hello world" };
}
Note, that XML formatter does not enabled by default, so you should add one using MvcOptions:
services.Configure<MvcOptions>(options =>
{
//options.InputFormatters.Add( ... );
//options.OutputFormatters.Add( ... );
});
I'm using Web API 2 (with MVC 5) to access some data from a MongoDb store. This is the action/method:
[Route("api/container/children/{parentId}")]
[HttpGet]
public HttpResponseMessage GetChildren(String parentId) {
ObjectId containerId;
if (!ObjectId.TryParse(parentId, out containerId)) {
IEnumerable<Container> containers = this.Connection.GetCollection<Container>().FindAs<Container>(Query.EQ(Container.FieldNames.ParentId, containerId));
return this.Request.CreateResponse<Container[]>(HttpStatusCode.OK, containers.ToArray());
}
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
Calling the method from jQuery with a $.get keep getting me a 404 when calling with the parameter ObjectId.Empty (which is 000000000000000000000000), so calling this Url gives me a 404:
/api/container/children/000000000000000000000000
but calling this url works fine:
/api/container/children/0000000000000000
is there some sort of limit to the length of the (id) parameter on Web API 2?
This is not a WebAPI problem.
The bug in the code is actually very simple. Remove the not (!) operator in the if condition
[Route("api/container/children/{parentId}")]
[HttpGet]
public HttpResponseMessage GetChildren(String parentId) {
ObjectId containerId;
if (ObjectId.TryParse(parentId, out containerId)) {
...
}
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}