Get PK value by passing in non-PK value using EntityFramework - c#

I'm working on building a Windows Phone 8.1 app that uses a Web API and Entity Framework to connect to a SQL database. With my current setup, I have data objects for my entities in my services project (which contain the PK id property) and models in my phone client project (which don't contain the PK id property in order to enable auto-increment when a new member is created. I'm trying to write a services method that returns the memberID value (PK of Member entity) when the username is passed to it. However, when I do so, I get the following error:
System.InvalidCastException: Unable to cast object of type 'System.Net.Http.StreamContent' to type 'System.IConvertible'.
I'm not sure if I'm trying to do something that doesn't work, or if there's a much easier way to do this, but my code builds successfully. The above error is a run-time error. Here's the code I'm using for my relevant classes:
This is the method that calls my server from my client's backend:
public async void GetMembers(String currUser, String currPass)
{
using (var client = new HttpClient())
{
//MembersListBox.Items.Add("using block entered");
client.BaseAddress = new Uri("http://nflff.azurewebsites.net");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//MembersListBox.Items.Add("client's defaultrequestheaders done");
//gets all members from table
HttpResponseMessage response = await client.GetAsync("api/Members");
//MembersListBox.Items.Add("after response reached");
if (response.IsSuccessStatusCode)
{
//reads all member objs from table as a json string
string s = await response.Content.ReadAsStringAsync();
//how can we pass the user's login credentials (including ID) to other pages? via HttpClient?
//converts string of members into a list of member objs
var deserializedResponse = JsonConvert.DeserializeObject<List<Members>>(s);
foreach (Members member in deserializedResponse)
{
//if current member matches a member found in list
if(member.compareUserAndPassword(currUser, currPass)) {
MembersListBox.Items.Add(currUser + " and " + currPass + " found.");
MembersListBox.Items.Add(member.userName + " " + member.password);
Members currMember = member; //this works
MembersListBox.Items.Add("Current member: " + currMember.ToString());
//how should memberID be remembered for user?
client.DefaultRequestHeaders.Authorization = CreateBasicHeader(currUser, currPass);
MembersListBox.Items.Add(client.DefaultRequestHeaders.Authorization);
HttpResponseMessage memResponse = await client.GetAsync("api/Members/" + currUser);
if (memResponse.IsSuccessStatusCode)
{
MembersListBox.Items.Add("memResponse successful");
}
//should only go to home page if successful
//int memID = Convert.ToInt32(await client.GetAsync("api/Members?MemberStr=" + currUser));
HttpResponseMessage thisMember = await client.GetAsync("api/Members?MemberStr=" + currUser);
var con = thisMember.Content;
var head = thisMember.Headers;
var rm = thisMember.RequestMessage;
int memID = Convert.ToInt32(thisMember.Content);//THIS IS THE LINE THAT GENERATES THE ERROR
//will need to call server's getidbyname method and pass result instead of currMember.memberID
//this.Frame.Navigate(typeof(HomeHub), currMember.memberID);
this.Frame.Navigate(typeof(HomeHub), memID);
}
}
}
//MembersListBox.Items.Add(Members.MembersList.Count);
foreach (var member in Members.MembersList)
{
// MembersListBox.Items.Add(member.ToString());
}
}
}
Here's my controller from my services project:
public class MembersController : ApiController
{
private GatoradeShowerDB db = new GatoradeShowerDB();
// GET: api/Members
public IQueryable<Member> GetMembers()
{
return db.Members;
}
// GET: api/Members/5
[ResponseType(typeof(Member))]
public async Task<IHttpActionResult> GetMember(int id)
{
Member member = await db.Members.FindAsync(id);
if (member == null)
{
return NotFound();
}
return Ok(member);
}
//GET: api/Members?MemberStr={memberStr}
[ResponseType(typeof(Member))]
public async Task<T> GetMemberIDByName<T>(String MemberStr) where T : struct
{
//var member = JsonConvert.DeserializeObject<Member>(MemberStr);
//Member member = await db.Members.FindAsync(MemberStr);
//var userId = ...;
var member = await db.Members.Where(x => x.UserName == MemberStr).ToListAsync();
if (member == null)
{
return (T)Convert.ChangeType(NotFound(), typeof(T));
}
return (T)Convert.ChangeType(member[0].MemberID, typeof(T));
//return member[0].MemberID; //hopefully gets id of first member in async list and returns it
//return Ok(member);
}
//other methods
}
Also, here's my client-side model:
public class Members
{
//[JsonProperty("MemberID")]
//public int memberID { get; private set; }
[JsonProperty("FirstName")]
private string firstName { get; set; }
[JsonProperty("LastName")]
private string lastName { get; set; } //both names should be optional
[JsonProperty("UserName")]
public string userName { get; private set; } //note: I don't think we should track first and last names
[JsonProperty("Password")]
public string password { get; private set; } //will probably need to implement validation in setter so won't be able to auto-implement
[JsonProperty("Email")]
private string email { get; set; }//same with this. will need validation
[JsonProperty("MemberCity")]
private string memberCity { get; set; }
[JsonProperty("MemberState")]
private string memberState { get; set; }
[JsonProperty("MemberZip")]
private string memberZip { get; set; }
[JsonProperty("MemberPhone")]
private string memberPhone { get; set; }//should also be optional
[JsonProperty("FaveTeamID")]
private int faveTeamID { get; set; }
public static List<Members> MembersList = new List<Members>();
public Members(string first, string last, string user, string pass, string email, string city, string state, string zip, string phone, int team)
{
//memberID = id;
firstName = first;
lastName = last;
userName = user;
password = pass;
this.email = email;
memberCity = city;
memberState = state;
memberZip = zip;
memberPhone = phone;
faveTeamID = team;
}
public override string ToString()
{
return "Member: " + userName + " in " + memberCity;
}
public bool compareUserAndPassword(string currUser, string currPass)
{
if (currUser.Equals(userName) && currPass.Equals(password))
{
return true;
}
else
{
return false;
}
}
}
Finally, here's my server-side data object:
public partial class Member
{
public int MemberID { get; set; }
[Required]
[StringLength(255)]
public string FirstName { get; set; }
[Required]
[StringLength(255)]
public string LastName { get; set; }
[Required]
[StringLength(50)]
public string UserName { get; set; }
[Required]
[StringLength(32)]
public string Password { get; set; }
[Required]
[StringLength(50)]
public string Email { get; set; }
[Required]
[StringLength(50)]
public string City { get; set; }
[Required]
[StringLength(30)]
public string State { get; set; }
[Required]
[StringLength(255)]
public string Zip { get; set; }
[Required]
[StringLength(255)]
public string Phone { get; set; }
public int FavTeamID { get; set; }
}
I know this is a lot of code, but I'd rather post too much than too little. One thought I had was to somehow add the MemberID value to the httpClient object and pass that as a parameter to other pages, but I'm not sure if that's possible either. How can I get the MemberID value for a specific member if that value is only stored in the server-side data object but not in the client-side model? I'm open to different approaches as well if there's an easier way to go about this. Thank you in advance for your help.
UPDATE
My issue seems to be originating from my GetMemberIDByName method in my controller. When I debugged it, I got the following error message:
Cannot call action method 'System.Threading.Tasks.Task`1[T] GetMemberIDByNameT' on controller 'WorkingVersionGetItDone.Controllers.MembersController' because the action method is a generic method.

