Pass EntityModel to view in asp.net mvc? - asp.net-mvc

I have An EntityModel that is named ECommerceEntities that contains several entities. If I want to use this model in a view in asp.net mvc, Can I pass ECommerceEntities instance to view or Sould I pass one entity in ECommerceEntities.
I mean :
//Can I use this?
public ActionResult Index()
{
ECommerceEntities entity = new ECommerceEntities();
return View(entity);
}
or
//Should I use this?
public ActionResult Index()
{
ECommerceEntities.OneEntity one_entity = new ECommerceEntities.OneEntity();
//filling one_entity here and then send to view
return View(one_entity );
}
Thanks.

If you are asking if it is possible, it is possible to do both. Yes, both options will work. However if you only need the sub entity in the view, I would just pass the sub entity into the view. No use in passing in more than needed right?
Do not forget that in MVC whatever object you pass in to your view,(EcommerceEntities for example) can have its properties set in the post by MVC's automatic model binding which maps data from the post into the object you pass into the view.
So, this means that someone can hijack the http post and can fill in EcommerceEntities and its sub entities with various bits of random data of their choosing if you are not careful and you may accidentally save this data to your db because you did not expect some of these properties to get set.
So, when working in MVC you have to protect properties that are not being used in your view but are passed into the view to ensure that nobody has injected them.
If you do decide to pass in EcommerceEntities, make sure that you use whitelisting or look at MVC's bind attribute to protect your data when your entity is posted back to your controller.
Because of the work involved in protecting that much extra data, I would say that the sub entity would be best if the screen will populate correctly just off of the sub entity object.
Hopefully this is helpful.

If you want to display a list of all entities (which the Index action is typically used for), you probably want to get all the entities from your database context:
public ActionResult Index()
{
// assumes dbContext is already initialized
ICollection<ECommerceEntities> entities = dbContext.ECommerceEntities
return View(entities);
}

Related

Web API OData Actions with Entity as parameter

I have a requirement to encapsulate pieces of business logic within a transaction in an OData Web API service. Some of these pieces will need to accept one or more entities.
An example use case might be StockProduct and this might accept a Product entity and a Location entity. It would create the product and update stock records for the Location.
The approach I've taken is to create an unbound OData action that accepts these entities so that both of these can be operated on in a single transaction. Unfortunately neither can Entities be used as an ODataActionParameter nor can they be part of a class and used as a complex parameter.
I can think of a two ways around this:
Create a DTO class that is not an entity that is a mirror of each of my mirror classes and convert from DTO to Model within my action. The problem here is that I already have a DTO for each Model eg. Product.cs and ProductDTO.cs and don't really want to have to create a third class. (Currently, the ProductDTO.cs is used for Posts, Puts, Patches and Deletes and the Product.cs is used for Gets).
Abandon OData actions and create a simple end point that accepts whatever I like. I'm not keen on going down the second route as I'd like to use OData exclusively.
Any thoughts or suggestions?
You can use the ActionConfiguration.EntityParameter() method to bind an entity as a parameter to your OData action method.
Here is an example:
ActionConfiguration validate = ModelBuilder.EntityType<TEntity>()
.Collection.Action("Validate");
validate.Namespace = "Importation";
validate.EntityParameter<TEntity>(typeof(TEntity).Name);
validate.CollectionParameter<string>("UniqueFields");
validate.Returns<ValidationResult>();
However, note that the ModelState will not check against the content of the supplied Entity and will set any missing properties to null and properties exceeding the StringLength(x) annotation in your model will still pass. If you wish to validate the entity itself after, use this bit of code in your action method:
[HttpPost]
public virtual IHttpActionResult Validate(ODataActionParameters parameters)
{
//First we check if the parameters are correct for the entire action method
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
else
{
//Then we cast our entity parameter in our entity object and validate
//it through the controller's Validate<TEntity> method
TEntity Entity = (TEntity)parameters[typeof(TEntity).Name];
Validate(Entity, typeof(TEntity).Name);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IEnumerable<string> uniqueFields = parameters["UniqueFields"] as IEnumerable<string>;
bool result = Importer.Validate(Entity, uniqueFields);
return Ok(result);
}
}
As for your StockProductDTO, it seems to me that this is an new Business Entity by itself and should be treated as such.
You can use a batch request to perform multiple operations within a single request. This allows you to use your existing controllers for inserting your two objects.
https://aspnetwebstack.codeplex.com/wikipage?title=Web+API+Request+Batching

