Null Values for Optional Parameters ASP.NET Web API - asp.net-web-api2

I have a Web API and a very quick page I threw together to test it (the actual page that will call the API is/will be written by an outside vendor).
My Search action takes several parameters, all of which are optional and should default to empty strings.
[ActionName("Search")]
public IEnumerable<Foo> Get(string param1 = "", string param2 = "", string param3 = "")
And the View that calls the API:
#using (Ajax.BeginForm(new AjaxOptions {
Url = ViewBag.APIUrl + "api/controller/Search",
HttpMethod = "GET",
OnSuccess = "successful" }))
{
#Html.TextBox("param1")
#Html.TextBox("param2")
#Html.TextBox("param3")
}
The GET request looks like this
[...]/Search?param1=&param2=&param3=
Every value that is empty on the form is being passed to the API Controller as null, and thus the default values of empty strings are not being used. (It does pass actual values as expected.) As it is I'm null-coalescing these into empty strings after the fact, but the old version of this API did not have to do that.
When I add
int skip = 0, int take = 0
as parameters, I get the
The parameters dictionary contains a null entry
exception. I know this can be fixed by making those params nullable, then null-coalescing them like the strings. But purpose-wise, they should not be nullable, they should be optional with a default value.
How do I make it use the default values of the parameters in the action? Am I doing something wrong in the form, or in the API Controller?

It is possible to use optional parameters if you change your API controller. Please refer to the following code snippet for an example (assuming Attribute Routing is used):
[RoutePrefix("api/TestWebApi")]
public class TestWebApiController : ApiController
{
[HttpGet]
[Route("GetFoo")]
public IQueryable<Foo> GetFoo(string param1 = "", string param2 = "", string param3 = "")
{
// your implementation
}
}
With the above controller, the following four test cases can be achieved :
Test case 1: Pass all three parameters
api/TestWebApi/GetFoo?param1=a&param2=b&param3=c
Test Case 2: pass param2 and param3
/api/TestWebApi/GetFoo?param2=b&param3=c
Test Case 3: pass param3
/api/TestWebApi/GetFoo?param3=c
Test case 4: use default values:
/api/TestWebApi/GetFoo
Hope this helps.

Related

SpringDoc Problem With Methods With Different Query Parameters

I want to do something like create two method for same url pattern with different arguments
#RequestMapping(value = "/searchUser", params = "userID")
public String searchUserById(#RequestParam long userID, Model model) {
// ...
}
#RequestMapping(value = "/searchUser", params = "userName")
public ModelAndView searchUserByName(#RequestParam String userName) {
// ...
}
Spring supports this and it works fine. SpringDoc does not. It creates a single endpoint with 2 parameters.Is this a known issue?
This is supported, but you will have to use swagger #Operation to describe your methods in one path.
One of the OpenAPI 3 rules.
Two POST methods for the same path are not allowed – even if they have different parameters (parameters have no effect on uniqueness).
More details are available on OpenAPI 3 site.
This has been explained here: https://github.com/springdoc/springdoc-openapi/issues/580

VS Code API to get method name and their parameters from selected text

I am just trying to develop a new VS Code extension.
Where I have the requirement to get method name, parameters, and return type if the user selects specific text.
public someMethodName(param_1:number, param_2:string):number{
.....some logic
}
Expected:
methodName: someMetodName
parameters = {
param_1,
param_2
}
returnType = number
Thanks, in advance.

Passing a JSON object to worklight java adapter

