I'm having trouble to write an "async" function that returns more than one value using "out".
public async void getArticle(int articleID, out string html, out string title, out string author, out string url)
{
}
this is enough to trigger the error. As soon as the keyword "async" ist part of the function header I get the following error when calling the function:
error: Argument 2: Cannot convert from `string?' to `GLib.AsyncReadyCallback?'
this is what the call looks like
getArticle(15752, out html, out title, out author, out url);
if I remove the keyword "async" everything starts working again. Is this even possible in vala or do I have to return an object containing all 4 strings to make it work?
Thanks for any help in advance
best regards, Jan
You have to use the out parameters on the end of the asynchronous method:
getArticle.begin(15752, (obj, result) => {
getArticle.end(result, out html, out title, out author, out url);
}
Related
I'm trying to convert a web forms page with a number of code-behind webmethod functions into an MVC view with a controller.
The data I get back is different. They have properly formatted JSON, but the webmethod returns JSON like this:
{"d":"{\"Success\":true,\"Data\":{\"QuoteId\":340439,\"LoginId\":40,
And the controller returns:
"{\"QuoteId\":340444,\"LoginId\":40,
Its not wrapping it in data.d like it is set up to handle in the javascript and there are no Success or Data objects. And when I try to parse it ($.parseJSON(data)) like I did with the webmethod, it gives me the old error at line 1 message.
I'm sure that if I played with it enough I could get it to work with the way the data is coming through, but I have many pages that I need to covert in the future and I'm just wondering if there is an easy way to get the controller to format it like the webmethod does.
I'm pretty sure that I know why the data is formatted differently, but it would make my life easier if I could just return the data in the same way. I've tried returning a JsonConvert.SerializeObject(obj), which is just a string, and a Return Json(obj), which I'm guessing is just a string as well, but they both return stuff the same, non-data.d way.
Okay, so I've decided to wrap the data in a "d", so that I can have a "data.d" in the Ajax result.
But for some reason the dates aren't being formatted correctly when I just send the data back via:
return Json(thewrappeddata);
they turn out weird.
So basically what I have to do is this:
public class JSONReturn {
public object d;
public static object Wrap(object data) {
return new JSONReturn() { d = data };
}
}
var thedata = new TonsofData();
return Json(
JSONReturn.Wrap(
JsonConvert.SerializeObject(thedata,
new JsonSerializerSettings {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
)
)
);
It seems like I'm "jsonifying" the data twice here, once with JsonConvert.SerializeObject() and once with Json() (I THINK that serializes), but it seems to work and now I get what I need and all the JS just works as it did before. If I leave out the JsonConvert.SerializeObject(), the Json() formats the dates incorrectly and it causes all sorts of failure down the line.
I'm trying to figure out whats the best way to have multiple Get actions in a REST controller.
I would like to do something like this:
Get By Id:
public ResponseType Get(Guid id)
{
// implementation
}
Get By Enum Type:
public ResponseType Get(EnumType type)
{
// implementation
}
Get By Other Enum Type:
public ResponseType Get(OtherEnumType otherType)
{
// implementation
}
etc..
Now when I do something like that, I get the next error message:
Multiple actions were found that match the request
I understand why I get the message and I was thinking how is the best way to do something like that (I want to stick with REST).
I know I can add a route like this:
routeTemplate: "api/{controller}/{action}/{id}"
But then I would need to change the action names and the urls - And this seems like a workaround when we are talking about rest.
Another thing I thought was to create multiple controllers with one Get - But that seems even wronger.
The third workaround was to handle one Get action with an input param that will have the state:
public ResponseType Get(ReqeustObj obj)
{
switch(obj.RequestType)
{
case RequestType.GetById:
// etc...
}
}
Anyway, I would like to know whats the best way to do something like that in REST (WebApi).
As you now, when Web API needs to choose an action, if you don't specify the action name in the route, it looks for actions whose name starts with the method name, GET in this case. So in your case, it will find multiple methods.
But it also try to match the parameters. So, if you include the parameters as part of the url (route parameters) or the query string, the action selector will be able to choose one of the available methods.
If you don't specify a parameter or specify the id in the url (or even in the query string) it should invoke the first overload. If you add the parameter name of the second action in the query string like this: ?type=VALUE it should choose the corresponding overload, and so on.
The question is that the parameter names must be different, or it will not be able to choose one or the other among all the overloads.
For example, if you use the urls in the comments in your browser, you'll see how the right method is chosen:
public class TestController : ApiController
{
// GET api/Test
public string Get()
{
return "without params";
}
// GET api/Test/5
public string Get(int id)
{
return "id";
}
// GET api/Test?key=5
public string Get(string key)
{
return "Key";
}
// GET api/Test?id2=5
public string Get2(int id2)
{
return "id2";
}
}
NOTE: you can also use route constraints to invoke differet methods without using query string parameters, but defining different route parameter names with different constraints. For example you could add a constraint for id accepting only numbers "\d+" and then a second route which accepts "key" for all other cases. In this way you can avoid using the query string
Why does my action method only bind the first word of a string I pass into it using a query string?
For example, in jquery, I build a queryString from the results of an ajax call:
success: return(resultData){
var queryString = "?ok=true&message=" + resultData.message;
}
Then I try to load a view into a dialog by calling a controller and passing the queryString
$dialogHandle.load("/Account/RegisterStatus" + queryString, function() { ... });
At this point the queryString correctly hold an entire message. However if I break in my controller:
public ActionResult RegisterStatus(bool ok, string message)
{
//break here
}
I notice that ok binds correctly but message only contains the first word of the error message passed in.
How can I pass a sentence as one string parameter?
Is there a better way to do this, without query string?
EDIT: hmm now that I think about it does make sense since urls cant have space but then how do I accomplish this... is there a specific word delimiter in the default model binder?
It's all about URL escaping: escape("It's me!") // result: It%27s%20me%21
Do that around your resultData.Message and it should work better. For debugging purposes, use Fiddler2 or some Web Inspector to see what request is being send. This is really valuable when you are debugging AJAX...
And of course, do the reverse in C#: HttpUtility.UrDecode Method (String)
I'm building a custom page caching utility that uses a syntax like {Substitution:GetNonCachedData} to get data that's not supposed to be cached. The solution is very similar to the built-in <# OutputCache %> stuff but not as flexible (I don't need it to be) and, most importantly, allows the session state to be available when retrieving non-cached data.
Anyway, I have a method that replaces the tokens in the html with the result of the static method named in the {Substitution} tag.
For example my page:
<html>
<body>
<p>This is cached</p>
<p>This is not: {Substitution:GetCurrentTime}</p>
</body>
</html>
will fill in the {Substitution:GetCurrentTime} with results of a static method. Here's where the processing happens:
private static Regex SubstitutionRegex = new Regex(#"{substitution:(?<method>\w+)}", RegexOptions.IgnoreCase);
public static string WriteTemplates(string template)
{
foreach (Match match in SubstitutionRegex.Matches(template))
{
var group = match.Groups["method"];
var method = group.Value;
var substitution = (string) typeof (Substitution).GetMethod(method).Invoke(null, null);
template = SubstitutionRegex.Replace()
}
return template;
}
the variable template is the html with custom tokens in it that need to be replaced. The problem with this method is that everytime I update the template variable with the updated html the match.Index variable no longer points to the right character start because of the template now has more characters added to it.
I can come up with a solution that works by either counting characters etc or some other screwball way of doing it, but I first want to make sure there's not some easier way to achieve this with the Regex object. Anyone know how to this?
thanks!
You should call the overload of Regex.Replace that takes a MatchEvaluator delegate.
For example:
return SubstitutionRegex.Replace(template, delegate(Match match) {
var group = match.Groups["method"];
var method = group.Value;
return (string) typeof (Substitution).GetMethod(method).Invoke(null, null);
});
Instead of using Matches and looping on the results, set the regex to compiled and use a single Match in a while loop until it stops matching.
I have a "format" method that works in a similar manner to the C# String.Format method, with the following signature:
In a class named StringTools:
/**
* Formats a string, based on C# String.Format method.
* #param raw A string with numbered tokens, such as "{0}, {1}"
* #param rest Values that replace the numbered tokens in raw.
*/
public static function format(raw:String, ...rest:*):String;
StringTools.format("{0}, {1}", "Hello", "World") returns the string "Hello, World" as expected. Now, I'm trying to get my logging class to use this method, but I'm having trouble passing the optional variables through. The signature of the method in the logging class is:
public static function infof(raw:String, ...rest:*):String;
If I pass "rest" directly into StringTools.format(raw, rest), it's passed in as an array, and not as a series of parameters, so if I call it liks this: infof("{0}, {1}", "Hello", "World"), I get the string "Hello,World, {1}", since it replaces the first token with the entire array of values.
I also tried constructing an arguments array, and calling the method like this:
var collectArgs:Array = [raw];
for (var i:Number = 0; i < rest.length; i++)
{
collectArgs.push(rest[i]);
}
var callFunction:Function = StringTools.format.call;
trace(callFunction.apply(null, collectArgs));
However, this traces "World,6". So, it looks like the parameters are shifted. So, I tried initializing collectArgs as [null, raw], and I get "Hello World,6. The number is {1}" again.
Am I doing something wrong? What is the correct way to pass optional parameters from one method that expects optional parameters to another method that expects optional parameters?
Thanks!
I think you are on the right lines using apply. This seems to do illustrate the behaviour you want:
static function f1(raw:String, ...rest:*):void
{
trace("f1: "+raw+" "+rest);
rest.unshift(raw);
f2.apply(null, rest);
}
static function f2(raw:String, ...rest:*):void
{
trace("f2: "+raw+" "+rest);
}
function passSomeArguments():void
{
f1("A",1,2,3);
}
EDIT: You need to pass 'null' as the 1st parameter to apply because the first parameter is what is considered to be 'this' when the function is called. Since the functions are static (and in any case have no dependency on 'this') you can pass null, but you must pass something.
You could also do something like this (of course this is not best implementation for the string formatting):
public static function format(raw:String, ...rest:*):String {
if (rest[0] is Array && rest.length == 1) {
rest = rest[0];
}
var r:RegExp = /(\{\d+\})/g;
var matches:Array = raw.match(r);
for (var i:Number = 0; i < rest.length; i++) {
raw = raw.replace(matches[i], rest[i]);
}
return raw;
}
Then your infof function would just look like this:
public static function infof(raw:String, ...rest:*):void {
var formatted = StringTools.format(raw, rest);
}
As mentioned in my comment, if you remove the call method from the end of you callFunction setter, then you do not need to supply null as the first argument. See http://livedocs.adobe.com/ to understand what the call method actually does, and what the first parameter is for.
As #stephen mentioned, it is a lot simpler to unshift your raw var onto the rest array, rather than building up a new one.
Actually, just found that it's my problem. It should work fine using the argument collection method described, as long as the first element in the arguments array is null. I'm not sure why null is necessary, but it works fine this way.