0

I have a table of data which contains newsarticles.

ive created standard CRUD views/forms and it has paging too.

eg at the moment i have urls's like this:

// GET: /News/
//      /News/Page/2  

News articles can be archived (a boolean value in the db)

i want a url to map to only archived data in the db or non archived data.

eg /News/Archived/Page/2 should map to page 2 of only Archived items.

and /News/Page/2 should map to page 2 of non archived items.

what do i need to do in global asax to achieve this. and what should the signature of the index method be?

//Signature in controller
public ActionResult Index(int? page)


//Route for paging
 routes.MapRoute(
               "NewsArticles",
               "News/Page/{page}",
               new { controller = "News", action = "Index" }
           );

3 Answers 3

1

First, I'd recommend getting rid of "/Page". It's not needed. You can default to the first page, and have it pass "1" to your 'Archived(int page)' and 'NonArchived(int page)' methods automatically. Also, if you want the word "/Page/" in your url, you are going to have to duplicate the maps below: one set without "/Page" in the url (as shown below), and another set with "/Page".

Note, MapRoute works in order. If you want /Page, then you have to have those two routes first (News/Archive/Page/{page} and News/Page), before you use the two urls below.

routes.MapRoute(
  "ArchivedArticles",
  "News/Archive/{page}",
  new { controller = "News", action = "Archived", page = 1 }
);

routes.MapRoute(
  "NonArchivedArticles",
  "News/{page}",
  new { controller = "News", action = "NonArchived", page = 1 }
);

If '/news/archive/' is used, page will equal 1. If '/news/archive/2' is used, then page will equal 2, and so on. Same for '/news' and '/news/2'.

Your NewsController would have two methods:

public class NewsController : Controller
{
  [AcceptVerbs(HttpVerbs.Get)]
  public ViewResult NonArchived(Int32 page)
  {
    ...
  }

  [AcceptVerbs(HttpVerbs.Get)]
  public ViewResult Archived(Int32 page)
  {
    ...
  }
}

You could actually skip the 2nd maproute above, if you use the default Index() route. The catch is you'd have to change the action method signature from "page" to "id" - and it will work. I just made it more verbose for more transparency by not using any assumptions from the mvc framework.

Sign up to request clarification or add additional context in comments.

2 Comments

the suggestion for getting rid of Page in the URL makes sense to me, but if all he's doing is returning the same view with the same model objects based on a bit field, it really seems silly to have two controller methods. Why not consolidate into one and make the controller take another parameter like in the solution I posted?
Funny, I just replied to your question stating why not to use the same action method. Both action methods above can return the same View with the same format. To each his own I suppose. lol
0

If you want to use the same action on your controller for serving both situations, I'd probably change the signature to something like this:

public ActionResult Index(bool archive, int? page)

Then, you can have two different routes for this. First for the non-archived stuff:

routes.MapRoute(
    "NewsArticles",
    "News/Page/{page}",
    new { controller = "News", action = "Index", archive = false }
);

And then for the archive version:

routes.MapRoute(
    "NewsArticlesArchive",
    "News/Archive/Page/{page}",
    new { controller = "News", action = "Index", archive = true }
);

Now you have the liberty in your action of filtering based on the archive bool. Also, I agree with the others here that the Page text in the URL is redundant. If you decide to remove it, you can just yank it out the routes above and everything should still work. Good luck!

8 Comments

I recommend against using the same action method to control two different data paths. This tends to create more complex logic within the action method, which is advised against for best MVC patterns - the action method should be logic and error agnostic, and should just pass the parameters down into the domain, and pass whatever data is returned into a View (or return any errors from the domain (if any)).
I disagree. The Controller is in charge of communicating with the model and obtaining results. I don't see how this goes against the MVC pattern at all. The OP stated that the only distinguishing factor between archived and non-archived results is a single bit field in the database. I see no harm in passing this off to your model to toggle the results you get back.
Also, it's not two different "data paths" as you outlined above. In your solution, the OP would either have to create two Views, or pass the name of the View to the View() method, and in either case his model objects will be identical for both controller methods. It just seems like adding code for the sake of coding to me...
Hehe, yes. Great minds think... oppositely. I approach things from TDD/BDD, where I would design two methods - not knowing anything about the other method.
I do BDD, too (thank god for mspec, xunit, and Moq). I can see the value in having two methods, especially for the future should these two code paths diverge, but simply passing a bool to this action is pretty harmless to me :)
|
0
//Signature in controller
public ActionResult Archive(int? page)


//Route for paging
routes.MapRoute(
               "NewsArticles",
               "News/Archive/Page/{page}",
               new { controller = "News", action = "Archive", page = 1 }
);

I would probably also simplify the routes to not include the word page ie: "News/Archive/{page}" and "News/{page}" but this depends on what other routes you have.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.