I'm pretty sure your method should look more like this:
public async Task<IHttpActionResult> GetMemberIDByName(string MemberStr)
{
var member = await db.Members.Where(x => x.UserName == MemberStr).ToListAsync();
if (member == null)
{
return NotFound();
}
return Ok(member[0].MemberID);
}
The caller will then either get a 404 (the NotFound()) or a 200 with a payload of the MemberID and you can process appropriately.
HttpResponseMessage memberResponse = await client.GetAsync("api/Members?MemberStr=" + currUser);
if(memberResponse.StatusCode == HttpStatusCode.OK)
{
// got the memberId...
var memberId = Convert.ToInt32( memberResponse.Content.ReadAsStringAsync().Result);
}
else if(memberResponse.StatusCode == HttpStatusCode.NotFound)
{
// member not found...
}

Related

How to display data on Xamarin.Android edit text using Web API

I'm trying to display the data from SQL server using web API, get method on edit text in Xamarin.Android. The data will display on the edit text once the button is clicked. I've followed all the steps (exactly) as in the YouTube tutorial but unfortunately, the data did not show up on the edit text, instead it shows JSON format on the screen. What should I do to fix this problem?
I've tried using Web services, still didn't show up.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.PersonalInfo);
ActionBar.SetDisplayHomeAsUpEnabled(true);
EditText email = FindViewById<EditText>(Resource.Id.txtEmail);
EditText firstName = FindViewById<EditText>(Resource.Id.txtFirstName);
EditText lastName = FindViewById<EditText>(Resource.Id.txtLastName);
EditText gen = FindViewById<EditText>(Resource.Id.txtGender);
EditText ic = FindViewById<EditText>(Resource.Id.txtIC);
EditText address = FindViewById<EditText>(Resource.Id.txtAddress);
EditText phoneNo = FindViewById<EditText>(Resource.Id.txtPhoneNo);
EditText username = FindViewById<EditText>(Resource.Id.txtUsername);
EditText password = FindViewById<EditText>(Resource.Id.txtPwd);
EditText payment = FindViewById<EditText>(Resource.Id.txtPayMethod);
Button btnGetAcc = FindViewById<Button>(Resource.Id.btnGetAcc);
btnGetAcc.Click += async delegate
{
VehicleRecord vehicRec = null;
HttpClient client = new HttpClient();
string url = "http://192.168.0.135/PMSAPI/api/clients/" + username.Text.ToString();
var result = await client.GetAsync(url);
var json = await result.Content.ReadAsStringAsync();
try
{
vehicRec = Newtonsoft.Json.JsonConvert.DeserializeObject<VehicleRecord>(json);
if (vehicRec == null)
{
//check for an array just in case
var items = JsonConvert.DeserializeObject<VehicleRecord[]>(json);
if (items != null && items.Length > 0)
{
vehicRec = items[0];
}
}
}
catch (Exception ex) { }
};
}
The expected output should display data from SQL server on edit text but the actual output is it display all the data in JSON-format.
The actual output:
The logic of your code is to show the JSON if vehicRec == null.
The JSON shown in the image is that of an array. Notice the [] square brackets wrapping the JSON object.
[{....}]
This would mean that asking to deserialize to an object would fail. Refactor the code to desrialize to an array and then extract the desired object out of the result.
//...omitted for brevity
var json = await result.Content.ReadAsStringAsync();
try {
vehicRec = Newtonsoft.Json.JsonConvert.DeserializeObject<VehicleRecord>(json);
if(vehicRec == null) {
//check for an array just in case
var items = JsonConvert.DeserializeObject<VehicleRecord[]>(json);
if(items != null && items.Length > 0) {
vehicRec = items[0];
}
}
}
catch (Exception ex) { }
if (vehicRec == null)
{
Toast.MakeText(this, json, ToastLength.Short).Show();
}
else
{
firstName.Text = vehicRec.firstName;
lastName.Text = vehicRec.lastName;
gen.Text = vehicRec.gender;
ic.Text = vehicRec.icNo;
address.Text = vehicRec.address;
phoneNo.Text = vehicRec.phoneNo;
username.Text = vehicRec.username;
password.Text = vehicRec.password;
payment.Text = vehicRec.paymentMethod;
}
//...omitted for brevity
Note also in the JSON that there are multiple items in the array. I would suggest you consider using a list to display the records in the array.
The code above will only show the first item in the array but can be easily refactored to use the array as a data source for a list view.
It was also noted that the names of the fields in the JSON do not match that of the class being populated. Which will cause the properties to not get any values.
From one of your previous questions I was able to see that you defined the class as
public class VehicleRecord {
public string firstName { get; set; }
public string lastName { get; set; }
public string gender { get; set; }
public string icNo { get; set; }
public string address { get; set; }
public string phoneNo { get; set; }
public string email { get; set; }
public string username { get; set; }
public string password { get; set; }
public string plateNo { get; set; }
public string model { get; set; }
public string col { get; set; }
public string paymentMethod { get; set; }
}
But the JSON shown in the image has all fields prefixed with a cl.
You would need to add a mapping so the JsonConverter knows how to populate the class
public class VehicleRecord {
[JsonProperty("clFirstName")]
public string firstName { get; set; }
[JsonProperty("clLastName")]
public string lastName { get; set; }
[JsonProperty("clGender")]
public string gender { get; set; }
//...etc
}
You may be better off using a JSON parser to generate the class for you which would also include the attributes to map the properties.

