ActionScript 3 Object to name value string - apache-flex

In a Flex application I am trying to turn an Object into a QueryString such as name1=value1&name2=value2... But I am having trouble getting the names of the Objects children. How do I enumerate the names instead of the values?
Thanks

I'm guessing you're doing a for each(in) loop. Just do a normal for(in) loop and you'll get the names instead of the values:
for(var name:String in obj) {
var value:* = obj[name];
// do whatever you need
}

Ok, first off, if you need that query string to actually query a server, you don't really need to get it yourself as this code will query the server for you
protected function callSerivce():void
{
var o:Object = new Object();
o.action = "loadBogusData";
o.val1 = "dsadasd";
service.send(o);
}
<mx:HTTPService id="service" url="http://www.somewhere.com/file.php" method="GET" showBusyCursor="true"/>
Will make a call to the server like this: http://www.somewhere.com/file.php?action=loadBogusData&val1=dsadasd
But in case you really want to analyze the object by hand, try using ObjectUtil.getClassInfo, it returns a lot of information including all the fields (read more on LiveDocs).

Related

ILGenerator. Whats wrong with this Code

I am trying to build a dynamic Property Accessor. Want something which is like really fast as close to calling the actually Property. Dont want to go the Reflection route as its very slow. So i opted to using DynamicAssembly and inject IL using ILGenerator. Below is the ILGenerator related code which seems to work
Label nulllabel = getIL.DefineLabel();
Label returnlabel = getIL.DefineLabel();
//_type = targetGetMethod.ReturnType;
if (methods.Count > 0)
{
getIL.DeclareLocal(typeof(object));
getIL.DeclareLocal(typeof(bool));
getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
//(target object)
//Cast to the source type
getIL.Emit(OpCodes.Castclass, this.mTargetType);
//Get the property value
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
getIL.Emit(OpCodes.Stloc_0); //Store it
getIL.Emit(OpCodes.Br_S,returnlabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Stloc_0);
getIL.MarkLabel(returnlabel);
getIL.Emit(OpCodes.Ldloc_0);
}
else
{
getIL.ThrowException(typeof(MissingMethodException));
}
getIL.Emit(OpCodes.Ret);
So above get the first argument which is the object that contains the property. the methods collection contains the nested property if any. for each property i use EmitCall which puts the the value on the stack and then i try to box it. This works like a charm.
The only issue is if you have a property like Order.Instrument.Symbol.Name and assume that Instrument object is null. Then the code will throw an null object exception.
So this what i did, i introduced a null check
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
getIL.Emit(OpCodes.Stloc_0);
getIL.Emit(OpCodes.Ldloc_0);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Ceq);
getIL.Emit(OpCodes.Stloc_1);
getIL.Emit(OpCodes.Ldloc_1);
getIL.Emit(OpCodes.Brtrue_S, nulllabel);
getIL.Emit(OpCodes.Ldloc_0);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
Now this code breaks saying That the object/memory is corrupted etc. So what exactly is wrong with this code. Am i missing something here.
Thanks in Advance.
Previously, if you had consecutive properties P returning string and then Q returning int, you would get something like this:
...
call P // returns string
call Q // requires a string on the stack, returns an int
box
...
Now you have something like this:
...
call P // returns string
store // stores to object
... // load, compare to null, etc.
load // loads an *object*
call Q // requires a *string* on the stack
store // stores to object *without boxing*
...
So I see two clear problems:
You are calling methods in such a way that the target is only known to be an object, not a specific type which has that method.
You are not boxing value types before storing them to a local of type object.
These can be solved by reworking your logic slightly. There are also a few other minor details you could clean up:
Rather than ceq followed by brtrue, just use beq.
There's no point in doing Stloc_1 followed by Ldloc_1 rather than just using the value on the stack since that local isn't used anywhere else.
Incorporating these changes, here's what I'd do:
Type finalType = null;
foreach (var methodInfo in methods)
{
finalType = methodInfo.ReturnType;
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (!finalType.IsValueType)
{
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Beq_S, nulllabel);
}
}
if (finalType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
getIL.Emit(OpCodes.Br_S, returnLabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Pop);
getIL.Emit(OpCodes.Ldnull);
getIL.MarkLabel(returnlabel);
Note that we can get rid of both locals since we now just duplicate the top value on the stack before comparing against null.

Change Single URL query string value

I have an ASP.NET page which takes a number of parameters in the query string:
search.aspx?q=123&source=WebSearch
This would display the first page of search results. Now within the rendering of that page, I want to display a set of links that allow the user to jump to different pages within the search results. I can do this simply by append &page=1 or &page=2 etc.
Where it gets complicated is that I want to preserve the input query string from the original page for every parameter except the one that I'm trying to change. There may be other parameters in the url used by other components and the value I'm trying to replace may or may not already be defined:
search.aspx?q=123&source=WebSearch&page=1&Theme=Blue
In this case to generate a link to the next page of results, I want to change page=1 to page=2 while leaving the rest of the query string unchanged.
Is there a builtin way to do this, or do I need to do all of the string parsing/recombining manually?
You can't modify the QueryString directly as it is readonly. You will need to get the values, modify them, then put them back together. Try this:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
nameValues.Set("page", "2");
string url = Request.Url.AbsolutePath;
string updatedQueryString = "?" + nameValues.ToString();
Response.Redirect(url + updatedQueryString);
The ParseQueryString method returns a NameValueCollection (actually it really returns a HttpValueCollection which encodes the results, as I mention in an answer to another question). You can then use the Set method to update a value. You can also use the Add method to add a new one, or Remove to remove a value. Finally, calling ToString() on the name NameValueCollection returns the name value pairs in a name1=value1&name2=value2 querystring ready format. Once you have that append it to the URL and redirect.
Alternately, you can add a new key, or modify an existing one, using the indexer:
nameValues["temp"] = "hello!"; // add "temp" if it didn't exist
nameValues["temp"] = "hello, world!"; // overwrite "temp"
nameValues.Remove("temp"); // can't remove via indexer
You may need to add a using System.Collections.Specialized; to make use of the NameValueCollection class.
You can do this without all the overhead of redirection (which is not inconsiderable). My personal preference is to work with a NameValueCollection which a querystring really is, but using reflection:
// reflect to readonly property
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isReadOnly.SetValue(this.Request.QueryString, false, null);
// remove
this.Request.QueryString.Remove("foo");
// modify
this.Request.QueryString.Set("bar", "123");
// make collection readonly again
isReadOnly.SetValue(this.Request.QueryString, true, null);
Using this QueryStringBuilder helper class, you can grab the current QueryString and call the Add method to change an existing key/value pair...
//before: "?id=123&page=1&sessionId=ABC"
string newQueryString = QueryString.Current.Add("page", "2");
//after: "?id=123&page=2&sessionId=ABC"
Use the URIBuilder Specifically the link textQuery property
I believe that does what you need.
This is pretty arbitrary, in .NET Core at least. And it all boils down to asp-all-route-data
Consider the following trivial example (taken from the "paginator" view model I use in virtually every project):
public class SomeViewModel
{
public Dictionary<string, string> NextPageLink(IQueryCollection query)
{
/*
* NOTE: how you derive the "2" is fully up to you
*/
return ParseQueryCollection(query, "page", "2");
}
Dictionary<string, string> ParseQueryCollection(IQueryCollection query, string replacementKey, string replacementValue)
{
var dict = new Dictionary<string, string>()
{
{ replacementKey, replacementValue }
};
foreach (var q in query)
{
if (!string.Equals(q.Key, replacementKey, StringComparison.OrdinalIgnoreCase))
{
dict.Add(q.Key, q.Value);
}
}
return dict;
}
}
Then to use in your view, simply pass the method the current request query collection from Context.Request:
<a asp-all-route-data="#Model.NextPageLink(Context.Request.Query)">Next</a>

How do I delete a value from an Object-based associative array in Flex 3?

I need to remove the value associated with a property in a Flex 3 associative array; is this possible?
For example, suppose I created this array like so:
var myArray:Object = new Object();
myArray[someXML.#attribute] = "foo";
Later, I need to do something like this:
delete myArray[someXML.#attribute];
However, I get this error message at runtime:
Error #1119: Delete operator is not supported with operand of type XMLList.
How do I perform this operation?
delete doesn't do as much in AS3 as it did in AS2:
http://www.gskinner.com/blog/archives/2006/06/understanding_t.html
However, I think your problem might be solved by simply using toString(), i.e.
var myArray:Object = new Object();
myArray[someXML.#attribute.toString()] = "foo";
delete myArray[someXML.#attribute.toString()];
Rather than delete it, try setting the value to null.
myArray[someXML.#attribute] = null;
That way it'll end up the same as any other value in the array that isn't defined.

Eval versus DataField in ASP:Datagrid

I have this really random problem with is bugging me. It works at the end of the day but the problem took some time to figure out and was wondering why this happens so if anyone shed some light on the subject I would be really grateful. Here is the problem
I have the following two columns on my datagrid
<asp:boundcolumn
datafield="contentsection.Id"
headerstyle-cssclass="dgHead"
headertext="Section"
itemstyle-cssclass="dgItem" />
and
<asp:templatecolumn>
<itemtemplate><%#Eval("contentsection.Id") %></itemtemplate>
</asp:templatecolumn>
The first column gives me the error of:
A field or property with the name 'contentsection.Id' was not found on the selected data source
but the second on runs fine. Any ideas or theories as to why this is happening ?
The way that I call and bind my data is like so:
Page Load Code Behind
ContentList.DataSource = ContentBlockManager.GetList();
ContentList.DataBind();
The GetList() function it is overloaded and by default passed a 0
public static List<ContentBlockMini> GetList(int SectionId)
{
List<ContentBlockMini> myList = null;
SqlParameter[] parameters = { new SqlParameter("#ContentSectionId", SectionId) };
using (DataTableReader DataReader = DataAccess.GetDataTableReader("dbo.contentblock_get", parameters))
{
if (DataReader.HasRows)
{
myList = new List<ContentBlockMini>();
}
while (DataReader.Read())
{
myList.Add(FillMiniDataRecord(DataReader));
}
}
return myList;
}
and my filling of the data record. The ContentSection is another Object Which is a property of the ContentBlock object
private static ContentBlockMini FillMiniDataRecord(IDataRecord DataRecord)
{
ContentBlockMini contentblock = new ContentBlockMini();
contentblock.Id = DataRecord.GetInt32(DataRecord.GetOrdinal("Id"));
contentblock.Name = DataRecord.GetString(DataRecord.GetOrdinal("Name"));
contentblock.SEOKeywords = DataRecord.IsDBNull(DataRecord.GetOrdinal("SEOKeywords")) ? string.Empty : DataRecord.GetString(DataRecord.GetOrdinal("SEOKeywords"));
contentblock.SEODescription = DataRecord.IsDBNull(DataRecord.GetOrdinal("SEODescription")) ? string.Empty : DataRecord.GetString(DataRecord.GetOrdinal("SEODescription"));
if (DataRecord.GetInt32(DataRecord.GetOrdinal("ContentSectionId")) > 0)
{
ContentSection cs = new ContentSection();
cs.Id = DataRecord.GetInt32(DataRecord.GetOrdinal("ContentSectionId"));
cs.Name = DataRecord.IsDBNull(DataRecord.GetOrdinal("ContentSectionName")) ? string.Empty : DataRecord.GetString(DataRecord.GetOrdinal("ContentSectionName"));
contentblock.contentsection = cs;
}
return contentblock;
}
There you go that is pretty much the start to end.
Databinding can only access "top level" properties on an object. For example, if my object is
Company with simple properties CompanyId and Name and a child object for Address, databinding can only access CompanyId and Name, not Company.Address.City.
Eval can access child object properties if you import the namespace using an #Import page directive.
The "Bind" marker is a two-way bind and is made using the default namespace attached to the datasource of the object. This can't be overridden, and because of this tightly coupled connection the namespace should be left off as assumed (since it's dynamically pulled from the datasource).
Eval is a one-way binding that can be used with any namespace that will fulfill a proper evaluation. Dates, strings, method calls, etc. The namespace provided in your example just provides eval with a marker on where to get the data relevant.
The key here is the nature of the binding. Eval is a "fire and forget" sort of binding where as Bind is more rigid to facilitate the two-way.
The DataField property approach isn't complicated enough to support dot notation; it expects a direct reference in your underlying data source; it takes that field and checks the data source, which it can't find it by the exact string.
The second approach, eval, is more dynamic, but actually I wasn't sure if it supported dot notation... learn something everyday.
HTH.
It's necessary take a look to your DataSource, but you can do a simple test: convert the first column to a template column a try to Run.
In EntityFramework is possible Eval Properties using code like this: <%#Eval("Customer.Address.PostalCode") %>.
I dont know if it is your case, but if you provide more details about how to retrieve the DataSource we can help you.

How to get a List<> throug a webmethod to javascript?

I use Page-/WebMethods for handling actuallisize data every x seconds.
Normaly I have 1 Object created on my won, which I get back with 3 informations: time / name / price.
Now I build a site with x members of my object is needed, so:
can I easily get a List<> of my own object back to JavaScript
how can I access specific rows, I mean, how I know that the time of row 1 in my list is for time of 1 in the site?
Return the result as JSON string and then parse that in client side.
I do not think, JavaScript would be able to detect if its a List<>. JSON is the way to send and receive data via PageMethods in ASP.NET Ajax. Did you check this link which uses array to send and receive data, http://forums.asp.net/p/1222967/2198696.aspx#2198696.
Okay... ahm... it's nothing special to get Lists back over JavaScript... I only make a funny syntax error.
So if someone is interessted:
<script type="text/javascript" language="javascript">
function UpdateAll()
{
setTimeout("UpdateAll()", 99990);
PageMethods.Update(OnSucceeded);
}
function OnSucceeded(result, userContext, methodName)
{
alert(result.detailsList[0].Preis);
}
[WebMethod(EnableSession = true)]
public static object Update()
{
Business.AuctionInformationDetails details = new Business.AuctionInformationDetails();
List<Business.AuctionInformationDetails> detailsList = new List<Business.AuctionInformationDetails>(); ;
//Fill list
return new
{
detailsList = detailsList
};
}
(AuctionInformationDetails are only an object with 3 string).

Resources