.Net core Routing URLEncoded URL not working - asp.net

I have a .Net core 2.2 WebAPI that works perfectly fine with "normal" style URLs e.g. /api/controller/action/param etc. I have a 3rd party service that does a POST to this API with a URL encoded path and the Asp.Net routing fails to route this request correctly.
The controller is at: .../api/file/uploadFile/{filename}
The POST from the 3rd party is:
".../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz".
Replacing the %2F in the path appears to work as expected:
".../api/file/uploadFile/MaintenanceReport_2019_08_05_17_11_10.html.gz"
The filename is: "MaintenanceReport_2019_08_05_17_11_10.html.gz"
Placing a Route Attribute with %2F instead of "/" sort of works, but looks very messy.
The filename passed into the path is also not resolving correctly as a parameters. I suspect this is due to the file extension being included.
I've searched the net and did not find anything related jumping out at me. Any suggestions/ideas?
[Route("api/[controller]/[action]")]
[Route("api%2F[controller]%2F[action]")]
public class FileController : Controller
{
...
}
I would have thought that the .Net core routing engine would detect the path

The default path separator in the url generated by the route is / .The issue seems that the separator before the parameter which is as part of the path value is not recognized or missing .
If you request the url like .../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz , you could try to use URL Rewriting Middleware like below :
In Configure
app.UseRewriter(new RewriteOptions()
.Add(RewriteRouteRules.ReWriteRequests)
);
2.Custom a class containing ReWriteRequests
public class RewriteRouteRules
{
public static void ReWriteRequests(RewriteContext context)
{
var request = context.HttpContext.Request;
if (request.Path.Value.Contains("%2F", StringComparison.OrdinalIgnoreCase))
{
context.HttpContext.Request.Path = context.HttpContext.Request.Path.Value.Replace("%2F", "/");
}
}
}
Reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.1&tabs=aspnetcore2x

Related

Symfony Route with Slash (/) in parameter not working

I have a Symfony Route configured with annotations where I want the last parameter to allow for slashes in it.
#[Route('/getFtp/{customerName}/{taskId}/{domainName}', name: 'get_ftp', requirements: ['domainName' => '.+'])]
public function index(string $customerName, string $taskId, string $domainName): Response
According to documentation https://symfony.com/doc/6.0/routing.html#slash-characters-in-route-parameters this should work.
It works for
http://mgr2.example.com/getFtp/quadramedia/abcdef/http:
but not for
http://mgr2.example.com/getFtp/quadramedia/abcdef/http:%2F
Using your exemple in my own project worked.
I tryied this url http://127.0.0.1:8080/getFtp/thomas/23/http:%2F
And then i dumped my param to be sure and got :
So, it is on your project that something is wrong.
I expect something like an other route is matching.
Try to define the route in yaml (or just on top of your controller) and put it on top of all the other to be completely sure that this is not working.
By the way, i tried your case in php 8.1 and Symfony 6.2
It works in Symfony 5.x versions. I would suggest take domainName as a request parameter in an argument. For example:
#[Route('/getFtp/{customerName}/{taskId}', name: 'get_ftp')]
public function index(string $customerName, string $taskId, Request $request): Response
{
$domainName = $request->query->get('domainName');
...
}

ASP.NET MVC, Is it possible to code a Response.AppendToLog in one place which will act on every Request?

I am using ASP.NET 4.7 and MVC5 with C# with IIS Express locally and published to Azure App Services.
I want to add something like:
Response.AppendToLog("XXXXX Original IP = 12.12.12.12 XXXXX");
Which adds an Original IP address to the request string in the "request" column in the web server log.
If I add this to a specific "get" Action this works fine. However I do not want to add this code to every Action. Is it possible to place it more centrally such that it gets executed on every "Get" / Request. This may be a simple question, but the answer alludes me at present
Thanks for any wisdom.
EDIT: Is this via Custom Action Filters?
if (filterContext.HttpContext.Request.HttpMethod=="GET")
{
Response.AppendToLog... //I know this will not work as Response not known.
}
You almost know the answer. Try handling OnActionExecuted that gets you the Response.
public class CustomActionFilter : ActionFilterAttribute, IActionFilter
{
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.HttpContext.Request.Method == HttpMethods.Get)
{
}
}
void IActionFilter.OnActionExecuted(ActionExecutedContext context)
{
var response = context.HttpContext.Response;
}
}
My solution to write out text:
filterContext.RequestContext.HttpContext.Response.AppendToLog("OrigIP");

