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

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.

Related

How to pass three parameters through an API and retrieve information accordingly

I am very new to C#. I am writing a program using visual studio c# where it will first ask the user to enter an employee name. Next, it will pass that name through an API and will retrieve and display the employee signature. I have completed this portion.
Next, the program will ask the user to enter a designated "to" and "from" date. Next, the program should pass the date information as well as the signature obtained previously through a second API and retrieve and display information on to a grid data table accordingly.
For the Grid view data table, I understand that I should be connected to a SQL data server, which I am.
My problem is that
I am not sure how to write a code which will pass three parameters to an API (the "to" and "from" date, and the employee signature). I have tried the code below, however, I receive an error when I try to link the corresponding button to the JSON code to retrieve data. The error states that
"There is no argument given that corresponds to the required formal
parameter 'toDate' of 'WebAPI.GetTime(double, double, string).'
I am not sure how to pass the signature previously obtained from a different API through the new API.
Any help would be much appreciated.
Code for defining the JSON variables:
namespace TimeSheet_Try11_Models
{
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class OracleHour
{
public string orderNumber { get; set; }
public DateTime dateOfWork { get; set; }
public string description { get; set; }
public string surveyor { get; set; }
public string hourType { get; set; }
public double hours { get; set; }
public int status { get; set; }
public string savedInOlsonTimezone { get; set; }
public double invoicelinevalue { get; set; }
public string articleType { get; set; }
public DateTime dateOfWorkInSavedTimezone { get; set; }
}
public class MyArray
{
public string orderNumber { get; set; }
public string projectnumber { get; set; }
public string noteToInvoicer { get; set; }
public List<object> oracleCosts { get; set; }
public List<OracleHour> oracleHours { get; set; }
}
public class Root1
{
public List<MyArray> MyArray { get; set; }
}
}
Code calling out the JSON:
namespace TimeSheets_Try_11.Controllers
{
class WebAPI
{
public string[] GetTime(double fromDate, double toDate, string username)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var cookies = FullWebBrowserCookie.GetCookieInternal(new Uri(StaticStrings.UrlNcert), false);
WebClient wc = new WebClient();
wc.Encoding = System.Text.Encoding.UTF8;
wc.Headers.Add("Cookie:" + cookies);
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
wc.UseDefaultCredentials = true;
string url = "";
url = $"{StaticStrings.UrlNcert}?user={username}&fromDate={fromDate:yyyy-MM-dd}&toDate={toDate:yyyy-MM-dd}";
var respons = wc.DownloadString(url);
OracleHour ndata = JsonConvert.DeserializeObject<OracleHour>(respons);
var Get_Odnum = ndata.orderNumber;
var Dt_Work = ndata.dateOfWork;
var hrType = ndata.hourType;
var hr = ndata.hours;
var des = ndata.description;
var surname = ndata.surveyor;
string[] myncertdata = { Get_Odnum, Dt_Work.ToString(), hrType, hr.ToString(), des, surname };
return myncertdata;
}
}
Partial code attempting to connect the corresponding button to retrieve data (the error appears at the very last line):
namespace TimeSheets_Try_11
{
public partial class Form3 : Form
{
WebAPI WA = new WebAPI();
public Form3()
{
InitializeComponent();
webBrowser2.Url = new Uri(StaticStrings.UrlNcert);
}
private void Form3_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'timesDataSet.NCert_Data' table. You can move, or remove it, as needed.
this.nCert_DataTableAdapter.Fill(this.timesDataSet.NCert_Data);
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void GtData_Click(object sender, EventArgs e)
{
var connetionString = ConfigurationManager.ConnectionStrings["Times"].ConnectionString;
try
{
using (SqlConnection conn = new SqlConnection(connetionString))
{
using (SqlCommand cmd = new SqlCommand())
{
conn.Open();
using (SqlCommand Sqlcmd = new SqlCommand("NCert_Data", conn))
{
Sqlcmd.CommandType = CommandType.StoredProcedure;
int counter; string projectnumber; double hrs; string respname; string describe; string[] prjstat; DateTime dates;
for (counter = 0; counter < (dataGridView1.RowCount) - 1; counter++)
{
hrs = 0;
projectnumber = dataGridView1.Rows[counter].Cells[1].Value.ToString();
prjstat = WA.GetTime(projectnumber);
}
}
}
}
}
}
}
public string[] GetTime(double fromDate, double toDate, string username)
needs 3 parameter but
prjstat = WA.GetTime(projectnumber);
has only one...?
Looks like you have to add 2 more parameters
prjstat = WA.GetTime((double), (double), "text");
double fromDate, but you have "projectnumber" a .toString() ...?
Without knowing how the structure of your table looks like there is no way to know what the parameters are. How ever I think your function call should look like this:
prjstat = WA.GetTime((double)dataGridView1.Rows[counter].Cells["fromDate"], (double)(double)dataGridView1.Rows[counter].Cells["toDate"], dataGridView1.Rows[counter].Cells["username"].toString());
Where ["fromDate"], ["toDate"] and ["username"] should be the correct indexes of your expected data.
You may could loop through the cols and output the data with something like that:
for (counter = 0; counter < (dataGridView1.RowCount) - 1; counter++)
{
for (int i = 0; i < dataGridView1.Columns.Count, i++)
{
if (dataGridView1.Columns[i].HeaderText != null) {
System.Console.WriteLine(dataGridView1.Columns[i].HeaderText);
}
System.Console.WriteLine(dataGridView1.Rows[counter].Columns[i].ValueType.ToString());
System.Console.WriteLine(dataGridView1.Rows[counter].Columns[i].Value.ToString());
}
if (counter == 2) { break; }
}
Or just give some dummy values and look what happens ( :P ):
prjstat = WA.GetTime(0, 0, "bla");
Edit: Please note that .Value can be different types like numbers colors dates or what ever. So you have to cast it to a type (double) or use Convert.XYZ. By ValueType.toString() you maybe know what type it is. Or you already know it at all, no idea... ;)
...should pass the date information as well as the signature obtained previously through a second API and retrieve and display information on to a grid data table accordingly.
Well now I'm confused. Could you clarify if you want to store data received by WA.GetTime to dataGridView1 or do you want to send data to WA.GetTime obtained by the dataGridView1?
Btw.: A DataGridView do not "require" an sql database. It can also use xml as example.

