API controller route attribute issue - c#

I have an issue with an api controller attribute routing. The API receives a get request containing a scanned barcode to the route: "api/[controller]/{userId}/{barcodeId}". Where the barcode is like: 0015A765248.
But we now have some new barcodes coming in this format: BBRT058/639.
I've found out through debugging that the extra / in the new barcode is causing the issue as the API controller is now not being accessed.
As I think it is trying to reach controller: "api/[controller]/{userId}/{barcodeId}/{barcodeID}"
Which doesn't exist. Is it possible to modify the API controller route attribute to accept the barcodeId containing the additional /?
Actually modifying the new barcode style in any way code wise is not an option I am told.
I have considered creating a new controller to accept the new barcode: "api/[controller]/{userId}/{barcodeIdpart1}/{barcodeIDpart2}" for example.
But i'm not sure if creating a new controller that is a duplicate of the current one, with the only difference being the routing is a good idea. Also both barcode formats are likely still going to be used in the future.

I don't believe you need to make any changes to your code/controller as such and that it seems to be correct. However, I would recommend you update the client to correctly URL encode the barcode before making the outbound call to your controller. This will ensure that the controller correctly parses the barcode and then processes it further. Additionally, this will also ensure that any other special non ASCII characters are correctly handled in the future.
This solution is not really changing the barcode format but is encoding it just before making the outbound HTTP call to correctly transmit it over the wire. Alternate solutions by hacking the controller will usually result in a non standard brittle solution and is not recommended.
Client calls URL
Current: api/controllername/userId/BBRT058/639
Proposed: api/controllername/userId/BBRT058%2F639
For further reading:
https://en.wikipedia.org/wiki/Percent-encoding
https://www.tutorialspoint.com/html/html_url_encoding.htm
https://www.w3schools.com/tags/ref_urlencode.ASP

