Append to route collection - asp.net-mvc-3

I have the following route data
object newsRoute = new
{
Area = "Admin",
Controller = "News",
Action = "Edit"
}
How can I append Title = "Hello" to the object routNews?
As in or similar
newsRoute.Append(Title = "Hello");

When you create the anonymous object you've effectively defined the properties of the anonymous class. I don't think you'll have much luck trying to redefine the type after the fact. You could create a new anonymous object with the new field and the original fields and copy the fields over, but I'm guessing you wouldn't want to do this.
You say that the object represents routedata, in that case it is probably a good idea to convert the anonymous object into a RouteValueDictionary instance using the following method
http://msdn.microsoft.com/en-us/library/system.web.mvc.htmlhelper.anonymousobjecttohtmlattributes(v=VS.98).aspx
Once converted the object has normal dictionary semantics so you can add new key value pairs at will.
You should then be able to use the RouteValueDictionary to generate your urls

Related

Custom serialization of specific return type for DataFetcher

I am using Spring for GraphQL (version 2.7.0-M1).
In my domain model, a lot of properties return an object Foo. This object must be serialized to a String based on data available from GraphQlContext. So the schema looks like:
type Parent {
code: String!
foo: String
...
}
It is easy to do this with #SchemaMapping for a specific parent type.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, DataFetchingEnvironment env) {
var context = env.getGraphQlContext();
return ...
However, this is not very DRY. I am looking for a way to have this code at one place, like a custom scalar.
Is there a way to do this with spring-graphql / graphql-java?
Example
An example is a Localized<T> object we use. For instance a Product instance has Localized<String> properties for title and description (and more).
For the GraphQL query we can set the context, part of the context is the Locale. For all Localized property values the value can be converted to the string value for the locale. We are looking for a way to do this automagically. Otherwise it creates a lot of boiler plate code
Would #ContextValue help here? This would remove a bit of boilerplate from your controller handlers.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, #ContextValue Foo foo) {
If you'd like something more involved, I think you should elaborate on the exact relationship between an attribute of one or multiple types in your schema, and some random value in the context.
Maybe you could come up with some concrete example here?

Why is my Enitty.Contains(attributeField) returning false when I am able to set the value?

