Trying to bind several form fields to one model - c#

Maybe what am i asking is totally dumb, but i cannot find any examples where several form fields are bind to one (complex) property of the model.
extract from my unit test
...
var formData = new MultipartFormDataContent(formDataBoundary)
{
{ new StringContent("0123456789"), "did" },
{ new StringContent("A"), "connectionStatus" },
{ new StringContent("Access Only 2432/160"), "descriptionOffer" },
{ new StringContent("ADSN4DSL"), "codeOffer" },
{ new StringContent("NORMAL"), "supportLevel" },
{ new StringContent("Entreprise TEST"), "finalCustomerDenomination" },
{ new StringContent("RUE"), "finalCustomerStreetCode" },
{ new StringContent("du Test"), "finalCustomerStreetName" },
{ new StringContent("45"), "finalCustomerStreetNumber" },
{ new StringContent("69389"), "finalCustomerCityCode" },
{ new StringContent("69009"), "finalCustomerCityPostalCode" },
{ new StringContent("Lyon 9e"), "finalCustomerCityName" },
{ new StringContent("TestCustomer"), "finalCustomerContactName" },
{ new StringContent("0987654321"), "finalCustomerContactPhoneNumber" },
{ new StringContent("TestOperator"), "operatorContactName" },
{ new StringContent("0512346789"), "operatorContactPhoneNumber" },
{ new StringContent("Un commentaire opérateur"), "operatorComment" },
{ new StringContent("Une note..."), "note" },
};
var response = await client
.PostAsync(CREATION_URL, formData)
.ConfigureAwait(false);
...
extract from my controller
[HttpPost]
public async Task<IActionResult> Post(
[FromForm] CreationOrderInput input)
{
...
extract from my input model
public sealed class CreationOrderInput
{
public FrenchPhoneNumber Did { get; set; }
public Address FinalCustomerAddress { get; set; }
...
}
public class Address
{
public virtual NonEmptyString? Designation { get; set; }
public virtual NonEmptyString StreetLabel { get; set; }
public virtual NonEmptyString? StreetCode { get; set; }
public virtual NonEmptyString? StreetNumber { get; set; }
public virtual NonEmptyString? Cluster { get; set; }
public virtual NonEmptyString? Building { get; set; }
public virtual NonEmptyString? Stair { get; set; }
public virtual NonEmptyString? Floor { get; set; }
public virtual NonEmptyString? Door { get; set; }
public virtual NonEmptyString? Logo { get; set; }
public virtual NonEmptyString? CityCode { get; set; }
public virtual NonEmptyString CityPostalCode { get; set; }
public virtual NonEmptyString CityName { get; set; }
}
Basically, i'm trying to make a address binder to bind finalCustomerXXX to several properties of Address, but IModelBinder.BindModelAsync seems rather obscure to me.
Any help would be appreciated.
Update
I've no control over the POST and the field names.

You seem to want to pass a complex object to the post method.
Since the fields of the class you provide are inconsistent with some of the field names provided in MultipartFormDataContent, I will simplify your class to make the code more clear.
Basically, i'm trying to make a address binder to bind
finalCustomerXXX to several properties of Address
If you want to bind the fields under the corresponding class in the form of finalCustomerXXX, you must first make sure that the content before XXX is the field name of the corresponding class, and they need to be separated by dots(.), or put XXX in square bracketswhich([]) like follow:
FinalCustomerAddress.XXX or FinalCustomerAddress[XXX]
Here FinalCustomerAddress is the field name of Address type in CreationOrderInput class, and XXX is the field name of Address class like CityCode.
The following is a complete case, please refer to it:
public sealed class CreationOrderInput
{
public string Name { get; set; }
public FrenchPhoneNumber Did { get; set; }
public Address FinalCustomerAddress { get; set; }
}
public class FrenchPhoneNumber
{
public string number { get; set; }
}
public class Address
{
public virtual NonEmptyString? CityCode { get; set; }
public virtual NonEmptyString CityPostalCode { get; set; }
public virtual NonEmptyString CityName { get; set; }
}
Test:
var formData = new MultipartFormDataContent(formDataBoundary)
{
{ new StringContent("Lisa"), "Name" },
{ new StringContent("0123456789"), "Did[number]" },
{ new StringContent("69389"), "FinalCustomerAddress[CityCode]" },
{ new StringContent("69009"), "FinalCustomerAddress[CityPostalCode]" },
{ new StringContent("Lyon 9e"), "FinalCustomerAddress[CityName]" },
//or
//{ new StringContent("0123456789"), "Did.number" },
//{ new StringContent("69389"), "FinalCustomerAddress.CityCode" },
//{ new StringContent("69009"), "FinalCustomerAddress.CityPostalCode" },
//{ new StringContent("Lyon 9e"), "FinalCustomerAddress.CityName" },
};
var response = await client
.PostAsync(CREATION_URL, formData)
.ConfigureAwait(false);
Here is the test result:

Related

Return null when passing data exists in c#

I have a problem that I am confused. I have a piece of code that executes a Post API command like this:
{
"chargeCriterias": null,
"containerType": "Dry",
"origin": {
"code": "ABC"
},
"destination": {
"code": "DYF"
},
"dateBegin": "2022-10-01T00:00:00",
"dateEnd": "2022-11-30T23:59:59",
"ratesFetcher": "XYZ",
}
I'm trying to write code to execute a command like this:
public class DataModel
{
public LocationModelBase origin { get; set; }
public LocationModelBase destination { get; set; }
public string dateBegin { get; set; }
public string dateEnd { get; set; }
public string chargeCriterias { get; set; }
public string containerType { get; set; }
public string ratesFetcher { get; set; }
}
public class LocationModelBase
{
public Int32 locationId { get; set; }
public string code { get; set; }
}
var addGetdata = new DataModel();
{
addGetdata.origin.code = "ABC";
addGetdata.destination.code = "DYF";
addGetdata.dateBegin = "2022-10-01T00:00:00";
addGetdata.dateEnd = "2022-11-30T23:59:59";
addGetdata.chargeCriterias = null;
addGetdata.containerType = "Dry";
addGetdata.ratesFetcher = "SSSS";
}
However I get the error: 'Object reference not set to an instance of an object.'.
I have checked the place value: addGetdata.origin and it says null. However I tried the ways but still didn't solve the problem. Where did I go wrong?
Looking forward to anyone's help or suggestions. Thank you
You are not creating an instance of the LocationModelBase on either the origin or destination so they default to null.
Either create them before you assign...
addGetdata.origin = new LocationModelBase();
addGetdata.origin.code = "ABC";
addGetdata.destination = new LocationModelBase();
addGetdata.destination.code = "DYF";
Or alternatively, create them as part of the construction of the class...
public LocationModelBase origin { get; set; } = new LocationModelBase();
public LocationModelBase destination { get; set; } = new LocationModelBase();
When initializing your DataModel class, you need to need initialize the other classes used for your model.
public LocationModelBase origin { get; set; }
public LocationModelBase destination { get; set; }
These properties have a type of another class and must be initialized before assigning values to that class' properties.
var addGetdata = new DataModel
{
origin = new LocationModelBase
{
code = "ABC"
},
destination = new LocationModelBase
{
code = "DYF"
}
...
}

Deserialize JSON object as .NET HashSet and Lists Failed

I have this kind of Json I want to save:
"data": {
"importMannerTypeList": {
"importMannerTypeID": 5,
"importMannerTypeDesc": "a"
},
"authoritySourceList": [
{
"authoritySourceID": 1,
"authoritySourceDesc": "b"
}
],
"permitStatusList": {
"permitStatusID": 4,
"permitStatusDesc": "c"
}}
All of them set as Arrays, but because authoritySourceList is multi select and not 1 object it look like this. here is the class that Deserialize the json, importMannerTypeList and permitStatusList failed to get the data from JSON why?
public class ImportPlantSettingsResponse
{
public ImportPlantSettingsResponse()
{
ImportMannerTypeList = new List<ImportMannerType>();
AuthoritySourceList = new HashSet<AuthoritySource>();
PermitStatusList = new List<PermitStatusResponse>();
}
public virtual List<ImportMannerType> ImportMannerTypeList { get; set; }
public virtual ICollection<AuthoritySource> AuthoritySourceList { get; set; }
public virtual List<PermitStatusResponse> PermitStatusList { get; set; }
As Selim Yildiz said,ImportMannerTypeList and PermitStatusList are not lists.Here is a demo:
Model:
public class ImportPlantSettingsResponse
{
public ImportPlantSettingsResponse()
{
AuthoritySourceList = new HashSet<AuthoritySource>();
}
public virtual ImportMannerType ImportMannerTypeList { get; set; }
public virtual ICollection<AuthoritySource> AuthoritySourceList { get; set; }
public virtual PermitStatusResponse PermitStatusList { get; set; }
}
action:
public IActionResult TestImportPlantSettingsResponse([FromBody] ImportPlantSettingsResponse importPlantSettingsResponse) {
return Ok();
}
result:

In nested class, how can control that the duplicate information is not recorded in a table

I have a web service that users can send for that information like the following example.
The problem occurs when the information sent in a class is the same. Like a "sampleLine" in code.
How can I control it not to be stored in the duplicate information "sampleLine" table?
public class samplePerson
{
public int ID { get; set; }
public string Name { get; set; }
public sampleCopmany PersonCopmany { get; set; }
public sampleLine PersonLine { get; set; }
}
public class sampleCopmany
{
public int ID { get; set; }
public string Name { get; set; }
public sampleLine CopmanyLine { get; set; }
}
public class sampleLine
{
public int ID { get; set; }
public string Name { get; set; }
}
public class sampleDBContext
{
private MyDBContext dBContext;
public sampleDBContext()
{
dBContext = new MyDBContext();
}
public void Save()
{
samplePerson samplePerson = new samplePerson();
samplePerson.ID = -1;
samplePerson.Name = "Reza";
samplePerson.PersonCopmany = new sampleCopmany()
{
ID = -1,
Name = "Test",
CopmanyLine = new sampleLine()
{
ID = -1,
Name = "line"
}
};
samplePerson.PersonLine = new sampleLine()
{
ID = -1,
Name = "line"
};
dBContext.Add(samplePerson);
dBContext.SaveChangesAsync();
}
}
Is it possible to control this item?
There is not any automatic way in EF that handles it for you and you need to manually check for the existence of data before creating it.
If the record exists, then use the existing key and if not then create the record as you have done in your sample code.

How do I create a Dictionary<string,string> for nested object

I am retrieving the following JSON via a POST to an API
{
"State":"Andhra_Pradesh",
"District":"Guntur",
"Fact":"SELECT",
"Description":"",
"FactDate":"",
"FactNumber":"",
"FactType":"SELECT",
"Fact":{"Id":"1"}
}
I am able to execute the Ajax request via javascript, but I also want to consume the API through C# code.
I am using the below code, but I'm not quite sure on how to add the Fact object?
var values = new Dictionary<string, string>
{
{ "State", selectedState },
{ "District", selectedDistrict },
{ "Fact", ""},
{ "FactType", ""},
{ "FactNumber", ""},
{ "Description", ""},
{"Fact", "{Id,1}" },
{"FactDate", factDate.Date.ToString() }
};
using (var httpClient = new HttpClient())
{
var content = new FormUrlEncodedContent(values);
var response = await httpClient.PostAsync("http://api.in/" + "test", content);
}
How do I add the Fact object to Dictionary?
You'll probably need to define the data you are sending as actual class before using httpclient.
If you had only name value pairs then you could have used the NameValueCollection and sent as a formurlencoded but since you have a complex type, you might consider this below.
See below.
public class Rootobject
{
public string State { get; set; }
public string District { get; set; }
public Fact Fact { get; set; }
public string Description { get; set; }
public string CaseDate { get; set; }
public string FactNumber { get; set; }
public string FactType { get; set; }
}
public class Fact
{
public string Id { get; set; }
}
Usage is as below. be sure to include a reference to System.Net.Http.Formatting.dll
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var model = new Rootobject { State = "Andhra_Pradesh", District = "Guntur", FactType = "SELECT", Description = "", CaseDate = "", FactNumber = "", Fact = new Fact { Id = "1"} };
var data = await client.PostAsJsonAsync("http://api.in/" + "test", model);
I think this is just a json object, you can either create a class which have the same properties of (state, district etc ..) and use json serializer
or you can create JObject using Json.Net
You can use Newtonsonft.Json to to the serializaton/deserialization job and the code will be like that.
public class Rootobject
{
[JsonProperty("State")]
public string State { get; set; }
[JsonProperty("District")]
public string District { get; set; }
[JsonProperty("Fact")]
public Fact Fact { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("CaseDate")]
public string CaseDate { get; set; }
[JsonProperty("FactNumber")]
public string FactNumber { get; set; }
[JsonProperty("FactType")]
public string FactType { get; set; }
}
public class Fact
{
[JsonProperty("Id")]
public string Id { get; set; }
}
And then, after instatiating your object, just serialize it.
Rootobject example = new Rootobject();
//Add values to the variable example.
var objectSerialized = JsonConvert.SerializeObject(example);
After that, you will have a json ready to be send wherever you want.
Just change {"Fact", "{Id,1}" } to {"Fact.Id", "1" },

How to retrieve following json string to separate objects in c#

hotel_pricesURL = string_builder.ToString();
RootobjectOne robjectOne = JsonConvert.DeserializeObject<RootobjectOne>(hotel_pricesURL);
List<OneStar> one_star_list = new List<OneStar>();
var check = robjectOne.onestar;
foreach(var items in check)
{
}
Including RootobjectOne class:
public class RootobjectOne
{
[JsonProperty("OneStar")]
public OneStar onestar { get; set; }
[JsonProperty("TwoStar")]
public TwoStar twostar { get; set; }
[JsonProperty("ThreeStar")]
public ThreeStar threestar { get; set; }
[JsonProperty("FourStar")]
public FourStar fourstar { get; set; }
[JsonProperty("FiveStar")]
public FiveStar fivestar { get; set; }
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
}
public class OneStar
{
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
[JsonProperty("median")]
public string median { get; set; }
[JsonProperty("lowest")]
public string lowest { get; set; }
[JsonProperty("value")]
public string value { get; set; }
//public string
}
**this is the response from the web service**
{
"5 star": {
"median": "134.04",
"lowest": "83.57",
"value": "134.04"
},
"1 star": {
"median": "28.86",
"lowest": "28.86",
"value": "28.86"
},
"4 star": {
"median": "76.35",
"lowest": "36.71",
"value": "76.35"
},
"2 star": {
"median": "24.78",
"lowest": "20.42",
"value": "24.78"
},
"3 star": {
"median": "37.65",
"lowest": "20.33",
"value": "37.65"
}
}
I am getting an error stating
Unable to cast object of type 'OneStar' to type'System.Collections.IEnumerator'
Why? And how do I solve this?
First, your class is implementing, but not inheriting the IEnumerable interface, so it is still not seen as a collection.
Second, even if you inherit it, you have no collections in OneStar and nothing to enumerate.
Third, all those Json flags are not necessary as you are just redefining the defaults that are already set.
Solution
You need an additional "wrapper" class that is your collection, or just omit your custom implementation of an enumerable collection (as it does not appear from your code that you need it) and just define the property that contains the class as a collection:
public class RootobjectOne
{
public List<OneStar> onestar { get; set; }
public List<TwoStar> twostar { get; set; }
public List<ThreeStar> threestar { get; set; }
public List<FourStar> fourstar { get; set; }
public List<FiveStar> fivestar { get; set; }
}

Categories