Passing contextual info to Views in ASP.NET MVC - asp.net-mvc

I wonder - what is the best way to supply contextual (i.e. not related to any particular view, but to all views at the same time) info to a view (or to master page)?
Consider the following scenario.
Suppose we have an app that supports multiple UI languages. User can switch them via UI's widgets (something like tabs at the top of the page). Each language is rendered as a separate tab. Tab for the current language should not be rendered.
To address these requirements I'm planning to have a javascript piece that will hide current's language tab on the client. To do this, I need current's language tab Id on the client. So, I need some way of passing the Id to master page (for it to be 'fused' into the js script).
The best thing I can think of is that all my ViewModels should inherit some ViewModeBase that has a field to hold current language tab Id. Then, whatever View I'm rendering, this Id will always be available for the master page's hiding script.
However, I'm concerned that this ViewModelBase can potentially grow in an uncontrolled fashion as number of such pieces of contextual info (like current language) will grow..
Any ideas?

If this contextual information is needed by all views then having a base view model seems like a good solution. The question is where to populate this information to avoid cluttering all your controller actions. A custom action filter seems like a good place. In the OnActionExecuted method you could get the view model returned by the controller action and populate the contextual part if it derives from the base type.
Another option is to put the contextual information into the ViewData (strongly typed views can also use ViewData) but personally I hate having magic strings and doing casting in my views (this could be overcome by using HTML helpers that will handle this ViewData).

If you think that ViewModeBase will grow to much you can also have viewmodels implement an interface.
The View or Partial can have the type of that interface.
Thats especially usefull if only some pages have that functonality.

Related

Exporting ViewData\ModelState to Child Action

As the subject says, is this a bad idea? If so, why?
Currently, if you are rendering some input fields from inside a #Html.Acion, the validation errors don't get displayed to the user as the ModelState gets cleared when the #Html.Action gets involved (in its context.)
So whats the best pattern around it?
You can access the parent contexts via ControllerContext.ParentActionViewContext or ViewContext.ParentActionViewContext (details here) but I think there are better solutions.
A child action is a good choice when you do not want to pollute all of your view models with data which are available independent from the current controller action and view (for example a user welcome label, a navigation bar, etc.).
For other reuse scenarios like common input fields a partial view is a better approach.
However if you give more details about your current scenario I try to suggest a more specific solution.

Rendering Navigation in MVC3

What's the best way to render Navigation in MVC3? In my app the Controller has to decide what should be in the Navigation but as far as I know there's no way to pass a Model up to the _Layout file (where the Navigation html lives) to give it this information.
You can make the model available to your layout.
Define a base class, MyBaseModel, with the properties you want available to the layout.
Have your models subclass MyBaseModel, and ensure that you populate the properties
Have your layout specify #model MyBaseModel
Use the properties
See also this blog post where a similar problem ("we often find ourselves needing to include the same information in every page") is tackled.
Best is a relative and subjective term. I would usually go with an approach similar to druttka's answer but another option is to use RenderAction() to invoke a controller action
<div>#Html.RenderAction("action", "controller")</div>
I will offer some counterpoints to #druttka's answer. But mostly, you have to decide which trade off you want to make.
If you use a model for your view, you are now forcing 2 things:
Every view must be strongly typed
Every action must call the function to populate all levels of nav included in your view model
The first point isn't so bad, because there are very few pages in a typical non-static site which wouldn't derive from a model anyway, and its easy enough to create an empty model for those pages. The second point is much more annoying however. Each function has to instantiate it's own model, and then populate the nav properties for every level of nav provided by the model. This can be quite cumbersome, but can be fairly elegantly handled in OnActionExecuted for at least nav which is not specific to a given action.
The alternative is to add the nav to the ViewBag. This can be done whenever and does not force you to specify a model for every view, which is great for the flexibility in those cases where you do not need to specify a model. It should be noted however that the ViewBag in asp.net mvc 3 is of type dynamic, which you cannot use as a parameter in a lambda function, thus preventing you from doing something like #Html.DisplayFor(viewBag => viewBag.MainNav) in your layout, which is a real drag. You can still render partial and specify the appropriate DisplayTemplate however.

Can I use a MVC Global Action Filter to disable form fields?

