I was going through a action method code and i saw one attribute was used there but i really did not understand the use. here is the code
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
if (!ModelState.IsValid()) return View(user);
try
{
user.save()
// return the view again or redirect the user to another page
}
catch(Exception e)
{
ViewData["Message"] = e.Message;
return View(user)
}
}
([Bind(Include = "Username,FullName,Email")]User user)
i just do not understand the above line Bind include etc
so please help me to understand this kind of attribute used & when people write this kind of code in mvc. it will be really good help if some one make me understand with sample small code where they will use this Bind attribute.
Update:
Suppose i have form from where user can enter only FirstName,LastName & Gender then my action method looks like
public ActionResult Edit(string FirstName,string LastName,string Gender)
{
// ...
}
this will work i think. then why i should use a Bind Attribute because my above action method will works fine.
Bind attribute lets you "fine-tune" the model-binding process of certain parameter Type, without registering a custom ModelBinder specific to the Type.
For example, assume your Action is expecting a Person parameter defined as follows:
public class Person
{
public Person(string firstName, string lastName, Gender gender)
{
this.FirstName = firstName;
this.LastName = lastName;
if (gender == Gender.Male)
this.FullName = "Mr. " + this.FirstName + " " + this.LastName;
else
this.FullName = "Mrs. " + this.FirstName + " " + this.LastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
// 'FullName' is a computed column:
public string FullName { get; set; }
}
And the Action:
public ActionResult Edit(Person person)
{
...
}
Now, if someone is posting the following JSON:
{
"FirstName":"John",
"LastName":"Smith",
"Gender":"Male",
"FullName":"Mrs. John Smith"
}
Your Action will now have a person with the wrong FullName ('Mrs' instead of 'Mr').
To avoid such behavior you can use the Bind attribute and explicitly exclude the FullName property from the binding process ('Black-list'):
public ActionResult Edit([Bind(Exclude="FullName")] Person person)
{
...
}
Alternatively, you can use Include to ignore ('Black-list') all properties and only include ('White-list') the specified properties:
public ActionResult Edit([Bind(Include="FirstName,LastName,Gender")] Person person)
{
...
}
More info on MSDN.
When this action is executed the MVC model binder will use the request parameters to populate the user parameter's properties, as you may already know. However, the Bind attribute tells the model binder to only populate properties with names specified.
So in this case only the Username, FullName and Email properties will be populated. All others will be ignored.
See here for more details: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/
The Bind attribute is one way to protect against over-posting in create scenarios. For example, suppose the Student entity includes a Secret property that you don't want this web page to set.
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public string Secret { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Even if you don't have a Secret field on the web page, a hacker could use a tool such as fiddler, or write some JavaScript, to post a Secret form value. Without the Bind attribute limiting the fields that the model binder uses when it creates a Student instance, the model binder would pick up that Secret form value and use it to create the Student entity instance. Then whatever value the hacker specified for the Secret form field would be updated in your database. The following image shows the fiddler tool adding the Secret field (with the value "OverPost") to the posted form values.
The value "OverPost" would then be successfully added to the Secret property of the inserted row, although you never intended that the web page be able to set that property.
It's a security best practice to use the Include parameter with the Bind attribute to whitelist fields. It's also possible to use the Exclude parameter to blacklist fields you want to exclude. The reason Include is more secure is that when you add a new property to the entity, the new field is not automatically protected by an Exclude list.
Related
I am trying to learn and understand C# Web API and MVC.
I understand the simple tutorials where one has a simple Product or Person class as a Model and then makes a CRUD Controller to make use of the model.
But I need it to be a bit more complex and can't figure it out.
I have following Model:
public class PersonModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public DateTime LastUpdated { get; set; }
}
Same as the table in my database. The LastUpdated column has a default constraint: (GETUTCDATE())
I am not interrested in exposing LastUpdated in my POST methods in PersonsController:
public void PostPerson(PersonModel person)
{
// Upload person to database
}
Because then one could insert an invalid datetime in LastUpdated - or I have to manuel set LastUpdated in my business logic, but why not just let my SQL server do it?
Anyway to hide LastUpdated in PostPerson?
As a sidenote I would like to be able to show LastUpdated in my GetPerson method.
How is that possible?
When you implement a property in a class, you can specify different access modifiers for the get vs. set accessors.
This is true whether you are implementing the property yourself, or using an automatic property.
Different combinations of access modifiers include:
get/set both public – client can read/write property value
get/set both private – client has no access to the property
get public, set private – property is read-only
get private, set public – property is write-only
// get/set both public
public string Name { get; set; }
// get/set both private
private string SecretName { get; set; }
// public get => read-only
public string CalcName { get; private set; }
// public set => write-only
public string WriteOnlyName { private get; set; }
You could create a custom DTO as a view model for the POST operation on this controller. This would be additionally handy because you probably also don't want the client to supply the Id value either (I assume). Something like this:
public class PersonDTO
{
public string Name { get; set; }
public string Title { get; set; }
}
This would be the input for the controller action:
public void PostPerson(PersonDTO person)
{
// Upload person to database
}
Then in the code you'd create a new PersonModel to add to the data context. Something like:
using (var db = new MyDataContext())
{
var newPerson = new PersonModel
{
Name = person.Name,
Title = person.Title
};
db.Persons.Add(newPerson);
db.SaveChanges();
}
(Or perhaps create a kind of translation method on the DTO which returns an instance of the model, acting as a sort of factory method and putting the logic in the object rather than in the controller.) This way the client isn't providing an entire PersonModel instance, just an object which describes the creation of that instance. The GET operation can still return the full PersonModel.
When building an API (using WebAPI, for example) it can often be really useful to fine-tune the inputs and outputs like this. And such custom DTOs/ViewModels really come in handy, albeit at the cost of slightly more code by creating essentially a translation layer to the backing models.
One tool I've found particularly handy in determining where in the API I need to tweak things is when using Swagger to generate my API docs. Looking through the generated docs, I may notice something which I don't want to be exposed. This is an indicator that I need to customize that API endpoint a little more so that the resulting docs are a little cleaner.
Try adding the exclude attribute above the property
[Exclude]
public DateTime LastUpdated {get; set(}
I'd like to bind to a dynamic object from the request querystring in ASP.NET Web API. Whilst decorating the action parameter with [FromUri] works with a normal class, it does not appear to work with dynamic (the dynamic object is empty).
public dynamic Get(string id, [FromUri]dynamic criteria)
{
return Ok();
}
Note that this needs to work for GET requests so there is no body.
You might be interested in the GetQueryNameValuePairs extension method (docs).
While it doesn't bind the query parameters to a model, it does allow you to access query parameters in a dynamic way (which sounds like your ultimate goal) via a dictionary-like object.
Also, see this answer.
var dict = new Dictionary<string, string>();
var qnvp = this.Request.GetQueryNameValuePairs();
foreach (var pair in qnvp)
{
if (dict.ContainsKey(pair.Key) == false)
{
dict[pair.Key] = pair.Value;
}
}
No it can't work.
The [FormUri] attribute tries to bind the object properties to the query string properties by name.
A dynamic object has no properties so it can't bind.
You can create your own model binder to achieve this goal. I don't suggest for you to go that way, but it is possible.
The "problem" with dynamics in this case is that it is not compiler safe and you can get errors at runtime if the parameters you expect are not part of the request.
While Web API complains that Multiple actions were found that match the request when overriding the Get method with a single parameter, you can "trick" the default model binder into binding the model you want by adding another parameter.
public class House
{
public string Color { get; set; }
public double SquareFeet { get; set; }
public override string ToString()
{
return "Color: " + Color + ", Sq. Ft.:" + SquareFeet;
}
}
public class Car
{
public string Color { get; set; }
public double EngineSize { get; set; }
public override string ToString()
{
return "Color: " + Color + ", cc: " + EngineSize;
}
}
public class ValuesController : ApiController
{
public string Get([FromUri] bool house, [FromUri] House model)
{
return model.ToString();
}
public string Get([FromUri] bool car, [FromUri] Car model)
{
return model.ToString();
}
}
Using the above code, the following URLs produce the respective output:
~/api/values?house=true&color=white&squarefeet=1500
<string>Color: white, Sq. Ft.:1500</string>
~/api/values?car=true&color=black&enginesize=2500
<string>Color: black, cc: 2500</string>
There is something weird going on in my app. It's not dammageable, but it's a curious behavior and I'm reaching out to you to understand what's happening.
I was working on some partial view based on a model, and it worked. I figured out I had to replace a lot of stuff with the correct input.
So here's a snippet of my old model:
public class SearchObjInfo
{
public string m_ObjName { get; set; }
public string m_ObjType { get; set; }
public decimal? m_ObjNumber { get; set; }
public string m_ObjSymbol { get; set; }
public string m_ObjPower { get; set; }
}
And here's the same snippet with the new class I made to construct this partial view:
public class SearchObjInfoPartial
{
public string m_ObjName { get; set; }
public IEnumerable<SelectListItem> m_ObjType { get; set; }
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:0}")]
public int m_ObjNumber { get; set; }
public IEnumerable<SelectListItem> m_ObjPower { get; set; }
public IEnumerable<SelectListItem> m_ObjSymbol { get; set; }
}
Now the way the render is made is actually quite identical, and not. I used lots of stuff like these before:
<label>
Text: Write a name, part of a name, or a word.
</label>
Object Name: #Html.TextBox("_objectName") <br/>
Object Number: <input type="number" min="0" max="9999" name="_objNumber" value="decimal" style="width: 70px"/><br/>
Type: #Html.DropDownList("_objType", "All") <br/>
Power: #Html.DropDownList("_objSymbol", "=") #Html.DropDownList("_objValue", String.Empty)<br/>
But now I render my partial view this way:
#model MyApp.Utilities.SearchObjInfoPartial
Object Name: #Html.TextBoxFor(item => item.m_ObjName, Model.m_ObjName, String.Empty) <br/>
Object Number: #Html.EditorFor(item => item.m_ObjNumber)<br />
Power: #Html.DropDownListFor(item => item.m_ObjPower, Model.m_ObjPower, String.Empty) #Html.DropDownListFor(item => item.m_ObjSymbol, Model.m_ObjSymbol, String.Empty)
Type: #Html.DropDownListFor(item => item.m_ObjType, Model.m_ObjType, String.Empty) <br/>
Before rendering I deal with the SelectLists, no problems here.
Now here's where it gets interesting:
In my controllers I used to have methods receiving huge amounts of data (see here: How to deal with many possible values to make a query?)
But now I made something else. Without thinking, I tried to add the old search model in the controller method like this:
public ActionResult BrowseObjectList(SearchObjInfo searchObj, string _objName, (...))
And I just found out that it works even if the receiving object is not the same as the one used in my partial view model. How is that even possible? I mean, the proper fields will fill up and I can "safely" deal with my searchObj item, though I do not find this secure after all...
Thats what MVC framework does for you man.
Browser simply sends the form collection to server as Name Value Collection. As the request hits server, MVC framework will match the values with parameter in the Action method.
Form collection values are mapped to Model object properties. This is done by doing a match with Property Name and Name of the value in Form collection. Just check the client side code by view source, you can see that the input tags will have an attribute 'name' which matches with the property name of model.
QueryString values will also be mapped to parameters in Action method based on name.
Even you add a hidden field and specify a parameter with same name in action method...tada you will get the value of hidden field in that variable on post back
In your case though the model is different, its property name are same m_ObjName, m_ObjType, m_ObjNumber, m_ObjSymbol, m_ObjPower. So MVC do a match for you.
Try with different property name and see the results ;-)
In my application When user Login at that time I want store some information of user like firstname, lastname, Id, employee Id, etc. which I want to use at many places in my web application.
Previously I was using form Authentication
FormsAuthentication.SetAuthCookie(empDetails.Employee.EmployeeId, false);
But It stores only one parameter. I want to store multiple data which I will use in my application.
Can any one tell me the best way to do this.
For your problem I would suggest storing your value in HTTPCOntext.Current.Session
First create a class like this
public class CurrentCustomer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
private string _Token;
public string Token
{
get
{
return _Token;
}
set
{
_Token = value;
}
}
}
Then after logging in of the user (means when the user is authorized)
fetch all your required data fill your CurrentCustomer object and then create your Seeion like this
HttpContext.Current.Session[CurrentCustomer] = CurrentCustomer;
And now wherever you need that value Create your CUrrentCUstomer Object.
CurrentCustomr obj = ((CurrentCustomer)HttpContext.Current.Session[CurrentCustomer]);
Thats all you need.
The auth cookie can be used to save a string. This string can encode all the data you want.
I usually create an object (e.g. ConnectedUser class) that has all the information I want saved. I then override the ToString() of the class to return a string in a fomrat that I can later decode to reconstruct the ConnectedUser instance. This is even made easier if all your models inherit from a single basemodel, then the basemodel can have a property of type ConnectedUser, then you can extend the DefaultModelBinder and override OnModelUpdated() to reconstruct the instance of connected user. Usually I do this through a method that accepts the requestcontext, like that I can call it from elsewhere in the code if the modelbinder has not been called for some reason.
EDIT
public class ConnectedUser{
public string FirstName{get;set;}
public string LastName{get;set;}
public override string ToString(){
return string.format("FirstName{0}{1}{2}LastName{0}{3}",EqualDelimiter, FirstName, EntryDelimiter, LastName);
}
}
And now in the constructor of the Auth cookie instead of passing in userId, you pass it an instance of ConnectedUser with FirstName and LastName filled in. When a request is received you can retrieve the connected user with these 2 methods which can be called from the custom extension of defaultModelBinder or inside an action method, etc.
public static ConnectedUser GetConnectedUser(HttpContextBase executingContext)
{
var dictionary = GetAuthCookieData(executingContext);
var toRet = new ConnectedUser
{
FirstName = dictionary["FirstName"],
LastName= dictionary["LastName"]
}
return toRet;
}
public static IDictionary<string, string> GetAuthCookieData(HttpContextBase executingContext)
{
HttpCookie toCheck = executingContext.Request.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket decrypted = FormsAuthentication.Decrypt(toCheck.Value);
string userData = decrypted.UserData;
return userData.ToDictionary<string, string>();
}
Extending the DefaultModelBinder should be straight forward just don't forget to register it in Global.asax. There are plenty of articles online on how to do both.
You could store a JSON string with all parameters you want:
{name:"NAME",id:"IDENTIFIER",email:"EMAIL"}
Then parse it on restore.
I have an Address object defined simply as follows:
public class Address
{
public string StreetNumber { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
Fairly simple. On the advice an answer to another question I asked, I am referring to this blog post when databinding my UI to an object of type Person (which contains an Address MailingAddress field).
The problem is that the IDataError interface method isn't validating any of the properties of the Address type.
public string this[string columnName]
{
get
{
string result = null;
// the following works fine
if(columnName == "FirstName")
{
if (string.IsNullOrEmpty(this.FirstName))
result = "First name cannot be blank.";
}
// the following does not run
// mostly because I don't know what the columnName should be
else if (columnName == "NotSureWhatToPutHere")
{
if (!Util.IsValidPostalCode(this.MailingAddress.PostalCode))
result = "Postal code is not in a know format.";
}
return result;
}
}
So, obviously I don't know what the columnName will be... I've stepped through it and it has never been anything other than any of the public properties (of intrinsic types). I've even tried running and breaking on a statement like:
if (columnName.Contains("Mailing") || columnName.Contains("Postal"))
System.Windows.Forms.MessageBox.Show(columnName);
All to no avail.
Is there something I'm missing?
You need to define IErrorInfo on all the classes that you want to supply error messages for.
Take a look at my answer here.
This explains how to use a modelbinder to add 'class-level' checking of your model without having to use IDataError - which as you have seen here can be quite clumsy. It still lets you use [Required] attributes or any other custom validation attributes you have, but lets you add or remove individual model errors. For more on how to use data annotations I highly recommend this post from Scott Gu.