I'm working on a web-api controller. I built a DTO to hold a Note.
public class NoteContainer
{
public long? NoteId { get; set; }
public string Type { get; set; }
public string NoteText { get; set; }
public NoteContainer(Note note, string type = null)
{
NoteId = note.Id;
NoteText = note.NoteText;
Type = type;
}
}
I have a method in my controller:
[HttpPost]
public void EditNote(NoteContainer container)
{
//do work here
}
Before the NoteContainer is sent from the client it has all values. When it gets to the server, type is null! Should I not use a variable named type? Why am I losing the value?
Using Postman I'm sending this json:
{
"noteId": 10,
"type": "person",
"noteText": "loves broccoli",
}
That needs default constructor I believe. The problem can be that the Note class gets instantiated first and is given to NoteContainer.
Related
I would like convert string to JSON while receiving the value from API. I am sending value from postman but I am unable to convert it to the JSON object in the model class ,I have decorated model class with the custom decorator. Thanks in Advance.
This is the Model Class and I wrote custom JSON convertor.
namespace WebApplication2.Models
{
[Serializable]
public class Test
{
[JsonConverter(typeof(UserConverter))]
public AS_AscContext AscParcelContext { get; set; }
}
public class AS_AscContext
{
public string ShellType { get; set; }
public string LayoutName { get; set; }
}
public class UserConverter : JsonConverter
{
private readonly Type[] _types;
public UserConverter(params Type[] types)
{
_types = types;
}
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
JObject o = (JObject)t;
IList<string> propertyNames = o.Properties().Select(p => p.Name).ToList();
o.AddFirst(new JProperty("Keys", new JArray(propertyNames)));
o.WriteTo(writer);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return _types.Any(t => t == objectType);
}
}
This is the controller receiving value
[HttpPost]
public IActionResult Privacy([FromBody]Test aS_AggregatorRequest)
{
return View();
}
This is the postman collection
Try to change your postman JSON like this,
{
"ascParcelContext": {
"shellType": "ceme-sales-wallaby",
"layoutName": "value"
}
}
Don't escape any of the JSON data.
your json has another json inside. So it is better to fix the api but if you don't have an access try this
[HttpPost]
public IActionResult Privacy([FromBody]JObject jsonObject)
{
jsonObject["ascParcelContext"]= JObject.Parse( (string) jsonObject["ascParcelContext"]);
Test test = jsonObject.ToObject<Test>();
.....
}
public class Test
{
[JsonProperty("ascParcelContext")]
public AS_AscContext AscParcelContext { get; set; }
}
public class AS_AscContext
{
[JsonProperty("shellType")]
public string ShellType { get; set; }
[JsonProperty("layoutName")]
public string LayoutName { get; set; }
}
(sample request param would be)
request object would have
( array[0] : {objects1,objects2}
array[1] : {objects1,objects2})
request = {
"RequestRowIds": row["RowId"], // objects1
"SelectedRequest": request // objects2
};
API call :
return common.utils.httpPost("/Test/Create?" + request ).then(function (response)
{
common.toastr.success('Saved ' + Create.name + ' successfully!');
});
Value has been assigned at "request" and while passing the values to the controller. Its getting skipped. (error is "request" property)
class property declaration :
public class RequestItems
{
public dynamic RequestRowIds { get; set; }
public dynamic SelectedRequest { get; set; }
}
and the controller would be :
public async Task<Result> TestCreate(List<RequestItems> request )
{
// serviceLayer(request)
}
The call doesn't comes to controller part from the frontend, its getting skipped frontend itself.
I have tried with
public class request
{
public IEnumerable<object> request{ get; set; }
public dynamic request{ get; set; }
public List<dynamic> request{ get; set; }
}
Please help to resolve this issue.
On frontend (appending image file, and JavaScript object with details about product):
let f = new FormData();
f.append('File', file);
objectToSend = {
...values
};
f.append('ProductDto', objectToSend );
await createProduct(f);
export const createProduct = async data => {
return axiosWrapper.request({
url: `/products`,
method: 'POST',
data: data,
});
};
On backend (receiving appended data as FromForm):
// POST: api/products
[HttpPost]
public async Task<IActionResult> Post([FromForm]ProductFile file)
{
// Create product
}
ProductFile class looks like this:
public class ProductFile
{
public IFormFile File { get; set; }
public ProductDTO ProductDto{ get; set; }
}
Issue is that ProductDto is always null, while File is populated as it should be.. I don't understand why is that ?
P.S I've tried appending it like this also:
f.append('ProductDto', JSON.stringify(objectToSend));
Cheers
You are appending an object in FormData. Form data accepts key-value pairs where the value is expected to be a string as described here.
Try converting the object to a string first
f.append('ProductDto', JSON.stringify(objectToSend) );
Then in your backend, before accessing it, convert it back to an object.
Your problem is that the content-type of the request is formdata so ASPNET uses a FormData Model Binder to populate the properties of the model. This model binder won't be able to deserialize the json and bind it to the model.
If you want the model binder to be able to set the values of the properties of you object they need to be defined as formdata in your request.
For exemple if your object as a structure like this :
public class ProductDTO
{
public int ProductId { get; set; }
public string Name{ get; set; }
}
You'll need to do :
f.append('ProductDto.ProductId', objectToSend.productId );
f.append('ProductDto.Name', objectToSend.name);
Another solution is to use a string in your model, and deserialize the DTO yourself :
public class ProductFile
{
public IFormFile File { get; set; }
public string ProductDto { get; set; }
}
[HttpPost]
public async Task<IActionResult> Post([FromForm]ProductFile file)
{
var productDto = JsonConvert.DeserializeObject<ProductDTO>(file.ProductDto);
}
I'm posting some form data through ajax to my server. I also grab a some Id's from an array in memory and add it to the form data:
var postData = $('#frmMoveToNewPackage').serializeArray();
postData.push({
name: 'DocumentIds',
value: _checkboxList.getAllChecked()
});
$.post('#Url.Action("MoveToNewPackage")', postData);
My model is this:
public class MoveToNewPackageModel
{
[Required]
public int OldPackageID { get; set; }
[Required]
public Package NewPackage { get; set; }
public List<string> DocumentIds { get; set; }
}
This works. However technically the list of DocumentIds should be a List<int>. If I change the type in my modal, and change the post data:
postData.push({
name: 'DocumentIds',
value: _checkboxList.getAllChecked().map(function(item) { return parseInt(item);});
});
Then my DocumentIds is an empty (but not null) list of ints. I've looked at the data being posted and it's a valid int array.
EDIT: Above is wrong. It was not correctly binding the list of strings. It was just jamming everything into the first item of the string array.
I am having trouble sending a complex object to my SignalR hub. My JavaScript object matches exactly to my C# object, so I would expect everything to work. However, I am unable to hit my UpdateEmployee method. I have other methods in my hub that work just fine with simple types. Here is what I currently have implemented -
SignalR Hub
public void UpdateEmployee(int userId, Employee employee)
{
// Update employee
}
Where Employee is defined as
public class Employee: Persistable
{
[DataMember]
public DateTime? DateOfBirth { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
Which just simply inherits Persistable
[DataContract]
public class Persistable
{
[DataMember(Name = "id")]
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
}
I am trying to hit that method from my SignalR JavaScript client
$.connection.myHub.server.updateEmployee(userId, employee);
Where my employee object in JavaScript looks like
{ Id: 1, FirstName: "Test", LastName: "One", DateOfBirth: "01012001" }
Is there anything I am doing wrong here?
Have you tried it without the DateOfBirth value?
Perhaps it isn't able to bind your value 01012001 to the nullable DateTime? I have a feeling it has to be either NULL or a bindable value, else the binding will actually fail.