Having trouble converting multi-level JSON string into object list. Any suggestions?

Hey all so here is the JSON string I expect back {\"status\":\"success\",\"locations\":[{\"id\":\"24\",\"name\":\"Test New Location Test\",\"contact_first_name\":\"Test\",\"contact_last_name\":\"Test\",\"contact_email\":\"test#email.com\",\"contact_phone_number\":\"(555) 555-5555\",\"billing_address\":\"Test\",\"billing_city\":\"Test\",\"billing_state\":\"AK\",\"billing_zip\":\"55555\",\"traps\":[]}]}
I am trying to store all the different parts that make up a location to an object list such as id, name, contact_first_name etc.. I think what is tripping me up is the status in front that is making it a little more difficult for me access the different locations.
I am following this tutorial that seems pretty clear but haven't gotten it to work on my end yet. https://www.youtube.com/watch?v=XssLaKDRV4Y
The below code is part of my Service class and it works in getting the expected http response (mentioned above) and getting the success message. When I uncomment the few lines of code below my app breaks and doesn't store any objects to a list.
public async Task<string> GetLocationData()
{
var user_id = Convert.ToString(App.Current.Properties["user_id"]);
var session = Convert.ToString(App.Current.Properties["session"]);
var key = "randomkeystring";
var body = new List<KeyValuePair<string, string>>();
body.Add(new KeyValuePair<string, string>("user_id", user_id));
body.Add(new KeyValuePair<string, string>("session", session));
body.Add(new KeyValuePair<string, string>("key", key));
try
{
using (var client = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, "apiurl/api/something") { Content = new FormUrlEncodedContent(body) };
var result = await client.SendAsync(request);
if (!result.IsSuccessStatusCode)
{
return "false";
}
//string representation
var stringResponseFromServer = await result.Content.ReadAsStringAsync();
//convert JSON to series of objects
//LocationCollection locationCollection = JsonConvert.DeserializeObject<LocationCollection>(stringResponseFromServer);
//System.Diagnostics.Debug.WriteLine(locationCollection.locations.Count);
var response = JsonConvert
.DeserializeObject<GetLocationDataResponse>(stringResponseFromServer);
if (response == null) return "false";
jsonString.HttpGetLocationDataString += stringResponseFromServer;
return stringResponseFromServer;
}
}
catch
{
return "false";
}
}
My locations.cs looks like this
public class Locations
{
public int id { get; set; }
public string name { get; set; }
public string contact_first_name { get; set; }
public string contact_last_name { get; set; }
public string contact_email { get; set; }
public string contact_phone_number { get; set; }
public string billing_address { get; set; }
public string billing_city { get; set; }
public string billing_state { get; set; }
public string billing_zip { get; set; }
public string traps { get; set; }
}
Then I have a LocationCollection.cs where i hope to store the different locations so I can loop through them later and do whatever I need to do to them.
public class LocationCollection
{
public List<Locations> locations { get; set; }
}
And then I call the method on my MainPage after the user logs in
insectService.GetLocationData().ContinueWith(async (task) =>
{
var getLocationDataResponse = JsonConvert.DeserializeObject<GetLocationDataResponse>(task.Result);
if (getLocationDataResponse.status == "failure")
{
await DisplayAlert("Location Data Failure", "Could not retrieve data", "Try Again");
await Navigation.PushModalAsync(new LoginPage(), true);
}
//System.Diagnostics.Debug.WriteLine(getLocationDataResponse.locations.ToString());
if (getLocationDataResponse.status == "success")
{
await DisplayAlert("Location Data Success", "Successfully Recovered Data", "Back to Main Page");
}
}); //TaskScheduler.FromCurrentSynchronizationContext());
Right now I am able to get the expect JSON string of {\"status\":\"success\",\"locations\":[{\"id\":\"24\",\"name\":\"Test New Location Test\",\"contact_first_name\":\"Test\",\"contact_last_name\":\"Test\",\"contact_email\":\"test#email.com\",\"contact_phone_number\":\"(555) 555-5555\",\"billing_address\":\"Test\",\"billing_city\":\"Test\",\"billing_state\":\"AK\",\"billing_zip\":\"55555\",\"traps\":[]}]} and am able to check if the status is success or failure. However I am having trouble storing the different parts of "locations" into a list. Any suggestions?
You can give a try deserilizing your api result in to a result model, then from there again de serialize to location model. Example:
My API Model
public class ApiResult
{
public Int32 Status { get; set; }
public string Message { get; set; }
public string Data { get; set; }
}
Inside Data I copy all my return result from API, then Deserialize to exact Model. Here is the example:
public static List<Models.OrderList> RetrieveOrderList(string host, List<Models.FilterCondition> filter)
{
string sResult = HttpHelper.httpPost(host + "api/Order/RetrieveOrderList", Newtonsoft.Json.JsonConvert.SerializeObject(filter));
Models.ApiResult mResult = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.ApiResult>(sResult);
if (mResult.Status == 0)
throw new Exception(mResult.Message);
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<Models.OrderList>>(mResult.Data);
}
If you see the above My return result(string), I deserialize to API result Model, then again finally deserialize to OrderList Model. Hope this help to sort out your issue.
Update: API Controller
I forgot to mention one more point. On the API Controller Side Your result need to copied to API Model.
Here is the Example
[HttpPost]
public Models.ApiResult RetrieveOrderList(List<Models.FilterCondition> conditions)
{
Models.ApiResult mResult = new Models.ApiResult();
try
{
List<Models.OrderList>mOrderList= BLL.Order.RetrieveOrderList(conditions);
mResult.Status = 1;
mResult.Message = "Success";
mResult.Data = Newtonsoft.Json.JsonConvert.SerializeObject(mOrderList);
return mResult;
}
catch (Exception ex)
{
mResult.Status = 0;
mResult.Message = ex.Message;
mResult.Data = "";
return mResult;
}
}
My locations model didn't match the JSON response. Once I read what the exception was in my catch statement I saw that 'traps' was supposed to be another list. After I changed traps property to a List and then made another class for 'traps' everything worked fine.

How to assign Room to an Event for meeting using Microsoft Graph API in a UWP App

I am calling the API for creating a meeting on a fixed date & time. I am using Microsoft Graph API for this. Here is the URL
var url = "https://graph.microsoft.com/v1.0/me/events";
I have taken care of the Authentication part and my code does the following thing to send the JSON response to the API
private async void sendInvites_Click(object sender, RoutedEventArgs e)
{
var httpClient = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage response;
var url = "https://graph.microsoft.com/v1.0/me/events";
CIBC.Models.SendMeetingInvites.RootObject obj = new CIBC.Models.SendMeetingInvites.RootObject();
CIBC.Models.SendMeetingInvites.Location loc = new CIBC.Models.SendMeetingInvites.Location();
loc.displayName = GlobalVariables.MeetingRoomName;
//loc.RoomEmailAddress = GlobalVariables.meetingRoomEmailID.ToString();
obj.subject = "Maths";
CIBC.Models.SendMeetingInvites.Body body = new CIBC.Models.SendMeetingInvites.Body();
body.content = "Its a booking for follow up meeting";
body.contentType = "HTML";
obj.body = body;
List<CIBC.Models.SendMeetingInvites.Attendee> attens = new List<Models.SendMeetingInvites.Attendee>();
for(int i=0;i<GlobalVariables.NumberOfParticipant.Count;i++)
{
CIBC.Models.SendMeetingInvites.EmailAddress email = new CIBC.Models.SendMeetingInvites.EmailAddress();
CIBC.Models.SendMeetingInvites.Attendee atten = new CIBC.Models.SendMeetingInvites.Attendee();
email.address = GlobalVariables.NumberOfParticipant[i].ParticipantADdress;
atten.emailAddress = email;
atten.type = "Required";
attens.Add(atten);
}
CIBC.Models.SendMeetingInvites.Start start = new CIBC.Models.SendMeetingInvites.Start();
start.dateTime = GlobalVariables.sendMeetingInviteStartDate;
start.timeZone = "UTC";
obj.start = start;
CIBC.Models.SendMeetingInvites.End end = new CIBC.Models.SendMeetingInvites.End();
end.dateTime = GlobalVariables.sendMeetingInviteEndTime;
end.timeZone = "UTC";
obj.end = end;
obj.attendees = attens;
obj.location = loc;
string postBody = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
// var postBody1 = "{'Subject':'Testing Organizer - 12','Location':{'DisplayName':'Some place'}," +
//"'Start': {'DateTime': '2016-07-15T15:00:00.0000000', 'TimeZone':'UTC'}," +
//"'End': {'DateTime': '2016-07-15T15:30:00.0000000', 'TimeZone':'UTC'}," +
//"'Body':{'Content': 'This is a test of Grap API.', 'ContentType':'Text'}," +
//"'IsOrganizer':'False','Organizer':{'EmailAddress': " + "{'Address':'organizer#some.com'} }}";
// var requestString = #"{"subject":"My event","start":{"dateTime":"2017-09-25T07:44:27.448Z","timeZone":"UTC"},"end":{"dateTime":"2017-10-02T07:44:27.448Z","timeZone":"UTC"}}"";
var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, url);
//Add the token in Authorization header
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",GlobalVariables.Token);
request.Content = new StringContent(postBody, UTF8Encoding.UTF8, "application/json");
response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{ }
// return await response.Content.ReadAsStringAsync();
else
{
}
//return "";
}
Here is the class file that I am using to pass to the HTTPResponse Message
namespace CIBC.Models.SendMeetingInvites
{
public class Body
{
public string contentType { get; set; }
public string content { get; set; }
}
public class Start
{
public DateTime dateTime { get; set; }
public string timeZone { get; set; }
}
public class End
{
public DateTime dateTime { get; set; }
public string timeZone { get; set; }
}
public class Location
{
public string displayName { get; set; }
//public string RoomEmailAddress { get; set; }
}
public class EmailAddress
{
public string address { get; set; }
public string name { get; set; }
}
public class Attendee
{
public EmailAddress emailAddress { get; set; }
public string type { get; set; }
}
public class RootObject
{
public string subject { get; set; }
public Body body { get; set; }
public Start start { get; set; }
public End end { get; set; }
public Location location { get; set; }
public List<Attendee> attendees { get; set; }
}
}
My requirement is to send a meeting invite to all the users and also mentioning the Room Details like Name& Email ID of the room.
I tried adding a RoomEmail address in the Request as under The Location class
public string RoomEmailAddress { get; set; }
When I tested this using Microsoft Graph Explorer website , i got the error message
{
"error": {
"code": "RequestBodyRead",
"message": "The property 'RoomEmailAddress' does not exist on type 'Microsoft.OutlookServices.Location'. Make sure to only use
property names that are defined by the type or mark the type as open
type.",
"innerError": {
"request-id": "1883d87d-a5d6-4357-a699-7c112da0e56b",
"date": "2017-09-26T12:03:50"
}
} }
How do I make sure that whenever I create a meeting request , I can assign a room to it?
Currently I am just able to pass DisplayName while sending the Request to the URL.
Once I remove the Email Address property (I added myself ), the code returns Success.
Any workarounds so that I can send the room email address also so that the room also receives a copy of the meeting invite ?
Add the room as an attendee with "type": "Resource". Then add the room's display name in the location property.