I would like to pass a complete JSON object to a java adapter in worklight. This adapter will call multiple other remote resources to fulfill the request. I would like to pass the json structure instead of listing out all of the parameters for a number of reasons. Invoking the worklight procedure works well. I pass the following as the parameter:
{ "parm1": 1, "parm2" : "hello" }
Which the tool is fine with. When it calls my java code, I see a object type of JSObjectConverter$1 being passed. In java debug, I can see the values in the object, but I do not see any documentation on how to do this. If memory serves me, the $1 says that it is an anonymous inner class that is being passed. Is there a better way to pass a json object/structure in adapters?
Lets assume you have this in adapter code
function test(){
var jsonObject = { "param1": 1, "param2" : "hello" };
var param2value = com.mycode.MyClass.parseJsonObject(jsonObject);
return {
result: param2value
};
}
Doesn't really matter where you're getting jsonObject from, it may come as a param from client. Worklight uses Rhino JS engine, therefore com.mycode.MyClass.parseJsonObject() function will get jsonObject as a org.mozilla.javascript.NativeObject. You can easily get obj properties like this
package com.mycode;
import org.mozilla.javascript.NativeObject;
public class MyClass {
public static String parseJsonObject(NativeObject obj){
String param2 = (String) NativeObject.getProperty(obj, "param2");
return param2;
}
}
To better explain what I'm doing here, I wanted to be able to pass a javascript object into an adapter and have it return an updated javascript object. Looks like there are two ways. The first it what I answered above a few days ago with serializing and unserializing the javascript object. The other is using the ScriptableObject class. What I wanted in the end was to use the adapter framework as described to pass in the javascript object. In doing so, this is what the Adapter JS-impl code looks like:
function add2(a) {
return {
result: com.ibm.us.roberso.Calculator.add2(a)
};
The javascript code in the client application calling the above adapter. Note that I have a function to test passing the javascript object as a parameter to the adapter framework. See the invocationData.parameters below:
function runAdapterCode2() {
// x+y=z
var jsonObject = { "x": 1, "y" : 2, "z" : "?" };
var invocationData = {
adapter : "CalculatorAdapter",
procedure : 'add2',
parameters : [jsonObject]
};
var options = {
onSuccess : success2,
onFailure : failure,
invocationContext : { 'action' : 'add2 test' }
};
WL.Client.invokeProcedure(invocationData, options);
}
In runAdapterCode2(), the javascript object is passed as you would pass any parameter into the adapter. When worklight tries to execute the java method it will look for a method signature of either taking an Object or ScriptableObject (not a NativeObject). I used the java reflection api to verify the class and hierarchy being passed in. Using the static methods on ScriptableObject you can query and modify the value in the object. At the end of the method, you can have it return a Scriptable object. Doing this will give you a javascript object back in the invocationResults.result field. Below is the java code supporting this. Please note that a good chunk of the code is there as part of the investigation on what object type is really being passed. At the bottom of the method are the few lines really needed to work with the javascript object.
#SuppressWarnings({ "unused", "rawtypes" })
public static ScriptableObject add2(ScriptableObject obj) {
// code to determine object class being passed in and its heirarchy
String result = "";
Class objClass = obj.getClass();
result = "objClass = " + objClass.getName() + "\r\n";
result += "implements=";
Class[] interfaces = objClass.getInterfaces();
for (Class classInterface : interfaces) {
result += " " + classInterface.getName() ;
}
result += "\r\nsuperclasses=";
Class superClass = objClass.getSuperclass();
while(superClass != null) {
result += " " + superClass.getName();
superClass = superClass.getSuperclass();
}
// actual code working with the javascript object
String a = (String) ScriptableObject.getProperty((ScriptableObject)obj, "z");
ScriptableObject.putProperty((ScriptableObject)obj, "z", new Long(3));
return obj;
}
Note that for javascript object, a numeric value is a Long and not int. Strings are still Strings.
Summary
There are two ways to pass in a javascript object that I've found so far.
Convert to a string in javascript, pass string to java, and have it reconstitute into a JSONObject.
Pass the javascript object and use the ScriptableObject classes to manipulate on the java side.

Web-Api 400 BadRequest when search parameter is blank

I am using web-api with mvc4
I am making searching functionality, in some cases like if i filter data then remove that textbox value and then press search button, need to show whole listing but in my case showing 400 bad request. as search parameter is blank, i know if search parameter blank then it will throw 400 error with web-api.
any one have proper solution then please let me know.
data: "CurrPage=" + JsCurrPage + "&PageSize=" + parseInt(pagesize) + "&BuildTypeName=" + $("#BuildTypeName").val(),
Here in some cases BuildType is blank. when search made
//controller
public HttpResponseMessage GetBuildTypeList(int CurrPage, int PageSize, string BuildTypeName)
{
}
Net -> XHR URL is :
http://{parentURL}/api/BuildTypeWebApi/GetBuildTypeList?CurrPage=1&PageSize=10&BuildTypeName=
public HttpResponseMessage GetBuildTypeList(string BuildTypeName, int CurrPage = 1, int PageSize = 0)
In you business logic you can assume that a PageSize of 0 means all records.
If you allow CurrPage and PageSize to be empty, then you need to accept nullable ints:
public HttpResponseMessage GetBuildTypeList(int? CurrPage, int? PageSize, string BuildTypeName)
Then, you'll update the query so it return the entire list if no filter values are provided.

Web API Routing error from RC to RTM with model binding

Upgrading an rc to rtm web api project
Default parameter binding for simple type parameters is now [FromUri]: In previous releases of ASP.NET Web API the default parameter binding for simple type parameters used model binding. The default parameter binding for simple type parameters is now [FromUri].
I believe is the change that is causing me greif.
Well now I'm not so sure. StrathWeb seems to make me thing it should just work as is.
Given this endpoint
[HttpGet]
public HttpResponseMessage Method(string a, string b)
{
...
}
I generate a url on the client using
#Url.RouteUrl("route", new { httproute = "", controller = "Controller", version = "1" })">
to get it to generate the url for this route.
routes.MapHttpRoute(
name: "route",
routeTemplate: "api/v{version}/{controller}/Method",
defaults: new
{
action = "Method",
controller = "Controller",
version = "1"
});
It creates the url fine. The urls looks like
.../api/v1/Controller/Method?optional=z
.../api/v1/Controller/Method?a=x&b=y&optional=z
It throws a 404 when requested. If I remove the parameters a and b in the api controller then it enters the method just fine.
What is the correct way to make these bind?
if you need 'a' and 'b' to be optional, then you would need to make them optional parameters:
public HttpResponseMessage Method(string a = null, string b = null)