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.
Related
This is a configuration issue on my WebAPI application.
When I pass this date as JSON from my Angular project to my WebAPI project it looks like this: created: "2019-01-09T16:16:06.149Z"
After it passes through Deserialization at WebAPI, it looks like this:
UPDATE: Initially, I was skeptical that this was a JSON.Net thing. But, as looked at my models more carefully, I realized this IS a JSON.Net. I have a base class that contains my "Created", "Updated" fields. Address inherits this class. HomeAddress inherits Address. This must be too much for JSON.Net to handle. When I removed the Inheritance from the Base class, and put my Created and Updated members on HomeAddress. It worked! So, this question really pertains to JSON.Net's capability to merge inherited members sourced in a base class.
WebAPIConfig.cs (no JSON.Net configuration for dates):
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{...}
}
WebAPI Controller:
[RoutePrefix("parents")]
public class ParentsController : ApiController
{
[HttpPost]
[Route("update")]
public bool UpdateParentInfo(Parent parent)
{
// when I inspect parent.Homeaddress.Created I get the DateTime().Min
}
}
HomeAddress.cs nested in Parent.cs:
public class Parent
{
[JsonProperty("parentID")]
public Guid ParentID { get; set; }
[JsonProperty("homeAddress")]
public Address HomeAddress { get; set; }
public Parent()
{
this.HomeAddress = new HomeAddress();
}
}
HomeAddress.cs:
public class HomeAddress: Address
{
public HomeAddress(){}
}
Address.cs
public class Address: Base
{
[JsonProperty("addressID")]
[Key]
public Guid AddressID { get; set; }
[JsonProperty("street1")]
public string Street1 { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("state")]
public string State { get; set; }
[JsonProperty("zip")]
public string Zip { get; set; }
}
Base.cs
public class Base
{
[JsonProperty("created")]
public DateTime Created { get; set; }
}
This date is in a nested object.
Can JSON.Net Detect Inherited Members -- this deep? Thanks for the help.
My short answer: No. And I'm running away from the abstraction as fast I can type. I'm putting my Created/Updated members in the HomeAddress class. And calling it a day.
So I have been learning some .net core and I am building an API with it. Normally I would work with angular and send requests there.
I have the following angular snippet:
//The data I need to send.
$scope.PersonalInfo = {
firstName: '',
lastName: '',
companyName: '',
email: '',
password: '',
confirmPassword: '',
imageLink: ''
};
Then there's the backend model for the same data:
public class UserProfileModel
{
public string userID { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string companyName { get; set; }
public string email { get; set; }
public string password { get; set; }
public string confirmPassword { get; set; }
public string imageLink { get; set; }
}
And finally the method that should send it:
$scope.UpdateProfile = function () {
var profile = JSON.stringify($scope.PersonalInfo);
$http.post('/api/Profile/Users', profile).then(function (response) {
debugger;
$log.log(profile);
$log.log(response);
});
};
No matter how many changes I have done, (send the data as a stringified JSON, or send the scoped object), when the request hits the controller, I end up with this:
$scope.PersonalInfo is full of data before the request is sent.
Any help is very appreciated. Thanks in advance.
You need to mention [FromBody] attribute in your post call. Like So,
[HttpPost]
[Route("api/bar/users")]
public IActionResult Users([FromBody]UserProfileViewModel profile)
{
return Json(new { Data = profile });
}
That should do it.
The necessity to use the FromBody attribute is so that the framework can use the correct input formatter to model bind. The default formatter used, for example, with content type application/json is the JSON formatter based on Json.Net
Detailed information at: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
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'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.
I know I am doing something stupid here but I'm hoping someone with some Breezejs experience can help me out (please) as I am new to it. So the problem is when I do a breeze manager.saveChanges() the navigation properties (and only the navigation properties) are not sent to the server. In my model all the navigation properties are just lookup items if that makes any difference and I am using knockout to do the binding. Here is a screenshot to show whats wrong:-
the relevant bit in my dataservice just does this:-
function createAssessment() {
return manager.createEntity('VulnerabilityAssessment');
}
Domain model:-
public class VulnerabilityAssessment
{
public int Id { get; set; }
public virtual AssessmentStatus Status { get; set; }
public virtual PupilRecord Pupil { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string LatestContact { get; set; }
public string Referrer { get; set; }
public virtual ReferralReason ReasonForReferral { get; set; }
public string SingleResponsibleAdult { get; set; }
public string CurrentIssues { get; set; }
public virtual ReferralSupport PrimaryReferralSupport { get; set; }
public virtual ReferralSupport SecondaryReferralSupport { get; set; }
public bool LikelyToLeaveWithoutQualification { get; set; }
public virtual Destination MovingOnDestination { get; set; }
public virtual Destination DestinationAfterOneMonth { get; set; }
public virtual Destination DestinationAfterSixMonths { get; set; }
public virtual Destination DestinationAfterTwelveMonths { get; set; }
public virtual ProtectedCharacteristic ProtectedCharacteristic { get; set; }
public string Undisclosed { get; set; }
}
Here is my viewmodel:-
define(['services/logger', 'services/dataservice'], function (logger, dataservice) {
var title = 'Vulnerability Assessment';
this.activate = function activate() {
var initialData = dataservice.getAssessmentLookups()
.then(function (data) {
vm.referralReasonCodes(data.referralReasonCodes);
vm.referralSupportCodes(data.referralSupportCodes);
vm.assessmentStatusCodes(data.assessmentStatusCodes);
vm.destinations(data.destinations);
vm.protectedCharacteristics(data.protectedCharacteristics);
vm.assessment(dataservice.createAssessment());
console.log('assessment: %A', vm.assessment());
})
.done();
logger.log(title, null, title, true);
return initialData;
}
this.save = function () {
console.log('in save: %A', vm.assessment());
dataservice.saveChanges();
}
var vm = {
activate: this.activate,
title: title,
referralReasonCodes: ko.observableArray(),
referralSupportCodes: ko.observableArray(),
assessmentStatusCodes: ko.observableArray(),
destinations: ko.observableArray(),
protectedCharacteristics: ko.observableArray(),
assessment: ko.observable(),
save: this.save
};
return vm;
});
View/HTML:-
<select id="reason-for-referral" class="form-control input-md" data-bind="options: $root.referralReasonCodes, optionsText: 'description', value: $data.reasonForReferral"></select>
Note: the select element above is within a another div that goes like this:-
<div class="row" data-bind="with: assessment">
Here is a look at my object just before it is sent to the server.
Totally stuck at the moment...
Many thanks for taking a look.
Breeze does not send "related" entities ( those available thru navigation properties) in a save UNLESS these related entities are "modified", "added" or "deleted". This is the default behavior when you call EntityManager.saveChanges without any parameters. The reason for this is that we don't want send any data that has not actually changed.
If, on the other hand, you are calling EntityManager.saveChanges and passing in a list of entities then you will need to include any related entities that you want send to the server as part of the list.
If not, then why do you want to send entities that have not changed to the server on a "saveChanges" call? Am I missing something?