How send image as byte array from Angular 9 to C# Web API Core, like are property of object? CRUD Client aplication with image

Frontend - Angular 9
Backend - ASP.NET Core Web API
/
Middleware Entity Framework 6.0
/
MS SQL SERVER
I don't know what type of object property I must set in Angular?
How I can add an image to my object and send them to Web Api?
How I can show them back in Angular app?
Web API Controller POST:
[HttpPost]
public async Task<ActionResult<Leaks>> PostLeaks(Leaks leaks)
{
// DateTime and Username implemented to backend
DateTime curDate = DateTime.Now;
leaks.Date = curDate;
var currentUser = HttpContext.User;
string userLastname = currentUser.Claims.FirstOrDefault(c => c.Type == "lastname").Value;
leaks.Repairer = userLastname;
//
_context.Leaks.Add(leaks);
await _context.SaveChangesAsync();
return CreatedAtAction("GetLeaks", new { id = leaks.Id }, leaks);
}
Leaks.cs:
public partial class Leaks
{
public int Id { get; set; }
public string Sn { get; set; }
public string ShiftSmt { get; set; }
public string ShiftMi { get; set; }
public string Location { get; set; }
public DateTime? Date { get; set; }
public string Repairer { get; set; }
public string AoiResult { get; set; }
public string OperatorSmt { get; set; }
public string ModelSmt { get; set; }
public string Platform { get; set; }
public string Remark { get; set; }
public string Defect { get; set; }
public byte[] Image { get; set; }
public string Status { get; set; }
public string Side { get; set; }
public string Extra1 { get; set; }
public string Extra2 { get; set; }
}
MS SQL Image data type is varbinary(MAX)
Leaks.component.ts:
// *ngOnInit start
ngOnInit() {
//Selected options loader
this.platformsService.getAllPlatforms()
.subscribe(res => this.platforms = res as []);
this.defectslistService.getAllDefectslist()
.subscribe(res => this.defect = res as []);
// input form validation
this.leaksForm = this.formbulider.group({
Date:[null],
Sn:[null, [Validators.required]],
ShiftMI:[null, [Validators.required]],
ShiftSMT:[null, [Validators.required]],
Location:[null, [Validators.required]],
Defect:[null, [Validators.required]],
Side:[null, [Validators.required]],
AoiResult:[null],
Platform:[null, [Validators.required]],
ModelSMT:[null],
OperatorSMT:[null],
Repairer:[null],
Image:[null],
Remark:[null],
Status:[null, [Validators.required]],
});
// *load all data from Database*
this.loadallLeaks();
this.toastr.info("Init Successfully Done");
//*Angular mat-table*
this.leaksService.getAllLeaks().subscribe(list => {
let array = list.map(item => {
return { ...item };
});
this.listData = new MatTableDataSource(array);
this.listData.sort = this.sort;
this.listData.paginator = this.paginator;
this.isLoading = false;
});
//*Angular mat-table end*
}
// *ngOnInit end*
loadallLeaks() {
this.allLeaks = this.leaksService.getAllLeaks();
this.leaksService.getAllLeaks().subscribe(res => {
this.dataSource = new MatTableDataSource(res);
})
this.toastr.info("Data Was Successfully Loaded");
}
onFormSubmit() {
this.dataSaved = false;
const leaks = this.leaksForm.value;
this.CreateLeaks(leaks);
this.leaksForm.reset();
}
loadLeaksToEdit(leaksId: string) {
this.leaksService.getLeaksById('/'+leaksId).subscribe(leaks=> {
this.massage = null;
this.dataSaved = false;
this.leaksIdUpdate = leaks.Id;
this.leaksForm.controls['Sn'].setValue(leaks.Sn);
this.leaksForm.controls['Date'].setValue(leaks.Date);
this.leaksForm.controls['ShiftSMT'].setValue(leaks.ShiftSMT);
this.leaksForm.controls['ShiftMI'].setValue(leaks.ShiftSMT);
this.leaksForm.controls['Location'].setValue(leaks.Location);
this.leaksForm.controls['Defect'].setValue(leaks.Defect);
this.leaksForm.controls['Side'].setValue(leaks.Side);
this.leaksForm.controls['AoiResult'].setValue(leaks.AoiResult);
this.leaksForm.controls['Platform'].setValue(leaks.Platform);
this.leaksForm.controls['ModelSMT'].setValue(leaks.ModelSMT);
this.leaksForm.controls['OperatorSMT'].setValue(leaks.OperatorSMT);
this.leaksForm.controls['Remark'].setValue(leaks.Remark);
this.leaksForm.controls['Repairer'].setValue(leaks.Repairer);
this.leaksForm.controls['Image'].setValue(leaks.Image);
this.leaksForm.controls['Status'].setValue(leaks.Status);
});
}
CreateLeaks(leaks: Leaks) {
if (this.leaksIdUpdate == null) {
this.leaksService.createLeaks(leaks).subscribe(
() => {
this.dataSaved = true;
this.toastr.success("Record Saved Successfully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
} );
} else {
leaks.Id = this.leaksIdUpdate;
this.leaksService.updateLeaks(leaks).subscribe(() => {
this.dataSaved = true;
this.toastr.success("Record Updated Successfully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
}); }
}
deleteLeaks(leaksId: string) {
if (confirm("Are you sure you want to delete this ?")) {
this.leaksService.deleteLeaksById(leaksId).subscribe(() => {
this.dataSaved = true;
this.toastr.warning("Record Deleted Succefully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
}); }
}
resetForm() {
this.leaksForm.reset();
this.massage = null;
this.dataSaved = false;
this.toastr.info("Form Succefully reseted");
}
leaks.ts:
export class Leaks {
Id:number;
Date:string;
Sn:string;
ShiftMI:string;
ShiftSMT:string;
Location:string;
Defect:string;
Side:string;
AoiResult:string;
Platform:string;
ModelSMT:string;
OperatorSMT:string;
Repairer:string;
Image:[];
Remark:string;
Status:string;
}
I would suggest you, use the File property in your C# model. Once you receive the image at backend (API) then convert it into the byte array and save it as where ever you want. I believe the trickiest part will be sending the image and the other properties from your angular application to Web API.
Here is an example. In your c# model
public partial class Leaks
{
// existing properties.
public IFormFile Image { get; set; }
}
Make sure you add using Microsoft.AspNetCore.Http; namespace in your class.
Angular application
export class Leaks {
// existing properties.
Image:File;
Remark:string;
Status:string;
}
I believe you must have fileupload in your html so for that you need to add onChange() event and assign file to Image property of your model or just create a variable in your componenet ex uploadedFile
fileChange(fileInputEvent: any) {
this.uploadedFile = fileInputEvent.target.files[0];
}
Now on onFormSubmit()
onFormSubmit() {
this.dataSaved = false;
const leaks = this.leaksForm.value;
leaks.Image = this.uploadedFile
this.CreateLeaks(leaks);
this.leaksForm.reset();
}
and for sending to server just create formdata object fill all properties as you declared in your backend object.
const formData = new FormData();
formData.append('Image', Leaks.Image, Leaks.Image.name);
formData.append('Remark', Leaks.Remarks);
-- and more properties
return this.httpClient.post<boolean>(url, formData);
In your API
[HttpPost]
public async Task<ActionResult<Leaks>> PostLeaks([FromForm]Leaks leaks)
{
// you must receive the file in leaks.Image.
// your logic to convert file to bytes.
}
I hope it helps.

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.

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

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...
}

Categories