Creating a dynamic route - c#

I am trying to create dynamic routes using ASP.Net Core and Razor Pages. Basically, I have two razor pages. One is called Pages/Home.cshtml and another is called Pages/Calendar.cshtml. Each user that logs in has their own username. So let's say I have two users in my database, Sam and Jessica and let's say Sam is logged in and goes to http://www.example.com/Sam, then it should render Pages/Home.cshtml. If Sam is logged in and goes to http://www.example.com/Sam/Calendar, then it should render Pages/Calendar.cshtml. If Jessica is logged in and she goes to http://www.example/com/Jessica, then it should render Pages/Home.cshtml.
So basically, ASP.Net Core should look at the URL and compare the username with what's in the database. If the signed in user's username matches the URL, then it should render their home page. If their username does not match the URL then it should continue down the routing pipeline. I don't need help with the database stuff or anything like that. I only need assistance on how to set up the routing.
If all this sounds confusing, then just think of Facebook. It should work exactly like Facebook. If you go to http://www.facebook.com/<your.user.name>, then it brings up your time line. If you go to http://www.facebook.com/<your.user.name>/friends, then it brings up your friends list.
I am basically trying to duplicate that same behavior that Facebook has in ASP.Net Core and Razor Pages. Can someone please provide a simple example or point me to an example? I feel like the way to do this is to use some custom middleware or a custom route attribute, but I am not sure.

You can do something like this. In the Program.cs/startup.cs modify the AddRazorPages like this.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/Index", "{user}");
options.Conventions.AddPageRoute("/Calendar", "{user}/calendar");
});
var app = builder.Build();
Now when you access a URL like https://localhost:7131/sam/calendar you will get the calendar page. You can access the user variable like this - #RouteData.Values["user"]
And on the calendar page, you can do something like this.
public class CalendarModel : PageModel
{
public void OnGet()
{
var user = RouteData.Values["user"];
//Query the calendar information from Database.
//If empty redirect the user to the home page or something.
}
}
You can find more details about this here - Razor Pages route and app conventions in ASP.NET Core

Related

Is there a way in a Razor Pages app to change the default starting route to an Area?

When you create an ASP.Net Core Web App with Individual Accounts it adds an Identity Area along with the regular Pages folder.
Since I don't want to be working between the Pages folder along with the Area folder, I want to create a Home Area that my app's default route "/" will route to.
I was able to accomplish this for the Index page by adding this to Program.cs:
builder.Services.AddRazorPages(options =>
{
options.Conventions.AddAreaPageRoute("Home", "/Index", "");
});
Obviously, this just takes care of the single Index page, but if I wanted to have an About or Privacy page, I would have to add AreaPageRoutes for them as well. I tried a couple different things with AddAreaFolderRouteModelConvention that I am too embarrassed to show here, but was ultimately unable to find out how to make it work.
Is it possible and secondly, is it bad practice, to map the default routing of Pages to a specific Area?
You can use a PageRouteModelConvention to change the attribute route for pages in an area:
public class CustomPageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
foreach (var selector in model.Selectors.ToList())
{
selector.AttributeRouteModel.Template = selector.AttributeRouteModel.Template.Replace("Home/", "");
}
}
}
Generally, my advice regarding areas in Razor Page applications is don't use them. They add additional complexity for no real gain at all. You have already found yourself fighting against the framework as soon as you introduced your own area. QED.
The only place areas serve a real purpose is within Razor class libraries, so you have to live with an area when using the Identity UI. But you don't have to use the Identity UI. You can take code inspiration from it and implement your own version in your existing Pages folder.

Asp.net core 5, using Identity, how do I change the default redirect of the [Authorize] Attribute?

The [Authorize] is wonderful for locking pages down but I am building a new product with few users and it makes no sense that it directs people to Login, because there is no one to login yet. It should direct them to Register instead.
But I am struggling to find an easy way to do that without a ton of middleware.
You can change the LoginPath on start up, but I suspect this does not answer your question because when enough users exists then what happens?
To change the login path you can add:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(cookieOptions =>
{
cookieOptions.LoginPath = "/register";
cookieOptions.AccessDeniedPath = "/account/denied";
cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(120);
});
However if you are wanting a switch when you have reached a critical mass then this will not suffice.
EDIT one approach could be something like:
Create a loginOrRegister page. Then on this page hit the database (or whatever you use to see whether you have hit critical mass or its a known user based on a cookie) and then either
Redirect to Login
OR
Rediect to register

Redirecting user to external site

