I am using to show controller and action name as below to use in my Views-BreadCrumb
#ViewContext.RouteData.Values["Controller"] / #ViewContext.RouteData.Values["Action"]
Output of this query is
HrMapPersonCertificate / Create
But i want to show different name for controllers. IE : Certification / New Certificate
Can i change the display names of actions and controllers?
EDITED
Actually i have some trouble with your solution. I did what you said but ie. in my Person model, now it has two more variable, route1 and route2. Route1 = "Person Information", Route2 = "Action Name : View Person". But i am using the same view also while editind or inserting with using this model. I am in trouble.
You should not be using the internal names of Controllers and Actions for displaying routes on the web site. This will make things hard to maintain and customize on the view-side of things (as you can see with this question) and inappropriately mixes the meta-data of your server side with the presentation level.
A better approach would be to create a BaseModel object that always contains the values that you want to display in your route:
public class BaseModel
{
public string Route1 {get; set;}
public string Route2 {get; set;}
}
The setup can obviously change - you could use different names or even a List<string> of names to store more than two, but the idea is to not be hard-coding the controller and action names into your view.
Then use pass this model through to every view and use these values to display your route.
#model BaseModel
...
#Model.Route1 / #Model.Route2
Every single model that you pass to every single View on your site that uses this layout should inherit from BaseModel. Thus these properties will be available to use on every single view. So if your current model on a given page is called MyModel, just change its definition to be public class MyModel : BaseModel and you can then use the BaseModel properties as well.
Related
I have noticed a pattern that in some MVC applications I inherited from a previous developer. When defining the models all the information containing the items for selects and check-boxes are passed in the model.
public class MyModel
{
int MyEntityField1 {get;set;}
string MyEntityField2 {get;set;}
public selectList SelectItens1 {get;set;}
public selectList SelectItens2 {get;set;}
}
...
MyModelInstance.SelectItens1 = new selectlist(...
MyModelInstance.SelectItens2 = new selectlist(...
return view (MyModelInstance);
the information on SelectItens1 and SelectItens2 is one way. What is the advantage of doing as above instead of using the ViewBag to pass Select Items to the view ?
public class MyModel
{
int MyEntityField1 {get;set;}
string MyEntityField2 {get;set;}
}
...
Viewbag.SelectItems1 = new SelectList ( ...
Viewbag.SelectItems2 = new SelectList ( ...
return view (MyModelInstance);
I think it just makes the model fat for no gain whatsoever.
Please advise.
Both approaches are fine, its just a developer preference
First Approach:
There is no harm in having the SelectListItem within your model, Moreover it gives you a clear picture of what the fields must be in your UI, So looking at the model you can confirm that the UI needs to render a dropdown list control for the 2 properties in your example.
Second Approach: If this model is used only in one or minimal pages then Viewbag should be okay. Again this might mean that the developer must have knowledge on what control the UI must render.
So the approaches are purely developers choice and I don't see any major performance improvements of one over the other.
I personally use the first approach as it more clean and keeps the controller code less.
Generally I would agree that models should be kept to the minimum.
However with Microsoft ASPNET MVC pattern you want to keep your controller clean and Microsoft they recommended approach is to fatten your Model and not your controller!
"In general, you should strive for fat models and skinny controllers.
Your controller methods should contain only a few lines of code. If a
controller action gets too fat, then you should consider moving the
logic out to a new class in the Models folder."
https://www.asp.net/mvc/overview/older-versions-1/overview/understanding-models-views-and-controllers-cs
I have the following model:-
[MetadataType(typeof(TMSServer_Validation))]
[Bind(Exclude = "TMSRack,ServerModel")]
public partial class TMSServer
{
}
and I have the following drop down inside my view:-
#Html.DropDownListFor(model =>model.Server.TMSRack.DataCenterID, ((IEnumerable<TMS.Models.DataCenter>)ViewBag.DataCenters).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.Name),
Value = option.ID.ToString(),
Selected = (Model.Server.TMSRack != null) && (option.ID == Model.Server.TMSRack.DataCenterID)
}), "Choose...")
Then on my controller class I have the following :-
ViewBag.Racks = repository.getrelatedracks(Server.TMSRack.DataCenterID);
But since I have excluded the TMSRack navigation property (mainly to avoid over-posting attacks), so the Server.TMSRack.DataCenterID will always be null. And to get its value I wrote the following:-
ViewBag.Racks = repository.getrelatedracks(Int32.Parse( Request.Form["Server.TMSRack.DataCenterID"]));
But I know that using Request.Form is not the right approach to follow, so my question is there a way to get the excluded property using more reliable way ?
Thanks
My answer is going to assume TMSServer is a domain model.
With that in mind, this is the perfect example of when to use a view model. By using a view model instead, you have complete control over how the properties are mapped from the view model to the domain model. Something like:
public class RackViewModel
{
public int DataCenterID
// other Rack properties
}
Then either send a list of RackViewModel to your view, or create a view model that encompasses all of that, too:
public class ContainerViewModel
{
public List<RackViewModel> Racks { get; set; }
// other view-specific properties
}
Now, when you POST the data back, not only do you have complete control over what properties you want to bind to your view models, you also have complete control over the mapping that takes place from converting your view models to domain models.
The bottom-line is this: if your view accepts a view model that only allows the user to POST the data they should be allowed to POST, over-posting doesn't even exist. Well-designed view models, or even making the distinction between a view model and an input model (i.e. a separate model that represents the data you want to bind back to in your action), eliminates over-posting entirely.
Over-posting only exists because you're not restricting the model binding process enough. If you ask it to bind to a class that has 10 properties in it when you only need 3 you're allowing the user to potentially stuff data into those other 7 properties.
This is one reason why view models are so popular. They allow you to narrow the scope of your view, whilst also narrowing the scope of the model binder. That leaves you free to properly manage the process of mapping from your view model to your domain model, without introducing a vulnerability.
Update
As you don't want to go the view model approach, your idea will work but you can do it slightly differently. Something along the lines of:
public ActionResult SomeAction(SomeModel model, TMSRack rack)
Where:
SomeModel is the type of model you're decorating with Bind(Exclude...) (it's not obvious what type that is from your question.
TMSRack is the type I assume you want to bind to.
As TMSRack is defined in your main model anyway, as long as you're using the Html.* helpers, it will have the correct names generated for it on the form in order to bind straight back to it as a separate parameter on your action. Then you can do whatever you want with it, without resorting to Request.Form.
There's probably a really basic answer to this question but I am new to Entity and MVC and am getting used to the basics.
I'm trying to automatically generate a MVC controller for the main table Sites with a dropdown for server. It seems like I would need a model like this:
public class Sites
{
public TTSites TTSites { get; set; }
public List<servers> server { get; set; }
public Sites()
{
server = new List<servers>();
}
}
This is using the classes TTSites and servers both with string server
But if I set this as my model class and my entity database as data context it says I need to define a key. Should I be using the base classes instead of the model or what? Do i need to set something up in the model or base class?
It seems like you've got some terminology confused. You code the controller actions in a controller class, and the routing engine determines what controller action to call based on the URL. For example, if you have a HomeController class with a default Index action, it might look like this:
public ActionResult Index()
{
// code here
}
This would be invoked with the default routing, if you went to your site with a URL like this (let's say your site can be hit via the www.mysite.com URL:
http://www.mysite.com/Home
That would get you into the Index action in the controller.
Ordinarily, one would use a view model to use on the UI side, and that would be populated from an entiy with the data you need in the view itself. If you had two entities like TTSite and Server, you'd populate the Sites view model like so, as a (very simple) example:
public ActionResult Index()
{
var servers = yourDbContext.Servers.ToList();
var ttSite = yourDbContext.TTSites.GetByID(1); // retrieve one entity by its ID value, this would be acquired dynamically based on some sort of user input rather than hard-coded
var viewModel = new Sites(servers);
viewModel.TTSite = ttSite;
return View(viewModel);
}
I'm not including anything regarding making drop-downs, just illustrating getting data into a view model and then creating a view with that view model.
Note that you would not use the Sites class as an entity but rather a view model, and setting its data based on entities from your database. You wouldn't be setting any primary keys in a view model class; those are the concern of the data model, and you've presumably already got those entities (such as TTSite) set up in a usable fashion in your data layer.
Once you've got a controller action and a view up and working, you can turn to getting the view model data into a form usable by a drop-down list, and going from there.
I'm using the ASP.NET MVC DefaultModelBinder to bind a request to a model class, but only using two of its properties:
namespace MVCApp.Models
{
public class Ticker
{
public string Symbol {get; set;
public string Exchange {get; set;}
}
}
namespace Domain //in another assembly
{
public class Quote
{
public string Symbol {get; set; }
public string Exchange {get; set; }
//lots of other properties we need for output
}
}
public ActionResult ShowQuote(Ticker ticker)
{
var quote = quoteRespository.GetQuoteBy(ticker);
return View(quote);
}
In the view, they can specify the Ticker and Exchange; and that's ModelBound using the DefaultModelBinder. However, each time we need to actually use this Ticker object for something, we need to go to the QuoteRespository and get all of the properties populated for that Ticker.
Question
Should I get rid of the Ticker Object and just create a custom modelbinder to Model-bind to the Quote object; and in the Modelbinder make the respository calls to actually fill out the Quote object? Or should I violate DRY and make the call to that respository in every place we need a quote? Is there a built-in framework way of doing this that I'm missing?
It appears there is a school of thought that says not to make service-layer calls in the Modelbinder.
Update
I created the Ticker class just because we had these two properties in (almost) every single action:
public ActionResult ShowQuote(string symbol, string exchange)
Since they always belong together, I created a small Model class in the UI layer to push them around together (the aforementioned Ticker class). Ticker is not a view model class, and it isn't meant to be.
"Or should I violate DRY and make the call to that respository in every place we need a quote? Is there a built-in framework way of doing this that I'm missing?"
You could always retrieve the quote as part of a Quote controllers OnActionExecuting function.
I wouldn't consider this a DRY violation. Just the cost of doing business. Chances are the way you retrieve quotes won't change and you'll probably have < 10 places were you need this functionality. Depends on how many times you'll need to include that line.
Better to have short and concise action methods than getting all mangled up in base controller and onactionexecuting stuff.
Don't get into model binding against your repository. Did it in a previous project and its the worst and most brittle piece of the application.
I would use AutoMapper to map between view models and domain models.
For me it would be important to see what does Quote contains ? You mention it has other properties for output but does it have other properties and methods which are only relevant to the Domain namespace? If yes then I would like to keep an abstraction between the types used for views and the types in your domain namespace.
So you could end up having a TicketViewModel which contains everything required by your views and as Darin mentioned, use AutoMapper to map TicketViewModel to Quote.
EDIT:
If you really want to ensure DRY, then you can create your own ModelBinder (it's easy, tons of tutorials on Google) and bind your viewmodel from repository in it.
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.