Passing in a date to WebAPI - No HTTP resource was found that matches the request URI

I have a GET request that I make in Chrome Postman. It looks like the following:
http://localhost/WCAPI/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13
Can anybody see why I would get this response in Postman?
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost/WCAPI/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13'.",
"MessageDetail": "No action was found on the controller 'WCClassDesc' that matches the request."
}
My code is:
using System;
using System.Web.Http;
/// <summary>
/// API for loading WCClassDescription which is shown on the PremByClass page.
namespace WCAPI.Controllers.Lookup {
[RoutePrefix("Lookup/WCClassDesc")]
public class WCClassDescController : ApiController {
[Route("State/{State}/Class/{Class}/DescCode/{DescCode}/EffDate/{EffDate}")]
public Models.Lookup.WCClassDesc Get(string ClassState, string ClassCode, string DescCode, DateTime EffDate) {
var desc = (new Premium.BLL.WCClassDesc()).GetCurrentWCClassDesc(ClassState, ClassCode, DescCode, EffDate);
var WC = AutoMapper.Mapper.Map<Models.Lookup.WCClassDesc>(desc);
return WC;
}
}
}
Any help or direction would be greatly appreciated.
Jason
There are multiple problems with your code, let's start from the URI:
Assuming you are testing your application using the root path of your host (localhost) and following your definition of RoutePrefix and Route attributes, the correct URI for your resource is the following:
http://localhost/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13
That's because there is no WCAPI defined in your RoutePrefix attribute.
The other problem is related to the route parameter mapping, you defined you parameters as {State} and {Class}, but then you are asking for ClassState and ClassCode inside your method.
Rename those parameters to match the ones defined in your route, or else Web API will not map them to your method parameters.

ASP.net MVC 5 Route with two parameter

I want create web application with 2 parameter. Add this Code to RegisterRoutes function:
routes.MapRoute(
"pageroute",
"page/{pageid}/{pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
and add this method in pageController:
public ActionResult Index(int pageid,string pagename)
{
return View();
}
Now when i running application with this parameter
http://localhost:1196/page/4/Pagename
Application run successfully but when running with this parameter
http://localhost:1196/page/4/Pagename.html
Application return 404 error
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
while add .html in parameter return 404 error. why?
Because by default HTML files are not being served through MVC/IIS.
Your application looks for a physical file named Pagename.html and cannot find it there. Hence - 404.
To make it work, you need to setup your IIS to catch requests for files with HTML extension and pass this request to MVC.
EDIT: Here is a similar question where OP found a solution by switching "Managed Pipeline Mode" to "Classic".
Try changing the Route to:
routes.MapRoute(
"pageroute",
"page/{pageid}/{*pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
This will then match everything as in page/1/* so the .html should go via this route.
I was unable to reproduce an issue where a .html file gave a 404 using a scenario similar to the question, so there may be some other routing issue or IIS configuration causing this.

How to prevent static resources from being handled by front controller servlet which is mapped on /*

I have a servlet which acts as a front controller.
#WebServlet("/*")
However, this also handles CSS and image files. How can I prevent this?
You have 2 options:
Use a more specific URL pattern such as /app/* or *.do and then let all your page requests match this URL pattern. See also Design Patterns web based applications
The same as 1, but you want to hide the servlet mapping from the request URL; you should then put all static resources in a common folder such as /static or /resources and create a filter which checks if the request URL doesn't match it and then forward to the servlet. Here's an example which assumes that your controller servlet is a #WebServlet("/app/*") and that the filter is a #WebFilter("/*") and that all your static resources are in /resources folder.
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/resources/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + path).forward(request, response); // Goes to your controller.
}
See also How to access static resources when mapping a global front controller servlet on /*.
I know this is an old question and I guess #BalusC 's answer probably works fine. But I couldn't modify the URL for the JSF app am working on, so I simply just check for the path and return if it is to static resources:
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.contains("/resources/")) {
return;
}
This works fine for me.

Resources