0

I have a bunch of mostly-static pages (about 40), like: order-form01.html, order-form02.html, orderform03.html etc..

Should each of them have its own Controller/Action, or is that possible to have one dynamic Controller/Action for all of them?

My Url should look like this: http://MyProject/GlobalController/IndividualView and for the above example: http://MyProject/OrderForm/order-form01, http://MyProject/OrderForm/order-form02 etc..

Thanks in advance.

user3378165
  • 6,546
  • 17
  • 62
  • 101
  • 1
    Depends on the criteria to select a file. Explain which page you want to render, show some example filenames. – CodeCaster Mar 13 '16 at 15:33
  • I'm not sure what you mean. I have to incorporate on my project a lot of static pages, I must create them as .cshtml because I want them to use my Layout page. is that possible to have one Action to return all these Views? – user3378165 Mar 13 '16 at 15:40
  • for one action there can be more than one view.It does not matter,but per one url you need one action. Because the once the user request for a url it navigate to controller/action – Nithila Shanmugananthan Mar 13 '16 at 15:48
  • Do you need dynamic controller/action? You may have to see http://stackoverflow.com/questions/3303801/how-to-achieve-a-dynamic-controller-and-action-method-in-asp-net-mvc – deyu Mar 13 '16 at 15:49
  • You can just use `@Html.Partial(Model.StaticHtmlFileName)` in your view. Then in your controller, decide (on whatever the criteria are, for example query string parameters) which file should be rendered. – CodeCaster Mar 13 '16 at 15:50
  • Would you be able to explain how this code will achieve my goal? – user3378165 Mar 13 '16 at 16:27
  • No, because you have still not explained how you want your program to decide which page to render. Please [edit] your question and include some example filenames and conditions when you want to display those files. – CodeCaster Mar 13 '16 at 16:55

2 Answers2

4

Yes it's very easy AND you don't need a switch statement or any other redundant logic.

public class MyController
{
  public ActionResult  Page(string file)
  {
    return View(file);
  }
}

The magic is in the Route Map:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // New MapRoute for your 40+ files..
        routes.MapRoute(
            "OrdeForm",
            "OrderForm/{file}",
            new { controller = "MyController", action = "Page", {file} = "" }
        );

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = "" }
        );

    }

Additionally:

I pass the View name in the query string.

Is not required, but is supported. The following urls will work:

// Url Parameters
http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02

// Querystring Parameters
http://MyProject/OrderForm?file=order-form01
http://MyProject/OrderForm?file=order-form02

The only catch is that you need to rename your html files to cshtml and place them in the correct directory for the ViewEngine to find.

@Erik, I also bit of new to mvc . Could you please explain your route map as of how is it possible with default raute again and again

Routes are broken down into 3 values:

Controller
Action
Parameter(s)

At a bare minimum, the controller and action are required. Where the values come from is not dependent on the Url. For example, in the following Url and Map Route...

// Url
http://MyProject/

// MapRoute
routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = "Home", action = "Index", id = "" }
);

// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
  public ActionResult Index() {
    return new EmptyResult();
  }
}

... everything still works because we provided a default value for the controller and action.

Ok let's break down the URL you want:

http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02

http://MyProject/<identifier>/{parameter}

You have one identifier that tells me route (OrderForm) and one changing value that because it changes and you want one value, should be a parameter.

http://MyProject/<identifier>/{file}

The name of the parameter makes no difference as long as it matches the signature of the controller method:

http://MyProject/{Controller}/{file}

public class HomeController {
  public ActionResult Index(string file) {
    return new EmptyResult();
  }
}

or

http://MyProject/{Controller}/{einstein}

public class HomeController {
  public ActionResult Index(string einstein) {
    return new EmptyResult();
  }
}

I named the parameter file, because it tells me it's the parameter is a name of a file, whereas the name einstein has no inherent description so is a terrible name for a variable.

http://MyProject/{Controller}/{file}

// MapRoute
routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = "Home", action = "Index", id = "" }
);

// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
  public ActionResult Index() {
    return new EmptyResult();
  }
}

Now we only want this route to run when the identifier is OrderForm so we don't allow that to be a value, we hard code it.

url: "OrderForm/...

Next we have a value that keeps changing, so we to add url parameter:

url: "OrderForm/{file}"

Now we have an issue because we aren't allowing MVC to parse values from the url to populate Controller nor Action so we must supply them.

routes.MapRoute(
  name: "",
  url: "OrderForm/{file}",
  defaults: new { controller = "Home", action = "Index", file = "" }
);

Here we've mapped the url http://MyProject/OrderForm/{file} to:

public class HomeController {
  public ActionResult Index(string file) {
    return new EmptyResult();
  }
}

