I've already read this an this, but this doesn't answer to my needs.
I'm learning Csharp and here's one of my first functions:
public void AskServer(string URL, WWWForm form)
{
WWWForm form = new WWWForm(URL);
form.AddField("step", StateManager.STEP_GET_CONF);
form.AddField("pseudo", this._pseudo);
form.AddField("jeton", this._dernierJeton.ToString());
/*... a bit more out of scope code...*/
}
I would like to do a (far more) generic stuff like this:
public void AskServer(string URL, ...)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(param[i], param[i+1]);
)
}
then call the function -somehow- like that:
AskServer("http://myweb", "pseudo", this._pseudo, "jeton", this._jeton);
Maybe if you have a nicer way of writing this, you are welcome, maybe something like in JavaScript:
AskServer("http://myweb", {
"pseudo": this._pseudo,
"jeton": this._jeton
});
One of my problems is that I need to pass value that may not be strings (key will always be).
The params keyword will let you specify a variable number of arguments (must be the last parameter). You can then treat that as an array.
public void AskServer(string url, params object[] args)
{
WWWForm form = new WWWForm(url);
for (int i = 0; i < args.GetLength(0); i++)
form.Addfield(args[i].ToString(), args[++i]);
}
Called as,
AskServer("http://myweb", "pseudo", 1, "jeton", 234);
Or as an alternative approach, use a list instead with strong type on the key (the generic declaration is ugly so you can alias it in namespaces)
using Kvp = System.Collections.Generic.KeyValuePair<string, object>;
....
public void AskServer(string url, List<Kvp> kvps)
{
WWWForm form = new WWWForm(url);
foreach (var arg in kvps)
form.Addfield(arg.Key, arg.Value);
}
Called as:
AskServer("http://myweb",
new List<Kvp>() {
new Kvp("pseudo", 1),
new Kvp("jeton", 234)
});
there are several ways to obtain this result.
parameter array, Tuple, anonymous types, ...
for example you can write
public void AskServer(string URL, params object[] values)
{
...
}
and pass as many parameters as you want
I would try this...
public void AskServer(string url, KeyValuePair<string, object>[] parameters)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(parameters[i].Key, parameters[i].Value);
)
}
Related
In my properties, I have several bools called Username, Frames, Time, and Rerecords. Also, there is a string called StringFormat. I will explain further in a moment.
I have an object called User with variables(is this the right word?) User.Username, User.Frames, User.Time, User.Rerecords. Each variable is a string, int, int, int respectively.
Finally, I have a method:
public void Display(string stringFormat, params object[] args)
{
// stringFormat = Properties.Settings.Default.Format
lbl_Display.Text = string.Format(stringFormat, args);
}
I wish uses the User variables as the args IF the property variables of the same names are True.
How can I do this? Currently, my research has lead me here, but it hasn't been of any help.
Any help would be greatly appreciated. Thank you.
Edit:
I did it with some spaghetti code, to simulate the response:
public void Display()
{
// spaghetti code - Fix later
NumberConverter nc = new NumberConverter();
List<bool> settings = new List<bool>
{
Properties.Settings.Default.Username,
Properties.Settings.Default.Frames,
Properties.Settings.Default.Time,
Properties.Settings.Default.Rerecords
};
List<string> args = new List<string> { };
if (settings[0])
args.Add(compList[listIndex].Username);
if (settings[1])
args.Add(compList[listIndex].Frames.ToString());
if (settings[2])
args.Add(nc.FormatTime(compList[listIndex].Frames));
if (settings[3])
args.Add(compList[listIndex].Rerecords.ToString());
lbl_Display.Text = string.Format(Properties.Settings.Default.Format, args.Cast<object>().ToArray());
}
My objective is to store all request(*QueryString,Form,Headers,Cookies*) information to a single NameValueCollection.
Here is my code so far
var mainNVC = new NameValueCollection();
mainNVC.Add(context.Request.Form); //works
mainNVC.Add(context.Request.Headers); //works
mainNVC.Add(context.Request.QueryString); //works
mainNVC.Add(context.Request.Cookies); // error: Argument 1: cannot convert from 'System.Web.HttpCookieCollection' to 'System.Collections.Specialized.NameValueCollection'
Tried using Request.Param however, I don't want the server variables to be included.
This doesn't work because Request.Cookies is of type HttpCookieCollection.
You'll need to convert it to a NameValueCollection.
You can create an extension method called ToNameValueCollection():
public static class CookieCollectionExtensions
{
public static NameValueCollection ToNameValueCollection(
this HttpCookieCollection cookieCollection)
{
var nvc = new NameValueCollection();
foreach (var key in cookieCollection.AllKeys)
{
nvc.Add(key, cookieCollection[key].Value);
}
return nvc;
}
}
And then when you add the Cookies:
mainNVC.Add(context.Request.Cookies.ToNameValueCollection());
I am using Chello (the c# wrapper for the Trello API). I need to pass the argument "createCard" as per the documentation here: https://trello.com/docs/api/card/index.html
And this is the function I am using from Chello:
public IEnumerable<CardUpdateAction> ForCard(string cardId, object args)
{
string queryString = BuildQueryString(args);
return GetRequest<List<CardUpdateAction>>("/cards/{0}/actions?{1}", cardId, queryString);
}
I have tried calling this in this way:
List<CardUpdateAction> cua = chello.CardUpdates.ForCard("5264d37736695b2821001d7a","createCard").ToList();
but I get the error: Parameter Count Mismatch
on this function:
protected static string BuildQueryString(object args)
{
string queryString = String.Empty;
if (args != null)
{
StringBuilder sb = new StringBuilder();
foreach (var prop in args.GetType().GetProperties())
{
sb.AppendFormat("{0}={1}&", prop.Name, prop.GetValue(args, null));
}
if (sb.Length > 0) sb.Remove(sb.Length - 1, 1);
queryString = sb.ToString();
}
return queryString;
}
The problem is the fact that your API you are using expects you to pass in a class that has public properties equal to the tags you want to use.
This is very easy to do using Anonymous Types (I am doing a slightly different example to help illustrate a point)
//This will cause BuildQueryString to return "actions=createCard&action_fields=data,type,date"
var options = new { actions = "createCard", action_fields = "data,type,date" };
List<CardUpdateAction> cua = chello.CardUpdates.ForCard("5264d37736695b2821001d7a",options).ToList();
string is an object. Every type in .NET platform inherits from Object. This is called Unified Type System.
On the other hand, we have the Liskov Substitution Principle, which put simply, says that if B is a subtype of A (B is A), then you should be able to use B, wherever A is used.
Based on these reasons, you can pass string to any method that accepts an object as an argument.
You can test it:
public void DoSomething(object args)
{
}
public void Main()
{
DoSomething("some string argument, instead of the object");
}
It works just fine. No error.
I've been trying to pass an array of int's created by the following function:
function getCurrentSwimmerList() {
var swimmerList = [];
$("#swimmerTable > tbody > tr").each(function () {
swimmerList.push( parseInt($(this).data('swimmerid')) );
});
return swimmerList;
}
Which I use in token-input to eliminate ceartin suggestions from the search box, so I've set up token-input up like so:
$("#swimmerTokenInput").tokenInput("Admin/retrieveTokensForQuery", {
urlParams: { "IDsAlreadyAdded": getCurrentSwimmerList },
I modified the token-input file to allow you to pass additional paramters in a request by setting urlParams, the addition I made to the code was (in the appropriate section):
//add params passed in as urlParams
if (settings.urlParams != null) {
for (var key in settings.urlParams) {
if (settings.urlParams.hasOwnProperty(key)) {
ajax_params.data[key] = settings.urlParams[key];
}
}
}
I tested and I successfully get these values in the query string (where Ol was typed into the search box):
IDsAlreadyAdded=5%2C6&q=Ol
Which chrome recognizes and parses correctly:
IDsAlreadyAdded:5,6
q:Ol
The signature of the method I'm calling is as follows:
public JsonResult retrieveTokensForQuery(string q, int[] IDsAlreadyAdded)
Each time q successfully get's the appropriate value, however IDsAlreadyAdded always gets a null value. I've looked at various answers on SO (trying traditional=true, or IdsAlreadyAdded[] = ..., having List<int> or IEnumerable<int>) to try fix the problem, but I couldn't get it to work.
Any help would be greatly appreciated.
You could always create a custom model binder that maps the string value to an int[] like this:
public class IntArrayModelBinder : System.Web.Mvc.DefaultModelBinder
{
public override object BindModel(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (!string.IsNullOrEmpty(valueProviderResult.AttemptedValue))
{
var items = valueProviderResult.AttemptedValue.Split(',');
var result = new int[items.Length];
for (var counter = 0; counter < items.Length; counter++)
{
result[counter] = int.Parse(items[counter]);
}
return result;
}
return base.BindModel(controllerContext, bindingContext);
}
}
and then just register the binder when you initialise your routing:
ModelBinders.Binders.Add(typeof(int[]), new IntArrayModelBinder());
I'm using ObjectForScripting property to interact with web page inside WebBrowser control and everything works fine except I can't figure out how to pass array of strings back to C#
HTML code
<input type="submit" onclick="window.external.save(Array('test', 'test2'))" />
Form
// Returns System.__ComObject
public void Save(object parameters)
{
}
// Throws an exception
public void Save(object[] parameters)
{
}
// Also throws an exception
public void Save(string[] parameters)
{
}
Rather than fight it; maybe approach the problem from another angle... could you (instead, either of):
delimit the data (with Array.join) and pass a single string, and split it (string.Split) in the C#
call Save multiple times, accepting a single string each time (Save(string s)), then call a final method to actually commit the changes
You can use an anonymous object instead of an array on the javascript side:
<input type="submit" onclick="window.external.save({first: 'test', second: 'test2'})" />
On the C# side (you need to use .NET 4.0 or more for the dynamic or use Type.InvokeMember if you are on an older version):
public void Save(dynamic parameters)
{
MessageBox.Show(parameters.first);
MessageBox.Show(parameters.second);
}
Not tested, but I think you can use reflection to discover the members.
Also look at this: http://dotnetacademy.blogspot.fr/2009/11/vbnetcnet-communication-with-javascript.html
function JS2VBArray( objJSArray )
{
var dictionary = new ActiveXObject( "Scripting.Dictionary" );
for ( var i = 0; i < objJSArray.length; i++ )
{
dictionary.add( i, objJSArray[ i ] );
}
return dictionary.Items();
}
Reference: http://msdn.microsoft.com/en-us/library/zsfww439(v=vs.80).aspx
<input type="submit" onclick="window.external.Save( JS2VBArray( ['test', 'test2'] ) )" />
This should go to the method.
public void Save(object[] parameters)
{
}
The string array is automatically passed as a comma-delimited string.
So this call:
window.external.save(Array('test', 'test2'));
Is received like so:
public void save(string fromjs)
{
string[] result = fromjs.Split(',');
}
It's a bit late for this, but typically when I need to pass objects or, in this case Arrays, I pass them as a JSON string.
var sArr = JSON.stringify(myArr);
window.external(sArr);
Then I have a JavaScriptSerializer on the other side that deserializes it back into an object / array.
Deserialize JSON with C#
To pass an array I found this to not be supported directly. I took the approach recommended by Marc Gravell to call multiple times but structured it in 3 methods instead, that are used in sequence: InitArgs, PushArg (multiple times), FinalArgs.
private System.Collections.Generics.Queue<string> _argsQ;
public void InitArgs()
{
_argsQ = new System.Collections.Generics.Queue<string>();
}
public void PushArg(string arg)
{
_argsQ.Enqueue(arg);
}
public void FinalArgs()
{
string[] parameters = _argsQ.ToArray();
// Save parameters
}
Now method calls can be used sequentially from html/js:
...onclick="var params = ['test', 'test2']; window.external.InitArgs(); for (var i=0; i<params.length; i++) window.external.PushArg(params[i]); window.external.FinalArgs();"...