Richard Ev
Richard Ev

Reputation: 54117

General approach for displaying a message on any page

I have a fairly simple (to explain) requirement for my ASP.NET MVC web application:

On any page, be able to display a message based on an event that happened on a preceding page. Messages may include dynamic content, such as information entered by the user in a form submission.

Similar to this...

Yes, success!

The approach must work in POST-REDIRECT-GET scenarios.

If the user has two browser tabs (which share session state) open on the application, then any message should only be displayed in the tab in which the related event happened.

For example:

  • After submitting a feedback form, a message thanking the user (by name)

  • When logging in, a message telling the user the date/time when they last logged in to the application

My first thought was to use a strongly-typed view with an appropriate model (with a string property) for this. However this would mean changing every single existing non-strongly-typed view to use this model, and updating all existing models to inherit from this new model.

This seems like overkill.

An alternative is to store the message in TempData:

// In my controller
TempData["Message"] = "Some kind of message";

// In my shared master view
@if (TempData["Message"] != null)
{
    <div class="message">@TempData["Message"]</div>
}

Using TempData is covered in a bit more detail in this blog posting. Interestingly, the author also suggests using a custom HTTP header as an alternative. An interesting idea, but does not work with POST-REDIRECT-GET.

Is using TempData the preferred option, or is there a "better" alternative? (e.g. something more strongly typed)

Upvotes: 3

Views: 193

Answers (3)

Bhushan Firake
Bhushan Firake

Reputation: 9458

It is best practice to use ViewModels to communicate between View and Controllers. You can have a base View Model and all other View Models derived from that as below:

   public class BaseVM
    {
       public string Message{ get; set;}
    }

    public class CreateViewModel: BaseVM
    {
       public string CustoomerName{ get; set;}
    }

You can populate the Message property while returning the model to the controller as below:

public ActionResult Step2()
{
   //Some Logic

    step2Model.Message = "Yes, Success..!!";

    return View(step2Model);
}

After that, on each view page, you can check if that property has something in it.You can do so as below:

 @if(!string.IsNullOrEmpty(Model.Message))
{
  //Show message
}

EDIT:

OP is well aware of this approach, but still keeping this answer as it has a snippet to show how to do this in code. Secondly, when it comes to use ViewModels, I agree with following comment by CodeCaster in his answer.

This is the only consistent, reusable, testable solution to do this that I can imagine, despite the extra work it may cause.

Upvotes: 1

Floremin
Floremin

Reputation: 4089

You could make a convention in your project that a message to display would always go into ViewBag.InfoMessage dynamic variable. So, in your layout file you would display it if it's passed into the view from a controller.

More strict way would be to create a base model class with InfoMessage property and derive all other models / viewmodels from that base.

To persist the message through POST-REDIRECT-GET scenario, use a session variable which you'd clear once the value is sent to the view - to avoid displaying on more than one page.

Here some code:

public class BaseViewModel
{
    public string InfoMessage { get; set; }
}
public class SpecificViewModel : BaseViewModel
{
    // other model properties
}

In your controller then:

SpecificViewModel vm = new SpecificViewModel();

vm.InfoMessage = Session["InfoMessage"] as string;
Session["InfoMessage"] = null;

// other code

return View(vm);

Of course your view will have strongly typed model: SpecificViewModel.

Upvotes: 0

CodeCaster
CodeCaster

Reputation: 151604

My first thought was to use a strongly-typed view with an appropriate model (with a string property) for this. However this would mean changing every single existing non-strongly-typed view to use this model, and updating all existing models to inherit from this new model.

This is the only consistent, reusable, testable solution to do this that I can imagine, despite the extra work it may cause.

Upvotes: 2

Related Questions