I have a block of code that is not working as I thought it would.
I have set an Entity up as follows and have a previous guid.
parentEnt = new Entity("vehicle_ent");
parentEnt.id = guid;
Now when I do a check with a statement:
if (parentEnt.Contains("attribute_field")) {
parentEnt["attribute_field"] = "test";
}
The above will never be called because the if statement fails.
However, if I remove the if statement. I am able to actually assign and run the code:
parentEnt["attribute_field"] = "test";
Is there something I am missing with the Contains Method? I thought it was used to check if the Entity contains the attribute?
On the Entity class, you can always assign an attribute like the example you provided whether or not it exists. If it exists, it will overwrite it (which is what you discovered).
So
parentEnt["attribute_field"] = "test";
Will always work, whether or not the attribute already has a value assigned.
When you run the constructor for a CRM entity object, and assign it a guid
Like
Entity parentEnt = new Entity("vehicle_ent");
parentEnt.id = guid;
you are creating a new object of the entity type with the 'vehicle_ent' logical name and a id of 'guid' At this point all the attribute/properties that belong to an entity with that name, are not created along with the entity object, and you only have an Entity class object with a LogicalName and id set.
If you want to check if an entity record with that id contains a certain attribute, you need to fetch is from the database, using your the organization service, like
ColumnSet attributes = new ColumnSet(true);
parentEnt = _service.Retrieve("vehicle_ent", guid, attributes);
After the retrieve is called you can check if the entity record contains the attribute you need to check.
I just add a couple of things:
The syntax entity[attributename] and entity.Attributes[attributename] are equivalent, the reason can be found inside the Entity metadata:
public object this[string attributeName] { get; set; }
the method maps at entity level the Attributes property (the type of this property is AttributeCollection an inherit from DataCollection<string,object> and the base type is an IEnumerable<KeyValuePair<TKey, TValue>>)
DataCollection contains this method:
// Summary:
// Gets or sets the value associated with the specified key.
//
// Parameters:
// key:
// Type: TKey. The key of the value to get or set.
//
// Returns:
// Type: TValue The value associated with the specified key.
public virtual TValue this[TKey key] { get; set; }
this method adds the key (our attributename) inside the collection if the key is not present before. For this you can assign a value to an attribute without using the Contains method first. Of course when you read the value you need to check if the key is present, this is the purpose of the Contains method, but to read the values the GetAttributeValue can be used as well (but it's necessary to pay attention to the default values returned when the attribute is not inside the collection)

Knockout Mapping - Fill Observable Arrays keeping Items' methods

I've been facing a problem that is basically the following:
I have a knockout ViewModel which contains observable arrays of items with observable properties and methods.
I need to pull data from the server. The methods need to exist after data is taken from server. So I create a new ViewModel and then update its value from what comes from server. (THIS DOES NOT WORK, THE RESULTING ARRAY HAS NO ITEMS)
If I create, with mapping, a new object using var newObj = ko.mapping.fromJS(data) the resulting Array has items, but its items have no methods. It spoils my Bindings.
The fiddle of my problem: http://jsfiddle.net/claykaboom/R823a/3/ ( It works util you click in "Load Data From The Server" )
The final question is: What is the best way to have items on the final array without making the loading process too cumbersome, such as iterating through every item and filling item's properties in order to keep the previously declared methods?
Thanks,
I changed your code little bit. Check this version of JSFiddle.
var jsonFromServer = '{"ModuleId":1,"Metadatas":[{"Id":1,"MinValue":null,"MaxValue":null,"FieldName":"Teste","SelectedType":"String","SelectedOptionType":null,"IsRequired":true,"Options":[]}]}';
Your code doesnt work because your jsonFromServer variable does not contain methods we need at binding like you described in your question. ( -- > Metadatas )
So we need to define a custom create function for Metadata objects at the mapping process like this :
var mapping = {
'Metadatas': {
create: function(options) {
var newMetaData = new MetadataViewModel(options.parent);
newMetaData.Id(options.data.id);
newMetaData.FieldName(options.data.FieldName);
newMetaData.SelectedType(options.data.SelectedType);
newMetaData.SelectedOptionType(options.data.SelectedOptionType);
newMetaData.IsRequired(options.data.IsRequired);
newMetaData.Options(options.data.Options);
// You can get current viewModel instance via options.parent
// console.log(options.parent);
return newMetaData;
}
}
}
Then i changed your load function to this :
self.LoadDataFromServer = function() {
var jsonFromServer = '{"ModuleId":1,"Metadatas":[{"Id":1,"MinValue":null,"MaxValue":null,"FieldName":"Teste","SelectedType":"String","SelectedOptionType":null,"IsRequired":true,"Options":[]}]}';
ko.mapping.fromJSON(jsonFromServer, mapping, self);
}
You dont have to declare a new viewModel and call ko.applyBindings again. Assigning the updated mapping to current viewModel is enough. For more information check this link. Look out for customizing object construction part.
The final question is: What is the best way to have items on the final
array without making the loading process too cumbersome, such as
iterating through every item and filling item's properties in order to
keep the previously declared methods?
As far as i know there is no easy way to do this with your object implemantation. Your objects are not simple. They contains both data and functions together. So you need to define custom create function for them. But if you can able to separate this like below then you dont have to customize object construction.
For example seperate the MetadataViewModel to two different object :
--> Metadata : which contains only simple data
--> MetadataViewModel : which contains Metadata observableArray and its Metadata manipulator functions
With this structure you can call ko.mapping.fromJSON(newMetaDataArray , {} , MetadataViewModelInstance.MetadataArray) without defining a custom create function at the mapping process.

MVC3 Html.BeginForm - passing arguments as RouteValueDictionary fails

I have a multi-step setup process where I would like to pass query string arguments appended to the URL only if they are relevant.
http://localhost:6618/Account/Profile?wizard=true&cats=dogs
#using( Html.BeginForm() )
worked great. It yielded: <form action="/Account/Profile?setup=true&cats=dogs" method="post"> i.e. it passed into the POST action any of the original query string parameters, and then in that Controller action I could chose which ones were relevant to pass to my next step, or necessary to add, by adding to the RouteValues and a RedirectToResult.
However, I need to assign a class to my form for styling purposes.
I tried:
#using( Html.BeginForm( "Profile", "Account", args, FormMethod.Post, new { #class = "mainForm" } ) )
which yields:
<form action="/Account/Profile?Count=1&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D" class="mainForm" method="post">
(args was generated by a filter, and is a RouteValueDictionary). The specification http://msdn.microsoft.com/en-us/library/dd505151.aspx indicates that you can pass arguments with a System.Web.Routing.RouteValueDictionary.
What I want is <form action="/Account/Profile?setup=true&cats=dogs" class="mainForm" method="post">
I should mention I would prefer not to do something like passing in new {key = value} instead, since there is a fair amount of logic to determine what I will be passing along to the next step.
Any suggestions on what to do here?
I am stymied by this seemingly simple task, and am surely missing something terribly obvious.
args was generated by a filter, and is a RouteValueDictionary
That's the key point here. In this case make sure you are using the correct overload of the BeginForm method:
#using(Html.BeginForm(
"Profile",
"Account",
args,
FormMethod.Post,
new RouteValueDictionary(new { #class = "mainForm" })
))
{
...
}
Notice the last argument? It must be an IDictionary<string, object> for this to work.
In your example it is this overload that gets picked up. But since you are passing a RouteValueDictionary for the routeValues parameter instead of an anonymous object it gets messed up.
So, you should either have both routeValues and htmlAttributes as dictionaries or both as anonymous objects.
Following will work.
#using (Html.BeginForm("Profile", "Account", new { id=122}, FormMethod.Post, new { #class = "mainForm" }))
the route value is created by object initialize syntax i.e new {key = value}
So you're using this overload:
http://msdn.microsoft.com/en-us/library/dd460542.aspx
Is it possible to make args a simple object with keys and values? I think that might solve your problem.
According to docs:
The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - this seems to be what is happening-- it's using reflections to get the properties of route dictionary- the properties being keys (collection of string) and values (collection of objects)
Another option would be to not use the html helper and create the form tag manually-- although that would kind of defeat the purpose of having the html helpers.
Just a thought, but, even for a multi-step form, wouldn't you want to either choose to make it all GET or POST? In the example above... it looks like you are using POST with the form... but still trying to use GET along the way.
Why not just use hidden POST values (using HTML INPUTs,) along the way?
Otherwise, users could more-easily change the values, right? (Though, that might not matter in this application. And this is mostly just food for thought.)

MVC - Passing a Type as an action parameter

Can I pass a parameter of Type to the Action method in MVC via a HTML.ActionLink().
e.g.
public ActionResult Get(Type containerType, string name)
{
throw new NotImplementedException("vkag");
}
<%=Html.ActionLink(flow.Source.Name, "Get", new { containerType = typeof(Worksheet), name = flow.Source.Name})%>
For some reason the type is always null. I also can't pass back a base type to allow for subtypes to be passed in it's place.
I don't know whether this is a limitation of the HTML ActionLink Helper or MVC.
I can't pass an Interface, I specify a base type parameter and use sub type as an argument in the place of a base type parameter, and I can't seem to pass a Type back. I'm pretty stuck here.
Is there another HTML Helper that will help?
Can I do anything with model binding?
Can I modify the state of my model during an ActionLink invocation before control is passed to my action method?
Kind a stuck here. Any help would be gratefully appreciated.
Thanks
The types you can pass into Routes must be passable via a URL if you think about it.
You cannot pass a Type as it would have to be serialised. Why not pass the containerType as a string and convert it back to a Type in the action?

Resources