Some users of our application will have read-only access to many of our pages, in our current web forms app this means they see the form, but all of the fields are disabled. We're looking at MVC 3 and searching for the cleanest, most idiomatic way of implementing this functionality.
Some ideas so far:
Some combination of a global action filter and edit templates.
A custom Html helper, something like Html.SecureTextBox etc...
I'm leaning towards number 1, but I'm wondering if any of you guys/gals with more MVC experience have solved this problem in a better way.
I agree with using a base view model, or perhaps just an interface with a "CanEdit" type of property. If you go the interface route, you could set the property in an ActionFilter in the OnActionExecuted method.
To tie it to the view, creating a new HtmlHelper would be pretty easy. I'd use TextBoxFor as the base class, since it has access to the view's model. You can then inspect the property and create the necessary HTML attribute. However, with going this route you will need to create a new helper for each type of input control you need (textbox, select list, etc).
Without knowing all the details of what you are doing, a much simpler idea would be to not provide a Save button for read-only users. The Save button would be driven by one property in the view model (or ViewData, if you like).
Several other people mentioned that a server-side restriction is still needed to prevent people from bypassing the client-restrictions. You will need an action filter for this. This link has a good idea about that.
My preference would be to set a variable in a common base view model (or ViewData), using a global action filter, and then use a bit of jquery to dynamically disable the input fields, delete buttons etc.
$(':input').attr('readonly', true);

MVC reusable propertygrid

In my web application framework (currently WebForms) I have a control that behaves like a classic propertygrid. It is initialized with an object ID (database key), then it reads metadata to determine the type of the object and the attributes of the object. It displays the attributes, string attributes as textboxes, bool attributes as checkboxes, enum attributes as dropdown lists. On page submit there is a method of the control ctrl.SaveData() that saved the changed attribute values back to the database.
The WebForm control tree and event model supports this approach quite nicely. Now I am asking myself if it is possible to achieve a similar solution for ASP.NET MVC. The main objective is to have a generic, reusable component that can be applied in a variety of situations with not much hassle. Additionally the solution must be flexible enough to put multiple instances of the component for multiple objects on a single page. Here the auto-generated WebForms HTML IDs also helped.
I am very curious about your ideas! Thanks a lot for answering!
You could achieve this effect using a custom ViewModel that contains enough metadata to identify the object being edited/saved. You would use this in conjunction with a partial view that renders the ViewModel. The main page would use the metadata in the ViewModel to either direct the post to a specific controller action to save that particular object or pass the metadata back to a common action (as hidden inputs, perhaps) in order that that action can choose the proper table in which to persist the data.
Personally, I would not take this approach. My feeling is that the more general you make a view/action, the more work it becomes to adapt it for different circumstances. I have done similar things for viewing sets of objects, but for a detail view or editing I like to work with more specific models and views.

Is the best approach a typed or not typed view in ASP.NET MVC?

In ASP.NET MVC it's possible to choice between having a typed view were you define in the codebehind what kind of data the view can should expect. But it's also possible to not define this and just pass any kind of data to view in a ViewData container.
What would the best model here or should I mix depending on what kind of data we're talking about (maybe just make sure to have data that's critical to the functionality of the view typed and other data not typed?)? I don't really understand why there is a option here ...
I would recommend always using the strongly typed ViewData... that way you have compile time checking, intellisense, you don't have to do casting in your view, and the ability to refactor your code much easier.
Earlier releases of the framework required you to choose between a ViewData dictionary and strongly typed view model.
Now you can mix the two. Combine this with some of the new features of Preview 5, such as ModelState, validation, and auto-binding to form fields and it becomes more compelling to use the ViewPage for the main model in your view being rendered.
You can still add data to the dictionary in the controller pipeline and request it later on using ViewData["key"] ... or even better ViewData.Get("key") from MvcContrib.
I had this thought too in the past. In my site, I used to strong-type the view, when the view is almost a 1:1 model of the class you are showing. Like showing a list of all users, I type to List, this way I don't need to cast anytime to have the right datatype.
In none specific views, I just strong-type to the most "heavy"/used type.
In forms, the form itself is the type of the view when returning View(form); ....

Resources