I have a MVC3 web application where I need to implement a database search functionality. I am creating a ViewModel class for my search form so that I get the search parameters from View to controller. I can successfully get all my search parameters (which includes search query and check boxes if user wants to narrow search) in my controller class and retrieve data from database using repository pattern
var searchResult = _repository.GetItems(searchParms, chkbox1, chkbox2, ..., chkbox10)
After this, I am passing my searchResult to pagination helper like
var paginatedSearchResult = new PaginatedList<Items>(searchResult, page ?? 0, pageSize);
I am displaying the retrieved data in my view page
return View(paginatedSearchResult)
The problem, I am facing is, besides the data from the database, I also need to show the search query string and topic (for which checkbox was used) in my view page so that user can see what they searched for. I did not find any proper solution to this and had to use ViewBag. And now my Controller page looks ugly with more than 10 ViewBag. I know there must some good solution to this but I am not able to find it.Any suggestions will be highly appreciated.
Thanks,
ACS
Direct answer to question's title is - alternative for viewbag in mvc is strongly typed ViewModel classes. Take a look at Create View Models
You are soooo close already.
You have a ViewModel you are using for the search - so you obviously know how to create a view model. Just create a new ViewModel that has your current ViewModel as a property and the database search viewmodel as a property.
public class SearchViewModel
{
public YourExistingSearchOptionsViewModel SearchViewModel {get;set}
public PaginatedList SearchResults {get;set;}
}
obviously that is very rough - but hopefully you get the idea there.
I think you might be searching for the strongly typed "ViewData" property
Related
I spent days to know the problems of my work, but no luck.
I created new MVC4 Web API project.
Add EF5 with my database (Project>Add>ADO.NET Entity Data Model>Create from database which is in Azure SQL).
Add two tables to edmx as below. And two *.tt files generate entities and model classes successfully.
I can see the breakpoint(result) gives query result normally.
But json gives abnormal stream without error message. (ie, http://localhost:41813/api/sheet/157 returns "157" which cannot download. in general, "157.json" is downloaded)
I copied properties in results to my handmade POCO-style class and it works.
What is my problem? I cannot use generated model classes to send data through Json.
I hardly find out problem because no error message and no debug step available after the result breakpoint.
The reason the serialization fails are yours Navigation Properties - while the serializer is trying to walk the object graph they result in circular dependencies.
For your simple sample to work you have few ways around it.
Remove Navigation Property Sheet from SheetDetail
Wrap your objects in ViewModel classes with Navigation Property Sheet omitted
Create a metadata class with JsonIgnoreAttribute and then attach it to your entity with partial class and MetadataTypeAttribute
Here you can find sample for third solution (sample makes some assumptions as I don't know your exact data types):
public class SheetDetailSerializationMetadata
{
[JsonIgnore]
public Sheet Sheet { get; set; }
}
[MetadataType(typeof(SheetDetailSerializationMetadata))]
public partial class SheetDetail
{
}
As #danludwig comment, http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization gives all answers about my problem.
Add below code in Global.asax solves the problem.
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;
I do know there are several similar questions out there that address this topic, but I am not happy with the answers.
What I'd like is to take full advantage of the Razor View engine that can use strongly typed views with layout pages and partial views. I'd like to declare the model at the top of my views and just pass in that model. So simple! No dynamic models that need to be constructed explicitly just before passing them into the view. EDIT: I'd like to do this outside of a Web application, inside a class library that can construct email bodies. That's the real issue here is making use of the Razor View Engine that is not a web app.
The idea behind this is if I have a User object with 20 properties on it and my first version of the Welcome email only uses the Name, but later I want to edit the template to use their City, State or Email address, then I want to be able to update the Razor view without having to add code and recompile and redeploy.
I see RazorEngine and I love the idea and simplicity, but everything is a dynamic type. My issue here is that I'll be pulling data as models from the database. By having to shove things into a dynamic type, I don't get all my properties on the View.
I also see MvcMailer, which is also nice in theory but it suffers from the same issue which is that all data models passed into the view are dynamic and not strongly typed.
I've begun to build out my own version of this, which will require several web namespaces like System.Web.Mvc, System.Web.Razor and System.Web.WebPages - and I'm okay with that. The issue is the lack of HttpContext and ControllerContext and RouteData .... which I'm trying to mock/stub so the. I'm currently trying to investigate DisplayModes and figure out how to mock these outside a real Web context.
Is there a better way? If you're going to suggest one of the two previously mentioned frameworks, please note my issues and let me know if there are workarounds.
EDIT 2: After playing a bit more with the RazorEngine, the strongly typed models is not necessarily as much of an issue as I thought. What I'm left wishing for now is the ability to use a Layout page and partial views as well. I can hack around this with string placeholders that get replaced, but probably not very efficient AND not very flexible.
Assuming you are trying to achieve this from within an action method of a controller, here's a simple way to do it.
This method will give you the output of a strongly typed view :
public static string RenderViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
try
{
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null);
ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.ToString();
}
}
catch(Exception ex)
{
return ex.ToString();
}
}
Then from within a controller method, all you need to do is call this method with the name of the view and the model.
public ActionResult Mail()
{
// whatever you use to get your User object
var model = new User();
var output = this.RenderViewToString("~/Views/User/Email.cshtml", model)
}
This will allow you to simulate the rendering of a strongly typed view, including its associated layout, and gather the output as a string which you can then use to send via email.
The answer is that it doesn't seem to matter whether the object passed in is dynamic or not. I can pass my strongly typed object, and it will be accepted as is without needing to make it dynamic or rebuild a dynamic object.
My prelim tests show that this should be fine and works well.
Try out Actionmailer.net: https://bitbucket.org/swaj/actionmailer.net/wiki/Home
I've been using it quite successfully.
Check out RazorMachine. It's like RazorEngine, but works with layouts.
We are working on an ASP.NET MVC 3 using ext.net and EF 4.
Data model is mapped using EF4.
Views’ content is rendered from customizable XML files.
Example: Within one view, I can display fields that are related to both objects “customer” and “order”, so from this view I can modify the customer data and also add a new order.
How can we bind the view to the custom model that contains 2 objects (customer and order)? Using non strongly typed views will require a source code that will check all different possibilities (If I remove/add a field to display from the XML file, object constructor and CRUD operations parameters will change also.
We are wondering how can we handle such dynamic application?
Is this a common issue that was raised before? Or is there any solution to use dynamic views bound to custom model (object, xml, etc.)?
Your help is very appreciated, please enlighten me.
Based on what you replied to my comment, I can defenitely say that you need strongly typed views. That said, you decide what the model of your view is. If your view needs to manage users and orders at the same time, you can make a class like this:
public class MyCustomViewData
{
public IEnumerable<User> Users {get;set;}
public IEnumerable<Order> Orders {get;set;}
}
and then strongly type your view to MyCustomViewData and you're set. My example is oversimplified but I think you can get the point.
Unless I'm missing something, I believe the normal way round this would be to strongly type your view to say 'user' and then on the user object, define a property which is a collection of 'orders'.
I need some suggestions about how to generates a view where data comes from 3/4 models.
I have attached an image where data is coming from 3 models. I have done that in web form using 3 different gridviews and binding different data sources.
But now I have to do the same in MVC 3 and finding it difficult.
I would really appreciate if anyone can give me some guide line about how to generate such view.
I would define a Model containing 3 Properties
public class CompositeModel
{
public MenuModel Menu {get; set;}
public OrderModel Order {get; set;}
public RestaurantModel Restaurant {get; set;}
}
And pass this model to the view.
You could, pass all your models through as properties of the 'Model' object, and then use partial views to render each section, passing through the particular model they use.
#Html.Partial("ViewName", this.Model.SubModel)
Or, use child actions, and have a separate action method for bit of the page. i.e. add this to your parent view:
#Html.Action("ActionName", "ViewName")
The advantage with the latter is you can using caching policies ([OutputCache] attribute on your action) for parts of your page which are more static that other parts.
You can use Tuple() to return more than one recordsets (models) to a view. Tuple() is a new feature in C# 4.0. View this article about Tuple().
http://www.abhisheksur.com/2010/11/working-with-tuple-in-c-40.html
You can use partialViews, and render them on page, or you can pass as much data as you want through Viewbag. Example:
ViewBag.Model1 = yourModel1;
ViewBag.SomeData = someOtherData;.....
And then in view you yust use it:
#ViewBag.Model1
You could even get data through ajax calls, and by the looks of your sample I would take that approach and use jquery templates to render view.
If a view needs to acces data from a model, do you think the controller should:
a) pass the model to the view
b) pass the data of the model to the view
c) neither; it shouldn't be the controllers concern. Let the view access the model directly to retrieve the data. Only let the controller give some parameters the view needs to filter the data from the model.
d) it depends on the situation.
e) none of the above, but [...]
Thanks
After some debate in the comments to an answer that was deleted by the user, maybe this needs clarification. My view of the MVC architecture is biased towards that of the Zend Framework (php) in which an action in a controller by default has a default view assigned to it. So it's not so much the model that dictates which view is approporiate, but rather the controller. Do you feel the model should dictate what view is appropriate? The only way I see fit to let the view be build based on a model, is by letting the controller pass the model to the view. Are there other techniques to let a view access a model without the controller being involved? Or is it perfectly fine to let a controller pass the model to a view, so that the view can be build based on the models attributes?
e) None of the above; pass in a view-optimised "ViewModel".
Example in ASP.NET MVC:-
public ActionResult Details(int id)
{
Product p = ProductService.GetProductById(id);
if(p == null) { return RedirectToAction("Index"); }
ProductViewModel model = new ProductViewModel(p);
return View(model);
}
both a) and b) "will do" subject to d). Never ever c).
Typically, the ViewModel just encapsulates the Model (if nothing complicated is going on, your view could access the model directly via ProductViewModel.Product). If the view needs to do anything complicated with the Model however, it's the ViewModel's responsibility to do that, rather than the responsibility of the Controller, or the View.
This keeps your concerns nice and segregated. Your Controller doesn't care exactly what specific data your View needs (beyond the fact that it's rendering some Details of a Product), or especially what format your View needs that data in. Your View doesn't depend on the implementation details of your Model. Your Model doesn't have to concern itself with how it's being Viewed. If you have two Views rendering Products (e.g. Create, Edit, Summary, MoreDetails etc), those Views can have different ViewModels to expose only the data that each specific View needs, so your Views aren't depending on eachother. Lovely :)
Some further reading from various viewpoints:-
http://www.thoughtclusters.com/2007/12/datamodel-and-viewmodel/
http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx
http://www.nikhilk.net/Silverlight-ViewModel-MVC.aspx
I think ViewModels are a particularly .NET thing, but I see no reason at all why the pattern can't be used in PHP.
Hope this helps.
Ideally, it should "pass the data of the model to the view" so the view doesn't need to know any explicit structure of the model and thus be more reusable and designer-friendly.
But practically, "pass the model to the view" works as just fine. Most of the time you will need a new view anyway because clients never share favorite colors (if you know what I mean :-) so views re-usability doesn't justify having a lot of tedious code required to copy data from the model to the view.
What you should concern more about is the modularity of the controller itself, since many websites do share common functionalities (controllers) such as web forums or a news listing but not looks (views)
This is late I know, but I'm having this issue on a project I am working on. I started with a) - for simplicity - and now running into road blocks.
I am coming around to this method:
e) None of the above; pass in a view-optimised "ViewModel".
because it avoid bloating both your model classes (instances of which are "transaction objects") and your views. For example, you may need to render a number with a specific number of decimal places (this is the problem I am having now).
With an intermediate "ViewModel" this is easy - you just write the relevant ViewModel "getXXX" method to return the number formatted how you wish.
If you just pass the model directly into the view, you will need to specify it in the view every time you use this figure (going against DRY - don't repeat yourself), or alternately, add a rendering method to your model classes (which goes against a class being for one purpose only).
Cheers
a) pass the model to the view
Otherwise the controller is manipulating the view via screening the model. This is what would happen in "b) pass the data of the model to the view". The b) option doesn't really even make sense in the pure MVC pattern. After all, the model IS the data. If the model is changed for consumption, a view has been applied, whether you choose to do it in the controller and pass it off as a controller function. What happens when you have a different view? Does the controller screen its data differently? You soon have two views for model, the controller sub-view and the view itself.
For me that's e).
As already mentioned here, ideally the view and the model are decoupled. The way I prefer to implement this is to have a viewHelper for a model. This has the API the view can use to get the data. Now views are not affected by changes in the model and the view doesn't need to 'get' the internals of the model. These are hidden away by the viewHelper.
example:
class Post {
public function export(ViewHelper $helper) {} // I try to avoid getters when I can
}
class PostViewHelper {
public function getTitle($parameters) {} // title of current post in the loop
}
class PostView {
private $helpers = array();
public function loadTemplate($path) {}
public function addHelper(ViewHelper $helper, $name) {}
public function __get($key) {} // if exists $this->helper[$key] etc
}
in a template
<h1><?php $this->post->getTitle(); ?></h1>
You may want to implement this differently. But my point is in how the view and the model are decoupled, introducing an intermediate viewHelper wich creates the view/template API.
I don't think it's that complicated. a or b.
The controller's job is to manage the relationship. It finds the model and view and provides the view all the model data it needs to do its job. That's it. MVC doesn't dictate the exact form the data takes.
(a) Start simple. It's pretty natural to pass the model objects directly to the view. If you have a page about a Foo, just pass the Foo.
(b) But at times-- and only at times-- you create a value object / DTO to get the data to the view (called a ViewModel above). Do this when there's a mismatch between the view and the native model, such as summary views. If the view is presenting a summary of 1,000,000 objects, you don't want to hand the view the model objects; you want to hand the view a summary of the 1,000,000 objects.
And the exact implementation really depends on the language and framework you are using. But I think these guidelines are a good start.
uhh b.
i dont really see the difference between a and b other then some technicallity of how you will be passing data.
usually you pass a map of data to the view with some data from the model