BaseViewModel for every Request - asp.net-mvc

Is there a way that I can pass the same BaseViewModel for every request without returning either the BaseViewModel or something that inherits from the BaseViewModel for each view? I'm using a shared view (_layout.cshtml).

No, there isn't a way. If your view or layout is strongly typed to a class BaseViewModel you need to return an instance of this class (or a derived class) from each controller action that is rendering this view.
As an alternative to the base view model approach you may checkout the Html.Action helper in order to encapsulate some common view functionality.

Related

In MVC do partial views inherit the models of their Parent views?

I'm passing some data to a View from my controller, which I wish to display inside a partial view inside that View (don't ask, it's complicated). I know I probably shouldn't even be passing a model to a view that's inded for another view, but I've noticed that the partial view is actually inheriting the Model from the parenmt View:
public ActionResult Index(){
Person p = new Person
{
FName = "Mo",
LName = "Sep"
};
return View(p);
}
Then inside my Index View I have:
<h2>Index</h2>
#Html.Partial("_IndexPartial")
and Inside _IndexPartial I have:
#Model.FName
and this Prints "Mo".
Is this behaviour intended like that in WPF where child controls inherit the data context of their parent View? And is it considered bad practise to use this in your application?
Thanks.
Is this behaviour intended like that in WPF where child controls
inherit the data context of their parent View?
Yes.
I see you are not currently passing any model to the
Would it work to just inherit the layouts, and then not need to use the partial at all?
If you want to keep using it like you are, maybe just be more explicit about it, and pass the current model to the partial.
#Html.Partial("_IndexPartial", Model)
If you look at the source for Html.Partial(view):
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName)
{
return Partial(htmlHelper, partialViewName, null /* model */, htmlHelper.ViewData);
}
It is passing the model via htmlHelper.ViewData, you can access the model in the same way in your view with #{ViewData.Model}, but this is NOT a good practice.
You can pass the model into the partial view as a second parameter using the overload:
#Html.Partial("viewname", Model)
Nothing wrong with this approach IMO as its the whole point in strongly-typed views and the benefits they bring...

How to authorize a set of controllers without placing the annotation on each one?

I have sets of controllers which are each used for each authorization type. For example, a class A authorization will have a set of controllers each which require class A authorization. Is there a way to place one [Authorize(Role="Class A")] attribute somewhere which will apply to each of those controllers without having to decorate each controller with the same attribute?
You can initialize those controllers derived from your base controller. namely put your attribute on a controller base class and to ensure that each controller within derived from base class.
[Authorize(Role="Class A")]
public class CustomBaseController : Controller{}
public class AController: CustomBaseController{}
public class BController: CustomBaseController{}
Yes there is a way, make all those A-class controller derived from one base controller and place on it the AuthorizeAttribute:
[Authorize(Role="Class A")]
public class AController : Controller
{
...
}
public class AFirstController : AController // Gets it's parent attribute
{
...
}
public class ASecondController : AController // Gets it's parent attribute
{
...
}
2 or 3 responses here explained how you can do it... but you can also use Fluent Security to handle all controllers + Actions setup in one file. Some of the benefits (from their website):
Code based configuration
No attributes or xml cluttering up your code.
Low imprint
Fluent Security won't spread like wildfire in your application. Your configuration can be kept in a single file.
You can inherit from a base controller, such as
[Authorize(Role = "Class A")]
public class ClassARequiredController : Controller {}
Otherwise you'd be looking at a global filter, and by your question I assume you have multiple roles and sets so I don't think global filters are for you.
Set the attribute on a Base Class and inherit, creating the hierarchy that best fits your scenario...

ASP.NET MVC View Model Base?

I am working on my model hierarchy and have a few questions.
1) I have a base model for each view type (Add, Edit and View). I put thing in these that are specific to each view type.
2) I then have a model base which the bases above inherit from. This allows me to include things that pertain to ALL views.
3) In my ModelBase, i have a couple of other view models like FeedbackViewModel, ShoppingCartViewModel, etc that I can consume on any view.
4) I have my MasterPage inheriting ModelBase.
Example
Public MustInherit Class ModelBase
Public Property ErrorMessage As String
Public Property InformationMessage As String
Public Property WarningMessage As String
Public Property FeedbackModel As New FeedbackViewModel
End Class
Public MustInherit Class ViewModelBase
Inherits ModelBase
'View Model Specific Stuff
End Class
'Allows contact us form to be submitted.
Public Class ContactUsViewModel
Inherits ViewModelBase
Public Property Name As String
Public Property EmailAddress As String
Public Property Phone As String
Public Property Comments As String
End Class
That is the basic structure of my models, but a few questions:
1) What do I do with a view that requires no model, but I need to pass the FeedabckViewModel, SHoppingCartViewModel, etc.? I was thinking of a GenricViewModel?
2) Do you see any flaws in this design?
Thank You!
Some points:
Why use ErrorMessage, InformationalMessage, WarningMessage, etc. ModelState should be more than enough, and it ties in better with the validation helpers as opposed to you writing the manual stiching in the View.
I think a "base" model to handle different view types is a bit overkill. I think a enum specifying the mode would be better, then you can make decisions accordingly.
Overall, there is nothing really wrong with your design. It's a matter of opinion - for which mine is i usually create a ViewModel per View. Keeps it simple. I use areas extensively so it doesn't get messy. I generally try and create the ViewModels to make the View simple - that's the ultimate goal, not to re-use code across View's, but to keep the View simple. Such as augmenting the model with nested models to make use of partials/templates, as opposed to having a bunch of strings.
1) What do I do with a view that requires no model, but I need to pass the FeedabckViewModel, SHoppingCartViewModel, etc.?
Doesn't that kind of contradict itself? :) If you just need "parts" of a couple of ViewModels, either create another ViewModel, or if it's just a couple of fields, just stick it in the ViewData.