I would try to replace "/" with "!" or "!!" for example (you can select any sign or combination you like) - BBRT058!!639 before sending to the controller and replace back with "/" inside of the action.
barcodeId = barcodeId.Replace("!!", "/");
if you can't modify the barcode then try this
Route[("api/[controller]/{userId}/{barcodeId}/{barcodeIdpart2?})"]
public IActionResult GetBarcode(int userId, string barcodeId, string barcodeIdpart2 = null)
{
if (!string.IsNullOrEmpty(barcodeIdpart2)) barcodeId=barcodeId + "/" + barcodeIdpart2;
....
}
It will work for both styles

Related

Routing: how do I redirect to a url when a parameter is missing?

I have routes like this:
example.com/{category}/articles.
There isn't a route for
example.com/{category}
example.com/
I want to redirect all that traffic to
example.com/{category}/articles with a default value.
I've read that I can use default values with a RouteValueDictionary:
routes.MapPageRoute("ArticlesAll", "{category}/articles/", "~/ArticlesPage.aspx", false, new RouteValueDictionary { { "category", "cats" } });
But that doesn't do any redirecting.
Would I need another route to forward to the one above or is there a more efficient way of doing this?
What you are asking is a bit unclear, but let me offer what I usually do.
If you are trying to make it so that two similar links can be written, for example www.example.com/read/penguin/article/ and www.example.com/read/panda/article. I would just write the whole string / URL with a variable in the middle:
private string destination = "penguin";
private string url = "www.example.com/read/" + destination + "/article/";
void Test () {
destination = "lion";
text.URL = url;
}
Sorry, I may have made gramatical mistakes in my code, but I hope you get the point. I may have completely misunderstood you though, so clarification would be appreciated.
You can setup these two routes:
routes.MapPageRoute("ArticlesAll", "{category}/articles/{*value}", "~/ArticlesPage.aspx");
routes.MapPageRoute("CatchAll", "{*value}", "~/ArticlesPage.aspx");
to catch anything and redirect to your desired page. I just assumed where you want to lead your users, change the aspx part as needed. Keep in mind that you can use {value} to access the whatever the user wrote.
For example if they wanted to navigate to dogs and you wanted to redirect to dogs/articles/ArticlesPage.aspx, you should use:
routes.MapPageRoute("CatchAll", "{*value}", "~/{value}/articles/ArticlesPage.aspx");
EDIT
If you want to actually redirect to the new URL and not just serve up the right page, you can use the CatchAll route to redirect to a page (say Redirect.aspx) that's sole purpose is to parse data from the RouteData object, construct the new URL and Redirect.

How to encode/decode url strings in an UWP App

I'm building a UWP App which communicates with a Web-Api. At some Point I'm sending a string in the url to the Web-Api which can be manipulated by the user. Because of that the string can include characters which could do evil things to the Web-Api.
For example:
This is my UserController
[Route("api/user/{uid}")]
public User GetUser(string uid)
{
return userRepository.GetByUid(uid);
}
For the sake of this example we assume that the user can put in the uid manually in a textbox. Now if he puts in
../vipuser
He could have access to the VipUserController. Because the ../ goes one hirachy up.
I searched a little and found this SO article which recommends the use of System.Web.UrlEncodeUnicode and System.Web.UrlDecode.
But since UWP Apps doesn't include the System.Web namespace I was wondering if there is an alternative to this methods, which I can use into a UWP-App?
Uri.EscapeDataString() and Uri.UnescapeDataString() will do the trick.
Prefer System.Net.WebUtility.UrlDecode and System.Net.WebUtility.UrlEncode over the methods on Uri.
This is because WebUtility handles space ( ) and plus (+) consistently across both "multipart/form-data" and "application/x-www-form-urlencoded" encodings.

Redirect any incoming URLs with diacritics to equivalent with no diacritics

How does one implement URL redirecting for URLs with accents? I'd like all potential URL requests with accents to be rewritten without the accent. This is for client names on a French language site. Users should be typing the name without the accent, but should they not do so then I'd like them to land on the correct page either way.
Example
User enters: www.mysite.fr/client/andré ==> user is redirected towww.mysite.fr/client/andre
The resource identifier (clientName) in the database is stored without the accent. Here's my RouteConfig.cs :
routes.MapRoute(
name: "ClientDetails",
url: "client/{clientName}",
defaults: new { controller = "Client", action = "ClientDetails" }
I understand that there are various methods for removing accents on a string. And yes, this would allow me to remove accents from the received URL parameter within the Controller method. However, I would like to be consistent, so that users always see URLs displayed without accents. Therefore, how do I implement redirecting URLs throughout my web application? Is there an easy way to do this in RouteConfig.cs or Web.config ?
I think you mean Redirect and not Rewrite given that Rewrite would mean that the URL stays the same, and you display the intended content (which I think is what you don't want).
The strategy that I think you want, can be implemented by creating a custom route constraint that matches everything that has an any special chars on it.
Make this custom route to be the first thing to be evaluated in your route table, and map this custom route to a "RedirectController" (that you will create) that takes care of removing the special chars from the URL and redirecting the user to a URL with no special chars
At the beginning of every request, you can make this check to perform a redirect. In your Global.asax.cs file, include the following...
protected void Application_BeginRequest()
{
var originalUri = HttpContext.Current.Request.Url;
var finalUri = new UriBuilder(originalUri);
finalUri.Path = RemoveAccents(
originalUri.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped)
);
// Check if the URL has changed
if (!originalUri.Equals(finalUri.Uri))
{
HttpContext.Current.Response.Redirect(finalUri.Uri.ToString(), true);
HttpContext.Current.Response.End();
}
}
You might also want to add another line for finalUri.Query and UriComponents.Query. For RemoveAccents, I tried the following code but you can use what you'd like:
public string RemoveAccents(string input)
{
return Encoding.UTF8.GetString(Encoding.GetEncoding(1251).GetBytes(input));
}

ASP.net MVC routing parameters

I have route which looks like this:
http://localhost:1936/user/someOne/##feed%233dbfc1b3-44b4-42b4-9305-4822ac151527
My routes are configured like this:
routes.MapRoute("Profile", "user/{userName}/{treningId}",
new { controller = "Profile", action = "Index", userName = UrlParameter.Optional, treningId = UrlParameter.Optional }
);
And Action in my controller like this:
public ActionResult Index(string username, string treningId)
{
//more code here
}
But I can't get this part: ##feed%233dbfc1b3-44b4-42b4-9305-4822ac151527, when I debugged code, I saw treningId was null.
My question is how can I get part of URL after ## ?
This is not possible as hashes are not included in the request; they are reserved for client-side use in URLs (typically to mark a specific location in/portion of a document).
You have two options. Either encode the hash character as %23:
%23%23feed%233dbfc1b3-44b4-42b4-9305-4822ac151527
Or use a different character/route.
You can't.
The browser doesn't send the stuff after the first # to the server at all (you can verify this by using the debugger in your browser to inspect the traffic between your browser and the server). That is because the # (hash) character carries special meaning in HTTP.
Why don't you just
use regular query parameters (so, something like http://localhost:1936/user/someOne?myparameter=feed%233dbfc1b3-44b4-42b4-9305-4822ac151527), or, alternatively,
choose another delimiter than "##".
The way you have your URL written, the browser would not submit any portion of the fragment identifier - the hash part of the URL. As such, your MVC app will never receive the value and thus will always have it as null.
To make that value available to MVC, escape the # to avoid them marking beginning of fragment portion of URL.

Safe Process.Start implementation for untrusted URL strings

My goal is to safely open a web page in a users default browser. The URL for this web page is considered "untrusted" (think of it as a link in a document opened with this software, but the document could be from anywhere and the links in it could be malicious)
I want to avoid someone passing "C:\Windows\malicious_code.exe" off as a URL
My current thought is to do something like this:
Uri url = new Uri(urlString, UriKind.Absolute);
if( url.Scheme == Uri.UriSchemeHttp || url.Scheme == Uri.UriSchemeHttps )
{
Process.Start(url.AbsoluteUri);
}
Am I forgetting about anything else that my 'urlString' might contain that makes this dangerous (e.g. a new line character which would allow someone to sneak a second process to be started in after the URL or a possible execution of a relative executable starting with http)?
I'm pretty sure both of those cases are handled by this (as I don't believe Process.Start allows you to start two processes as you would in a BATCH file and this should only allow strings starting with http: or https: and are valid urls)
Is there a better way to do this in C#?
What you want to check is the scheme of the url (i.e. ftp://, http://, file://, etc.) Here is a list of schemes: http://en.wikipedia.org/wiki/URI_scheme#Official_IANA-registered_schemes
To find the scheme of a URL, use:
Uri u = new Uri("C:\\Windows");
String scheme = (u.GetLeftPart(UriPartial.Scheme).ToString());
For me, the above example gives file://. Just check the scheme, using the code above, and reject the ones you want to filter. Also, surround the parsing with a try-catch block and if an exception is caught, reject the URL; it can't be parsed so you shouldn't trust it.
If you want to ultra-paranoid-safe, you could always parse the URL using a URL parser and reconstruct it, validating each part as you go along.

Categories