in ASP.NET MVC application I want to verify entity ownership on edit action (already on get).
I have implemented custom IPrincipal, so I have actual user ID, but how to compare it with entity property?
The only way I see is to load the entity and compare it, which makes bunch of if conditions in every action method.
Ideal would be some attribute, but inside the attribute I have only the entity ID, not the entity itself and you can't pass any object (nor entity neither repository) to attribute.
How do you solve this?
Thanks
I solved this by extension method over the EntityBase implementing interface IOwnedEntity (with two properties: Id and OwnerId).
In this extension method I compare the IOwnedEntity.OwnerId with actual user Id (got from cookies) and if not equal I throw my own typed exception (NotAuthorizedException).
Related
I have an action that has this signature:
public ActionResult Update(ContactForm contactForm)
ContactForm is a class from an edmx file. No code first. Its EF 5.0.0.
The edmx file is auto generated.
I have a relation from ContactForm to ContactFormField, which causes a navigation property.
I named it "Fields". It is of type
EntityCollection<ContactFormField>
When I have fields (and only then) included in the posting caused by post variables that looks like this:
ContactForm.Fields[0].Name=foo&ContactForm.Fields[1].Name=bar
etc...
I get an InvalidOperationException before the action is even called.
It occurs in the setter of Fields.
The message is:
The EntityCollection has already been initialized. The
InitializeRelatedCollection method should only be called to initialize
a new EntityCollection during deserialization of an object graph.
If I try to have an action that takes Fields separately, adding an argument like
public ActionResult Update(ContactForm contactForm,
IEnumerable<ContactFormField> fields)
...those will be retrieved correctly, but for each field I have yet another list of ContactFieldAlternative. In other words, I need to be able to post sub objects.
How do I get rid of the exception?
The problem here is how the model binder is interpreting your URL string. The model binder doesn't have any logic which allows it to assume that multiple parameters in the URL string represent the same object. Therefore, instead of creating one instance of ContactForm and binding your fields, it's trying to create an instance of ContactForm and bind Fields[0] to that, then trying to create another instance of ContactForm to bind Fields[1] to, which obviously your method signature doesn't accept. Without creating a custom overload to the model binder, you really can't submit your form values with this URL pattern (and shouldn't anyway, imo). The intended method for accepting a complex object through a post is either through form elements or JSON. One of the prime objectives of the ASP.Net MVC framework is the use of restful URLs, which your parameter list in the URL isn't.
I'm new to MVC and I've been looking through a bunch of examples.
For the HttpPost on some edits they call UpdateModel(entity).
In other examples such as:
http://www.asp.net/mvc/tutorials/mvc-music-store-part-5
UpdateModel(entity) isn't called at all.
What's the point of calling this function when it appear unneccessary in MVCMusicStore?
Apparently it " Updates the specified model instance using values from the controller's current value provider."
However I've found from the MVCMusicStore example the updated values are already posted through?
Could someone please explain this to me?
There should be no reason for you to use UpdateModel in the newer version of ASP.NET MVC
Originally it was provided because when you posted your data back to the action on your controller, a FormsCollection would be passed in to to the action and then a call to UpdateModel(entity) would be required.
However in newer versions of ASP.NET MVC the concept of ModelBinding has been introduced which will allow your actions to define a .net object to be passed in to your action methods and the model binder will take care of "binding" the values to the model.
To be completely honest, I'm not sure why they don't just deprecate the UpdateModel() method because AFAIK it's completely redundant.
Use UpdateModel for PATCH semantics. From RFC5789:
The PATCH method requests that a set of changes described in the
request entity be applied to the resource identified by the
Request-URI.
This means you are making modifications to an existing resource (e.g. from the database).
Use the object as action method parameter for PUT semantics.
The difference between the PUT and PATCH requests is reflected in the
way the server processes the enclosed entity to modify the resource
identified by the Request-URI. In a PUT request, the enclosed entity
is considered to be a modified version of the resource stored on the
origin server, and the client is requesting that the stored version be
replaced.
In practice, there's not much difference if the request contains values for all of the resource members. But if the request only contains values for a subset of the resource members, in PATCH the other members are left unmodified, and in PUT are set to their default value (usually NULL).
i don't think ModelBinding is only introduced in newest version of asp.net mvc (newest version is 3). it was present at least in v-2 so far as i can tell. when you call the updatemodel you call Modelbinding explicitly. when you receive at as action method parameter Modelbinder is called implicitly.
In Edit scenario updateModel is used when we fetch original entity from db and tell controller to update it using UpdateModel like
public ActionResult Edit(int id)
{
var entity = db.GetEntity(id);
UpdateModel(entity);
db.SaveChanges();
}
Other scenario is when you are not fetching db entity but ModelBinder gives you an entity created from form fields etc. and you tell you db that object is already there and it has been modified outside the db and you better sync with it like in MusicStore tutorial.
I am somewhat confused on how to properly use LINQ in combination with an ASP.NET MVC strongly typed view.
My situation is as followed.
1) I retrieve a single object through LINQ
2) I pass this LINQ object to a strongly typed view. (edit form)
3) The user submits the form and the controller receives the LINQ object.
So my questions are:
1) Is the object the controller method receives after the submit still tight to the original datacontext or is it a newly created instance?
2) What is the preferred way to store the updated values in the database using LINQ. If it is still tight to the original datacontext a simple call to SubmitChanges() would be sufficient. But how to maintain the datacontext?
I would like to be able to save these data objects without having to use really ugly linq update statements. (Like retrieving the row again and manually update its values)
Any help, insights and preferably code samples would be appreciated.
Regards,
Dennis
You should fetch the existing object again, and update it, somthing like:
public ActionResult Edit(int ID)
{
DataEntity entity = _service.GetMyEntity(ID);
UpdateModel(entity);
//Saving code goes here.
return View();
}
The entity that you are talking about retrieving is no longer attached to the data context.
Is the object the controller method
receives after the submit still tight
to the original datacontext or is it a
newly created instance?
It won't be attached to a DataContext at all on Submit.
What is the preferred way to store the
updated values in the database using
LINQ. If it is still tight to the
original datacontext a simple call to
SubmitChanges() would be sufficient.
But how to maintain the datacontext?
The preferred way is to create a new DataContext, retreive the old object from the database, update the fields based on what was submitted to your Form, and then save the updated copy from the new Context.
Use your linq objects to get the data and put it into a POCO (plain old c# object) Model specifically for your view.
Your linq2sql/ef objects can be structured to store data which do not necessarily reflect your views
Your model can be updated and validated by the MVC framework by placing it in the call to the post.
public ActionResult EditPost(EditModel model)
When you have a valid model you can then transfer the data back to the database via your linq2sql/ef objects
if(ModelState.IsValid) // save to db
Create a DataContext when you need to load and save, don't persist it
1) It is a new instance (through model binding feature) and it is not attached.
2) It depends, but the best would be probably new instance using(var context = new DBContext()) etc.
3) The most simple thing is fetch the object, pass in the updated values and SubmitChanges() (as you describe). Other option is described in this article. You create new instance of the object (or you have it from the model binding), attach it to the context and submit changes:
public ActionResult Test(MyModel model)
{
DbContext.Models.Attach(model);
DbContext.Refresh(RefreshMode.KeepCurrentValues, model);
DbContext.SubmitChanges();
}
I have a site where I'm using fluentNhibernate and Asp.net MVC. I have an Edit view that allows user to edit 8 of the 10 properties for that record (object). When you submit the form and the Model binds, the two un-editable fields come back in the view-model as Empty strings or as default DateTime values depending on the type of property.
Because I'm also using AutoMapper to map my view-model to my Domain Entity, I cannot just load a fresh copy of my object from the database and manually set the 2 missing properties. Whats the best way to persist those fields that I don't want edited?
One way that does work is to persist the values in hidden Input fields on my View. That works but feels gross. I appreciate any recommendations. Is there a way in my AutoMapper to configure this desired functionality?
UPDATE:
Ok, So I guess I'm not trying to ignore the fields, I'm trying to make sure that I don't persist null or empty string values. Ignoring the fields in AutoMapper does just that, they get ignored and are null when I attempt to map them before Saved to my repository.
The asp.net mvc DefaultModelBinder is extensible, and you can override it to create your own binding schema. But this will involve more work than two "hidden Input fields", which , in my point of view, is not that gross.
You can tell Automapper to ignore the 2 properties:
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());
Possible related question.
Can you use the AutoMapper.Map overload that also accepts TEntity?!
entity = Mapper.Map(viewmodel, entity);
As long as you do not have the properties on your viewmodel, it won't change the values on your entity. It takes the entity being passed in and applies only the properties from the viewmodel back to the entity.
Short: how does modelbinding pass objects from view to controller?
Long:
First, based on the parameters given by the user through a search form, some objects are retrieved from the database.
These objects are given meta data that are visible(but not defining) to the customer (e.g: naming and pricing of the objects differ from region to region).
Later on in the site, the user can click links that should show details of these objects.
Because these meta data are important for displaying, but not defining, I need to get the previously altered object back in the controller.
When I use the default asp.net mvc modelbinding, the .ToString() method is used. This off course doesn't return a relevant string for recreating the complete object.
I would have figured the ISerializable interface would be involved, but this is not so.
How should I go about to get the desired effect? I can't imagine I'm the first one to be faced with this question, so I guess I'm missing something somewhere...
The default model binding takes form parameters by name and matches them up with the properties of the type specified in the argument list. For example, your model has properties "Price" and "Name", then the form would need to contain inputs with ids/names "Price" and "Name" (I suspect it does a case insensitive match). The binder uses reflection to convert the form values associated with these keys into the appropriate type and assigns it to the properties of a newly created object of the type specified by the parameter (again derived by reflection).
You can actually look at (and download) the source for this at http://www.codeplex.com/aspnet, although you'll have to drill down into the MVC source from there. I'd give a link to the DefaultModelBinder source, but the way they are constructed, I believe the link changes as revisions are introduced.
So, to answer your question, you need to have parameters (could be hidden) on your form that correspond to the properties of the object that you want to recreate. When you POST the form (in the view) to the controller, the binder should reconstitute an object of the specified type using the form parameters. If you need to do translation from the values in the form parameter to the object properties, you'll probably need to implement your own custom model binder.
[EDIT] In response to your second post:
Let's say that we want to have a link back to an action that uses a customized object. We can store the customized object in TempData (or the Session if we need it to last more through more than one postback) with a particular key. We can then construct the action link and provide the key of the object as value to the ActionLink in an anonymous class. This will pass back the key as a Request parameter. In our action we can use the key from this parameter to retrieve the object from TempData.
<%= Html.ActionLink( ViewData["CustomObject1",
"Select",
new { TempDataKey = ViewData["CustomObject1_Key"] }
) %>
public ActionResult Select()
{
Entity custObj = null;
string objKey = Request.Params["TempDataKey"];
if (!string.IsNullOrEmpty(objKey))
{
custObj = (Entity)TempData[objKey];
}
... continue processing
}
#tvanfosson
Thanks for your explanation, but what about links? (no forms involved)
Currently the Html.ActionLink(c=>c.Action(parameter), "label") takes objects as parameter. These have to be translated into URL parts. For this, MVC ALWAYS goes to the .ToString() method. I don't want to serialize my object in the ToString method.
Shouldn't I be able to somehow help the framework serialize my object? Say through the ISerialize interface or something?