ASP MVC 4 managing object state in controller

I am new to MVC and am having a conceptual problem with state and object persistence and hope someone can put my thoughts in order.
I have a remote webservice which provides methods to manage orders. An order consists of a header and Lines as you would expect. Lines can have additional requirements.
I have my domain objects created (using xsd2code from the webservice schema), the webservice calls and object serialization all working fine. I've build the DAL/BLL layers and it's all working - tested using a WinForms testbed app front-end.
I have view model objects mapped from the domain objects using Automapper. As the order is returned from a single webservice method complete with lines etc I have an OrderViewModel as follows
public class OrderViewModel
{
public OrderHeaderViewModel OrderHeader { set; get; }
public List<OrderLineViewModel> OrderLines { set; get; }
public List<OrderLineAdditionalViewModel> OrderLineAdditional { set; get; }
public List<OrderJustificationViewModel> OrderJustifications { set; get; }
}
Firstly I'm wondering if I should dispense with the OrderViewModel as if I pass this as a model to a view I'm passing far more data than I need. Views only need OrderHeader or OrderLines etc - not the entire order.
Now my conceptual problem is in the controllers and the views and object persistence.
My Order controller has a Detail Action which performs the load of the order from the webservice and maps the Domain object to the OrderViewModel object.
public ActionResult Details(string orderNumber)
{
OrderViewModel viewModel = new OrderViewModel();
var order = WebServiceAccess.LoadOrderByOrderNumber(orderNumber,"OBOS_WS");
viewModel = AutoMapper.Mapper.Map<BusinessEntities.Order, ViewModels.OrderViewModel>(order);
return View(viewModel);
}
But the Order/Details.cshtml just has the page layout and a call to two partial pages for the header and the lines (I swap the Headerview for a HeaderEdit using Ajax, same for the LinesView)
#{ Html.RenderPartial("DetailsHeaderViewPartial", Model);}
#{ Html.RenderPartial("DetailsLinesViewPartial", Model);}
At the moment I'm passing the model into the main Details container page, then into the RenderPartials, However I don't think that the model should be passed to the main Detail page, as it doesn't need it - the model is only needed in the DetailsHeaderViewPartial, DetailsLinesViewPartial so I'd be better off using #RenderAction here instead and passing the model into the Header/Lines views instead.
However, The Order is retrieved from the webservice in the ActionResult Details() how can I make the retrieved OrderViewModel object available in the ActionResult HeaderDetails() / LineDetails() methods of the controller to pass as the model in return PartialView(...,model) ?
Should I use a User Session to store the Order ViewModel so it can be used across actions in the controller.
Moving on from this stage the user will be able to maintain the order (add/remove lines - edit the header etc). As the webservice call to save the order could take a few seconds to complete I'd rather only call the save method when the user has finished with the order. I therefore would like to persist the in-progress order locally somewhere whilst it's being worked on. User session ?
Many thanks for any advice. Once I've got my head around state management for the ViewModels I'll be able to stop reading a million Blog posts and actually write this thing !
You actually have a few questions here so I will try to address them all the best I can.
1) Dispensing with the view model : I would say no. The view model represents the data that you need in order to populate your view. It seems like you are using the view model as an identical container to the domain model object. So you are asking if you should dispense with it and just pass the domain model to the view while your original concern is that you are passing along more data then you really need as is?
Rather then dispensing with the view model, I would revisit your properties on your view model. Only use properties that you need and create the mapping logic (either with automapper or on your own) for taking the complex domain object and populating the properties on the view model.
summation: build the view model to be only things that the view needs and write mapping logic to populate that view model.
2) This is just a statement of best practice before I breakdown your specific scenario.
You describe your architecture as having a BLL and DAL. If that is the case then you should not be persisting any objects from your controller. The controller should not have any knowledge of the database even existing and the objects used in the controller should have no idea of how to persist themselves. The objects that are going between your controller and the web service should strictly be Data Transfer Objects (DTO's). If you are unfamiliar with what constitutes a DTO then I highly suggest that you do some research and try to build them into your solution. It will help you conceptually see the difference between view model objects, domain objects and data transfer objects.
3) I would not try to store an order object in the session. I would re-analyze how you are breaking up the partial views within the view so that you can call actions with the ordersviewmodel being the parameter in a way that you need. It sounds like you are needlessly breaking up views into partial views.
4) You should not be concerned with state management for the view model object. Your view (which can be comprised of many partial views) is filled based on properties provided by the view model. The user can make changes using the UI you have developed. Since you express the desire to only save once they are finished making all changes to optimize calls to the web service, you just need to repopulate the fields of the view model upon clicking submit. Now you have a "state" for orderviewmodel that represents the users changes. You can send this object to the web service after converting back to a DTO (if you do what I said above) or by mapping it to the domain object.
1 final note. You are using automapper to map your domain to the view model. I am assuming that your view model is too complex and includes things that you don't need because you built your view model to emulate the domain object so that automapper could map by naming convention. Automapper has an api for doing complex (custom) mappings that fall outside of standard same name properties. Don't let automapper constrain you to building your view models a certain way.
Hope this helps