Reusable Content Box Data In ASP.NET MVC?

If I create a PartialView for a box that holds a header, image and content what is the best way to store the content without using a database?
Example: TurboTax
I doubt the content for the boxes in the sidebar are stored in a database but to make reusable code it would be beneficial to create the structure in a PartialView and populate the content areas. I can create a PartialView and pass a Model from the parent Controller to the PartialView but then I would be stuck copying and pasting that same content if I wanted to use the same box on another page.
For fixed content you might want to think about using XML+XSLT or even HTML snippets in the file system and simply rendering them. An HtmlHelper method might make more sense for this than a partial view - Html.RenderXml() or Html.Include(). The only real difference between these and partial views is that the view engine isn't invoked since there aren't any substitutions. I do this sort of thing with my privacy policy and terms and conditions. I'd certainly consider keeping these cached.
If these really are templates and you are just substituting content, then I think the partial view works well and I would consider putting the data in a database, again, maybe using caching if I found that performance suffered. You could use this in combination with the former -- say keep your images/xml in the file system and a pointer to them in the database so you know which ones to pick in the partial.
Passing data to partial view that is used in many places can be done in many ways:
Create base model class for all your models. In base class define PartialModel property which will be holding model for partial view (there may be many of them if use have many partial views). Now you can populate the PartialModel property in controller action, but to make code more reusable you can create your own Action Filter which will insert the partial view data just after the action method is executed (but before the model is passed to the view)
public class PartialViewModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
BaseViewModel model;
if (filterContext.Controller.ViewData.Model == null)
{
model = new BaseViewModel();
filterContext.Controller.ViewData.Model = model;
}
else
{
model = filterContext.Controller.ViewData.Model as BaseViewModel;
}
model.PartialModel = new PartialModel(...) // Partial model initialization
base.OnActionExecuted(filterContext);
}
}
Then you can use it like:
[PartialViewModel]
public ActionResult Index()
{
//...
}
Another option: you can create BaseController class for all your controllers and create PartialModel on base controller initialization. Then PartialModel can be stored in ViewData[] dictionary. Because using ViewData dictionary in views is bad, create extension method on HtmlHelper like:
public static PartialModel GetPartialModel(this HtmlHelper helper)
{
return helper.viewContext.ViewData["PartialModel"] as PartialModel
}
So you could obtaint the model this way:
<% Html.RenderPartial("MyPartial", Html.GetPartialModel()); %>

Provide user object to every view

How can I provide a user object to every view in ASP.NET MVC without having to create a ViewModel for absolutely every view I have?
When using ASP.NET Membership, I just get a Profile variable in the views with the profile information, but when rolling my own I don't see a way to export that information.
Inherit your controllers from base controller. In base controller override OnActionExecuting and set ViewData["UserObject"] here. Something like this:
public class YourBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData["UserObject"] = ...
}
}
Or create custom filter with the same OnActionExecuting method if you want only certain controllers providing user object to View.
UPDATED:
Create custom Html helper if you dont want to cast ViewData["UserObject"] every time:
public static object RenderUserObject(this HtmlHelper html)
{
return ((html.ViewData["UserObject"] as UserObject) ?? new UserObject()).ToString();
}
Inherit your ViewModel classes from a master ViewModel with a User property.
Alternatively, you can pass the object in ViewData collection and use an extension method to make it easy to access the object in the view.
One alternative to having a base ViewModel class, and so having to define a ViewModel class for every view, is to create a generic ViewModel<T> class which exposes a property T InnerModel, or something similar. Then you can pass a ViewModel<Foo> rather than having to explicitly create a FooViewModel class.
Of course if you also need more bespoke ViewModels in places, you can keep the ViewModel base class, and have ViewModel<T> and your bespoke ViewModels extend it.

Resources