After i populate some form(asp.net mvc) and press submit button after that form values are the same as before submit the form and i do not repopulate input fields from backend code. Can explain me how values are persisted cross request(and that values are not repopulated)?
Assuming you are asking about how MVC moder binder works(parsing posted data on the server), the default Model binder, which was designed to effectively bind most model types, does a relatively simple and recursive logic for each property of the target model.
1 It determines whether the property is a simple type or complex type by checking the property name are registered as a prefix. The prefix pattern is [ParentProperty].[Property]
2 Get the ValueProviderResult from the registered value providers for the property’s name.
3 If the property is a simple type, it tries to convert the property using the properties TypeConverter from the source value of type string to the from the source value of type string to the target type
4 Otherwise, the property is a complex type, so perform a recursive binding.
If you try to see the posted value the browser sends to the server, you could understand how to form data is sent, and get the idea. For reference, consult this link https://msdn.microsoft.com/en-us/magazine/hh781022.aspx
Related
In in post back to server side MVC controller action, to maintain the data for a MVC model property that is not for user input, the following topic suggests to use hidden field on markup view page:
MVC3 - Why are navigation properties null on postback
But to me, such an hidden field works just for a primitive C# types like int, bool, string etc. But complex-type property such as user-defined class or collection of primitive types (like List) does not work with hidden field on post back to server. Is my thought correct?
In fact, I tried such a hidden field for complex type property and the post back model property is null. Server side session object or database re-query is a rescue to re-populate complex-type property on server post back. Is there some other way to keep data for complex-type model property between post back?
I appreciate your help.
Update:
The hidden field for complex-type property is not data sensitive, no need data security for it. What I need to use some way rather than database re-query or server-side session variable. So, instead of using the hidden property as complex type in my MVC model, I use a string property that is complex-type serialized. On post back, I deserialize that hidden property to feed data for another property. Any idea?
I'm developing own custom field type in JIRA.
My class is very simple, it extends GenericTextCFType.
My goal is to store some identifier (ID) of field value in database but to show human-readable caption of the field value on Issue form.
I searched methods of GenericTextCFType class and found method getSingularObjectFromString, and I don't understand, what it does.
JIRA javadoc says: "Returns a Singular Object, given the string value as passed by the presentation tier"
But what is the Singular Object and what is it needed for?
Yes, it's not a great name. I wrote about it in detail in "Practical JIRA Plugins"
(O'Reilly). Here's an extract from there describing many of the methods in detail (sorry about the formatting). The book also has worked examples available at https://bitbucket.org/mdoar/practical-jira-plugins
CustomFieldType Methods
The example’s custom field type class will implement the CustomFieldType interface as usual, but instead will extend a class higher up in the inheritance hierarchy than NumberCFType. The class we will extend is AbstractCustomFieldType and it’s at the root of most classes that implement CustomFieldType.
The methods in the CustomFieldType interface with “SingularObject” in their name refer to the singular object, in this example a Carrier object. All other methods in JIRA 4 custom fields that refer to an Object are referring the transport object, e.g., a Collection of Carrier objects. JIRA 5 removed the use of Object in most custom field methods.
For more information about what changed in JIRA 5.0 with custom fields see https://developer.atlassian.com/display/JIRADEV/Java+API+Changes+in+JIRA+5.0#JavaAPIChangesinJIRA5.0-CustomFieldTypes. There were some major changes in the class hierarchy, and most classes now have a Java generic as a parameter instead of just using an Object as before.
There are two objects that are typically injected into the constructor of a custom field type’s class. The first is a CustomFieldValuePersister persister object, which is what will actually interact with the database. The second is a GenericConfigManager object that is used for storing and retrieving default values for the custom field. Other objects are injected into the constructor as needed—for example, the DoubleConverter in Example 2-2.
The first set of methods to consider are the ones that the custom field type uses to interact with the database in some way.
getSingularObjectFromString()
This method converts a string taken from the database such as “42.0###The answer” into a Carrier object. A null value means that there is no such object defined.
Fields with Multiple Values
Collection<Carrier> getValueFromIssue(CustomField field, Issue issue)
This is the main method for extracting what a field contains for a given issue. It uses the persister to retrieve the values from the database for the issue, converts each value into a Carrier object and then puts all the Carrier objects into a trans- port object Collection. A null value means that this field has no value stored for the given issue. This is one of the methods that used to return an Object before JIRA 5.0
createValue(CustomField field, Issue issue, Collection<Carrier> value)
updateValue(CustomField field, Issue issue, Collection<Carrier> value)
These methods create a new value or update an existing value for the field in the given issue. The persister that does this expects a Collection of Strings to store, so both of these methods call the method getDbValueFromCollection to help with that.
getDbValueFromCollection()
A private convenience method found in many custom field type classes, sometimes with a different name. It is used to convert a transport object (e.g., a Collection of Carrier objects) to a Collection of Strings for storing in the database.
setDefaultValue(FieldConfig fieldConfig, Collection<Carrier> value)
Convert a transport object (a Collection of Carrier objects) to its database repre- sentation and store it in the database in the genericconfiguration table.
Collection<Carrier> getDefaultValue(FieldConfig fieldConfig)
Retrieve a default value, if any, from the database and convert it to a transport object (a Collection of Carrier objects). The FieldConfig object is what represents the context of each default value in a custom field.
The next set of methods to consider are the ones that interact with a web page in some way. All values from web pages arrive at a custom field type object as part of a Custom FieldParams object, which is a holder for a Map of the values of the HTML input elements.
validateFromParams(CustomFieldParams params, ErrorCollection errors, FieldConfig config)
This is the first method that is called after a user has edited a custom field’s value. Any errors recorded here will be nicely displayed next to the field in the edit page.
getValueFromCustomFieldParams(CustomFieldParams customFieldParams)
This method is where a new value for a field that has been accepted by validate FromParams is cleaned and converted into a transport object. The custom FieldParams object will only contain strings for the HTML elements with a name attribute that is the custom field ID—e.g., customfield_10010. A null value means that there is no value for this field.
getStringValueFromCustomFieldParams(CustomFieldParams parameters)
This method returns an object that may be a String, a Collection of Strings or even a CustomFieldParams object. It’s used to populate the value variable used in Chapter 3: Advanced Custom Field Types Velocity templates. It’s also used in the Provider classes that are used by custom field searchers.
String getStringFromSingularObject(Carrier singularObject)
This method is not the direct opposite of getSingularObjectFromString as you might expect. Instead, it is used to convert a singular object (Carrier) to the string that is used in the web page, not to the database value. The returned String is also sometimes what is stored in the Lucene indexes for searching (“More Complex Searchers” on page 57). The singular object was passed into this method as an Object before JIRA 5.0.
The final set of CustomFieldType methods to consider are:
Set<Long> remove(CustomField field)
This method is called when a custom field is entirely removed from a JIRA instance, and returns the issue ids that were affected by the removal. The correct method to use for deleting a value from a field is updateValue.
String getChangelogValue(CustomField field, Object value)
String getChangelogString(CustomField field, Object value)
These methods are how the text that is seen in the History tab of an issue is gen- erated. When a custom field of this type changes, these methods are called with the before and after values of the field. The difference between the two methods is that the if the value later becomes invalid, the string will be shown instead (https://developer.atlassian.com/display/JIRADEV/Database+Schema#DatabaseSchema-ChangeHistory).
extractTransferObjectFromString()
extractStringFromTransferObject()
These methods are not from the CustomFieldType interface but they exist in the standard Multi fields for use during project imports.
Other Interfaces
There are a few other interfaces that are commonly implemented by custom field types.
ProjectImportableCustomField
The getProjectImporter method from this interface is used to implement how the custom field is populated during importing a project from an XML backup. If you don’t implement this interface then project imports will not import values for your custom field.
MultipleCustomFieldType
MultipleSettableCustomFieldType
These two interfaces are used by custom fields with options and that furthermore can have more than one option. For these classes, the values can be accessed using the Options class, which is a simple subclass of a Java List. These interfaces are not really intended for use by general-purpose multiple value custom field types.
Fields with Multiple Values | 41
SortableCustomField
This interface contains a compare method for comparing two singular objects. This is used by the Issue Navigator when you click on a column’s heading to sort a page of issues. This is actually a slower fallback for custom fields that don’t have a searcher associated with them (see Chapter 4).
RestAwareCustomFieldType
RestCustomFieldTypeOperations
These two interfaces are how the JIRA REST API knows which fields can be retrieved or updated. New in JIRA 5.0.
I'm trying to update a backbone model, the server side is asp.net mvc 4. I'm getting:
"System.ArgumentException: An item with the same key has already been added" exception.
The reason is because backbone is sending Id and id to the server as properties, and the JsonValueProvider tries to add this to a dictionary.
Here is my model:
var Task = Backbone.Model.extend({
url: "/tasks/task",
idAttribute: "Id"
});
This is send to the server via Put request:
{"Id":294912,"Task":"test","DueDate":"2012-03-24T02:00:00.000Z", "id":294912}
Is there a way to prevent backbone in sending the "id" property?
The problem here is because the conventions in C# is not the same as in JavaScript. In C# classes have properties that starts with capital letters (Pascal Case) and it's the norm in JavaScript to start your properties in lower case (Camel Case).
Thus when serializing view models the default behavior of the JSON.NET serializer is to serialize the object exactly with the same capitalization of properties. I could rename the properties on the view model to be camel case, but it would be as "weird" as to have properties with pascal case in your JavaScript objects.
So instead to force Backbone into a non convention way, I've change the serialization of the objects to convert the Pascal case properties into Camel case properties by leveraging JSON.NET's Contract Resolver functionality.
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
JsonSerializer serializer = JsonSerializer.Create(settings);
JsonConvert.SerializeObject(object, Formatting.None, settings);
Now this creates consistency on the client side with my code and with all the cool libraries out there.
Sounds to me like the issue is in your server-side code, not with the call from Backbone. A PUT is an edit operation on the server, so you're updating an existing entity. You need the ID property to identify the model on the server and update the properties that have changed.
If ASP.NET MVC is complaining that the model already exists in the database, you are trying to do an INSERT instead of an UPDATE. We'd need to see the controller and data access code to see where things are going awry.
UPDATE: What happens if you leave off the idAttribute property? From the Backbone documentation:
A special property of models, the id is an arbitrary string (integer id or UUID).
If you set the id in the attributes hash, it will be copied onto the model as a
direct property.
The id attribute should be sent by default; it looks like you're forcing it to be included a second time.
Under idAttribute in the docs:
A model's unique identifier is stored under the id attribute. If you're directly communicating
with a backend (CouchDB, MongoDB) that uses a different unique key, you may set a Model's
idAttribute to transparently map from that key to id.
ASP.NET MVC's model binding should be able to cope with id vs. Id.
UPDATE: Found a good blog post that describes using a view model to aid in serializing your C# objects into the format Backbone expects. This seems like a reasonable, if slightly annoying, solution.
In my understanding, the ViewModel pattern was designed to pass all the relevant data to View because 1) the view shouldn't perform any data retrieval or application logic and 2) it enables type-safety, compile-time checking, and editor intellisense within view templates.
Since dynamic expressions are defined at runtime, does this mean we don't get any of the 2)'s goodies?
You do not lose any of the existing functionality. You can still have a strongly-typed view such that when you access the Model property it will be of your specified type. The only thing that is added is a shorter way of accessing items in the ViewData dictionary.
Instead of the following
ViewData["MyData"]
you can have
View.MyData
Notice that you do not lose any type-safety because you never really had any. In the former case the key is a string (no certainty that it exists in the dictionary) and the value is an object so unless you cast it you can't do that much with it. In the latter you also get no intellisense and the returned value must be cast to something useful.
In fact the implementation of View.MyData simply takes the property name ("MyData") and returns the value coming from the ViewData dictionary.
Arguably the one thing you lose is the ability to have spaces or other characters that are not legal C# identifiers in your key names.
PLEASE NOTE: I've answered my own question with a link to an answer to a similar question. I'll accept that answer once I'm allowed to (unless anyone comes up with a better answer meantime).
I have a database column defined as NVARCHAR(1000) NOT NULL DEFAULT(N'') - in other words, a non-nullable text column with a default value of blank.
I have a model class generated by the Linq-to-SQL Classes designer, which correctly identifies the property as not nullable.
I have a TextAreaFor in my view for that property. I'm using UpdateModel in my controller to fetch the value from the form and populate the model object.
If I view the web page and leave the text area blank, UpdateModel insists on setting the property to NULL instead of empty string. (Even if I set the value to blank in code prior to calling UpdateModel, it still overwrites that with NULL). Which, of course, causes the subsequent database update to fail.
I could check all such properties for NULL after calling UpdateModel, but that seems ridiculous - surely there must be a better way?
Please don't tell me I need a custom model binder for such a simple scenario...!
Might be duplicate or something in the line of this:
MVC binding form data problem
I fear custom model binder will be necessary. ;)
You might want to use a partial class implementation of your entity that implements the on property changed handler for that particular property. When you detect that the property has been changed to NULL, simply change it to string.Empty. That way anytime NULL is assigned to the property it gets reset to the empty string.