I'm converting my code to Asp.net core 3.1 in a web api project. my code is something similar to bellow:
When i call http://localhost:44307/PersonDetails I would like to get "Result1" and when i call http://localhost:44307/Person/2207 i should get "result2".
The first route works as i expected but for the second one, I get 404. it works if i call http://localhost:44307/PersonDetails/Person/2207 but it is not what i expected.
Appreciate if you could help me.
Try it like below:
[HttpGet]
[Route("~/Person/{personId}")]
public ActionResult<Person> Get([FromQuery]int personId)
{
return Ok("result2");
}
When you add ~ before it, it will ignore the route attribute on your controller.
[Route("[controller]")]
when you use a route on your controllers, all child actions will use that. so in this case, because your controller name is PersonDetails you have to enter the controller name in your URLs.
but, you can use this trick :
step1: remove this line:
[Route("[controller]")]
step2: add PersonDetails to your Get method
[Route("PersonDetails")]
Public ActionResult Get()
Related
I have a JobPosts/Index page with multiple GET parameter bindings to allow filtering: let's take CityId and IsRemote for example. I don't want these to be passed as query string parameters, instead I want to use friendly routes for them. So I have defined these:
options.Conventions.AddPageRoute("/JobPosts/Index", "cities/{cityId}/jobs");
options.Conventions.AddPageRoute("/JobPosts/Index", "remote-jobs");
options.Conventions.AddPageRoute("/JobPosts/Index", "jobs");
The routes work just fine when I type them in the browser and the CityId one is bound properly, but two things are missing.
First, there is no way to specify a default value for my IsRemote param, which I want to set to true ONLY when using the remote-jobs URL.
And second, when trying to generate a URL like this:
<a asp-area="" asp-page="/JobPosts/Index" asp-route-cityId="#Model.CityId"></a>
I get the following URL:
https://localhost:44391/jobs?cityId=2265885
When what I actually expect is:
https://localhost:44391/cities/2265885/jobs
So it looks like the tag helper or the part responsible for constructing the URL doesn't look at all at the different routes to try and get a best match based on the list of parameters. Actually, it will always use the last page route defined for that page.
Nor do I have the option anywhere to specify a route name for the page route and then use asp-route to explicitly say which route I want.
Any ideas how to achieve that? Or if it's something that's on the roadmap for Razor Pages?
EDIT: Hardcoding the href is not an option. I want this to go through the proper routing services as there are other things to be done as well, like generating culture-specific URL for non-english users (eg. {cultureId}/cities/{cityId}/jobs - this is done through route conventions. Hardcoding the href would obviously bypass that.
There is a easy way to set IsRemote default value.
public bool IsRemote { get; set; } = true;
This tag asp-page will link to Page /JobPosts/Index.csthml directly,
https://localhost:44391/JobPosts?cityId=2265885
= https://localhost:44391/JobPosts/Index?cityId=2265885
If you are looking forward the URL https://localhost:44391/jobs?cityId=2265885
you could try this a tag to request.
Go to JobPosts
———————————————————————————————
Using a middleware to handle /remote-jobs
app.Run(next => async context =>
{
if (context.Request.Path == "/remote-jobs")
{
return View with default IsRemote
}
});
I would like to create friendly routes that map to different query string values of a single Razor Page and it's base GET handler. I'd be fine with switching the query string to being a part of the route as well. The idea is we have a single page that loads a file list and can filter. I'd prefer it if the URL was more straight forward. If it's not possible I could just go with /Files/In or /Files/Out
Example
/Files?direction=In -> /In
/Files?direction=Out -> /Out
Is there any way to do something like this?
You can use route data parameters which are defined in a Route Template as part of the #page directive in the .cshtml file :
#page "{direction?}"
Then you can access the route parameter value in OnGet method of your file page :
public void OnGet(string direction)
{
if (!string.IsNullOrEmpty(direction))
{
//filter files based on direction
}
}
You can pass direction value as /Files/In or /Files/Out , without filter directly use /Files .
I have in the controller folder like this:
-Controller(Main Folder)
-HomeController(Main Controller)
-HomeBasic1Controller
-HomeBasic2Controller
-HomeBasic3Controller
-HomeBasic4Controller
When I execute the program, first it´s going to HomeController, until here everything is correct, then in HomeController I can call to any controller, I can go to HomeBasic1Controller or to any other HomeBasicXController.
The problem is in the URL, it´s showing like this
http://localhost:XXXXX/HomeBasic1
but I want to be like this
http://localhost:XXXXX/Home
no matter from which controller is calling!
The easy way to do this is to put all your actions on the Basic1,2,3, and 4 controllers all on HomeController. This is the generally accepted convention. If you can't do that, then what you want is "custom routing". The straightforward way to start this approach is to add a route for each action in Basic1 with each specific URL. A single route might look something like this:
routes.MapRoute(
"Basic1SomeAction",
"home/someaction",
new { controller = "HomeBasic1", action = "SomeAction" }
);
Microsoft has a good tutorial for getting your first ASP.NET Web API project going:
http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
...but what's unclear to me -- how is the mapping between the API URIs and my C# controller methods defined?
for ex:
/api/products/{id}
resolves to
public IHttpActionResult GetProduct(int id)
{
[...]
}
...but im not sure how. automagic?
I ask because I want to create a new mapping for this URI:
/api/setReportNotificationsAsRead?uid={username}&items={itemIDs}
to this new method in my controller:
public IHttpActionResult SetReportNotificationsAsRead(string username, string itemIDs)
{
[...]
}
...but im not sure how. automagic?
The Automagic lies with HTTP Verbs in Web API. The route /api/products/{id} can map to anything that starts with GET (or just method name Get) if you make a GET request for the WebAPI.
If you make a POST request then it will map to any POST method (or else is you use route prefix).
This link can help you understand the magic. That can also help you understanding how you can configure SetReportNotificationsAsRead function to be called.
You're very close to having a working solution. You have your method parameter names mixed up:
public IHttpActionResult SetReportNotificationsAsRead(string uid, string items)
{
//Do your stuff!
}
The name of the HTTP GET parameter should match the name of the method parameter. This is part of the ASP.NET MVC naming convention.
One final note, if you are actually expecting a group of items (i.e. multiple item ids) you can actually save yourself some work and use a string[] parameter so long as your HTTP parameters are sent correctly. In this case you would want the URI to look like: /api/setReportNotificationsAsRead?items=123&items=456&items=789. Notice how the parameter name is repeated multiple times, but with different values.
For more information about the routing system I would suggest heading over to the ASP.NET MVC routing overview.
Drupal has a function called "drupal_is_front_page". Does YII have something similar to deal with navigation in this way?
Unfortunately not. And while the information needed to piece this together is available, doing so is really more pain than it should be.
To begin with, the front page is defined by the CWebApplication::defaultController property, which can be configured as discussed in the definitive guide. But there's a big issue here: defaultController can in reality be any of the following:
a bare controller name, e.g. site
a module/controller pair, e.g. module/site
a controller/action pair, e.g. site/index
a module/controller/action tuple, e.g. module/site/index
If you have specified the defaultController as #4 (which is the same as #3 if your application does not include any modules) then everything is easy:
function is_home_page() {
$app = Yii::app();
return $app->controller->route == $app->defaultController;
}
The problem is that if defaultController is specified as #1 or #2 then you have to examine a lot of the runtime information to convert it to form #3 or #4 (as appropriate) so that you can then run the equality check.
Yii of course already includes code that can do this: the CWebApplication::createController method, which can accept any of the valid formats for defaultController and resolve that to a controller/action pair (where controller is dependent on the module, if applicable). But looking at the source doesn't make you smile in anticipation.
To sum it up: you can either assume that defaultController will always be fully specified and get the job done with one line of code, or borrow code from createController to determine exactly what defaultController points to (and then use the one line of code to check for equality).
I do not recommend looking into solutions based on URLs because the whole point of routes is that different URLs can point to the same content -- if you go that way, can never be sure that you have the correct result.
In my experience, there is no such function in Yii. However, you can retrieve the followings:
base url: Yii::app()->request->baseUrl
current URL : Yii::app()->request->requestUri.
current page controller with Yii::app()->getController()->getAction()->controller->id .
With these APIs, it should be possible to find out whether the current page is front page.
another simple idea:
in your action (that one you use to present your 'main front page'), you could set up a variable using a script in its view:
Yii::app()->getClientScript()->registerScript("main_screen",
"var main_front_page = true;",CClientScript::POS_BEGIN);
put that code in the "main view", (the rest view pages dont have this piece of code).
so when you need to check if a page is the "main page" you could check for it using javascript, quering for:
if(main_front_page){..do something..}.
if you need to recognize the main page in php (in server side), use the method proposed by Jon.
another solution, based on a common method for your controller:
Your controllers all of them must extend from CController, but, when you build a new fresh yii application Gii creates a base Controller on /protected/components/Controller.php so all your controllers derives from it.
So, put a main attribute on it, named:
<?php
class Controller extends CController {
public $is_main_front_page;
public function setMainFrontPage(){ $this->is_main_front_page = true; }
public function getIsMainFrontPage(){ returns $this->is_main_front_page==true; }
}
?>
well, when you render your main front page action, set up this core varible to true:
<?php
class YoursController extends Controller {
public function actionPrimaryPage(){
$this->setMainFrontPage();
$this->render('primarypage');
}
public function actionSecondaryPage(){
$this->render('secondarypage');
}
}
next, in any view, you could check for it:
<?php // views/yours/primaryview.php
echo "<h1>Main Page</h1>";
echo "is primary ? ".$this->getIsMainFrontPage(); // must say: "is primary ? true"
?>
<?php // views/yours/secondaryview.php
echo "<h1>Secondary Page</h1>";
echo "is primary ? ".$this->getIsMainFrontPage(); // must say: "is primary ? false"
?>