Now I would choose to to update the defaults to something more specific and descriptive:

routes.MapRoute(
  name: "",
  url: "OrderForm/{file}",
  defaults: new { controller = "OrderForm", action = "Index", file = "" }
);

public class OrderFormController {
  public ActionResult Index(string file) {
    return new EmptyResult();
  }
}

Hope that all makes sense.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • I upvoted your answer but what you have shown is for the get action method what will he do about post? Since he has 40 different forms that means 40 different models and hence 40 parameters to post action method? Then he will have to have default null for each parameter because it depends which form he has submitted and then in his post action he will have to check which object is not null and perform activity accordingly – Mohit Shah Mar 13 '16 at 17:53
  • 1
    RouteMaps do not care about the Http Method. There is only 1 parameter, so I don't know what you're referring too. I'll update my answer if he needs more information about his question. – Erik Philips Mar 13 '16 at 17:55
  • He has 40 forms right so he wants to do post action thats what i am talking about :) – Mohit Shah Mar 13 '16 at 17:56
  • Then he needs to update the question to include that criteria. This site is not designed around answering comments, it's around answering questions (literally). – Erik Philips Mar 13 '16 at 17:58
  • Updated per your request. – Erik Philips Mar 13 '16 at 20:10
  • @Erik Philips, Thank you very much for your answer, it seems exactly what I was looking for, but for some reason I can't get it to work, I'm getting a 404 error. Should I add this code snippet on my RouteConfig.cs file: routes.MapRoute( name: "", url: "OrderForm/{file}", defaults: new { controller = "OrderForm", action = "Index", file = "" } ); ? – user3378165 Mar 13 '16 at 20:47
  • The order in which you add it to the routes is important. It has to be before the default route. – Erik Philips Mar 13 '16 at 21:02
  • I got it to work, your answer is AMAZING, brilliant! Thanks a million!! – user3378165 Mar 13 '16 at 21:05
  • @Erik Philips, it is also very well explained, more than the good answer, I earned learning and understanding a new thing! Thank you very much! – user3378165 Mar 13 '16 at 21:15
1

After the question edited :my solution is, you can have one controller/action and it should call view (cshtml). Your querystring data should be pass to view as of viewbag variable and partial views should be called acording to the viewbag variable. noo need of editing routing table even(if you are willing to pass it as a query string).

//your routeconfig will be
routes.MapRoute(
  name: "default",
  url: "{controller}/{file}",
  defaults: new { controller = "OrderForm", action = "Index", file = "" }
);
//here no need to have 40 routing table one is enough
//your controller/action will be
public class OrderForm
{
  public ActionResult  Index(string file)
  {
    ViewBag.Orderform=file
    return View(file);
  }
    }
//view bag variable is accessible in view as well as in javascript

But I would say as best practice, you can modify default routing to access all urls and navigate it to same controller/action and let that action to return the view. After that use angular / knockout js to handle client side routing and based on it the partial views should be loaded.(still your url will be different for your 40 pages but noo need to pass it as query string)

//your route table will be
 routes.MapRoute(
      name: "default",
      url: "{controller}/{file}",
      defaults: new { controller = "OrderForm", action = "Index"}
    );

//your controller will be
 public class OrderForm
    {
      public ActionResult  Index()
      {
        return View(file);
      }

Navigation should be handled by client side routing

  • Thank you, but in this case I will have to write 40 conditions, one for each View, I was looking for a more global solution. – user3378165 Mar 13 '16 at 16:04
  • If that is the case you try with partial views and client side routing. – Nithila Shanmugananthan Mar 13 '16 at 16:06
  • How Partial Views can achieve this goal? – user3378165 Mar 13 '16 at 16:09
  • You have to create one view(.cshtml) and create 40 partial views(.html).Your controller/action for the view not for partial views. from the view you have to navigate through client side routing (you may use angular or knock-out). – Nithila Shanmugananthan Mar 13 '16 at 16:15
  • Yes, I have to have 40 Urls. With Partial Views, if I understand correctly, I will have one Url: "http://MyProject/MyGlobalController/myGlobalView" for all my pages, and each time the page itself will be different? If this is the case it won't solve my issue, I can't have the user clicks on AboutUs or ContactUs and stay on the same Url. Isn't there any way to program one global Controller to return each time a different View based on a query string parameter? – user3378165 Mar 13 '16 at 16:26
  • You try with modify the default routing table in routeconfig .cs as for any url that particular controller/action should be fired.after that action fired it will call your view then your client side routing should come across with angular/ knockout. – Nithila Shanmugananthan Mar 13 '16 at 17:16
  • -@Nithila Shanmugananthan, Thank you for all your help! – user3378165 Mar 13 '16 at 21:20