Get an Entity in Save Method, What is correct form?

I'm begginer in asp.net mvc and i have some doubts.
P.S: I'm using DDD to learn
I have an ACtion in a Controller and it'll save an entity (from my model) by a repository (for a database).
My doubts is, How can I get the informations from the View and save it by a repository in my Controller ?
Is it correct to get an entity of my Model in Save method of controller, like this:
public ActionResult Save(Product product)
{
// validate object
// save data in repository
return View("Success");
}
Or Need I get an DTO (with a structure similar to my entity) and create an object passing property by property to an entity ?
I didnt' like of FormCollection and I'd like to know, What is recommended architecturally ?
Thanks a lot guys
Cheers
I you want to follow DDD practices as described by the Blue Book you should bind your views to DTO's which can be forwarded to a thin 'Application' layer where Domain objects are created or retrieved from database. This application layer can be a simple facade with methods or can leverage command pattern.
For a live demo, you can see my project -- DDDSample.NET
This kind of problem can be fixed by adding so called view model.
Basically - a view model is DTO that provides data for particular view. In similar fashion - view models are used to get data back from view via model binding. Then - controller just forwards necessary data to domain model.
Typically, in ASP.NET MVC your controller actions will receive strongly typed objects returned by the DefaultModelBinder when editing entity types. Using this pattern you can pass a "Product" to your GET view either by itself or as part of a DTO and then your "Save" method would receive a "Product" object in its parameter list.
So long as you are using either editor templates or fields with matching names (i.e. Html.TextBox("Name") corresponds to Product.Name) then the DefaultModelBinder should be able to correctly fill the typed entity object passed to the action method. You shouldn't have to mess with the FormCollection except in certain edge cases.
[HttpGet]
public ActionResult Create() {
return View("Create", new Product());
}
[HttpPost]
public ActionResult Create(Product product) { //or Save(Product)
...
}
As long as your form has fields which match the fields in Product, they should automatically be populated for you based on the values. How you save the entity depends on the data model, whether you're creating a new record or editing an existing one, etc.

Model Binding With Entity Framework (ASP.NET MVC)

