First of all, I realise that the core of my problmen probably is the way that I'm trying to solve it, so let me first explain what I'm trying to do.
I have a Layout where I output a property.
Layout.cshtml
inherits Umbraco.Web.Mvc.UmbracoTemplatePage
...
//More of the layout here
<title>#Model.Content.GetPropertyValue("title")</title>
...
This is the base of the other templates:
FullWidth.cshtml
#{ Layout = "Layout.cshtml"; }
... layout here
This all works well, I make sure every document type has a property called title and it gets printed all the time.
Now I'm creating a page, where some data from a database is being displayed. So I created a custom controller:
public class ProductController : RenderMvcController
{
public ActionResult Index(Rendermodel model, int id)
{
var viewModel = new CustomRenderModel(model.Content);
viewModel.Product = Database.GetProductById(id);
return CurrentTemplate(viewModel);
}
}
This works great too, but the next thing I want to do is also set the title based on whatever is retrieved from the database. Something like this:
var viewModel = new CustomRenderModel(model.Content);
var product = Database.GetProductById(id);
viewModel.Product = product;
viewModel.Content.SetPropertyValue("title", product.name");
Obviously this doesnt work because the IPublishedContent is readonly. I'm just wondering what the best way is to modify a property like that.
I realise that exposing a SetPropertyValue is a bad idea probably, but what would be the way to solve this.
I would render this title in a separate partial view and give that partial view a specific model to render.
Have a look at this blog post I wrote which shows you how to do that.
http://www.codeshare.co.uk/blog/how-to-optimise-your-website-for-search-engines-seo-in-umbraco/
Kind regards
Paul
I know, this is an old post, but other people might search for a solution to this question. It absolutely makes sense to be able to overwrite property values, especially in route hijacking scenarios. The solution is to write an own implementation of IPublishedContent. It only needs a few lines of code. The solution is shown in this blog post:
https://www.formfakten.de/themen/2018/08/publishedcontent-with-overridden-properties
Related
From what I read in various tutorials, or simply the sample project, the Controller use the ViewBag to store anything that will be dipsplayed on the page.
In the Controller I can just type ViewBag.AnythingIWant = "Foo";, and it'll render in the HTML. Apparently that's what is done in the sample project, at least for title and various texts.
But most of the text is hardcoded in the HTML and obviously I don't want that. Considering I'm not new to C# or MVC in Xamarin (mobile development), I feel like I should grasp this pretty quick, but I don't. Could someone clarify to me the following :
My Controller knows the ViewModel (which does most of the work) and himself uses the Model privately. I'm used (from iOS dev) for the controller to be the last layer of UI, and inside the controller I would just have all my labels and whatever I want, and I can fill them with whatever is available in the ViewModel.
Here, there is this HTML layer that I don't know how to connect to the controller.
I have a strong feeling that putting everything in the ViewBag cannot be the way to go. Could anyone briefly reveal the piece I am missing to use proper objects inside the HTML ?
Razor might be what's confusing me, considering whatever I add publicly in my Controller, I can't find it in the related HTML using #MyProperty
I know this is pretty broad question but I know that I only miss a small piece of knowledge to unlock everything.
As noted in the comments, pass a ViewModel to the View to be rendered!
Controller
public ActionResult Index() {
var viewModel = new MyViewModel { Name = "some string" };
return View("Index", viewModel);
}
Index.cshtml
#model MyViewModel #* Tell Razor which ViewModel to expect *#
#{ string name = Model.Name; }
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...
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)
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.
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.
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.
I'm hoping you guys can answer me a question?
I've only just started out using ASP.NET MVC3 have come unstuck at a certain point. I've been learning this stuff from books and I'm slightly unsure on a few things.
Can a VIEW, only have one #Model reference?
At the moment I have a VIEW setup with a HTTP-POST on a ViewResult, that validates the data in the View, entered by the user and then "on post", passes this info to a method that writes it back to a database(ADO.NET - Access). Now I need to change my VIEW, so that I can replace a couple of my text boxes for Dropdownlistfor controls. The Data to populate these controls will need to be passed in from the Database.
Would I be correct in saying that this data needs to be passed in the HTTP-GET Viewresult of the page, and if so, can i reference more than one #Model in this same View (*.cshtml).
I have a class that takes in the user response, and this is referenced in the View. But will i need to create a new class for the dropdownlist data and reference that too. So that in the background I populate the data into a SelectListItem, pass it to the View and then populate each drop down control within the view?
I'm sorry if this is poorly written, very hard to explain, I find learning from books hard and I'm pretty stuck now. Any help would be appreciated. Just to give me an understanding of how this all wraps around. I'm comfortable with the C# syntax, but very unsure of MVC3!
There are two ways you can handle this.
Use a View Model.
In this scenario you have a class that contains your data model as well as other things required by the view, so something like this:
public class ViewModel
{
public MyDomainModel Model { get; set; }
public IEnumerable<SelectListItem> SelectListItems { get; set; }
}
Use ViewBag.
In this case you add everything extra into the ViewBag dictionary. So in the controller, you'd have stuff like this:
ViewBag.SelectListItems = new SelectListItem[] { ... };
Then you can reference in the view itself
#Html.DropDownList("myselectlist", ViewBag.SelectListItems)
I think that this will help you pluralsight mvc3 intro. It sure helped me
I'm trying to create a weblog with mvc. I made a database code first with EF. Now I have a page where you can see one post per page. Below I want to show all comments on the post. Thats all working fine. But now I want to make a create comment functionality on that same page.
I'm not sure how to do this? Because this has to create a new object 'comment' instead of the 'post' object I've set as Model in my view. So I've got different models in my view? I don't think that's possible right? Maybe I can just use the 'post' model because it has comments as a list<> in it?
Do I need to use partial views for this or maybe a model view?
Hope you know what I mean and what I'm trying to accomplish. Tnx in advance for any help!
If your Post model contains a List<Comment> then you could of course use that. Even if you do go that route, using a ViewModel to wrap all of your model objects is never a bad idea.
Simply for the sake of maintainability, I would use partial views for the different models rendered on your page, but that's is purely a matter of personal preference.
Yes you can do it by using a partial view. Make a partial view that posts comments to server. Display this partial view below comments list. When user post the comment then submit it via json call and on success make html string of comment and append it in the comments list.
In this way your comment will be posted as well as loaded in comments list without reloading the whole model
Your post should have a comment collection of some sort. You should be able to just add a non-model-bound form; in your controller, you have your collection, just pull the data out of that.
What I mean is: in your view, you'll have something like
#Html.TextArea("CommentText")
In your controller:
public ActionResult Create(FormCollection collection) {
string commentText = collection["CommentText"];
Post p = ... ; // Not familiar with EF
p.Comments.Add(new Comment(commentText));
p.Save(); // ActiveRecord style, not sure about EF
}
It should be pretty straight-forward. I use ActiveRecord on NHibernate, so I'm not sure about Entity Framework specifically. Was there some specific problem you got stuck on?
After I found this in our code, I realized a few things:
"get it done now, get it right later" has a limit
I don't actually know where this goes with MVC3
#model int
#using Company.Core.Logic.Financial
#using Company.Core.Repositories
#{
var values = from AccountPlan e in new AccountPlanRepository().GetItemList()
where String.IsNullOrEmpty(e.PromoCode) // filter out promotional plans
select new { id = e.AccountPlanId, name = e.Description };
var items = new SelectList(values, "id", "name", Model);
}
#Html.DropDownListFor(m => m, items)
This specifically is an editor template (#Html.EditorFor(m => m.AccountPlan)), but it made me realize that I don't know where this kind of code goes for common things like menu-builders. If you're using Layouts for MVC3 (and who isn't), where is the code for building a menu across the top based on the user's roles? I'd imagine the view code would be iterating through pre-built menu items and HTML-ifying them, but since the Model is strong-typed, does that mean that all Models need to have knowledge of the menu items?
For once, this is where Webforms made more sense to me, since this would go in the CodeBehind, but I really want to get away from that.
edit: even though I started asking about Layout code, I'm under the assumption it works for EditorTemplates and DisplayTemplates as well. If this is an incorrect assumption, please let me know where these are supposed to go.
edit2: What I ultimately want is to have a clean, possibly even dependency-injectable place to run code that's called from an EditorTemplate. Perhaps this is a case where the EditorTemplate calls immediately into a RenderAction?
Looks like this solves the problem pretty well (see the marked answer, not the original question):
http://forums.asp.net/t/1566328.aspx/1?Building+ASP+NET+MVC+Master+Page+Menu+Dynamically+Based+on+the+current+User+s+Role+s+quot+
Basically, call RenderAction(...) and it will build the model it needs, rather than forcing you to have every model require a list of menu items.
For me personally, I do a lot of menu filtering based off of active directory groups so I need to know what their access levels are across the entire application.
I create a new controller that I call ControllerBase
public class ControllerBase : Controller
{
//authorization group setting an menu creation here.
//set properties and objects to ViewBag items to access from the front end.
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
and then on all the other controllers in my project I just extend from ControllerBase
public class HomeController : ControllerBase
{}
This keeps all my server logic in one file for managing permissions and gives all my pages access to these variables when I need to hide or show different ui elements based on permissions.
Child Actions are perfect for this scenario. The logic required to generate the view is wrapped up in a controller action, like normal, and the view that wants to make use of the child action simply renders the action..
You can also cache these partial views, which would make sense for something like a main menu - as presumably the users permissions won't change that often.
e.g.
[OutputCache(Duration = 300)]
[ChildActionOnly]
public ViewResult MainMenu()
{
var model = GetMenuModel();
return View(model);
}
The view that wants to render the child action does so like this.
#{ Html.RenderAction("MainMenu", "Account"); }
And thus the view calling the ChildAction has no need to know what model the view requires.
There are also overloads on RenderAction, should your child action require you to pass parameters to it.
You shouldn't (have to) access the Repository inside the View. That belongs in the Controller.
And the Menu is implemented in the Masterpage, you don't give much details on specifics.