Within a controller called AccountController, I have a method MeetingLog() that gathers the info I need and it stores it within a ViewModel. I then take that ViewModel called meetingInfo and try to pass it into the view/razor page using "return View(meetingInfo)". Normally, to access the ViewModel I would have gone right into a Views folder and insert "#model ITMatching.ViewModels.MeetingLogViewModel" at the top of MeetingLog.cshtml file. Unfortunately, this razor page is located within the "identity pages" and requires a bit more work to access the ViewModel.
The problem with this specific directory "Areas/Identity/Pages/Account/Manage/MeetingLog.cshtml" is that makes using the anchor tag helper attribute (asp-controller) hard to use in the _ManageNav.cshtml file.
Image of the identity directory the view is located in
The example I'm working with:
code of where asp-controller is used
asp-controller could have been accessed using asp-controller="Manage/Account" but it always converts the '/' into "%2F" making the page inaccessible. And only using asp-controller="Account" ignores looking into the "Areas/Identity/..." directory when that's what I need it to do.
To pass a ViewModel into view within Identity pages or between two requests, you could use Sessions or TempData(backed by session state. After enabling the session middleware, you could store the object (need to add the session extension or TempData extension) using session and TempData, then in the Razor Page OnGet method, you could get value from the session and TempData and assign it to the View Model.
More detail information, check the following links:
Sending objects(And Child Objects) from a Razor page to another
Session and state management in ASP.NET Core
asp-controller could have been accessed using
asp-controller="Manage/Account" but it always converts the '/' into
"%2F" making the page inaccessible. And only using
asp-controller="Account" ignores looking into the "Areas/Identity/..."
directory when that's what I need it to do.
For the Areas, if the folder structure using MVC folder structure(contains Controllers and Views), then, in the View page, you could use asp-area, asp-controller and asp-action attribute to generate the link:
<a asp-area="" asp-controller="Home" asp-action="About">/Home/About </a>
For the Razor page folder structure, you could use asp-areas and asp-page attribute add the hyperlink:
<a asp-area="Products" asp-page="/About"> Products/About </a>
Besides, you could also directly use the href attribute:
<a class="nav-link" href="/Identity/Account/Manage/Index">View Meeting Logs</a>
More detail information about areas, see Areas in ASP.NET Core
[Note] For the protected pages, it required the user to login first, so, it will redirect the Login page. For example: https://localhost:44310/Identity/Account/Login?ReturnUrl=%2FIdentity%2FAccount%2FManage%2FIndex. After login success, it will redirect to the Manage/Index page.
Related
I am new to Razor Pages. I have just one page, I have Index.cshtml and Index.cshtml.cs with
public class IndexModel : PageModel
There is also _Layout.cshtml.
I need to get username from HttpContext Header. and show username in _Layout.cshtml (there is navigation bar).
But I do not get where is the best place to put this code in Razor Pages?
I cannot put it into Index.cshtml.cs OnGet, because I need in Layout, at least I think so.
This is outside this question, but FYI I use Azure Easy Auth and from documentation (and also other non Razor Pages projects) I see that HttpContext.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"] would contain Name I need.
You can access the current HttpContext inside of a Razor Page using the Context property:
<p>#Context.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"]</p>
This approach is documented in Use HttpContext from a Razor view.
#Context is not available in razor page in .NET 6
But you can use #Request.HttpContext
I'm trying to achieve overriding of existing 'Theme' pages, located in 'Pages/Theme', by placing another page with the same name in the 'Pages/Overrides' folder.
I have done so by creating a PageRouteModelConvention named ThemeTemplatePageRouteModelConvention. Any pages in the 'Pages/Overrides' folder will be reachable without the '/Overrides/' route prefix and have priority over the similarly named view in the 'Pages/Theme' folder.
See my example repository here: https://github.com/bryandh/razor-page-override
In the current setup, we have three pages in Pages/Theme:
Index
About
Contact
And two pages in Pages/Overrides:
Index
About
The behaviour that I would like to have with these pages:
Index page with / route used from Pages/Overrides
About page with /about route used from Pages/Overrides
Contact page with /contact route used from Pages/Theme
This works as I want it to work.
However, the anchor tags created in the Pages/Theme/Components/_Header partial to a non-overriden page in Pages/Theme using the anchor tag helper does not create the correct route.
See the root/index page where the _Header component is included. The About page link is generated correctly as the About page is also in the same folder. However, the Contact page link does not seem to be generated properly. This link to the Contact page only works when you're on the Contact page itself, as that is situated in Pages/Theme.
Generation of the anchor tag doesn't seem to take the locations views can be situatied in into account.
Because the link is in a component that I do not want to override, I can't modify the asp-page attribute to fix the problem.
How can I let the Header component generate a link to the Contact Theme page from the overriding Index page?
[UPDATE]
To clarify further, see the page override structure below.
The asp-page tag helper can't find the Contact page to create a route for.
Note: the Contact page is reachable by manually navigating to /contact.
I have just begun working on the registration/login/logout functionality of a new web app using Asp.Net Core 2.2.
I have scaffolded out the Identity pages, just easier for me. I'm not a fan of this new methodology.
My page code generates the link for the register page like so
<div class="text-right reg-button">
<a asp-area="Identity" asp-page="/Account/Register" class="submit">Register</a>
</div>
this generates the link
<div class="text-right reg-button">
<a class="submit" href="/Identity/Account/Register">Register</a>
</div>
clicking on that link produces a error
NullReferenceException: Object reference not set to an instance of an object.
The link looked right so I suspected there is something wrong with the layout its trying to use since this is also part of the error detail.
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_Shared__Layout_Industry.b__14_0() in _Layout-Industry.cshtml
+
var controllerName = this.ViewContext.RouteData.Values["controller"].ToString();
so I set the layout to null directly in the Register page and the page rendered in its basic form.
So the question becomes two fold;
Why does the layout I've set in the Identity sections ViewStart file (The layout I also have set in the Views/Shared folder) fail with all the Identity pages, but work perfectly fine in any other page not under the Areas folder?
Even If I set the layout full path directly in the file, it still fails with the same error. The layouts file name is _Layout-Industry but I noticed in the error detail it shows it as _Layout_Industry, is that hyphen causing an issue?
Here is the site when first opened
If you click on the Register/Link button in top right corner it should take you to the Register page but it fails
The register page is the default register page that comes in the default web application, the Layout page is my own, and it works on all 14 other pages that are NOT under the Identity area, and are in the standard Views subfolders
UPDATE:
I have a view component that loads the meta tag section to the page. Here is the code
#{
var controllerName = this.ViewContext.RouteData.Values["controller"]?.ToString();
var actionName = this.ViewContext.RouteData.Values["action"]?.ToString();
var userid = UserManager.GetUserId(User);
}
<!--Meta Tags- Using MetatagViewComponent-->
#if (controllerName != null && actionName != null)
{
#await Component.InvokeAsync("Metatag", new MetatagViewComponent.MetatagRequest { Controller = controllerName, Action = actionName })
}
The controller and action calls were failing because there are no controllers in the Identity pages. I made them nullable and bypass them and the register page now loads. Is there a way to get the view name from the identity pages, I can then retrieve the metatags as I do for all other pages.
It's using your layout. The problem is that your layout literally throws an exception. Now, the reason it throws an exception when used by a Razor Page vs a traditional MVC view is that with Razor Pages, there's no controller, and therefore ViewContext.RouteData.Values["controller"] is null. Trying to call ToString() off that results in your NullReferenceException.
With Razor Pages, neither "action" nor "controller" will be in your RouteData, since neither of those concepts apply. Instead, you'll have "page" and "handler". If you want to use this same layout with both Razor Pages and MVC views, then you'll need to adjust the logic around what you're doing with the controller name to accommodate Razor Pages as well.
I am confused on how to call or create server/controller methods in razor pages. When I do MVC, I would create methods in the controller and would use an anchor tag to call it like this:
<a href="/Security/LogOut/">
How do I do this in razor pages? I ended up creating a new page name "SignOut" and implemented the login inside the OnGet and used an anchor tag like this:
<a href="/SignOut">
What if I have more than one action method I want to group in a file? Do I need to create a page for every action?
You've probably long since found the answer you were looking for. For others that see this question, you can use:
<a asp-page="/SignOut">Sign Out</a>
In the case of Razor Pages, the GET and POST methods are handled by each code-behind file. For instance, for the Razor Page Details.cshtml, there is a code-behind file called Details.cshtml.cs that defines OnPostAsync and OnGetAsync which handle POST and GET requests respectively. For more information, see:
Microsoft Razor Pages Tutorial
I've read some previous questions here and on other sites, but being new to ASP.net and MVC I'm having a bit of trouble understanding the information presented.
I want/need/was told to get the current URL of the page I'm on through the View layer, and use that information to apply an id to a li tag allowing for specific css. We've moved our left navigation bar from being embedded in every single page (done by a previous co-op) to putting the list in a partial view that I'm going to call on all of the required pages. Styling requirements for the site have a specific highlight on the left navigation a tag of the page the user is currently on.
Some of the examples I've read including using:
<%= Request.Url.PathAndQuery %>
Request.Url.ToString() or Request.Url.AbsoluteUri
var request = HttpContext.Current.Request
but I know not all of them can be used in the View layer. What would be the best approach? Are there any tutorials that I haven't been able to find yet that anyone could recommend?
It probably isn't the best idea, in my opinion, to use the URL for this.
Instead, a quick and easy way to achieve this is to use ViewContext.RouteData that will contain values for both the controller and action of the current request. It can be accessed from the view layer easily.
ViewContext.RouteData.Values["Controller"].ToString()
ViewContext.RouteData.Values["Action"].ToString()
So in your view you could do something like
<ul class="nav">
<li class="#(ViewContext.RouteData.Values["Controller"].ToString() == "ControllerName" ? "active" : "")">Foo</li>
</ul>
You could push it further to make it prettier, but you get the basic idea.
I was looking for a solution on this for asp.net 3.0 and found the following to give direct access to the URL path (what page you're currently loading/showing):
ViewContext.HttpContext.Request.Path
I'm using this in an if statement to decide dynamically between different View Imports, works very well.