I want to redirect a user to an external site, outside of my ASP.NET MVC application, through a simple anchor tag. The tricky part is, the user can enter the link himself.
up up and away!
If the user enters: www.google.com in a field (bad user), he is being redirected to http://www.example.com/page/www.google.com.
which is totally understandable, he should use http:// in front of his link...
It works as expected if I hardcode the http://in front of the link like so: up up and away!
BUT if the user was to enter http://www.google.com (good user), the browser redirects to http://http//www.google.com which goes nowhere..
So now the question: Is there a helper or method or something that routes to an external site no matter if the link contains http://or not? Something like #Url.ExternalLink(model.Url) would be great.
I could write this myself, but no need to reinvent the wheel, right? So if the wheel exists, please provide the wheel! Thanks in advance!
Checked a bunch of links, but they didn't satisfy my needs of the variable user input (never trust a user!):
How to properly encode links to external URL in MVC Razor ,
Redirect to external url from OnActionExecuting? ,
Why does Response.Redirect not redirect external URL? ,
url.Action open link in new window on ASP.NET MVC Page , ...
Your use case is quite specific, MVC framework doesn't have any extension methods for this.
You need to develop it by yourself. You have the following options:
Create extension method (as you mentioned) for UrlHelper class - #Url.ExternalLink(model.Url)
Create extension method for HtmlHelper - #Html.ExternalLinkFor(model => model.Url)
As url comes from your model you can validate/modify it before passing to View. In this case up up and away! will still be valid.
Add regex validator to a View where user types in url
You can easily extend UrlHelper with a method:
public static string ExternalLink(this UrlHelper helper, string uri)
{
if (uri.StartsWith("http://")) return uri;
return string.Format("http://{0}", uri);
}
Examples
#Url.ExternalLink("http://google.com")
#Url.ExternalLink("google.com")

Stackoverflow style URL (customising outgoing URL)

If I navigate to the following stackoverflow URL http://stackoverflow.com/questions/15532493 it is automatically appended with the title of the question like so:
http://stackoverflow.com/questions/15532493/mvc-custom-route-gives-404
That is, I can type the URL into my browser without the question title and it is appended automatically.
How would I go about achieving the same result in my application? (Note: I am aware that the question title doesn't affect the page that is rendered).
I have a controller called Users with an action method called Details. I have the following route defined:
routes.MapRoute("UserRoute",
"Users/{*domain}",
new { controller = "User", action = "Details" },
new { action = "^Details$" });
As this is an intranet application the user is authenticated against their Windows account. I want to append the domain and user name to the URL.
If I generate the URL in the view like so:
#Html.ActionLink("Model.UserName", "Details", "User", new { domain = Model.Identity.Replace("\\", "/") })
I get a URL that look like this:
Domain/Users/ACME/jsmith
However, if the user navigates to the URL Domain/Users/ by using the browsers navigation bar it matches the route and the user is taken to the user details page. I would like to append the ACME/jsmith/ onto the URL in this case.
The research I have done so far indicates I might have to implement a custom route object by deriving from RouteBase and implementing the GetRouteData and GetVirtualPath methods but I do not know where to start with this (the msdn documentaiton is very thin).
So what I would like to know is:
Is there a way of achieving this without implementing a custom route?
If not, does anyone know of any good resources to get me started implementing a custom route?
If a custom route implementation is required, how does it get at the information which presumably has to be loaded from the database? Is it OK to have a service make database calls in a route (which seems wrong to me) or can the information be passed to the route by the MVC framework?
It's actually pretty simple. Since the title is just there for SEO reasons you do not need to get to the actual question, so the Question controller (in SO case) will load the correct question based on the id (in the URL) and redirect the user with a 301 status code.
You can see this behavior with any web inspector
You could do it client-side with Javascript:
history.pushState({}, /* Title Here */, /* URL Here */ );
Only downside is not all browsers support it.

MVC 3 dynamic routing for hosted site

I'm working on an MVC 3 site hosted by GoDaddy and I need to store dynamic variables in the URL. Something like:
http://www.example.com/{Cat}/{List}/{Item}/{Action} or
http://{Cat}.example.com/{List}/{Item}/{Action}
The latter would be the best.
The site allows users to create custom lists, list categories, and list items. A list category could be something like Sports or News, a list could be NBA Teams or Politics, and a list item would be Lakers or Pres. Obama. The user is able to generate any one of the 3 (only no duplicates).
My goal is to make the URL be something like http://sports.example.com/nba/lakers and have the user routed to Controller = "Items", Action = "Details", with params Cat = "sports", List = "nba", Item = "lakers" and if the user specifies an Action (like Edit, Delete, etc), it replaces Details.
I'm not super familiar with IIS (more specifically IIS via GoDaddy), so IDK if the subdomaining would work (but that is the ultimate goal) and if it is possible, I'd like to know what I would need to do (i.e. self host + steps).
Thanks
this section is a domain http://sports.example.com/ translating to physical address e.g. 203.10.01.1 you'll have to register a subdomains with GoDaddy. ASP.NET MVC will handle ... nba/lakers section. So your domain will be http://sportworldwide.com/ with subdomains like http://nba.sportworldwide.com/lakers. If want to use MVC 3 only. try something like
sportworldwide.com/sport/nba/lakers.
routes.MapRoute("DefaultSport", "sport/{action}/{id}",
new { controller = "Sport", action = "", id= "" });
EDIT:
I can't comment too much on wildcard DNS records performance or etc. The only problem I see is you'll need to write a custom route handler, then you'll need to get the subdomain part of Url e.g. sport and change the action or id value to handle your subdomain urls.
here is example of modifying the route through a routehandler:
asp.net MvcHandler.ProcessRequest is never called

Categories

Resources