0

As a specific example within my application, I would like to have the information of the room (which is a combination of hotel name and room name) at http://mybooking.com/{hotelName}/{roomNr} passed onto my reservation controller at http://mybooking.com/reservation, and I really wonder what would be the best practice for doing it.

To be more specific, within the Room page (at http://mybooking.com/{hotelName}/{roomNr}), when user clicks on a button called "Book this room", he/she will be redirected to Reservation page. Thus, I want to know the most appropriate way to preserve the hotelName and roomNr from Room page to Reservation page.

I tried passing it through the URL like http://mybooking.com/reservation/{hotelName}/{roomNr}, but I believe this isn't the best solution, since I can only then access to the hotelName and roomNr in the specific index method of this controller:

//ReservationController
[HttpGet("/Reservation/{hotelName}/{roomNr}")]
public IActionResult Index(string hotelName, int roomNr)
{
    //hotelName and roomNr can only be accessed here
}

I do need this piece of information for other methods within the controller or the service as well, and I wonder if it is applicable with the current implementation.

Any suggestion on this case?

Linh Bui
  • 15
  • 6

3 Answers3

4

Your scenario is this: you have different hotels and rooms on your site which users can view, and you have a "reservation" or "checkout" process that exists of mutiple pages, where a user can book such a room.

When a user wants to book a room, you want to remember their hotel and room identifiers throughout the entire checkout process, so you know which room in which hotel they want to book.

You do not use sessions or TempData (which in ASP.NET MVC <= 5 and ASP.NET Core < 2.0 used to be saved in the session by default, but now in cookies) for this, because sessions and cookies are shared across tabs. So in this scenario, the user will book the wrong room:

  • User looks at room 1, clicks "Book this room". The data of room 1 is saved in the session. User goes through the checkout until the last step, but does not finish yet.
  • User opens a new tab, looks at room 2 to compare, clicks "Book this room" to view the conditions, payment details, whatever.
  • User decides they want room 1 anyway, goes back to the checkout tab and finishes their order.
  • Because the second "Book this room" click has now filled the session with the details of room 2, which is the room that will be booked.

You do not want this, because your user does not want this. What you should do, is pass the hotel and room identifiers to each page in the checkout process.

Whether you do this using hidden form fields and POST actions, or through the query string and GET actions is up to you.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
2

Without seeing what sort of code you have, it's sort of difficult to see what you are doing. Generally though, if you were to hit the url http://mybooking.com/{hotelName}/{roomName}

On that Controller you would know these details and be able to render them out onto the View. From this View, if you have a button which is "Reserve this Room", the button would be within a Form. Within this Form you would have the information about the hotel name and room name, probably in the form of Ids so that they are fully unique. When the user clicks the button, you are posting the Ids to the ReservationController which can then use this information on it's view.

e.g. something like

/{hotelName}/{roomName}

<form action="/reservation" method="post">
<input type="number" name="hotelId" value="{hotelId}" class="hidden" />
<input type="number" name="roomId" value="{roomId}" class="hidden" />
<button type="submit">Reserve Room</button>
</form>

The ReservationController would need to have a method that takes a HttpPost and has the arguments hotelId and roomId

Something like

[HttpPost]
public IActionResult Index(int hotelId, int roomId){
   // do something with the ids
   // stick them in a ViewBag
   Return View();
}
Tim B James
  • 20,084
  • 4
  • 73
  • 103
  • That is more or less what I am doing currently, but it does not actually answer my question. Let's say when I click on the "reserve this room" button, I will be redirected to the reservation page, and what I want to know is how to keep ```hotelName``` and ```roomNr``` to the reservation controller without passing it through the URL like ```/Reservation/{hotelName}/{roomNr}```. Because with this way I can only access to the hotel name and roomNr at ```public IActionResult Index(string hotelName, int roomNr)``` and nowhere else in the controller. – Linh Bui Jan 07 '20 at 10:05
  • @Linh you shouldn't _want_ to use it anywhere else. This is the only correct answer. Using POST is the idiomatic way to do this. Don't use sessions or TempData for this, because a user using your site on two tabs will then be very surprised to say the least. If your problem is that your reservation controller has a wizard-like process, so multiple pages for entering your details, then you need to POST the data to each page. Again, do NOT use TempData or sessions for this. – CodeCaster Jan 07 '20 at 10:37
  • @CodeCaster I see what you are indicating. If so, is there any possible way to retrieve those ```hotelName``` and ```roomNr``` elsewhere in the Reservation controller? For example, currently I want to perform a client-side remote validation, and I need ```hotelName``` and ```roomNr``` to find this room in the database, but I have no idea how to get it, and it is a different method than the index method so I cannot access it. – Linh Bui Jan 07 '20 at 10:52
  • When you post to the reservation controller, the values that you post will not be in the URL. You can post whatever you want, the names, the Ids. Once in the reservation controller, you will have access to all the values and can display in the view. – Tim B James Jan 07 '20 at 10:52
  • @Linh if you call a (non-action) method in the same controller, you can just pass the model values to that method. – CodeCaster Jan 07 '20 at 10:55
  • @TimBJames @CodeCaster thank you for your help, it works perfectly now. One last question: within the post action (with hidden form fields), the fields somehow still exist for me and I have no idea why it is not hidden. My code for this case is `````` – Linh Bui Jan 07 '20 at 11:11
  • 1
    @LinhBui You would need to add a css class called `hidden` that has `display: none` as the styling. Alternatively, you can use `type="hidden"` which is built into an `input` control. – Tim B James Jan 07 '20 at 11:13
0

A very simple way of transferring data between two controllers is to use TempData

Assuming that you are handling a HTTPPost in http://mybooking.com/{hotelName}/{roomName} which redirects to http://mybooking.com/reservation, you can use

TempData["hotelName"] = "a";
TempData["roomName"] = "b";

before calling RedirectToAction.

In the controller method of http://mybooking.com/reservation you can access TempData again.

You can read more about TempData here:

ASP.NET Core exposes the Razor Pages TempData or Controller TempData. This property stores data until it's read in another request. Keep(String) and Peek(string) methods can be used to examine the data without deletion at the end of the request. Keep() marks all items in the dictionary for retention. TempData is particularly useful for redirection when data is required for more than a single request. TempData is implemented by TempData providers using either cookies or session state.

citronas
  • 19,035
  • 27
  • 96
  • 164