Create Action Method Name That Matches User's Name? - asp.net

I am using mvc 5 to create user accounts , and I want the users to have profile paths like so example.com/username
is it possible to do it and how if yes ?
Thanks

You need to create a routing entry in your global.asax:
RouteTable.Routes.Add(new Route
{
Url = [username],
Defaults = new { Controller = "YourController", Action = "YourAction" }
});
Then your controller should look like this:
class YourControllerController : Controller
{
public ActionResult YourAction(string username)
{
...
}
}

Related

Getting an Actionresult Parameter in MVC4

I'm working on a simple MVC application, where I am generating below path
#Html.ActionLink(#objcity.CityName, "AgentProfiles", "Home", new {#Id=objcity.MaProvision.ProvinceName+"/"+#objcity.CityName }, null)
It makes a url like this:
http://localhost:45896/Home/AgentProfiles/Ontario/testt
In the controller I have written this method:
public ActionResult AgentProfiles(String Id)
{
//Code
}
Is it possible to get in /Ontario/testt in Id variable?
You want to get /Ontario/testt in Id(route parameter) for this you have to modify your default routes little bit or you have to make a custom route but in my opinion for your simple requirement try below answer.
Instead of
#Html.ActionLink(#objcity.CityName, "AgentProfiles", "Home", new {#Id=objcity.MaProvision.ProvinceName+"/"+#objcity.CityName }, null)
Modify Actionlink this way
#Html.ActionLink(#objcity.CityName, "AgentProfiles", "Home", new { ProvinceName=objcity.MaProvision.ProvinceName ,CityName = objcity.CityName }, null)
Controller Action :
public ActionResult AgentProfiles(string ProvinceName,string CityName ) //get ProvinceName and CityName which will be coming as querystring variables as shown here.
{......}
OR
EDIT :- Try this as per your comment.
Add one more route in RouteConfig.cs file inside AppStart folder as shown below :
routes.MapRoute(
"MvcRoutes", // Route name
"{controller}/{action}/{provincename}/{cityname}", // URL with parameters
new { controller = "Home", action = "Index", provincename = "", cityname= "" } // Parameter defaults
);
Don't forget to put this custom route above default route.
Modify ActionLink as shown below :
#Html.ActionLink(#objcity.CityName, "AgentProfiles", "Home", new { provincename = objcity.MaProvision.ProvinceName , cityname = objcity.CityName }, null)
Controller Action :
public ActionResult AgentProfiles(string provincename ,string cityname)
{......}
you can modify your routing like-
{controller}/{action}/{*catchall}
and in action method
public ActionResult AgentProfiles(string catchall)
{
// your code
}
Then you will have value /Ontario/testt in your catchall parameter which you can use in action method.

How to have a route that goes to 2 destinations