JSON Object and Simple Type to Model in WebAPI using FromBody

I am creating a Web Api method that should accept a JSON Object and a Simple Type. But all parameters are always null.
My json looks like
{
"oldCredentials" : {
"UserName" : "user",
"PasswordHash" : "myCHqkiIAnybMPLzz3pg+GLQ8kM=",
"Nonce" : "/SeVX599/KjPX/J+JvX3/xE/44g=",
"Language" : null,
"SaveCredentials" : false
},
"newPassword" : "asdf"}
And my Code looks like:
[HttpPut("UpdatePassword")]
[Route("WebServices/UsersService.svc/rest/users/user")]
public void UpdatePassword([FromBody]LoginData oldCredentials, [FromBody]string newPassword)
{
NonceService.ValidateNonce(oldCredentials.Nonce);
var users = UserStore.Load();
var theUser = GetUser(oldCredentials.UserName, users);
if (!UserStore.AuthenticateUser(oldCredentials, theUser))
{
FailIncorrectPassword();
}
var iv = Encoder.GetRandomNumber(16);
theUser.EncryptedPassword = Encoder.Encrypt(newPassword, iv);
theUser.InitializationVektor = iv;
UserStore.Save(users);
}
The current JSON you are sending maps to the following classes
public class LoginData {
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string Nonce { get; set; }
public string Language { get; set; }
public bool SaveCredentials { get; set; }
}
public class UpdateModel {
public LoginData oldCredentials { get; set; }
public string newPassword { get; set; }
}
[FromBody] can only be used once in action parameters
[HttpPut("WebServices/UsersService.svc/rest/users/user")]
public void UpdatePassword([FromBody]UpdateModel model) {
LoginData oldCredentials = model.oldCredentials;
string newPassword = model.newPassword;
NonceService.ValidateNonce(oldCredentials.Nonce);
var users = UserStore.Load();
var theUser = GetUser(oldCredentials.UserName, users);
if (!UserStore.AuthenticateUser(oldCredentials, theUser)) {
FailIncorrectPassword();
}
var iv = Encoder.GetRandomNumber(16);
theUser.EncryptedPassword = Encoder.Encrypt(newPassword, iv);
theUser.InitializationVektor = iv;
UserStore.Save(users);
}
As per the Parameter Binding in ASP.NET Web API, "At most one parameter is allowed to read from the message body". Means only one parameter can contain [FromBody]. So in this case it will not work. Create one complex object and add required properties to it. You can add newPassword to your complex object to make it work.
More than one [FromBody] does not work in Api. Check this Microsoft Official blog
So now you can do like this, create a complex object which should contain both your oldCredentials and newPassword. For example LoginData class in my example bellow. And myLoginRequest is another object class which is to deserialized your LoginData.
[HttpPut("UpdatePassword")]
[Route("WebServices/UsersService.svc/rest/users/user")]
public void UpdatePassword([FromBody]LoginData MyCredentials)
{
loginRequest request = JsonConvert.DeserializeObject<myLoginRequest>
(json.ToString());
// then you can do the rest
public class DocumentController : ApiController
{
[HttpPost]
public IHttpActionResult PostDocument([FromBody] Container data)
{
try
{
if (string.IsNullOrWhiteSpace(data.Document)) return ResponseMessage(Request.CreateResponse(HttpStatusCode.NoContent, "No document attached"));
return ResponseMessage(IndexDocument(data, Request));
}
catch (Exception ex)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.NotAcceptable, ex.Message));
}
}
}
public class InsuranceContainer
{
[JsonProperty("token")]
public string Token { get; set; }
[JsonProperty("document")]
public string Document { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
}
var fileAsBytes = File.ReadAllBytes(#"C:\temp\tmp62.pdf");
String asBase64String = Convert.ToBase64String(fileAsBytes);
var newModel = new InsuranceContainer
{
Document = asBase64String,
Text = "Test document",
};
string json = JsonConvert.SerializeObject(newModel);
using (var stringContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"))
using (var client = new HttpClient())
{
var response = await client.PostAsync("https://www.mysite.dk/WebService/api/Document/PostDocument", stringContent);
Console.WriteLine(response.StatusCode);
var message = response.Content.ReadAsStringAsync();
Console.WriteLine(message.Result);
}

Request.CreateResponse returns blank data to postman

I have encountered a problem when trying to call my web api with a post request, a empty array is returned.
My method is:
// POST: Api/v1/transaction/
[HttpPost]
public HttpResponseMessage Post(string user)
{
var userId = new Guid(user);
var transactions = new Collection<TransactionDataTransferObject>();
try
{
var seller = _databaseContext.Sellers.Single(s => s.Id == userId);
var sellerMedias = _databaseContext.Medias.Where(m => m.TakenBy.Id == seller.Id);
foreach (var sellerMedia in sellerMedias)
{
var allLogsForMedia = _databaseContext.Logs.Where(l => l.ObjectReferenceId == sellerMedia.Id);
foreach (var logMedia in allLogsForMedia)
{
var transaction = new TransactionDataTransferObject
{
Date = logMedia.DateTimeInUtc,
Amount = sellerMedia.PriceInSek,
MediaName = sellerMedia.FileName,
UserName = seller.FirstName + " " + seller.LastName
};
transactions.Add(transaction);
}
}
}
catch (Exception exception)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, exception);
}
return Request.CreateResponse(HttpStatusCode.OK, transactions);
}
When I debug transactions variable, I see two objects in the collection.
My response to postman is
[
{},
{}
]
What have I done wrong? Where is my data which is sent?
Ok, after some hours of slaming my head in the table i found out that I used
[DataContract] as filter on the ViewModel,TransactionDataTransferObject.
Like this:
[DataContract]
public class TransactionDataTransferObject
{
[Display(Name = "Date")]
public DateTime Date { get; set; }
public string MediaName { get; set; }
public Guid MediaId { get; set; }
public string UserName { get; set; }
public Guid UserId { get; set; }
[Display(Name = "Description")]
public string Discriminator { get; set; }
[Display(Name = "Amount")]
public decimal Amount { get; set; }
}
Which was wrong in this case...
Thanks for reading!

Categories