So I have been googling how to remove any and all usage of ViewBags in favour of something more elegant and effective. Unfortunately virtually all of the information I have come across is for prior versions of MVC, and I have yet to find something that both works and is really effective.
One of my primary objective is to be able to populate both the page and the layout at the same time, so that I can add a page title to both the <h2> as well as the <title>. I also want to be able to, if needed, to supply the first paragraph of the body content, which is drawn from the database as a separate column, to the meta-description (this is a special case where all first paragraphs are their own separate entry in the row in the db, purely for the purpose of also acting as the meta-description).
I have run across something that I believe will meet my needs, but I cannot seem to properly implement the fifth code block:
Now create the view base class. You need to create two versions to
have support for typed views.
public class ViewBaseWithLayoutModel : WebViewPage{
public LayoutViewModel LayoutModel {
get { return (LayoutViewModel)ViewBag.LayoutModel; }
}
}
public class ViewBaseWithLayoutModel<T> : WebViewPage<T>{
public LayoutViewModel LayoutModel {
get { return (LayoutViewModel)ViewBag.LayoutModel; }
}
}
Specifically, it is the “create the view base class” that has me tied up in knots -- are they talking about an entirely new section in the project, similar to the Views, Controllers, Models, Extensions, Validators, etc., such that the namespace would be namespace Project.ViewBase {?
And if I can put the fifth code block straight beside another controller like BaseController (inside the Project.Controllers namespace but below the BaseController class in that file), why do both classes throw the errors,
'ViewBaseWithLayoutModel' does not implement inherited abstract member 'WebPageExecutingBase.Execute()'
As well, the sixth code block references
<pages pageBaseType="Namespace.To.ViewBaseWithLayoutModel">
So in the above case would it be 'Project.Controllers.ViewBaseWithLayout'?
Any help would be greatly appreciated.
Related
I have a model class named Server, it contains many navigation properties and properties, which I want to prevent users from binding it. So I find two approaches of doing so to avoid over-posting attacks.
The first approach is to go to each model class and define an Exclude Bind list , with all the properties and navigating properties that should not be bind by users , as follow:-
[MetadataType(typeof(TMSServer_Validation))]
[Bind(Exclude = "Technology,IT360SiteID, VirtualMachines, TMSServer1,DataCenter,OperatingSystem,Rack,ServerModel,TechnologyBackUpStatu,TechnologyRole,TechnologyStatu ")]
public partial class Server {
}
}
The second approach is to create a view model class , with only the properties that can be modified by users as follow:-
public class ServerViewModel
{
public int ServerSize { get; set; }
[Required]
public String OperatingSystem { get; set; }
public String Commnet { get; set; }
}
I find that the first approach is faster to implement , as I only need to define the Exclude list, while the second approach will require me to create view-model class for each of the domain classes. So which approach is recommended to use and why ?
Thanks
Over-posting occurs due to the default model binder not knowing which fields you actually included in the form.
It will try to map all values in the request to object. Attackers can use your form to add additional fields to
query strings/form post data and add properties as part of the request. The default model binder won't
know the difference. Your Server class will deactivate once the mapping is complete and the update is processed.
To prevent over-posting, set the annotation to include fields in the binding, or create a ViewModel like you mentioned in your code.
So which approach is recommended to use and why ?
Both annotation and ViewModel allow binding only on specified fields, but when you use ViewModel you will not bind against business objects or entities, and you will only have properties available for the input you expected.
Once the model is validated, you can then move values from the input model to the object you used in the next layer.
k. Soctt Allen has a good article about which approach is better, you can take a look at by the following link:
http://odetocode.com/blogs/scott/archive/2012/03/11/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx
It's difficult to tell without seeing the rest of your code, but in general I'd say using the ViewModel is probably a better approach for the following reasons:
You separate your view from your business logic
It is safer. If in the future someone adds a property on Server and forgets the Bind-exclude, you're exposed to over-binding without knowing it. If you use the ViewModel-approach you have to explicity add new properties
Maybe this question is a little bit ambiguous because the answers are going to be based on opinions or something. But I'll try to answer it the best I can and indeed is kind of my opinion. So this is the way I see it:
First approach (Bind attribute): Is faster to implement because you only need to add on your class the name of the property you don't want to expose, but the problems comes when you want your class to exclude some properties for one feature and other properties for another feature, and you can't add fields and sometimes in MVC, the views need more fields that the ones provided by the model class and then you're gonna need to use ViewBag or something else. This approach is very handy for fast and smalls projects, but I still don't like to use ViewBag (For aesthetics reasons)
Second approach (ViewModels): Is more work, and more time but at the end (again in my opinion) you get a cleaner and ordered code and you don't need to use the ViewBag, because you can have the perfect object to send to the view depending on what this View needs, so if you a have an object with different views, again depending on the needs, they could share the same ViewModel or they could have a ViewModel for each one. If you have a solution or a big web project, this approach is going to be very handy to keep an ordered code.
Let me know.
So somebody asked me the question:
When would I return View() and when would I return PartialView()?
My immdiate reaction was, if it's a patial use PartialView(). Then I realised that I have quite often returned View() for a partial view with no, apparent, detremental effects?! So what's the point in the return PartialView() call?
I found this question What's the difference between “return View()” and “return PartialView()”. This appears to be particular to MVC2. i.e. talks about .aspx and .ascx control extensions. Using Razor all our views are .cshtml whether they are partial or not.
Which got my thinking is the PartialView() just a hangover from MVC2 and not really relevant in MVC3+ (When using Razor anyway)? Or am I missing some crucial feature of PartialView()?
tl;dr: PartialView() does not use a layout for the view being returned.
You can set a default layout file within _ViewStart.cshtml (located in the Views folder) which will then be used by all views. By doing that, you avoid having to set the Layout property within each view. PartialView() will not include that layout file or any other.
If you want to return a partial view, e.g. in a child action called using #Html.Action(action, controller), use PartialView. If you want to return a "full" view including the layout, use View().
MSDN Reference:
If you contrast the MSDN definition for ViewResult() Object with the MSDN definition for PartialViewResult() Object
you find the only difference is that ViewResult has an extra property:
public string MasterName { get; set; }
Otherwise, both Objects inherit from ViewResultBase and seem to inherit all other properties and methods from the base class.
Unfortunately, the implementation of the abstract method ExecuteResult() is not published, but I have no doubt it uses the MasterName field to find and render the Master Layer.
Our shared experience:
Just like you, I have returned partial views =using View(). I don't recommend it. But the apparent difference isn't big.
It does seem a touch wasteful to have an extra object just for MasterName, but the more important difference is probably the implementation of ExecuteResult().
When you choose View() method and create a ViewResult Object rather than using PartialView() to create a PartialViewResult Object, you are being less efficient; your application is doing the extra work of checking if your MasterName field is assigned.
Are helpers in MVC3 used in the controller as well as the views?
Is a helper the right place to put commonly used controller methods?
I want to create a common method to get all sub children IDs in a database and make sure it is in the right area. I just want to make sure I am putting my logic in the right area.
Thanks
You could implement a base Controller for that logic. Helpers, or extension methods, are good for when you don't want to change the interface for something.
The HtmlHelper is not available to the controller, because the controller should not be responsible for generating HTML, but the UrlHelper is available within the controller.
A method to get specific data from your database does not belong in your controller, or in a UrlHelper or an HtmlHelper. You should create a separate class for this logic, and then call the method on this class from within your controller. If you are using Dependency Injection, which I suggest, your controller code might look like this:
public class MyController
{
IMyDataUtil _dataUtil;
public MyController(IMyDataUtil dataUtil)
{
_dataUtil = dataUtil;
}
public ActionResult SomeAction(int parentId)
{
var childIds = _dataUtil.GetChildIds(parentId);
...
}
}
As you can see, this allows you to keep the data-access code in a class specifically designed for that purpose. The fact that this controller depends on that utility class is immediately obvious, and doesn't take that much more code than calling an extension method on a helper. Controllers that don't deal with that class's methods won't need to have it available.
On the other hand, if there are methods that are likely to be used by a bunch of different controllers, injecting this same data class into all of them may become cumbersome. In that case, you could:
Extend a base class that has an instance of the data-access class injected into it via method or property injection, and which then exposes it to sub-classes via a protected or public property, or
Create your own helper class that wraps the classes and methods you're likely to use in all your controllers, and inject that class so you only have one dependency for a variety of common functions, or
Combine steps 1 and 2.
If by "helpers" you're referring to things such as HtmlHelper then, no, these aren't used by the controller as in theory you could take your controllers and re-use them with an entirely different rendering engine (for example WPF) as the controller isn't responsible for rendering.
If you're talking about, as I think you are, helper classes/methods that manipulate your data ready for it to be put into a Model by a Controller and then handed off to a View for presentation, then you could consider a "business logic" layer. For example, if you were talking about (the ever typical) Bank Account example, you could have a:
public class BankAccountService
{
public IEnumerable<string> GetAllAccountIdsForCustomer(int customerId)
{
// Talk to the database here and retrieve the account id's for a customer
}
public string GetCustomerName(int customerId)
{
// Talk to the database here and retrieve the customer's name
}
}
Your controller would then:
public ActionResult AccountNumbers(int customerId)
{
var model = new AccountNumbersModel();
model.CustomerId = customerId;
model.AccountNumbers = BankAccountService.GetAllAccountIdsForCustomer(customerId);
return View(model);
}
Obviously in this example you'd need to have a class called AccountNumbersModel defined and you'd also probably want to consider using Dependency Injection to provide an instance of BankAccountService to your controller, but describing how to go about all that is kinda outside the scope of this answer.
The advantages this approach gives you are testability and separation, each piece of code is responsible for one task, and you reduce the complexity of each individual piece and make it easier to make changes without breaking things.
I want to create a common method to get all sub children IDs in a database and make sure it is in the right area. I just want to make sure I am putting my logic in the right area.
That sounds like a job for an ActionFilter.
I've been at this same question in different forms now for a while (see e.g. Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and it's still bugging me, so I thought I'd put it a little more generically:
I feel this can't be a very unusual problem:
You have an entity object (using Entity Framework), say User. The User has some simple properties such as FirstName, LastName, etc. But it also has some object property lists, take the proverbial example Emails, to make this simple. Email is often designed as a list of objects so that you can add to that object properties like Address and Type (Home, Work, etc). I'm using this as an example to keep it generic, but it could be anything, the point is, you want the user to be able to add an arbitrary number of these items. You should also be able to delete items (old address, or whatever).
Now, in a normal web page you would expect to be able to add these items in the same View. But MVC as it seems designed only makes it easy to do this if you call up an entirely new View just to add the address. (In the template for an Index View you get the "Create New" link e.g.).
I've come across a couple of examples that do something close to what I mean here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
and
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
The problem is, although the sample projects on these sites work fine, with mock model objects, and simply lists (not an object with a child list), it's a different thing if you actually want to do something with the posted information - in my case save to database through the Entity Framework model. To adapt these cases to that, all of a sudden I'm in a maze of intricate and definitely not DRY code... Juggling objects with AutoMapper and whatnot, and the Entity Framework won't let you save and so on (see above link if you're interested in the details).
What I want to get at is, is it really possible that this is such an uncommon thing to want to do? Update a child collection in the same View as the parent object (such as the email addresses in this case)? It seems to me it can't be uncommon at all, and there must be a standard way of handling this sort of scenario, and I'm just missing it (and no one here so far has been able to point me to a straighforward solution, perhaps because I made it too abstract with my own application examples).
So if there is a simple solution to what should in my view be a simple problem (since the design is so common), please tell me.
Have you tried updating the project at your link to Steven Anderson's blog to bind to a complex object? Create a class in models called Sack and give it a single property and see if you can get it to work.
public class Sack
{
public IEnumberable<Gift> Gifts { get; set; }
}
It only took me a minute to get it up and running as I think you intend. The improvement I would have made next would be to add an HtmlHelper extension that is essentially the same as Html.EditorFor(m => m.SomeProperty), only call it something more meaningful and have it interface with the prefix scope extensions provided in the project.
public static class HtmlExtensions
{
public static IHtmlString CollectionEditorFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if (/* type of expression value is not a collection */) throw new FailureToFollowTheRulesException("id10t");
// your implementation
}
}
My terminology is probably way off here but basically I'm trying to pass multiple data models to a view. To help put the question in context, take this example:
Say I was making a blog. When I log in I want the home screen to display a list of all new unapproved comments, as well as a list of recently registered users, and a list of the most recently submitted blog posts.
Most discussions I've seen suggest strongly-typing the view page so it can be called with something like "return View(RecentComments)" and iterate through the comments in the view, or to cast the data model like "var NewUsers = (MembershipUserCollection) ViewData.Model". What I'm ideally after is the 'right', or at least a 'right-enough', way of passing multiple models while still maintaining appropriate logic separation.
One way is to create a new type that encapsulates both pieces of model data:
public class MyBigViewData {
public SubData1 SubData1 { get; set; }
public SubData2 SubData2 { get; set; }
}
public class SubData1 {
... more properties here ...
}
public class SubData2 {
... more properties here ...
}
Another way is to store the "main" model data as the strongly-typed data and store other data in the view data as dictionary items:
ViewData["username"] = "joe"; // "other" data
ViewData["something"] = "whatever"; // "other" data
ViewData["subdata1"] = new SubData1(...);
return View(myRealModelData);
The advantage of the second approach is that you don't need to do anything special at all: It works right out of the box.
What I've done in the past is written a class that contained instances of both the classes I will need on the view.
ie
public class City{
public Mall TheMall;
public School TheSchool;
}
Then your view will be strongly typed as City, and you will use Model.TheMall.Property and Model.TheSchool.Property to access what you need
EDIT
This is an example of what other posters mean by creating an object with both objects as fields/properties
Sadly, the only way to accomplish passing multiple objects is either by creating an object with both objects as fields/properties, or by using a weakly typed array.
The way to pass multiple models to a view is to create what we call a Form View Model which has your other models within it.
Then in your view you can pass the individual models contained in your Form View Model to the Partial Views responsible for rendering the data in said models.
Makes sense?
edit
btw: a form view model is simply a class. it's not a special type as may have been suggested by my answer.
In addition to my other answer, another way to do this would be not to strongly-type the view and master pages in the page directive, but instead make use of the generic type-based ViewData extensions from MVC Contrib. These extensions basically use the fully-qualified type name as the ViewData dictionary key. Effectively, the typing benefits are the same as the strongly-typed page approach, with less class overhead in terms of the number of view model classes required. Then in your actions you do
ViewData.Add<Car>(car);
ViewData.Add<LayoutAData>(layoutAData);
and in the views you do
<%= ViewData.Get<Car>().Color %>
and in the master page you do
<%= ViewData.Get<LayoutAData>().Username %>
You could cache these Get<> calls inline in the views to mitigate the cost of casting multiple times.
After working on a large ASP.NET MVC app, I found the approach that was most productive while minimizing runtime casting was based on using generics to mimic the nested structure of views. Essentially views get their own data type. Typically these are either domain objects, or collections of domain objects that include metadata. Generic versions of these types are available across all possible master pages, taking a type parameter that defines data relevant to the master page.
public class Car {
// can be used as a model
}
public class CarCollection: Collection<Car> {
public BodyTypes BodyType {get;set;}
public Colors Color {get;set;}
// can also be used as a model
}
public interface ILayoutModel<TLayout> {
TLayout LayoutModel {get;set;}
}
public class CarView<TLayout>: Car, ILayoutModel<TLayout> {
// model that can be used with strongly-typed master page
}
public class CarCollection<TLayout> : CarCollection, ILayoutModel<TLayout> {
// model that can be used with strongly-typed master page
}
public class LayoutAData {
// model for LayoutA.master
}
public class LayoutBData {
// model for LayoutB.master
}
It's also possible to invert the generic-ness, but since the view dictates the layout, the view data should dominate over the layout data in my opinion. LayoutA.master would derive from ViewMasterPage<ILayoutModel<LayoutAData>> and LayoutB.master would derive from ViewMasterPage<ILayoutModel<LayoutBData>>. This keeps the view data and the layout data separate, in a consistent, strongly-typed and flexible way.
Creating an object that can encapsulate your other objects is the best way to go. Otherwise you're stuck with a bunch of ugly ViewData tags in the controller and the view.
One thing no one seems to have mentioned is that in the original questioners example, it might make sense to create the view out of a series of child actions that handle their own area of functionality rather than making a mega view model. That way the components such as unnapproved messages etc can be reused.
This also gives better encapsulation.