I am building a blog engine using MVC 3 and razor. In this scenario, I have given options like a user can have multiple blogs (similar to blogger.com)
Now say a user 'yasser' has the following 3 blogs
TechStory
GameGeek
MeMyStory
so I want all other users to access these blogs by the following urls
www.domainName.com/blogs/TechStory
www.domainName.com/blogs/GameGeek
www.domainName.com/blogs/MeMyStory
And more blogs can be added hence more such url will be acessed in future.
I know that something needs to be done with Routing, but being new to MVC dont seems to get it. Please can some one guide me on this.
Add this route on top of your Default one:
routes.MapRoute(
"Blog",
"Blogs/{blogName}",
new { controller = "Blogs", action = "Index" }
);
Your controller will look like this:
public class BlogsController : Controller
{
public ActionResult Index(string blogName)
{
BlogModel model = // find blog by blog name
return View(model);
}
}
Also, one suggestion: Keep your controller names in singular mode: BlogController instead of BlogsController. Change URL and Routing accordingly if you decide to do so.
Related
My ecommerce application stores URL's for item pages in the database. There are thousands of these URL's, which are all root level (i.e. domain-name.com/{item-page-url}).
If I add all of these URL's to the route table by using a simple for loop to call RouteCollection.MapRoute for each URL site performance degrades exponentially. Why? The reason for this is here.
How should I properly handle this situation? Adding all of the routes to the route table doesn't seem right (not to mention the performance pretty much confirms that). I've seen a few ideas about inspecting all incoming URL's and then trying to match that to the URL's in the database but don't fully understand how I'd implement that, nor am I sure if it's the best approach.
Any ideas or suggestions? This seems like it would be not so uncommon, but I haven't found a concrete way to handle it.
If you can change your route to
mycreativeshop.com/product/my-product-name then adding following route to the top of your route config file can help you.
routes.MapRoute(
"CustomRouteProduct",
"product/{id}",
new { controller = "yourcontrollername", action = "Index" }
);
and in the action map the parameter value with name of your product name
public ActionResult Index(string id)
{
//var prdName = id.Replace("-", " ");
//look up prdName in database
return View();
}
Update
Added following as a top route
routes.MapRoute(
"CustomRouteProductZX",
"{id}",
new { controller = "Content", action = "Index" }
);
and by accessing http://localhost:12025/Car-Paint I was directed to Index action of ContentController where I accessed "Car-Paint" in parameter id
But, above having above blocks patterns like http://localhost:12025/Home/ (here Home is also treated as a product)
I'm putting together a simple enough brochure site and decided to use MVC3 as a learning opportunity. Content of certain sections of the website will be stored in a DB and can be updated by an admin via a simple GUI. I decided not to use a prebuilt CMS again to learn how to do database operations in this language which is new to me.
I want a very simple URL structure:
foo.com (home)
foo.com/bio
foo.com/news
foo.com/about
foo.com/events
etc
The straightforward way to achieve that is to have a controller for each page, and use the Index() ActionResult of each controller.
Is it OK / best practice to have a controller for each of these pages of the site? News and Events won't have subpages, but might have paging, with the URL looking something like
foo.com/news/
foo.com/news/page2
foo.com/news/page3
foo.com/news/page4
If I had a single controller, and used multiple actions, the URLs by default look like
foo.com (home)
foo.com/home/bio
foo.com/home/news
foo.com/home/about
foo.com/home/events
Which would then have me updating the routing to achieve what I want.
With respect to the use of controllers, I think the best practice is to have a particular controller for a domain of action or domain of content, not by the hierarchy of your main menu.
For example:
Your main page:
foo.com
Controller -> Home
Method -> Index
Parameter -> null
foo.com/news/2
Controller -> news
Method -> Index
Parameter -> 2
But Home and News are two different "equal" controllers, it just happens that the first controller the user interacts with is the Home controller.
In the case you want to use a single controller, you might try,
routes.MapRoute(
name: "Default",
url: "{action}/{page}",
defaults: new { controller = "Home", action = "Index", page = UrlParameter.Optional },
constraints: new { page = new PagingConstraint() }
);
as route defination. And to only allow paging for "news" and "events", use a custom route constraint as,
public class PagingConstraint : IRouteConstraint
{
private static readonly string[] PagingEnabledActions = new string[] { "news", "events" };
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return string.IsNullOrEmpty(values[parameterName].ToString()) || new Regex(#"^[Pp][Aa][Gg][Ee][0-9]+$", RegexOptions.Compiled).IsMatch(values[parameterName].ToString())
&& PagingEnabledActions.Contains(values["action"].ToString().ToLower());
}
}
Hope this helps.
I am making a Blogging Engine using ASP.NET MVC3,
I have my database design in place, I was wondering on how to handle URL of each post in mvc3 ?
Say for example, a user write two post with titles like
My first post
My second post
So now, I can insert these titles and content of these post into my database.
What I dont know is how to show these post with url like ...
www.example.com/2012/06/my-first-post
www.example.com/2012/07/my-second-post
I am not sure if this is very easy in MVC or not, please can someone guide me on this.
Yasser,
this will get you started:
Global.asax replace default route with:
routes.MapRoute(
"Default", // Route name
"{year}/{month}", // URL with parameters
new { controller = "Posts", action = "PostGroup" }
);
Your action method in your Posts controller will look something like:
public ActionResult PostGroup(int year, int month)
{
var viewModel = _serviceTasks.All<Post>()
.Where(x => x.PostDate.Year == year
&& x.PostDate.Month == month);
return View("Index", viewModel);
}
This should get you > 50% into the guts of your solution, the remainder being your own hard toil :-0.
I'm migrating an ASP.NET web forms application to ASP.NET MVC 3. I kind of understand routing, but I sort of don't. In my application, I have created three .cshtml files in the directory located at /internal/products/find/. For the sake of demonstration, those .cshtml files are named "view1.cshtml", "view2.cshtml", and "view3.cshtml".
I have a controller named "InternalController". My goal is to use InternalController for all of the locations inside the /internal path. I'm not sure if what I'm trying to do is allowed. I assume it is. Either way, at this time, I have the following in InternalController:
public ActionResult View1()
{
return View();
}
public ActionResult View2()
{
return View();
}
public ActionResult View3()
{
return View();
}
In my global.asax.cs file, I'm trying to register the routes to these views as follows:
routes.MapRoute(
"View1",
"{controller}/products/find/view1",
new { controller = "Internal", action = "View1" }
);
routes.MapRoute(
"View2",
"{controller}/products/find/view2",
new { controller = "Internal", action = "View2" }
);
routes.MapRoute(
"View3",
"{controller}/products/find/view3",
new { controller = "Internal", action = "View3" }
);
Whenever I try to visit /internal/products/find/view1 in my browser, I see the ASP.NET error screen and it says:
The view 'View1' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/internal/View1.aspx
~/Views/internal/View1.ascx
~/Views/Shared/View1.aspx
~/Views/Shared/View1.ascx
~/Views/dashboard/View1.cshtml
~/Views/dashboard/View1.vbhtml
~/Views/Shared/View1.cshtml
~/Views/Shared/View1.vbhtml
What am I doing wrong? The path /internal/products/find/view1 is the most important part for me. Ideally, I would like to expose that in InternalController everytime. But I'm having a rough go at it. What am I doing wrong?
Thanks!
When you write
routes.MapRoute(
"View1",
"{controller}/products/find/{action}",
new { controller = "Internal", action = "View1" }
);
it means that whenever user writes into his browser:
http://mysite.com/blahblah/products/find/blahblahview
it will activate action view1 inside controller blahblahview. But it doesn't mean that view1.cshtml file is at that path. Actually, asp.net mvc looks for views at directories defined by convention...and convetion is:
~/Views/ControllerName/ViewName
so, your view should be in a folder:
~/Views/Internal/View1.cshtml
Unlike ASP.NET WebForms you are used to, ASP.NET MVC is pretty much driven by naming conventions as you could probably see (you always name your controllers like BlahBlah*Controller*, you always place your views inside Views folder etc... Read some tutorials here and catch up with basics.
I come from a Rails background and I'm having problems wrapping my head around Microsoft's MVC framework.
Today it's Routing. Rails gives you namespaces (e.g. Admin) which is the equivalent of Areas in .NET MVC3. Rails also allows you to define nested resources within your routes that will give you for example /posts/1/comments/1/edit and in your action you basically get params[:post_id] and params[:id].
I need something similar in ASP.NET MVC3 but not sure how to go about this. Googling for this results in at least 30 different ways to accomplish this and non of them mention areas.
It feels like I should add/modify something within here:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
But not sure where. Any suggestions?
I think you're in the right file (your AreaRegistration.cs file). I prefer being a little more explicit with my routes rather than using the default 'catch all' type of route that they provide. So here's an example of how I'd handle this:
Add something like this before the existing route (or get rid of the existing one all together) in the RegisterArea method
context.MapRoute(
"Edit_Comment",
"posts/{postId}/comments/{commentId}/edit",
new { controller = "Comment", action = "Edit" }
);
Then in your CommentController.cs you would have the following action:
public ActionResult Edit(int postId, int commentId)
{
// Do your edit logic then return an ActionResult
}