Earlier I created an AddClient page that (when posted) passed a client object and I used db.AddToClient(obj) in my repository to persist it. Easy stuff.
Now, I have a details page whose save submits a post to an action "UpdateClient". Before that action is hit, my custom model binder creates my Client object and it's conveniently handed to the action. The thing is, this client object is not connected to a EF context yet. Where is the correct place to do that? In the modelbinder, or maybe when we get it from the controller, or perhaps we wait until we do a repository call and link it up there? What's the recommended process?
From what I remember, you will either need to attach the object again to the context and set it as modified
Or reload the object from the database and apply your changes.
This article explains it better:
http://msdn.microsoft.com/en-us/magazine/ee321569.aspx#id0090022
What version of EF are you using ?
If an EF object has been created outside a context, you need to Attach the object to the context.
See: http://msdn.microsoft.com/en-us/library/bb896271.aspx
I know this is an old thread but in the interest of new readers:
Based on my observations using VS 2012, MVC 4 and EF 4.0 with a view that has an EF object for a model that submits a form back to the controller.
On the controller:
public ActionResult SubmitEFObject(tblData data, FormCollection col)
"data" will only have the properties used in the view (#Html.xxxFor) filled.
It appears that when "data" is created, the posted FormCollection is used to set data's properties. If you had a property that wasn't used, DataID for example, then data.DataID will have a null/default value. Add a "#Html.Hidden(m => m.DataID)" to your view and THEN DataID will be filled.
As a 'quick n dirty' way to work with this, I created a method that would merge the incoming 'data' with the 'data' in the database and return the merged object:
// Note: error handling removed
public tblData MergeWithDB(DBContext db, tblData data, params string[] fields)
{
tblData d = db.tblData.Where(aa => aa.DataID == data.DataID).Single();
if (fields.Contains("Field1")) d.Field1 = data.Field1;
if (fields.Contains("Field2")) d.Field2 = data.Field2;
if (fields.Contains("Field3")) d.Field3 = data.Field3;
// etc...
return d;
}
On the controller:
public ActionResult SubmitEFObject(tblData data, FormCollection col)
{
DataEntities db = new DataEntities();
tblData d = MergeWithDB(db, data, col.AllKeys);
db.SaveChanges();
}
You could make this more generic using reflection or maybe more efficient by looping through the string[] fields instead of all the ifs but for my purposes this was 'good enough'.
Database work should be put in the repository call.
Are you directly binding to an entity framework object in your model binding? If not, you should consider do some mapping between your custom object and entity framework object.

Using LLBL as Model in MVC

I have settled on trying to use ASP.NET MVC but the first part I want to replace is the Model. I am using LLBL Pro for the model.
I have a table called "Groups" that is a simple look up table. I want to take thhe results of the table and populate a list in MVC. Something that should be very simple... or so I thought.... I've tried all kinds of things as I was getting errors like:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[glossary.CollectionClasses.GroupCollection]'.
private GroupCollection gc = new GroupCollection();
public ActionResult Index()
{
gc.GetMulti(null);
return View( gc.?????? );
}
This is all I am trying to do, I've tried lots of variations, but my goal is simply to take the data and display it.
Not sure if this would work, but you could try wrapping the EntityCollection into a ViewModel class and passing it to the View like so:
public class GroupsViewModel()
{
public GroupCollection Groups { get; set; }
// other items in your view model could go here
}
then convert your controller method to
public ActionResult Index()
{
GroupCollection gc = new GroupCollection();
gc.GetMulti(null);
GroupsViewModel vm = new GroupsViewModel();
vm.Groups = gc;
return View(vm);
}
I like this approach because each ViewModel is an object in-and-of itself.
You can use the AsEnumerable extension where your ????? are or change the type of your ViewUserControl(in the markup) to be of type System.Collections.Generic.List. Basically what you need to correct is the mismatch between the type of the View and the Model being passed in.
I'm not sure about your exact error, but I'd venture a guess that one of two things are happenging:
You are making some sort of invalid / illegal call on your LLBLGen object. If this is the case make sure you are setting it up right / calling right method / property etc.
The model you are passing to the veiw is too hairy for it to deal with. In this case, and in general, you should create a light 'View Model' class with just the data you want displayed and populate it from your LLBLGen object first then pass it to the view, which will be able to easily handle your view model class.
Here are some references:
http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx
http://nerddinnerbook.s3.amazonaws.com/Part6.htm
http://www.codinginstinct.com/2008/10/view-model-inheritance.html
Stemming off what Yuriy said, it looks like your view is strongly typed to a "collection" of a collection of your groupentity, and you are trying to pass just the collection of your groupentities. Make sure your "collection" type (IEnumerable, IList, etc) matches what type of collection you are sending in your controller, along with the type of the actual object in the collection.
View:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Controller:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Just a thought

Resources