Exclude controller from route with string param .NET core - asp.net-core

I want to have an endpoint that looks like: localhost:5000/abc123
This is basically to replicate the functionality of tinyurl.
Controller
[HttpGet("/{myString}")]
public async Task<IActionResult> Get(string myString)
{}
This works but all files now come through this contoller eg: localhost:5000/runtime.js etc
Is this possible to do only for certain strings?

Use Route constraint to filter values for myString
For example, if a file name is a string containing a dot . is a valid suggestion in your case, you can use the following regex to accept alphanumeric strings
[HttpGet("/{myString::regex(^\\w+$)}")]

Related

How to I write ModelBinder that access all fields by prefix?

For example, I like my ModelBinder to transform all "field_???" values to my single custom object.
How I could do that?
ValueProvider.GetValue only allows me to access by exact name, and I can't enumerate all possible fields...
Try this:
public IActionResult OnPost([Bind(Prefix = "field_")] Whatever model)
Read the article https://learn.microsoft.com/ru-ru/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0

Retreive WCF query parameters as a single string

I need to define a WCF GET method which can retrieve all the query parameters as a single string. Example:
https://xxx.xxx.xxx.xxx/token?client_id=abc_def&client_name=&type=auth&code=xyz
I want to grab the string "client_id=abc_def&client_name=&type=auth&code=xyz".
How do I define the URI template for the method? I tried the following, but it doesn't work as I will get 400 Bad Request. Replacing the /" with "?" makes no difference.
[WebGet(UriTemplate = "token/{Params}")]
[OperationContract]
Stream GetToken(string Params);
The method will call an external service and just forward whatever query parameters that it receives. I don't want individually retrieve each parameters, as it is possible that the parameters may increase.
Another URL would be like this:
https://xxx.xxx.xxx.xxx/person/123456?client_id=abc_def&client_name=&type=auth&code=xyz
In this case, I would like to grab the two strings "123456" and "client_id=abc_def&client_name=&type=auth&code=xyz".
How do I define the URI template for the method?
You can set the expected query string parameters in UriTemplate, like this:
(UriTemplate = "token/{Params}&client_id={clientId}&client_name={clientName}&type={type}&code={code})
And the method can be declared like this:
Stream GetToken(string Params, string clientId, string clienteName, string type, string code);
You could omit the URI template and use the NameValueCollection from
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters
Then just make a 'ToString()' call and you will get what you want
String fullQueryParams = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters.ToString()
If you need the path as well, for example to retrieve the person and 123456 strings in the url:
https://xxx.xxx.xxx.xxx/person/123456?client_id=abc_def&client_name=&type=auth&code=xyz
you could use WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RelativePathSegments. Then your OperationContract implementation will be something like this:
String fullQueryParams = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters.ToString();
//fullQueryParams = "client_id=abc_def&client_name=&type=auth&code=xyz"
var pathsCollection = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RelativePathSegments;
//pathsCollection = ["person","12345"]

Howto select a ASP.NET Core action from a JSON property in the body?

I have a REST interface endpoint like
POST /items/12345/actions
I utilize a generic actions sub collection to be apply to apply changes to 12345 which are not easily mapped to the content or direct other sub collections of it.
My question is the following: Since there could be multiple different action types I identify the action by a JSON property of the content of an uploaded document.
How do I select a action by a part of the JSON body of the request. Is there something possible like...
[Route("api/v1/items")
public class ItemsController : Controller
{
[HttpPost("{id}/actions")]
[CheckJsonBody("type", "ActionA")]
public ActionResult DoActionA(int id, ActionA a)
{
// do something
}
[HttpPost("{id}/actions")]
[CheckJsonBody("type", "ActionB")]
public ActionResult DoActionB(int id, ActionB b)
{
// do something
}
}
The request would look like ...
{
"type": "ActionA",
"abc": "xyz"
}
I have digged myself up into the code till Microsoft.AspNetCore.Mvc.ActionConstraints.ActionMethodSelectorAttribute (GitHub).
However starting from there, I am a bit lost to reach a high-performance solution. Do I need to decode the body or is that something which is already done at that time the constraint is evaluated?
ps: And yes, I know I could handle them in one action and do a switch on the "type" property.
An ASP.NET team member was so friendly to direct me to an answer: In the ActionMethodSelectorAttribute you can read the body into a memory stream, read till the property for the selection filter. Then you seek the memory stream to zero and replace it in the request (for later model binding). You can cache the criteria value in HttpContext.Items to speed it up if you use the same property for multiple actions.

Web API 2 Routing based on Parameter's Value

Is it possible to setup Web Api 2 route based on a parameter's value in the query string.
I have the following requirement:
/api/controller?data=param.data1
should go to controller's action 1
/api/controller?data=param.data2
should go to controller's action 2
any other value of data must go to action 3.
I know there's an option to set a constraint with a regex, but the examples I've found are for generic scenarios and not as specific as mine.
This is what I've tried
config.Routes.MapHttpRoute(
name: "test",
routeTemplate: "api/Hub/{data2}",
defaults: new { action = "Test" },
constraints: new { data2 = #"^(param\.data2)$" }
);
Is there a way to do it? Maybe there's a better way?
Important to note, I cannot change the URI of the service. It must have ?data=[value]
This is a fallback for a legacy system :(
You can use Attribute Routing, new in Web API 2.
Let's say you have the following actions, where the data param is, let's say, a string:
public Stuff GetStuffForData1(string data) { ... }
public Stuff GetStuffForData2(string data) { ... }
public Stuff GetStuffForData(string data) { ... }
Since you mentioned regex, you can specify route constraints for each of the above actions using a regex like the one you mentioned in your question1, for example:
[Route("controller/{data:regex(#"^(param\.data1)$")]
public Stuff GetStuffForData1(string data) { ... }
[Route("controller/{data:regex(#"^(param\.data2)$")]
public Stuff GetStuffForData2(string data) { ... }
// No need for a route constraint for other data params.
public Stuff GetStuffForData(string data) { ... }
The general syntax is {parameterName:constraint(params)} (params is optional and is not used for all constraints). In the above example, the first route will only be selected if the data segment of the URI matches the data1 regex. Similarly, the second route will be selected if the data segment of the URI matches the data2 regex. Otherwise, the last route will be chosen.
In general, the total ordering is determined as follows:
Compare the RouteOrder property of the route attribute. Lower values are evaluated first. The default order value is zero.
Look at each URI segment in the route template. For each segment, order as follows:
Literal segments.
Route parameters with constraints.
Route parameters without constraints.
Wildcard parameter segments with constraints.
Wildcard parameter segments without constraints.
In the case of a tie, routes are ordered by a case-insensitive ordinal string comparison (OrdinalIgnoreCase) of the route template.
You can even create your own custom route constraints by implementing the IHttpRouteConstraint interface and registering it in the Register method of your WebApiConfig class, assuming you're hosting on IIS, or in the Configuration method of your Startup class if self-hosting using OWIN.
Note I haven't personally tried any of the above, but it should all work; at the very least it should give you some ideas. For more details, including very nice examples, you should start by taking a look at the following article (which I shamelessly used extensively in my answer):
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#constraints
1 I'm really not an expert on writing regexes, so unfortunately I can't advise you on the specific ones you'll need.

Different action method depending on parameter value?

I have two urls like this,
/products/home?subcat=abc
/products/home?subcat=xyz
I would like to have two action methods in products controller - homeabc, and homexyz.
How can I construct the route so it goes to the correct action method, depending on the value of the 'subcat' parameter?
PS: I don't have the freedom to change the url format, it has to stay the same.
Thanks.
Since you cannot change the URL formats and you only have one or two, the easiest way would be to do some type of switch in the Home/Index method
public ActionResult Index(string subcat){
switch(subcat.ToLower())[
case "abc":
return RedirectToAction("abc");
case "xyz":
return RedirectToAction("xyz");
default:
return RedirectToAction("UnknownCategory", "Errors");
}
}
Unfortunately, the routing engine does not allow you to route based on query string parameters (?). The only other possibility would be a url rewrite.