Model Binding null versus User given null - c#

I am fairly new to .net core c# and wanted to know the following.
Whenever we put thru a HTTPRequest with body, c# model binding binds the same to a complex object (in my case). But in cases, where the the body did not have certain attributes populated, the model binding marks those as null. But in some cases, the user might populate it as null. I want to differentiate this and depending upon the same, I want to know whether I can overwrite what is already present in DB. Or I can read from Db, merge with the new request and then write again. Please let me know if there is a way to approach this problem, thanks :)
Example
[HttpPut]
public HttpResponseMessage PutAlbum(Album album)
{
}
Album
{
public int songs;
public string name;
public string composer;
.
.
}
Request
Req 1
{
songs = 2,
name = "xyz"
}
Req 2
{
songs = 2,
name = "xyz"
composer = null
}
In Req1, model binding assigns to null. Whereas in Req2, the user assigns composer to null. Is there a easy and optimal way to differentiate the same ??

Related

How to add example values for parameters in Swagger-UI built by Nancy.Swagger package?

I have used Nancy.Swagger package and MetadataModule to build a Swagger UI for my APIs (according to this link: https://github.com/yahehe/Nancy.Swagger/wiki/Nancy.Swagger-for-Nancy-v2).
I get the UI, but the problem is that I cannot add example values for the properties of the object, which is passed as a parameter in body.
I see, for example, this output:
Here, instead of the word "string", I would like to have a real example value. But I don't know how I can add example values in this approach, and I would appreciate any help.
Snippet from the API and the parameter (object of PRequest):
Post("/", async (x, ctx) =>
{
PRequest PostRequestModel;
try
{
postRequestModel = this.Bind<PRequest>();
}
Snippet from MetaDataModule:
Describe["Post"] = desc => desc.AsSwagger(
with => with.Operation(
op => op.OperationId("Post")
.Tag("User")
.Summary("Post a new User")
.Description("This creates a new user.")
.BodyParameter(bp => bp.Description("A PRequest object").Name("PRequest").Schema<PRequest>())
I know it has been absolutely ages since you opened this, but I figured I'd share anyways.
First you need a model, like so:
public class Model
{
public string ExampleString { get; set; }
}
You need to create an instance of this model filled with whatever examples you want.
var exampleModel = new Model() { ExampleString = "foobar" }
Then you can add it to the BodyParameter like so:
.BodyParameter(para => para.Name("Example").Schema(
new Schema() { Example = exampleModel }
).Build())
I just created a public static class to hold all my example objects, then I set them like Example = Examples.Example1. I think this is the most readable approach.
A couple problems exist with this approach that I haven't found a solution to (yet). One is that the Example object does not seem to respect whatever settings you're using for Json serialization. Also, I've been unable to get this working concurrently with the Model view, but the Model view was always mostly useless in my eyes anyway. I'll update this if I ever figure any of these issues out. :)

Object reference updating, update all collections property?

Introduction
I found a very weird situation, so essentially I've a collection property called Matches and an object property called Match.
The Matches collections contains a list of item of Match, like this:
private ObservableCollection<Match> _matches = new ObservableCollection<Match>();
public ObservableCollection<Match> Matches
{
get { return _matches; }
}
this collection is valorized when the application start, infact, the software take some data from an Internet site and then, with a scraper fill the collection with the correspond object model Match.
Where the bug start
The Matches collection is binded to a DataGrid. When the user click on an element (Match), available on the DataGrid, the code fire the event SelectionChanged, inside this event I create a copy of the Match clicked, so I can use this object inside all my application:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
as you can see with the use of Linq, I check if the Match clicked by the user have the same link of a Match contained in the Matches collection, infact, each Match in the collection have a unique link like a GUID for example.
The bug
The Match object look like this:
private Match _match;
public Match Match
{
get { return _match; }
set
{
_match = value;
OnPropertyChanged();
}
}
and as I said it contains the Match clicked by the user. This object allow me to get the data from Internet only for this Match, from all methods inside my app. This working pretty well. Until now.
My application allow the user to apply some filters, essentially the user press a button and then the Match saved is updated with the property filled by the user, for example:
Match.League.Rounds = availableRounds;
this code cause the bug, but I'll try to explain the bug better later, I need to explain a bit what happen here.
Essentially the current Match saved in the application should update only the own property League.Rounds, this property is a list of Rounds available for this Match, the structure is very simple:
public class Round
{
public int Id { get; set; }
public string Name { get; set; }
}
the update working good but, the line Match.League.Rounds = availableRounds; update also all the property League.Rounds available in the objects collection Matches.
I don't understand why happen this, I've not created a reference of the object clicked:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Practice example of what's happening
before filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 10 and Name foo
after filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 11 and Name foofoo
but it should not be modified, only the Match should be modified.
but a new object. Someone could explain how to fix this? Best regards.
I've not created a reference of the object clicked
Yes, you have. This does not create a new Match object:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
It gets a reference to the already existing Match object in the Matches collection.
If you want to create a new object, you should use the new operator:
var existing = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Match match = new Match();
//set all properties of the new object...
match.Prop1 = existing.Prop1;
Also note that you need to create new Round objects as well. You should consider implementing the IClonable interface.
The FirstOrDefault() method doesn't clone the object for you.

Show Hide divs in views based on boolean value

I'm currently working on an app using Asp.Net MVC and C#. One of the requirement is to check what process the item is and then to only show the appropriate div. So I've decided to create a Table in the Db which consist of:
Id ProcessDescription DivOneVisible DivTwoVisible
1 Approved True False
2 Analysis True True
...
NOTE - The Id's and ProcessDescription will never change
Currently the table only holds 10 rows of data but the idea is, in future more rows/columns can be added.
I then go ahead and create the appropriate methods, one for each Div as follows
public bool ShowDivOne(int id)
{
var data = uow.GetRepository<ItemProcess>().GetById(id);
bool showDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
if (showDivOne)
return true;
else
return false;
}
I use the same code as above for ShowdivTwo() method, but match the different column. Then in the view I do
#if(ShowDivOne){//div one code here}
#if(ShowDivTwo){//div two code here}
This works but I was wondering if there is a more generic way where I can write one method which will cover each scenarios even if new columns or rows are added.
The main thing you still need to have a mapping between Database and ViewModel somewhere. At the moment it is hard coded in your methods.
You can make it absolutely generic if you start use reflection and have a mapping array with properties name. But I would nt recommend doing it as it over complication and hard to maintain and change.
(If you want I can go into details of implementation).
For you example I would suggest to have a viewmodel per item, that contains properties of divs to display.
public class ProcessViewModel
{
public int Id {get;set;}
public bool ShowDivOne {get;set;}
public bool ShowDivTwo {get;set;}
ProcessViewModel(){}
ProcessViewModel(ItemProcess data){
Id = data.Id;
ShowDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
ShowDivTwo = data.DivTwoVisible.HasValue ? data.DivTwoVisible.Value : false;
}
}
You still query for each item individually or query them altogether and pass data to viewmodel to construct it.
And a simple foreach on a view to traverse through the list of viewmodels.
Extending it to contain more properties would be very easy and strait forward, with minimum code to maintain.

Removal of one value in an array in MVC

I am using a few methods and interfaces in this one. What i need is for the method I'm making to just simply remove 1 value in an array of attributes. All of the stuff here was previously created by someone else, and I'm just creating the removal part for the attribute to be removed. At any rate, the method that does the profile attribute work and sets the value does some work on the back end. I have a method for a UserProfileAttributeSetRequest that looks like this:
public UserProfileAttributeSetRequest()
{
}
public UserProfileAttributeSetRequest(Guid userIdentifier, Dictionary<string, string> profileAttributes)
{
UserIdentifier = userIdentifier;
ProfileAttributes = profileAttributes;
}
This fires a method on the back end that will take in the information being passed to it and change whatever needs to be changed. The method I'm building in the controller probably needs some work, I'm still fairly new to MVC, but here's what I've got:
public ActionResult RemoveEmployeeID(UserInfo userInfo)
{
User usr = UserManager.GetUser(userInfo.UserGuid);
var empID = usr.ProfileAttributes.FirstOrDefault(e => e.ProfileAttributeID == 3);
usr.ProfileAttributes.Remove(empID);
UserProfileAttributeSetRequest upd = new UserProfileAttributeSetRequest();
}
I'm grabbing the complete user, and isolating the single attribute I want to be changed, but the Request complains when I put any parameters in it. What am I doing wrong?
try like this
var emp = usr.ProfileAttributes.Where(e => e.ProfileAttributeID == 3).FirstOrDefault();
usr.ProfileAttributes.Remove(emp);
you have to update the database after removing the item.

How can I retrieve a calculated property without expanding to related navigation properties?

I followed the great advice here (Handling calculated properties with breezejs and web api) to allow Breeze to access my calculated properties which I have set up in a partial class on the server side:
public partial class EventPerson
{
[NotMapped]
public Decimal TotalAmountPaid
{
get
{
return this.EventPersonPayments.Sum(p => p.AmtPaid);
}
}
}
But for each EventPerson I retrieve, this value shows up as 0 unless I use .expand("EventPersonPayments") clientside or .Include("EventPersonPayments") serverside.
I don't want all the data in EventPersonPayments to be serialized and sent to the client; all I want is the summed value. Is this possible?
EDIT: If my calculated property is derived from other properties already in the entity, it works fine. For example:
public partial class EventPerson
{
[NotMapped]
public String DisplayName
{
get
{
return this.FirstName + " " + this.LastName;
}
}
}
returns the DisplayName in the JSON payload. The former type of calculated property always returns 0 or null unless I specifically load all the extra information.
I considered converting these into User Defined Functions in SQL Server, but I shouldn't have to throw out my C# code just to make it work the way it should.
One approach is to use a projection that incorporates both the entities being queried and some calculated properties as well. i.e. your server query might look like this:
[HttpGet]
public IQueryable<Object> CustomersAndFreightTotals(companyName) {
var stuff = ContextProvider.Context.Customers
.Where(c => c.CompanyName.StartsWith(companyName))
.Select(c => new { Customer = c, FreightTotal = c.Orders.Sum(o => o.Freight)) });
return stuff;
}
This query will load all of your customers that start with a specified company name but will also give you the "total freight" for all of the orders on each customer.
You would call this with code something like this:
var query = EntityQuery.from("CustomersAndFreightTotals")
.withParameters({ companyName: "C" });
myEntityManager.executeQuery(query).then(function(data) {
var results = data.results;
results.forEach(function (r) {
// note that each customer WILL also be added to the local entityManager
// because it is an entity, whereas the freightTotal is only available here.
var customer = r.Customer;
var freightTotal = r.FreightTotal;
// and if you wanted to hack the customer entity
// you could do this.
customer.freightTotal = freightTotal;
});
}
I came across this problem also, and there are a couple of other questions/answers that seem to point to what's going on:
My unmapped properties in breeze does not seems to work whith a projection
UnMapped property on the Angular/Breeze SPA template
From my understanding, to put it shortly, [NotMapped] prevents Breeze/Entity Framework from correctly wiring up to the field. Yet Json.NET will serialize the field and send it to Breeze, which will populate the field if you've manually set it up via the class's constructor, and the data has been retrieved by using expand for the other property which Entity Framework recognizes. This seems to be almost an accident you can get [NotMapped] fields to work on the client in this given case; the Breeze+Entity Framework does not seem to be designed for this case.
There is a suggestion at Breeze's User Voice that you could vote and comment on. I'm not sure that Breeze could solve this problem themselves without some work from the Entity Framework team, but at least it could put the issue on their radar.

Categories

Resources