PostAsJsonAsync not calling the Controller when <Tvalue> has null fields - json

My TValue object has foreign key related objects, which has null values when posting; I am having the logic to set the FK objects in the repository. The issue I am facing is that API controller is not getting called when FK objects have all fields null. Please see screenshot. The same code works if I set the value for all but the ID field of the FK objects from the front end.
Is the issue because Json serializer checking for nulls? I have also tried to set the null check ignore option. I am not getting an error on PostAsJsonAsync and the control simply goes to the next line of code
return await result.Content.ReadFromJsonAsync();
without calling the API controller and send an exception
public async Task<SubContract> AddSubContract(SubContract subContract)
{
/* On the injected httpClient, call the PostAsJsonAsync method and pass the subContractObject
* We also need to specifi the api Uri in the parameter list */
JsonSerializerOptions option = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
var result = await httpClient
.PostAsJsonAsync<SubContract>("api/SubContracts", subContract, option);
//Use the content object and ReadFromJsonSync method and typecast it to <SubContract>
return await result.Content.ReadFromJsonAsync<SubContract>();
}
Screenshot
--- Further observations ---
#Serge Thanks for the response. You are right, I am using .Net 6. I have now commented out the nullable but I still have the same issue. Further, I tried to change the function to PostAsync instead of PostAsJsonAsync; below is the new code
// ---- Post Asysc Option -----
var subContractSeralized = JsonSerializer.Serialize(subContract, option);
var stringContent = new StringContent(subContractSeralized,
encoding: System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("api/subcontract", stringContent);
return await response.Content.ReadFromJsonAsync<SubContract>();
I initially thought it was a serialization issue because of the nulls in the nested object but when I debug the new code, I get the below result
subContractSerealized = '{"Id":0,"Name":"Aquatic-Repairs","Status":"In-Progress","WorkTypeId":1002,"WorkType":{"Id":0},"SiteId":3,"Site":{"Id":0},"OrganizationId":3,"Organization":{"Id":0}}'
If you compare this with the Debug screen shot in my first post, you can see that the null value fields in the nested objects are omitted out
Response StatusCode = “Not Found-404”
I am not sure how Response Status code is obtained as the API is not called. I.e. httpClient.PostAsync does not transfer control to the API and my debug breakpoint is not hit.
I tried the same code for an Entity model that has no nested foreign key related objects and it works fine and I am able to add the record to the DB. I have the “Required” validation set on the field properties of the entity models; however, after the API call, I have my repository that is taking care of it. So, I doubt that is an issue. In any case, the code is not even hitting the API and simply returns an 404 NotFound on httpClient.PostAsync.

you must be using Net 6 API, and it causes a validation error. Try to comment Nullable in your API project (your serializer option is not working in this case)
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<!--<Nullable>enable</Nullable>-->
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

Related

Solr custom query parser "fl" parameter not returning desired result

I am currently working on replacing an existing searching platform with Solr. I am new to Solr and currently using Solr Version 6.6.0. Legacy system accepts a JSON object with search parameters. Thus I was asked to implement a custom query parser which accepts a query string in JSON format.
Essentially NO other parameter is passed to Solr except "q" which contains all the required parameters encoded in a JSON formatted string. All the common parameters and local parameters required to execute the query is then extracted by the query parser itself.
This feat was successfully achieved except the "fl" parameter will not give the expecting results. Which means query result composes of all the fields that are present in the document. Code looks like this;
public static final String FIELD_LIST = "fl";
Collection for storing the key value pairs.
HashMap<String,Object> paramMap = new HashMap<String, Object>();
Decoding and formatting the field list.
String ifld = getFieldList();
Parameters are put in the collection thus.
paramMap.put(Constants.FIELD_LIST,ifld);
SolrParams are then generated.
return SolrParams.toSolrParams(new NamedList<>(paramMap));
Each and every query parameter is processed this way and finally in the query parsers parse() method i have this.
//calls the factory method to get the appropriate request type translator
JSONRequestTranslator jrt = (JSONRequestTranslator)JSONQParser.getTranslator(requestType);
//converts the arguments to solrparams.
qstr = jrt.getQueryString();
localParams = jrt.getLocalParams();
params = jrt.getParams();
req.setParams(SolrParams.wrapDefaults(params, this.req.getParams()));
return jrt.parse(qstr, localParams, params, req);
parse() method in classes implementing the JSONRequestTranslator interface looks like this
#Override
public Query parse(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) throws SyntaxError {
return new DisMaxQParser(qstr, localParams, params, req).parse();
}
This works fine but the "fl" parameter seems to have no effect. I don't have a default setting in solrconfig.xml file and while i'm debugging i always find the "fl" parameter set to correct value. I have tried several other approaches like writing custom search component plugins but please explain how to fix this and what am i missing here. Thank you.

My RCP Client is not returning a deep copy of an object

I have been working on an RCP Client to handle weather data.
What i do is 2 things, first i scraped the JSON i will be using and put it into a dart file. See: https://dartpad.dartlang.org/a9c1fe8ce34c608eaa28
My server.dart page, will import the weather data, and then carry out the following:
import "dart:io";
import "weather_data.dart";
import "dart:convert";
import "package:rpc/rpc.dart";
find ApiServer _apiServer = new ApiServer(prettyPrint:true);
main() async {
Weather w = new Weather(WeatherJson);
TestServer ts = new TestServer(w);
_apiServer.addApi(ts);
HttpServer server = await HttperServer.bind(InternetAddress.ANY_IP_V4, 12345);
server.listen(_apiServer.httpRequestHandler);
}
class Weather{
Map weather;
Weather(this.weather){
Map get daily => weather["daily"];
}
}
#ApiClass(name:"test_server", version: 'v1', description: 'This is a test server api to ping for some quick sample data.')
class TestServer {
Weather myWeather;
TestServer(this.myWeather){
}
#ApiMethod(method:'GET', path: 'daily')
Map<String, Object> getDaily(){
return myWeather.daily;
}
}
So, the server starts correctly, and i will go to localhost:12345/test_server/v1/daily and it will return this:
{
"summary": {},
"icon": {},
"data": {}
}
which is not correct. If you look up the JSON data, summary and icon are both strings and data is an array. They are also empty, and should contain the data i wanted to return.
Why does this occur? Is it because i am returning a Map<String, Object>? I was trying to set it up to be: Map<String, dynamic> but the dart compiler didnt like it.
How do i get this data to return the correct dataset?
The Dart website for RPC is located at: https://github.com/dart-lang/rpc
and you can see that under methods, the return value of a method can be either an instance of a class or a future. That makes sense as per usual, so I set it to be a Map<String,Object> though trying to be vague about it by saying: Map was not sufficient.
Edit:
When doing this mostly in dart pad without RPC, it seems to work correctly, by a sample of: https://dartpad.dartlang.org/3f6dc5779617ed427b75
This leads me to believe something is wrong with the Parsing tool as it seems the return type in dartpad allows to return Map, Map<String, Object>, and Map<String, dynamic>.
Having had a quick look at the RPC package README here https://pub.dartlang.org/packages/rpc, it seems that methods marked as Api methods (with #ApiMethod) should return an instance of a class with simple fields such as:
class ResourceMessage {
int id;
String name;
int capacity;
}
The RPC package will take that instance and serialize it into JSON based on the field names.
From the README:
The MyResponse class must be a non-abstract class with an unnamed
constructor taking no required parameters. The RPC backend will
automatically serialize all public fields of the the MyResponse
instance into JSON ...
You are returning a nested Map representation of the JSON you want the RPC operation to emit and would guess that the RPC package does not handle it as you are expecting it to.
Re: this from your question:
This leads me to believe something is wrong with the Parsing tool as
it seems the return type in dartpad allows to return Map, Map, and Map.
There is no 'parsing' on JSON going on on your example. The data you have is a set of nested literal Dart Maps, Lists and Strings with the same structure as the JSON it was derived from. It just happens to look like JSON.
In your example you are just selecting and printing a sub-map of your data map (data['daily']), which prints out the String that results from calling toString() - which is recursive so you get the contents of all the nested maps and lists within it.
So it's not a 'deep copy' issue, but a difference in how toString() and the RPC code processes a set of nested maps.
BTW: the return type of your getDaily() method is immaterial. What is returned is just a Map whatever the declared return type of the method is. Remember types in Dart are optional and there for editors and compilers to spot potentially incorrect code. See https://www.dartlang.org/docs/dart-up-and-running/ch02.html#variables.
I am going to piggyback off of #Argenti Apparatus here as there was a lot of information gained from him.
Long story short, the required return type of the method:
#ApiMethod(method:'GET', path: 'daily')
Map<String,Object> getDaily(){ // <-- Map<String,Object>
return myWeather.daily;
}
is the error.
I went through and updated the method signature to be Map<String,String> and it parsed it entirely correct. It did not parse the object as a string, but actually parsed it as a full recursed object.
I went through and for the sake of code cleanliness also changed signatures of Weather properties to reflect what they actually were, Map<String,Object> as well.
All in all, When defining it to be an value type of Object, it was returning curly braces, but setting it as a String parsed it correctly.
I ran it through JSLint to confirm it is correct as well.
I gave a +1 to the helper, I had to dig deeper into the code to see WHY it wasnt doing a Map correctly.
This also I feel, is plausibly a bug in RPC Dart.

MVC4 Model Binding - Null Values

I know there are a bunch of questions on this already - I'm having a hard time sorting out which ones are related to problems with versions, and which ones are related to jQuery (which I'm not using), etc. I have the MVC4 RC (4.0.20505.0), Visual Studio 2010 Ultimate SP1.
I have a complex type in my model:
public HttpResponseMessage Post([FromUri]Person person)
{
TableStorageHelper personHelper = new TableStorageHelper();
personHelper.Save(personHelper.GetTableNameForType("Person"), person);
var response = Request.CreateResponse<Person>(HttpStatusCode.Created, person);
return response;
}
I am passing in this JSON string - using Fiddler mostly, but also trying from code in another controller (trying to do all testing locally just to verify that I can get values in the object received by the controller):
The JSON:
{"FirstName":"Andy","LastName":"Schultz","PartitionKey":"USW","RowKey":"per-928c8f74-2efd-4fc2-a71c-fb3ea8acc6d7","NickName":null,"FullName":"Andy Schultz","Description":null,"ImageLocation":null,"Region":"USW","CommentsAboutMe":{"Comments":[]},"CommentsByMe":{"Comments":[]}}
All of the properties here do exist in the class.
The code from the other controller:
HttpWebRequest request = HttpWebRequest.Create("http://127.0.0.2:8080/api/persons/") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/json";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
Person person = new Person("Andy", "Schultz", "USW");
Formatting formatting = new Formatting();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(person, formatting, settings);
writer.Write(json);
}
Every time, I get an empty Person object in my controller (I'm debugging on the very first line there). Every value is NULL.
You may have noticed the [FromUri] attribute on my controller - I had to do that to get around an error telling me there was no ModelBinder for an undefined type, but I'm not sure that it's correct - I'm not passing any info in the Uri, it's in the body, as you can tell.
Thank you Mike Stall: http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx
The [FromUri] attribute did indeed tell my controller to read the uri and not the request body looking for the parameter for my controller method. It wasn't there, so everything was null.
The error that adding that attribute fixed, which said there was no formatter defined for a type of content Undefined, was caused by my improperly declaring the content-type of the request. The correct way was "Content-Type: text/json; charset=utf-8

ASP.NET MVC 3 ModelState.IsValid is always returning true for JSON encoded data using Ext.Direct

I have a form and the only item that is required is the customer name. So in my model, I have:
[DisplayName("Customer name*:")]
[Required]
public string CustomerName
{ get; set; }
Previously, I was doing an HTML post and everything worked fine including validation.
Now, I've "ajaxified" the form, using Ext.direct.mvc (http://code.google.com/p/ext-direct-mvc/), which is a significant fact, and posting the data in Json format and the data is getting posted successfully.
When I put a breakpoint in my code (currently modified for debugging purposes):
[DirectInclude]
[HttpPost]
public ActionResult SaveOrUpdateOrderLines(CustomerOrderModel customerOrderModel)
{
if (!ModelState.IsValid)
{
return ModelState.JsonValidation();
}
return null;
I see that the CustomerOrderModel.CustomerOrderHeader.CustomerName = ""
But the ModelState.IsValid is true.
Now for some of the things I've tried:
I have inserted the following code, just before checking for ModelState.isValid, in order to ensure that CustomerName = null
customerOrderModel.CustomerOrderHeader.CustomerName = null;
I have tried using TryUpdateModel(customerOrderModel) but I get the following error message:
TryUpdateModel threw an exception of type 'System.MissingMethodException'
I've tried modifying the json data so that the "root" "CustomerOrderHeader" was renamed to "customerOrderModel" to match the parameter.
None of these things worked. So what could I be doing wrong that validation isn't working anymore? What steps can I take to debug the issue?
EDIT for counsellorBen
EDIT 2 for counsellorben
The problem is that when trying to bind a Json response, the name of the variable in your controller action must match the name of the variable passed on the client side. Your model is valid, because CustomerOrderHeader is null.
In your client script, you should wrap your entire model in an element named "customerOrderModel", so the name matches the variable name in your action.

Zend_Json_Server and dojo.rpc.JsonService, can a served class return an object?

I am trying to serve up my user repository via zend_json_server. The problem is the service is returning empty objects. What have i missed?
server side:
$repo = App_User_Repository::getInstance();
$server = new Zend_Json_Server();
$server->setClass($repo);
if ('GET' == $_SERVER['REQUEST_METHOD']) {
$server->setTarget('/service/json-rpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
// Set Dojo compatibility:
$smd->setDojoCompatible(true);
header('Content-Type: application/json');
echo $smd;
return;
}
$server->handle();
client side:
var object = new dojo.rpc.JsonService('/service/json-rpc.php');
var deferred = object.getById(1);
deferred.addBoth(function(result) {console.log(result)});
Firebug console output:
Object {}
This should be a User object
When doing the actual RPC with the "getById()" method, an dojo.deferred object is returned. At this point, a asynchronous request is running. By using the deferred object, you can define callbacks and error handlers in advance whilst waiting for the response to be returned.
Check if the actual response object isn't empty as well. Remember, you still have to use the return keyword in your attached classes to return results back to Zend_Json_Server. Zend_Json_Server will then serialize and send back the returned value automatically. A response from Zend_Json_Server is always a serialized object in JSON, containing an id (which increments automatically with each request), an string indicating what jsonrpc version is being used (ie. 2.0) and of course a result containing the returned data from the attached class.
The setClass() method should not be a object instance, but a string containing the className of the class you want to attach. Zend_Json_Server handles the creation of the object instance by itself, as well as generating the SMD (Service Method/Mapper Description). Remember to document each public method with docblocks, as Zend_Json_Server uses those docblocks to determine the SMD.
Furthermore, it is much more handy to use a fluent-like interface with the then() method like so:
var myService = new dojo.rpc.JsonService('/service/json-rpc.php?');
var deferredObj = myService.doThis('myArgument');
deferredObj.then(callback, errorHandler).then(afterCallback).then(cleanUp);
In above example, the variables callback, errorHandler, afterCallback and cleanUp, are actually references to functions. The first then() method you call, automatically passes the rpc result to the callback function. If you throw an exception from within the attached rpc class, the errorHandler method (second optional argument of the first then() method call) will be called instead.
More information: http://www.sitepen.com/blog/2010/05/03/robust-promises-with-dojo-deferred-1-5/
I recently ran into the same problem and it wasn't a problem with dojo deferred. I'm assuming getById(1) is your remote function call, in which case if your server finds results dojo shouldn't get the empty object. Even using addBoth method on a deferred object would still show the result from the server, which leads me to believe your problem is not in any of the code you've listed, but getById(1) call in your App_User_Repository class. Did you use Zend_Dojo_Data or something else to json encode before returning? That would clobber your result, Zend_Json_Server does the encoding for you.