I need the ability to have routes like the following URLs.
/authorid
/documentid
/authorid/documentid
I am trying to not to do
/author/1
/document/5
author/1/document/25
How can this be done?
Clarifications.
A document and an author can have the same id. BUT the author should take precedence.
Author: {ID: "djQuery" }
Document: { Aurhor: "Bob", ID: "djQuery" }
Should be accessible via /Bob/djQuery
But if you just go to /djQuery you should get a list of djQuery's documents.
You can achieve what you want with three routes and the appropriate RouteConstraints.
First, you need to establish your Routes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Author_Document", // Route name
"{author}/{document}", // URL
new { controller = "ShowDocument", action = "AuthorDocument" }, // Parameters
new { author = new MustBeValidAuthor(), document = new MustBeValidDocument() }
routes.MapRoute(
"Author", // Route name
"{author}", // URL
new { controller = "ShowDocument", action = "Author" }, // Parameters
new { author = new MustBeValidAuthor() }
routes.MapRoute(
"Document", // Route name
"{document}", // URL
new { controller = "ShowDocument", action = "Document" }, // Parameters
new { document = new MustBeValidDocument() }
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Next, you need to create your RouteConstraints, which must verify that the information provided is valid:
using System;
using System.Web;
using System.Web.Routing;
namespace ExampleApp.Extensions
{
public class MustBeValidAuthor : IRouteConstraint
{
public MustBeValidAuthor() { }
private DbContext _db = new DbContext();
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return (_db.Authors.Where(u => u.AuthorName == values[parameterName].ToString()).Count() > 0);
}
}
public class MustBeValidDocument : IRouteConstraint
{
public MustBeValidDocument() { }
private DbContext _db = new DbContext();
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return (_db.Documents.Where(u => u.DocumentName == values[parameterName].ToString()).Count() > 0);
}
}
}
The RouteConstraints will enfoce the validity of the request, and placing the Routes in this order fulfills your requirements.
I do not think that it is possible to do this just by configuring routes.
The problem is how does the program know if the number that you send is an authorid or a documentid.
What you can do is that /1 goes to a page, on that page you do a check to see if it is a document or an author, then you do a Response.Redirect to the actual page, say /author/1.
Assuming you want
/1
/2
/1/2
I don't think you can achive that beacuse the first two urls will call the same routing rule.
You can't know when to call a method instead of another.
The only solution I can think of, is that if you can discern the ids (for example id from 1 to 10 are authorid while the others are documentId) you can write your custom rulehandler and act accordinlgy calling the right method.
Otherwise you have to put something in the url to make it unique:
"/a1" for authorid and "/d2" for DoumentId would have something like that
routes.MapRoute("", "a{authorId}", new { controller = "Home", action = "AuthorDetail" }, new { authorId = #"\d+" });
routes.MapRoute("", "d{documentId}", new { controller = "Home", action = "DocumentDetail" }, new { documentId = #"\d+" });
EDIT: after your clarification the answer from counsellorben should do what you want
You can use something like this where IsAuthorConstraint has a look up to determine if document or author. Alternatively you can route to a bridging Action and put the logic there, before passing on to document or author action.
context.MapRoute(
"authorid",
"{authorid}",
new { action = "Author", controller = "Controller",
authorid = -1 },
new { authorid = new IsAuthorConstraint() }
);
context.MapRoute(
"document",
"{documentid}",
new { action = "Document", controller = "Controller",
documentid = -1 }
);
// assume overload on author action
context.MapRoute(
"document and author",
"{authorid}/{documentid}",
new { action = "Author", controller = "Controller",
documentid = -1, authorid = -1 }
);
I'm not at a computer so may not be exactly right, but hope you get the idea.
You can only achieve this with Route constraints as #counsellorben suggested but there should be no same id for authorid and documentid.
If there is, a conflict is going to occur there.

?Length=16 being appended to my URL in my MVC3 application

Here's the controller code:
public ActionResult AddFriend(string username)
{
//Todo: Add functionality to add a friend.
//Then redirect to that same profile.
return RedirectToAction("Detail", "Profile", username);
}
Contents of username is stapia.gutierrez, not 16 or anything like that.
When I visit the link:
http://localhost:9198/profile/friend/add/stapia.gutierrez
The above action is called because I create a route in Global.asax:
routes.MapRoute("AddFriend", // Route name
"Profile/Friend/Add/{username}", // URL with parameters
new { controller = "Profile", action = "AddFriend" } // Parameter defaults
);
After clicking the URL is shown as:
http://localhost:9198/Profile/stapia.gutierrez?Length=16
Any ideas?
You need to pass the route values like so:
return RedirectToAction("Detail", "Profile", new { username="value" });

RedirectToAction usage in asp.net mvc

I want to post some questions about ASP.Net MVC. I am not familiar with web developing, But I was assigned to the web part of a project. We are doing the following: first, we create get & set properties for the person data:
public class Person
{
public int personID {get;set;}
public string personName {get;set;}
public string nric {get;set;}
}
and after login, we put the data in a class Person object and we use RedirectToAction like this:
return RedirectToAction("profile","person",new { personID = Person.personID});
It's working normally, but the parameter are shown in the URL. How can I hide them and also
can I hide the action name? Guide me the right way with some examples, please.
The parameter are shown in the URL because that is what the third parameter to RedirectToAction is - the route values.
The default route is {controller}/{action}/{id}
So this code:
return RedirectToAction("profile","person",new { personID = Person.personID});
Will produce the following URL/route:
/Person/Profile/123
If you want a cleaner route, like this (for example):
/people/123
Create a new route:
routes.MapRoute("PersonCleanRoute",
"people/{id}",
new {controller = "Person", action = "Profile"});
And your URL should be clean, like the above.
Alternatively, you may not like to use ID at all, you can use some other unique identifier - like a nickname.
So the URL could be like this:
people/rpm1984
To do that, just change your route:
routes.MapRoute("PersonCleanRoute",
"people/{nickname}",
new {controller = "Person", action = "Profile"});
And your action method:
public ActionResult Profile(string nickname)
{
}
And your RedirectToAction code:
return RedirectToAction("profile","person",new { nickname = Person.nickname});
Is that what your after?
If you don't want the parameter to be shown in the address bar you will need to persist it somewhere on the server between the redirects. A good place to achieve this is TempData. Here's an example:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
And now on the Profile action you are redirecting to fetch it from TempData:
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if (nickname == null)
{
// nickname was not found in TempData.
// this usually means that the user directly
// navigated to /person/profile without passing
// through the other action which would store
// the nickname in TempData
throw new HttpException(404);
}
return View();
}
Under the covers TempData uses Session for storage but it will be automatically evicted after the redirect, so the value could be used only once which is what you need: store, redirect, fetch.
this may be solution of problem when TempData gone after refresh the page :-
when first time you get TempData in action method set it in a ViewData & write check as below:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
now on the Profile action :
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if(nickname !=null)
ViewData["nickname"]=nickname;
if (nickname == null && ViewData["nickname"]==null)
{
throw new HttpException(404);
}
else
{
if(nickname == null)
nickname=ViewData["nickname"];
}
return View();
}
Temp data is capable of handling single subsequent request. Hence, value gone after refresh the page. To mitigate this issue, we can use Session variable also in this case. Try below:
public ActionResult Index(Person _person)
{
Session["personNickName"] = _person.nickName;
return RedirectToAction("profile", "person");
}
And in "profile" actionmethod:
public ActionResult profile()
{
Person nickName=(Person)Session["personNickName"];
if(nickName !=null)
{
//Do the logic with the nickName
}
}

ASP.NET MVC SEO URL

My goal is to have the url routing as following:
http://www.abc.com/this-is-peter-page
http://www.abc.com/this-is-john-page
What is the simplest way to achieve this without placing controller name an function name in the url above? If page above not found, I should redirect to 404 page.
Addon 1: this-is-peter-page and this-is-john-page is not static content, but is from database.
Similar to KingNestor's implementation, you can also do the followings which will ease your work:
1) Write Your Model
public class MyUser{public String UserName{get; set;}}
2) add route to global asax
routes.MapRoute(
"NameRouting",
"{name}",
new { controller = "PersonalPage", action = "Index", username="name" });
3) Roll your own custom model binder derived from IModelBinder
public class CustomBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var username = getUserNameFromDashedString(request["username"]);
MyUser user = new MyUser(username);
return user;
}
}
4) in your action:
public ActionResult Index([ModelBinder(typeof(CustomBinder))] MyUser usr)
{
ViewData["Welcome"] = "Viewing " + usr.Username;
return View();
}
I personally wouldn't suggest a route like that but if it meets your needs you need to do something like:
Have the following route in your Global.asax file:
routes.MapRoute(
"NameRouting",
"{name}",
new { controller = "PersonalPage", action = "routeByName" });
Then, in your "PersonalPageController", have the following method:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult routeByName(string name)
{
switch (name)
{
case "this-is-peter-page": return View("PeterView");
case "this-is-john-page": return View("JohnView");
case Default: return View("NotFound");
}
}
Make sure you have the appropriate views: "PeterView", "JohnView" and "NotFound" in your Views/PersonalPage/.
I don't think this can be done. AFAIK ASP.NET MVC recognizes routing parameters via the character "/".
Your format, on the other hand, goes by "{controller}-is-{id}-{action}" -- so there is no way the controller can be distinguished from the id and the action.
I think using "/" characters doesn't affect or degrade SEO; it only affects human readability and retention of the URL.
Anyway, the following URL is possible: http://www.abc.com/this-is-the-page-of/Peter by adding another route in the Global.asax RegisterRoutes method:
routes.MapRoute(
"AnotherRoute",
"this-is-the-page-of/{id}",
new { controller = "PersonalPage", action = "Details", id = "" }
);
...assuming that PersonalPageController implements a Details ActionResult method that points to the desired page.

Resources